前一阵子吕震宇先生为我们创作了一系列的华容道游戏解题程序设计,里面的内容很精彩,尤其是算法性能方面给与我们很深刻的印象。我因此也禁不住诱惑,也像参和一下。不过我并不打算从算法的角度做更多的讨论,我要讨论的可能是另外一个角度,也许算是从程序结构方面的讨论。当然,我的想法也许还不是很成熟,有错误之处欢迎指正。
在开始之前,我想分享一段与写程序没有太大关系的经历。半个月前一次喝早茶的时间里面,我听到两个商人在谈生意,其中有两个地方最为有趣,内容大致如下:
……
A:请问你给我的计划里面提到的这个50多岁的人是不是一定要跟她打点关系才行?
B:嗯,是的。
A:那这个事情我不干了,没法干啊!
B:(惊慌失措状)为什么?这个关系不打点确实是不行的,在别的地方做的话也需要打点关系的。
A:打点关系没错,我做了这么多年也知道,在中国就得打点关系。可是如果你说非得要有这个50多岁的人,那我是没有办法做下去了。比如说我们跟他打点好关系了,但是他有什么变故突然又不干了,没有把车皮批给我们,我们的货怎么出去?或者如果他退休了,我们还干不干了?
B:哦,这个不一定是非要跟这个人打点关系,只要跟这个“公司”里面的相关人员打点关系就可以了。只是说这么多人里面这个人最可靠。
A:这就对了嘛,只要能够找到相关人员,为什么非要跟这个人不可呢?不就是找这个“公司”的人吃吃喝喝嘛,这个我明白了。
……
A:行,这个事情就这么说定了。不过我有一个建议,最好跟老板谈的时候,不要谈那么多的细节。我跟你老朋友了没关系,要是其他老板听你说,一会儿要先要在天津成立一个公司,人家说好这个没问题,然后你再说不行,还要跟某某某打点关系,再一会儿又是别的什么事情。人家会觉得,哇,怎么这么多的事情,好烦啊!算了这个生意不做了,为什么?搅糊涂了呗。其实谈生意不就是,我给你钱,你给我保证一二三四点。比如你保证货物能够按时按计划给我发出,那不就成了吗?至于那些成立什么公司,找什么人,那些问题只要你能够解决,或者你告诉我有办法解决哪怕要我来做,就可以了,没必要再谈成生意之前说这么多的细节。
B:是是……
……
这段对话之所以让我觉得有趣,是因为这个正好对应了程序开发里面的两个很关键的问题。前者是面向抽象的设计思路,后者是则是职责要分明(并且是单一职责)。如果说上面的对话放到华容道商业应用的项目开发小组里面,看起来又会是怎么样的呢?下面由我这个见习程序员和我的项目经理Frank来主演。
Frank:Sumtec,现在我们有一个游戏项目,是关于战旗类游戏的。我们首先做一个简单的演示,要求能够由计算机解题。我想也许做一个华容道比较简单,因为这个游戏只要一个参与者就可以了,算法我想也没有那么复杂对吧?你对做这个华容道有什么看法,或者说你打算怎么开始?
Sumtec:哦,华容道还行,我想算法就是广优
Frank:嗯,很好,那……
Sumtec:既然用到广优的话,我们就需要一个树型数据结构……
Frank:这个……
Sumtec:噢!也许需要一个复杂一点的,搜索的每一层需要有一个特殊的结构,比如单项或者双向链表,好帮助我们进行广优的搜索,更正要的是让我们知道我们搜索到哪一层了。(看,已经在讲解细节了。)
Frank:那个……
Sumtec:哈,对了,为了避免重复搜索,我们需要一个哈希表(Frank已经在搜肠挂肚的想,哈希表?哈气?打喷嚏?),来记录已经搜索过的情况,也就是剪枝……
Frank:(作挠头痛苦状)等等,为什么一定要用哈希表?用平衡二叉树或者堆栈可以吗?(其实Frank正在担心的是,为什么写一个游戏非得依赖于一个具体的哈希表?至少这不是一开始要关心的内容。)
Sumtec:这是因为……
Frank:得了,你也不多说,赶紧给我弄一个简单的代码出来看看,你打算怎么开始。
Sumtec:好吧。心想:哎,为什么不愿意听我说完呢?(其实Frank的职责并不关心这个,只要你告诉他没问题就差不多了,虽然还可以说一些对于他来说更加动人的话。)
奋战了一个小时之后,Sumtec已经组织了一堆的棋子、棋盘、链表、哈希表、二叉或者n叉树,棋子又派生出各种各样的棋子等等。当然了,纵使是盖茨先生亲自操刀,要一个小时之内作出一个正确解题的华容道程序,是不太可能的事情。Sumtec当然更糟糕,不要说能够正确解题,连正常运行都还没有搞定,因为组装工作还没有开始。偏偏这个时候Frank来问话了:
Frank:怎么样?让我看看?
Sumtec:还早呢……
Frank:哦,不不不,这不对。
Sumtec:怎么不对了呢?
Frank:我先问你一个问题,难道你打算就这么组装一堆的二叉树链表哈希表以技数组,使他们成为你的华容道游戏?
Sumtec:对啊!算法需要这些东西。
Frank:哦,见鬼,这肯定不是我想象中的东西,但是我也不知道怎么说。
Sumtec:(心里面冒出来那句台词:Sumtec很生气,后果很严重)你说不对,但是又不知道怎么做,那我该怎么办?
Frank:呵呵,我不会炒鸡蛋,但是看了你打算这么做的这碟炒鸡蛋就没有胃口。具体怎么办你找Jack,看他有什么建议。
Sumtec:噢,那好吧。没有其它问题了?
Frank:有!刚才那个问题其实我不关心,我只是顺便问问。我想知道的是,你打算怎么开始这个工作?我想是不是应该这样的:
(Frank在白板上面写:)
game = new HuaRongDaoGame();
game.Player = new MyComputerPlayer();
game.Play();
MessageBox.Show(game.IsWin); // 或者MessageBox.Show(game.Records)
Frank:你看,我们需要一个游戏对吗?这个游戏要有一个玩家,对吗?然后需要开始玩,没错吧?游戏结束了总要有一个结果,对不对?
Sumtec:嗯……嗯……嗯……嗯……(思考当中……)
Sumtec:可是我想的是这样的(也在白板上面写起来:)
layout = LayoutFactory.CreateModelOne(); // 这里已经把棋子摆进去了。
queue = new MyTreeQueueCollection(); // 这个用于广优算法里面记录每一层的所有可能的走法。
hashtable = new Hashtable(); // 这个用于记录重复的情况。
Resolve(layout); // 这个是一个广优的算法。里面通过while来完成循环求解……
(Sumtec还没有写完,Frank已经几乎要晕过去了)
Frank:不不不,这肯定不对。我们的游戏到哪里去了?参与的玩家跑哪里去了?
Sumtec:这不就是一个游戏吗?Resolve就是一个电脑玩家,也许就是你所说的那个MyComputerPlayer。
Frank:或者这样说吧,如果我们决定不用广优解题,比如用“窄优”(这个Frank也确实比较白吃,应该是深优),你打算怎么修改你的代码?
Sumtec:这个……
Frank:如果我们打算让一个真实的人参与这个游戏,你又打算怎么修改你的代码?
Sumtec:那个……
Frank:再比如说我们现在要把游戏换成象棋,你又打算怎么办呢?
Sumtec:呃……
Frank:也许我的想法也不正确,我对这方面其实也不懂,你去问问Jack吧,看他怎么说。你怎么做我不管,只要最后能够交差就行了。
这个时候Sumtec像打翻了五味瓶,只好去问他敬仰的Jack,看他怎么说。(待续)
在开始之前,我想分享一段与写程序没有太大关系的经历。半个月前一次喝早茶的时间里面,我听到两个商人在谈生意,其中有两个地方最为有趣,内容大致如下:
……
A:请问你给我的计划里面提到的这个50多岁的人是不是一定要跟她打点关系才行?
B:嗯,是的。
A:那这个事情我不干了,没法干啊!
B:(惊慌失措状)为什么?这个关系不打点确实是不行的,在别的地方做的话也需要打点关系的。
A:打点关系没错,我做了这么多年也知道,在中国就得打点关系。可是如果你说非得要有这个50多岁的人,那我是没有办法做下去了。比如说我们跟他打点好关系了,但是他有什么变故突然又不干了,没有把车皮批给我们,我们的货怎么出去?或者如果他退休了,我们还干不干了?
B:哦,这个不一定是非要跟这个人打点关系,只要跟这个“公司”里面的相关人员打点关系就可以了。只是说这么多人里面这个人最可靠。
A:这就对了嘛,只要能够找到相关人员,为什么非要跟这个人不可呢?不就是找这个“公司”的人吃吃喝喝嘛,这个我明白了。
……
A:行,这个事情就这么说定了。不过我有一个建议,最好跟老板谈的时候,不要谈那么多的细节。我跟你老朋友了没关系,要是其他老板听你说,一会儿要先要在天津成立一个公司,人家说好这个没问题,然后你再说不行,还要跟某某某打点关系,再一会儿又是别的什么事情。人家会觉得,哇,怎么这么多的事情,好烦啊!算了这个生意不做了,为什么?搅糊涂了呗。其实谈生意不就是,我给你钱,你给我保证一二三四点。比如你保证货物能够按时按计划给我发出,那不就成了吗?至于那些成立什么公司,找什么人,那些问题只要你能够解决,或者你告诉我有办法解决哪怕要我来做,就可以了,没必要再谈成生意之前说这么多的细节。
B:是是……
……
这段对话之所以让我觉得有趣,是因为这个正好对应了程序开发里面的两个很关键的问题。前者是面向抽象的设计思路,后者是则是职责要分明(并且是单一职责)。如果说上面的对话放到华容道商业应用的项目开发小组里面,看起来又会是怎么样的呢?下面由我这个见习程序员和我的项目经理Frank来主演。
Frank:Sumtec,现在我们有一个游戏项目,是关于战旗类游戏的。我们首先做一个简单的演示,要求能够由计算机解题。我想也许做一个华容道比较简单,因为这个游戏只要一个参与者就可以了,算法我想也没有那么复杂对吧?你对做这个华容道有什么看法,或者说你打算怎么开始?
Sumtec:哦,华容道还行,我想算法就是广优
Frank:嗯,很好,那……
Sumtec:既然用到广优的话,我们就需要一个树型数据结构……
Frank:这个……
Sumtec:噢!也许需要一个复杂一点的,搜索的每一层需要有一个特殊的结构,比如单项或者双向链表,好帮助我们进行广优的搜索,更正要的是让我们知道我们搜索到哪一层了。(看,已经在讲解细节了。)
Frank:那个……
Sumtec:哈,对了,为了避免重复搜索,我们需要一个哈希表(Frank已经在搜肠挂肚的想,哈希表?哈气?打喷嚏?),来记录已经搜索过的情况,也就是剪枝……
Frank:(作挠头痛苦状)等等,为什么一定要用哈希表?用平衡二叉树或者堆栈可以吗?(其实Frank正在担心的是,为什么写一个游戏非得依赖于一个具体的哈希表?至少这不是一开始要关心的内容。)
Sumtec:这是因为……
Frank:得了,你也不多说,赶紧给我弄一个简单的代码出来看看,你打算怎么开始。
Sumtec:好吧。心想:哎,为什么不愿意听我说完呢?(其实Frank的职责并不关心这个,只要你告诉他没问题就差不多了,虽然还可以说一些对于他来说更加动人的话。)
奋战了一个小时之后,Sumtec已经组织了一堆的棋子、棋盘、链表、哈希表、二叉或者n叉树,棋子又派生出各种各样的棋子等等。当然了,纵使是盖茨先生亲自操刀,要一个小时之内作出一个正确解题的华容道程序,是不太可能的事情。Sumtec当然更糟糕,不要说能够正确解题,连正常运行都还没有搞定,因为组装工作还没有开始。偏偏这个时候Frank来问话了:
Frank:怎么样?让我看看?
Sumtec:还早呢……
Frank:哦,不不不,这不对。
Sumtec:怎么不对了呢?
Frank:我先问你一个问题,难道你打算就这么组装一堆的二叉树链表哈希表以技数组,使他们成为你的华容道游戏?
Sumtec:对啊!算法需要这些东西。
Frank:哦,见鬼,这肯定不是我想象中的东西,但是我也不知道怎么说。
Sumtec:(心里面冒出来那句台词:Sumtec很生气,后果很严重)你说不对,但是又不知道怎么做,那我该怎么办?
Frank:呵呵,我不会炒鸡蛋,但是看了你打算这么做的这碟炒鸡蛋就没有胃口。具体怎么办你找Jack,看他有什么建议。
Sumtec:噢,那好吧。没有其它问题了?
Frank:有!刚才那个问题其实我不关心,我只是顺便问问。我想知道的是,你打算怎么开始这个工作?我想是不是应该这样的:
(Frank在白板上面写:)
game = new HuaRongDaoGame();
game.Player = new MyComputerPlayer();
game.Play();
MessageBox.Show(game.IsWin); // 或者MessageBox.Show(game.Records)
Frank:你看,我们需要一个游戏对吗?这个游戏要有一个玩家,对吗?然后需要开始玩,没错吧?游戏结束了总要有一个结果,对不对?
Sumtec:嗯……嗯……嗯……嗯……(思考当中……)
Sumtec:可是我想的是这样的(也在白板上面写起来:)
layout = LayoutFactory.CreateModelOne(); // 这里已经把棋子摆进去了。
queue = new MyTreeQueueCollection(); // 这个用于广优算法里面记录每一层的所有可能的走法。
hashtable = new Hashtable(); // 这个用于记录重复的情况。
Resolve(layout); // 这个是一个广优的算法。里面通过while来完成循环求解……
(Sumtec还没有写完,Frank已经几乎要晕过去了)
Frank:不不不,这肯定不对。我们的游戏到哪里去了?参与的玩家跑哪里去了?
Sumtec:这不就是一个游戏吗?Resolve就是一个电脑玩家,也许就是你所说的那个MyComputerPlayer。
Frank:或者这样说吧,如果我们决定不用广优解题,比如用“窄优”(这个Frank也确实比较白吃,应该是深优),你打算怎么修改你的代码?
Sumtec:这个……
Frank:如果我们打算让一个真实的人参与这个游戏,你又打算怎么修改你的代码?
Sumtec:那个……
Frank:再比如说我们现在要把游戏换成象棋,你又打算怎么办呢?
Sumtec:呃……
Frank:也许我的想法也不正确,我对这方面其实也不懂,你去问问Jack吧,看他怎么说。你怎么做我不管,只要最后能够交差就行了。
这个时候Sumtec像打翻了五味瓶,只好去问他敬仰的Jack,看他怎么说。(待续)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器