通用词汇

通用词汇是专业学科的基本要素。
《PMI 项目管理术语词典》[4] 收录了基本的专业词汇,供组织、项目组合、项目集和项目经理及其他项目相关方统一使用。
《术语词典》会随着时间的推移而更改。
本指南的词汇表包含了《术语词典》中的词汇以及其他定义。
项目可能会采用由行业文献定义的相关行业特定的术语。

道德与专业行为规范

PMI 发布了《道德与专业行为规范》[5],为项目管理专业人员增强了信心并帮助个人做出明智的决策,尤其是在面对被要求违背正直诚信或价值观的困境时。
全球项目管理业界定义的最重要的价值观是责任、尊重、公正和诚实。《道德与专业行为规范》确立了这四个价值观的基础地位。

《道德与专业行为规范》包括期望标准和强制标准。
期望标准描述了身为 PMI 会员、证书持有者或志愿者的从业者力求遵循的行为规范。
尽管对期望标准的遵循情况进行衡量并非易事,依照这些标准行事仍是对从业人员专业性的期待,并非可有可无的要求。
强制标准做出了硬性要求,在某些情况下限制或禁止从业者的某些行为。
身为 PMI 会员、证书持有者或志愿者以及不依照这些标准行事的从业者将受到 PMI 道德审查委员会的纪律处罚。

第一个python手写识别程序

我的第一个AI应用是参考实战:从0搭建完整 AI 开发环境写出第一个 AI 应用AI应用开发实战 - 从零开始配置环境两篇文章进行的实施,故以该文做出相应的补充。

遇到的问题

‘python’ 不是内部或外部变量

命令行执行python –version提示’python’ 不是内部或外部变量,在命令行中输入

1
set PATH="C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64";%PATH%

之后,再输入

1
python --version

输出版本为3.6.5
但是关闭命令行之后,再输入python –version时,依旧提示 ‘python’ 不是内部或外部变量
故在计算机→属性右键→高级系统设置→环境变量→选择PATH→点击新建→将C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64添加→确定,之后再运行python –version,显示正常。

saved_model.pb路径不对

单独参考第一篇文章进行配置时,发现没有samples-for-ai\export\saved_model.pb这个路径。
原因是没有启动examples\tensorflow\TensorflowExamples.sln这个解决方案,将MNIST项目设置为启动项目并运行,则会有samples-for-ai\export\saved_model.pb这个文件了。

命令行无响应

安装scipy-1.1.0mxnet_cu90-1.2.0时,命令行一直无响应,解决方案是到scipy-1.1.0mxnet-cu90 1.2.0下载指定的文件,然后通过pip3命令来执行安装,其余问题也可以通过类似命令来解决。

1
2
pip3 install D:\scipy-1.1.0-cp36-none-win_amd64.whl
pip3 install D:\mxnet_cu90-1.2.0-py2.py3-none-win_amd64.whl

通过下载的文件可以得知,文件较大,命令行无法及时完成下载,所以需要有一定的耐心等待

注意需要将C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\Scripts添加到PATH变量中。

cudnn版本不对

现在官网https://developer.nvidia.com/cudnn提供的cudnn版本是7.4.1,而微软示例代码中的cudnn版本是7.0.3,高版本的cudnn也会导致编译失败,需要找低版本的7.0.的cudnn替换到*C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\bin\cudnn64_7.dll

运行结果

解决了这部分问题之后,能正常展示winform界面,运行结果如下:
正确识别
错误识别
该部分涉及到训练模型是否足够多的问题,该文不做深入的研究。

总结

参考资料中提及的两篇文章都已经是做手写识别非常好的入门资料,该文仅仅是对这两篇文章做一个相应的补充,以作备忘。
另外我希望早日掌握以下技能

识别开心消消乐的游戏界面,然后通过能够确定执行的最佳下一步,达到这个目的,我觉得我对人工智能的了解和我的AI编程就进入了新的层次了。

#参考资料

休假之我思

在11月初的时候,预估了项目的进度,提出了月底休假四天的申请;为了让这次休假顺利进行,优化了跨团队的一些沟通成本,将一些自己手头上别人可以胜任的工作分配出去,结合昨日的最终产出来看,基本上做到公司有我和我没有一个样。
上周我休假了四天,原意是术业专攻,好好练车,没想到这件事情竟然还有了一些意外收获。这期间比较受关注的社会新闻是网易的暴力裁员和高以翔的猝死事件。基本上讲的是过劳。我这个假期中基本上都是12点前睡觉,7点多自然醒。因为不慌不忙的生活节奏,看了几本书,甚至还做了一些可能自己才能吃的面条和午饭。和十一假期比起来,因为十一要张罗搬家之后的添置物件等事项,这个假期显得更加轻松自在。
昨天朋友跟朋友聊天的时候,要她给我出个题,写一写命题作文。她要我针对下图做一个看图作文

暴力裁员

这图上,已经有各种哈姆雷特,不一一评论。里面有”是不是有必要认识一些大V,以备不时之需”这一句话,让我有些感触。以下我浅谈对这句话的理解。
我有一个姑姑,她无比操心我的婚事:
18年的大年30日,带我去相亲看了一个吴姓的妹子。那时候我是个200斤的胖子,结果可想而知。
19年的九月30日,吴姓妹子的奶奶给我姑姑推荐在珠海工作的一个姑娘,后来因为我个人觉得不合适,就没有了后文。
19年的十月30日,我姑姑给我介绍了一个在长沙的超级超级好看的姑娘,身高170,在上市公司工作,有些美好到虚幻。
19年的冬月30日,吴姓妹子的奶奶(请注意这是个连续剧)又给我做媒,说在深圳有个姓易的姑娘,这个还没有任何开始。
我姑姑估计是做过项目管理,每月的月底都给一个月度相亲计划,不成功就下一个项目计划,不允许项目延期迟迟不交付。回到正题,我姑姑就像是相亲届的大V,但是她这种热衷于相亲的事情估计也就对我如此上心,矫情一点的讲,这就是爱啊。如果不能从我这里获得一点爱的成就感,热脸贴到冷屁股上面,又何必如此上心。
换个角度来讲,我姑姑这个相亲大V有各种资源,比如长沙,深圳,珠海等各地的资源,甚至她还能通过资源扩展资源。奈何我自己不争气,不能好好珍惜大V提供的资源。大V再有能耐也无事于补嘛。
无论是工作,还是生活,如果本身的实力不允许,大V的再怎么协助也只能协助一时,寄希望于大V来协助解决问题终究有点本末倒置的感觉。喜欢和员工称兄道弟的大V刘强东在网易暴力裁员事件爆出来以后声明京东员工遭遇不幸的话 将负责子女费用到22岁。总不能为了免去子女22岁之前的费用还让自己遭遇一个不幸吧?正常作息、健康饮食、锻炼身体、枸杞人参,保证高的生活质量,提高工作效率,劳逸结合降低不幸的发生几率,让自己成为真正的大V,这才是幸福生活应该做的事情。
这个八天长假即将过去,不敢说我的失眠症状已经完全好了。但是很明确的是无论是工作还是生活,事情都在好转,渐渐地多了一些有条理的感觉。深化和储备在一步一步的推进,这就是生活中值得欣喜的地方。

红颜蓝颜

红颜

每当听到红颜这个词,我容易联想到关公,也容易想到红颜薄命。
红颜,某种层面上来讲就是朋友之上,恋人未满。娶了白玫瑰,红的就成了心口上的一颗朱砂痣。
我没有红颜,只有——我就要读研毕业了,“你来我学校陪我吃谢师宴吧”的雪姐。
我没有红颜,只有——我在某某地方旅游,谁需要明信片的学妹。我还厚着脸皮问人家要的那种。
我没有红颜,只有——大学毕业前三天才认识的倩姐,作为公务员,为人民服务,传授于我一些与人相处之道。
我没有红颜,只有——周末有空没,过来帮我弄个看房名额,我请你吃饭的女汉子。
我没有红颜,只有——你妈做的酸枣糕真好吃,带点到长沙来,来我家吃饭吧,我跟你买的徒弟。
我没有所谓的红颜,只有一些哪里有好吃的,好喝的,好玩的就惦记着我的异性朋友,然而我就是这样胖起来的。

蓝颜

蓝颜,另一角度的朋友之上,恋人未满。
我不是蓝颜,只是有数学老师跟我说——出了地铁那一刻莫名其妙地想哭。
我不是蓝颜,只是有家庭主妇跟我说——家里突生变故,能否给予一些经济帮助。
我不是蓝颜,只是有敬业同事跟我说——我只是觉得别人做得都比我好,我应该做得更好。
我不是蓝颜,只是有相亲对象跟我说——我觉得你人挺优秀的,很绅士,幽默,但是我确实没有什么感觉和想法。

后记

我是一个头脑简单的人,只有冰(路人),水(朋友),水蒸气(恋人)三种状态。如果进入冰点,或者沸点。这种状态也不会长久,换句话说就是于我而言,没有永久的红颜,或者永久的蓝颜这种状态,详情参见热力学定律。

两个人相遇,只要三观不过于奇葩,既不易完全成为路人,也不易一下子就沸腾起来变成水蒸气。总得有个通过相处加热的过程。所谓的顺其自然,只不过是在说“你看这酒精灯里面的灯芯我还在让它燃着了,最后沸不沸腾就看造化了。”
红颜也好,蓝颜也罢。我即不批判也不反感,只是觉得这不是一种稳定状态。找个人好好恋爱,好好结婚就好了嘛~

补充说一句:杨紫与张一山,黄晓明与赵薇,何炅与谢娜是有着革命友谊的亲人。

闲谈权游

小恶魔、小指头、小玫瑰、小剥皮、二丫、三傻、龙母、火吻、弑君者、色后、灰虫子、猫姨、肉山、猎狗、红袍女、核桃大帝、乔大帝、托曼大帝、阿多(瓦德)、臭佬、巨人克星、大美人、闪电大王……,这部拥有超多绰号的美剧《权利的游戏》终于迎来了它的终结。
我就不对剧中喜欢的角色来做分析和讨论了,我就对冰与火之歌改编成权游这件事情做一点自己的分享。
2DB(权游的编剧)在阅读了《冰与火之歌》这个伟大的史诗魔幻巨作之后,看重了其中的无限商机,就找到还年轻的乔治马丁老爷子说想把书拍成电视剧,马丁老爷子就问他们”琼恩·雪诺”的母亲是谁,这两个被吐槽脱离原著加持,便毫无创作力可言的两编剧还真答出来了,最终确定了拍成电视剧的想法,并经过优秀的特效团队的后期,以及演员的精湛表演,才给我们奉献上了高清无码的大片(Ice And Fire又译Fxxk and Kill)。试想若是他们答不出来,就不会让剧迷们看到这么让人无奈的第八季了。
为什么第八季这么让人不满意?因为《冰与火之歌》这本书还停留在琼恩·雪诺被捅了四刀那一段。之后剧情中的故事全部由2DB两个编剧基于已有故事情节进行人物的重构以及剧情的再创作。
那为什么《冰与火之歌》最后两卷《凛冽的寒风》和《春晓的梦想》这么难产?马丁老爷子曾说过:

“这几年我一直在努力去写,《凛冽的寒风》虽然只是小说中的第六卷,但是比一部小说还难些,简直是好多部小说,每一部都有一个主人公视角,还相应搭配着互不相同的一整套的队友、敌人、盟友、支持者,而所有这些又互相关联,关系交织在一起成了一张特别复杂的关系网络,牵一发而动全身,所以写到现在这个程度, 还要继续往下写就非常具有挑战性了。相对而言,外传《血火同源》就显得很容易写,并不是简单,这本书也花了我几年才完成,但是相对得心应手。”

换个软件行业的角度来讲,这不就是一个写了20多年的高度耦合的软件系统越来越难以维护了么?剧迷们看到波德瑞克和詹德利都分不清,更何况剧中牵扯不清的人物关系,一个人是哥哥,又是儿子他爸。一会是阿莲.石东,一会是三傻。要从各个POV视角中厘清各个人物关系以及地图背景需要对原著通读好几遍然后才行。书中可以突然某一段冒出一个珍妮.普尔(局部变量)作为珊莎的侍女嫁个小剥皮,而电视剧不能这么拍,人物的出场必须得有一些前因后果。所以剧情会根据演员的情况,以及一些不可抗拒的因素做一些相应的调整,权力的游戏本身就很黄暴,而书更加黄暴,所以猫姨死后在水里泡了三天三夜被闪电大王复活的情节基本上从电视视觉上一开始就注定被人看不到了。既然电视剧是对书的二次创作,所以就根本不可能完完整整对书进行重现。
因为最终还有原著的编剧的加持,所以对前五季整个剧情的走向并不会太偏。后面随着两个编剧(策划)对整个系统的进度的把控严重失误,强行dispose多恩线和高庭线,导致这个电视剧像被人咀嚼过一遍的甘蔗,全是渣。
两个编剧在面对庞大的演员阵容,高昂的演出费用和特效费用,在原有系统停滞不前,孤立无援地情况下,只好自作主张拿起笔杆,自己来写,结果导致了大量剧迷对第八季的强烈不满。像是一个优秀的系统在两个完全外行的人手里瞎折腾一番之后变成了一个烂尾作品。而这两个编剧就像是耗费2个多亿,耗时2年多,连一个可用的网站或者APP都没有交付出来的某某某咨询公司。
其实第八季不让人那么满意的原因并不能仅仅责怪那两个编剧,如果能预见马丁老爷子写书慢,多做一些风险控制,在马丁老爷子不务正业正传都没有写完去写前传的时候多跟马丁老爷子做一些整个人物框架的构建,多做一些人物分析,少做一些out of memory 或者Out Of Character的剧情,也许整个剧集就不至于崩坏得这么一塌糊涂。
开篇时,我就提到我不想讨论剧情,写到这里还是讨论一下夜王的死法。其实我挺认可这种表现形式的,就像是二战纪录片诺曼底登陆那一段,一个年轻人拿着枪在岸边冲,结果一下子就躺在那里一动不动了。抑或是电影“死于明日”和“天劫余生”里面表现的死亡形式一样,死亡就像是抽烟喝酒一样平常,如果夜王不被艾丽娅·史塔克的匕首捅死,难道非得被托尼·史塔克的响指带走才合理么?难道布兰突然站起来说,我是“逆闪”然后用“震波”解决掉夜王?剧中就凡人皆有一血的二丫是最终解决夜王的人做了居多铺垫,比如二丫和大美人对打那一段。在此不赘述。也不再吐槽两编剧在第八季第三集展示出来的军事才能了。
闲谈一下生活中的事情,像两个编剧没有原著加持这种釜底抽薪的事情也不少见,比如高通及其他美国的芯片供应商不再向华为供货,但是任正非们在几年前就意识到要做自己的核心处理器芯片,这种强烈的危机意识才不至于成为殃及池鱼中的那条鱼。就是别人的产品我可以借鉴,但是一定得弄到其原理,才不会受制于人,才可以做到青出于蓝而胜于蓝。自己不强大,可依赖的对象失去了的时候那就是苦日子到来的时候了。

重构技巧之添加参数

最近在经手一个Winform项目,里面有个需求:TreeView控件选择不同的TreeNode时,需要展示不同的右键菜单。记录一下重构过程。

需求

现将公司内部需求初始需求转换如下:
如果TreeView选中的TreeNode是国家,则右键菜单展示”添加省”,一个选项。
如果TreeView选中的TreeNode是省份,则右键菜单展示”添加市”,”删除”两个选项。
如果TreeView选中的TreeNode是城市,则右键菜单展示”添加区”,”删除”两个选项。
如果TreeView选中的TreeNode是区,则右键菜单展示,”删除”一个选项。
这部分的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var area = TreeView.SelectedNode.Tag as Area; //
if(area!=null)
{
var areaType=area.type;
ContextMenuStrip menuStrip = new ContextMenuStrip();
if(areaType==AreaType.国家)
{
menuStrip.Items.Add(new ToolStripMenuItem("添加省"));
}
if(areaType==AreaType.省份)
{
menuStrip.Items.Add(new ToolStripMenuItem("添加市"));
menuStrip.Items.Add(new ToolStripMenuItem("删除"));
}
if(areaType==AreaType.城市)
{
menuStrip.Items.Add(new ToolStripMenuItem("添加区"));
menuStrip.Items.Add(new ToolStripMenuItem("删除"));
}
if(areaType==AreaType.区)
{
menuStrip.Items.Add(new ToolStripMenuItem("删除"));
}

menuStrip.Show(e.Location);
}

后来业务发展了,除了AreaType.国家这个选项,右键菜单都需要添加一个”打开地图”的右键菜单,且位于右键菜单的最上方。
重构之后的示例代码变成了如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var area = TreeView.SelectedNode.Tag as Area; //
if(area!=null)
{
var areaType=area.type;
ContextMenuStrip menuStrip = new ContextMenuStrip();
if(areaType==AreaType.国家)
{
menuStrip.Items.Add(new ToolStripMenuItem("添加省"));
}
if(areaType==AreaType.省份)
{
menuStrip.Items.Add(new ToolStripMenuItem("打开地图"));
menuStrip.Items.Add(new ToolStripMenuItem("添加市"));
menuStrip.Items.Add(new ToolStripMenuItem("删除"));
}
if(areaType==AreaType.城市)
{
menuStrip.Items.Add(new ToolStripMenuItem("打开地图"));
menuStrip.Items.Add(new ToolStripMenuItem("添加区"));
menuStrip.Items.Add(new ToolStripMenuItem("删除"));

}
if(areaType==AreaType.区)
{
menuStrip.Items.Add(new ToolStripMenuItem("打开地图"));
menuStrip.Items.Add(new ToolStripMenuItem("删除"));
}

menuStrip.Show(e.Location);
}

这次需求变动,已经让我闻到了代码中的坏味道。增删改一个右键菜单需要修改好几处地方,删除右键菜单也是同理。
故需要对代码进行重构。

重构

提取函数,伪代码如下

1
2
3
4
5
6
7
8
private ContextMenuStrip menuStrip = new ContextMenuStrip(); //菜单转为私有属性
private void AddToolStripMenuItem(string controlName, bool isAdd)
{
if (isAdd)
{
this.menuStrip.Items.Add(new ToolStripMenuItem(controlName););
}
}

故调用处的实现代码变成了如下

1
2
3
4
5
6
7
8
9
10
11
12
var area = TreeView.SelectedNode.Tag as Area; //
if(area!=null)
{
var areaType=area.type;
this.menuStrip.Items.Clear();
AddToolStripMenuItem("添加省",areaType==AreaType.国家);
AddToolStripMenuItem("打开地图",!areaType==AreaType.国家);
AddToolStripMenuItem("添加市",areaType==AreaType.省份);
AddToolStripMenuItem("添加区",areaType==AreaType.城市);
AddToolStripMenuItem("删除",!areaType==AreaType.国家);
menuStrip.Show(e.Location);
}

若以后需求变更,打开地图需要改成打开百度地图,然后新增打开高德地图也只需要修改一行代码,并新增一行代码即可。

总结

该重构过程运用的是提取函数和函数添加参数。
AddToolStripMenuItem函数只关心菜单项是否添加,而不关心菜单项添加的逻辑是什么。
重构之后,右键菜单的可能的菜单项也一目了然,每一个菜单项对应的添加条件也一目了然。若isAdd参数对应的表达式过长,则可以将该表达式封装成函数进行传递。
通过该重构提高了项目的可维护性,也算是一种成就。

委托在重构中的运用

最近在工作中的一次重构过程中运用到了委托,记录一下。

场景

有一段示例代码如下

1
2
3
4
5
6
7
8
9
10
11
12
public class ProjectAClass
{
public static void CallMethod(bool isTrue)
{
if (isTrue)
{
ProjectB_StaticClass.DoSomething();
}
}

}

需求

后来因为业务的不断发展,需要把ProjectB从整个解决方案中移除掉。
ProjectB_StaticClassB.DoSomething();需要替换成 ProjectC_StaticClassC.DoSomething();
但是项目ProjectC需要引用ProjectA,故不能直接进行引用,否则会造成项目之间的循环依赖。

解决方案

ProjectAClass添加一个委托事件,CallMethod函数添加一个Dosometing dosometing的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ProjectAClass
{
public delegate void Dosometing();

public static void CallMethod(bool isTrue, Dosometing dosometing)
{
if (isTrue)
{
dosometing?.Invoke();
}
}
}

具体的调用代码处就变成了

1
ProjectAClass.CallMethod(true,()=>{ProjectC_StaticClassC.DoSomething();});

扩展

若ProjectAClass.CallMethod方法多地方出现,然而没有办法一下修改到位。可以通过参数默认值的方式来实现修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void CallMethod(bool isTrue, Dosometing dosometing=null)
{
if (isTrue)
{
if(dosometing == null)
{
ProjectB_StaticClass.DoSomething();
}
else
{
dosometing.Invoke(); // or dosometing()
}
}
}

该方法可以避免原来的调用方法进行大面积的修改。

总结

重构之后的代码ProjectAClass只需要判断条件是否满足,满足则dosometing,而不需要知道dosometing这个委托方法中具体细节。

游戏的乐趣

昨天跟朋友聊天,问他我的率土账号值多少钱了,他说应该值好几千块钱了吧。因为运气好和氪金,我招募了属性值了特别好的武将,然后因为个人时间关系一直都没有在玩,就委托给他在玩,他对这个账号爱不释手,他说他现在特别渴望来一个武将曹操,且这个游戏最有意思的就是武将搭配了。晚上闲来无事,顺便登陆了同样交给另外一个人搭理的一款游戏——英雄传奇,发现来了一个很久以前梦寐以求的英雄——李师师。
然而,这两个游戏却没有给我带来一种很强烈的愉悦感。

游戏为什么不好玩了?

痛苦的记忆

我表弟原本是一个王者荣耀的游戏迷,去年的时候拿我手机非得下载王者荣耀和我的网友对打,局局被虐,然后急上脸了还有再来一局,再来一局的。今天过年回家,问他怎么不玩王者荣耀了,然后他说没味,迷上了球球大作战,蛇蛇大作战之类的游戏。论游戏,王者荣耀的皮肤比蛇蛇大作战的皮肤要好看,操作也更加复杂,五连杀也更比蛇蛇大作战的五杀甚至百杀有意思得多,为啥不喜欢了?究其原因就是现在他想起这个游戏就会想起偷偷花了几千块钱买皮肤,然后被父母教育的事情。这个王者荣耀于他来讲是和一段不美好的记忆挂钩的,不玩就减少了回忆的可能性。

缺乏对游戏的喜好

我有一个同事特别喜欢玩欢乐斗地主,若一起吃饭,就能看见她拿着手机在玩欢乐斗地主。她玩这个游戏却兴趣盎然,在抢地主之后会心里默默念来个8,来个8,最终发现4个8都在上家手里,而且她只要有当地主的机会,则一定叫地主,抢地主。若是以前的话,我也喜欢玩斗地主,但是自从脑子抽风,算出斗地主有138712181744994种排列组合之后,看待斗地主这种游戏的态度就变了。若跟陌生人组成一个牌局,也就是138712181744994种斗地主组合方式中的一种而已,而且结局无外乎两种,要么赢,要么输,于我而言,因为觉得跟陌生人在网上斗地主没有多少精神上的满足,故基本上不再跟陌生人玩这种牌类游戏了。

游戏的固定模式

为什么王者荣耀会让这么多人都废寝忘食的玩个不停?个人觉得主要是加强了朋友之间的联系,然后每一局的可能性都比较多,最重要的一点,有些角色勤加练习就可以达到熟能生巧,起到了一个放松心情,减压的效果。个人并没有怎么玩过王者荣耀,技术比我表弟还要菜。我倒是玩过率土之滨和英雄传奇两种卡牌游戏,只不过现在这两个游戏都转交给我朋友去玩了。因为我运气比较好,两款游戏中比较主流的英雄武将我都拥有,故没有多少期待属性值特别特别厉害的武将,然后如果非得氪金去和别的网友比个高低,回报是远小于付出的。率土之滨相对好一点,基本上公平,充钱再多也不一定获得心仪的武将卡。而腾讯的游戏则不然,只要有钱就是大爷。VIP15基本上就是需要投资60万。充了钱的人通过使用李师师和虞姬组队在一起刷牌,然后虞姬还配上一个回春技能。基本上就是秒杀全场的节奏。玩家是希望通过游戏来减压,和放松自己的,而不是被各种氪金玩家虐待的。率土在于你充钱了,你也不是大爷。而英雄传奇就是你充的钱足够足够多,那就是大爷。光比谁砸的钱多的这种游戏对于普通玩家来讲个人放松的心理是得不到满足的。如果你们对我举例的这两款游戏不熟,那俄罗斯方块和贪吃蛇就是很好的固定模式的例子。

什么样的游戏才好玩?

千个读者有千种想法,我代表不了你们。我只表达一下我心目中的好游戏。

好游戏是有回报的

比如说我现在正在减肥,减肥是很痛苦的过程,因为它增加了个人欲望,我以前只想吃,不考虑瘦不瘦的事情。而现在,我既要想着吃,还要想着怎么吃和怎么瘦的问题。为什么要辜负长沙臭豆腐,炸鸡翅,牛肉丸,开心果,奶茶等等各种人世间的美好?如果把减肥当做一场游戏,就显得简单了许多。减肥成功的回报之一就是——再也不用担心踩在小树枝上会断,再大一点的奖励就是可以通过小树枝爬上从来没有征服过的猪头石顶部,更大的奖励就是整个人都脱胎换骨,可以去体验不一样的人生。

好游戏满足社交属性

球类游戏,狼人杀之类的桌游基本上都需要好几个人参加,在这些游戏中,虽然是你输我赢的结局,但是在你来我往的不同战术的交锋过程中促进了对团队之间不同人的理解。这也就是大学入校以来,宿舍第一件事情就是玩升级,从2打到A,玩到凌晨两点丝毫不困的原因。

好游戏满足人的成就感

蚂蚁庄园的登山赛游戏在某些人眼里看起来简单弱智,但是分数越高,然后可以兑换的奖品越多,最重要的一点,其具备的公益属性会满足一个人的积少成多和做出了奉献的成就感。

好游戏满足人的好奇心

纪念碑谷或地狱边境或者机械迷城等游戏都是很好的满足人类的求知欲或者好奇心的例子。限于篇幅不对其做具体介绍。

后记

若去问小孩子,他们一般都会觉得游戏会被读书有趣。学习并不见得一定是一件很枯燥无非的东西,如果这个读书满足了他的成就感,新鲜感,好奇心,让他交到了更多的朋友,这个学习便成为了一件有趣的事情。其余有趣的东西亦是如此。

参考资料

用Dictionary替换switch case的注意事项

最近试图重构一段现做现卖的祖传代码,结果改完之后,性能急速下降,下面给出示意代码的截图,以便提醒自己工作需要更加认真和细心。

示例代码

错误的重构

差异对比
Dictionary的执行时间竟然是Switch case的四倍以上?原因是啥?我们来看一下各个动物的构造函数
构造函数
即生成Dictionary的每一个键值对的值的时候,都实例化了一个Animal的子类,每个子类的实例化都等待了十秒钟,总实例化就耗费了40秒钟。

正确的重构

正确重构
先获取对象的type,然后通过Activator.CreateInstance(type)创建对象。

总结

switch case转换成dictionary算得上是一种重构,起到了减少代码量,提高可维护性的效果。
这次我的失误也算是明白了一个深刻的道理,所有的重构需要建立在完整的测试机制的前提下,否则可能会造成严重的损失。
最后一句箴言如无必要,勿动祖传代码