昨天我在Clojure Tic Tac Toe中实现了一项功能,用户可以选择与计算机对战。 这不是一个战略参与者(在此阶段),只是一个随机选择可用空间的参与者。
当我估计它时,我认为它会比较快。 这是我如何分解的:

为了乐观和现实,我给自己加了1分(一天半),对于悲观的估计,我给了自己2分(一整天)。 我认为将其分解为所需的所有步骤确实很有帮助。 如果只是随机移动,它可能会在20分钟内完成(包括研究时间),但是由于要使所有这些故事都可演示,因此这需要更多的工作。
如我所料,构建随机计算机播放器非常快,我发现困难的部分是设置多个播放器。
在面向对象的语言中,设置播放器非常简单。 我过去所做的就是创建一个标记为“ X”或“ O”的玩家对象(人或计算机),给他们一种转弯的方式,将其传递给游戏类,我们在我们的路上。
在没有对象或状态的功能语言中,它不太直接。 我绝对不知道我的解决方案是否是一个好的解决方案,但是它正在起作用,所以我将其视为胜利!
在app-runner.clj
(defn选择玩家[players] (输出/打印消息(输出/播放器类型(如果(空的播放器)“ X”“ O”)) (让[更新的玩家(玩家类型/选择玩家的玩家(玩家类型/选择玩家(输入/获取玩家))))] (如果(= 2(计数更新的玩家)) (游戏运行者[]个更新的玩家) (更新的玩家重复播放)))
- 用一个我称为
players
的空向量调用select-players
函数。 - 输出一条消息,要求用户为“ X”或“ O”选择播放器类型。 如果玩家是空的,它将在屏幕上打印“ X”,否则(这意味着我们有一个玩家)在屏幕上将显示“ O”。
- 获取用户的输入以选择播放器类型,将其放入新版本的
players
,并将此新向量称为“updated-players
。 - 如果向量中包含两个元素,则用一个空白向量(将是我们的棋盘)和此
updated-players
向量(其中的玩家类型为“ X”和“ O”)调用游戏运行者,否则递归再次呼叫select-players
,这一次我们传递了updated-players
。
在让玩家转弯时,我们执行以下操作:
(defn单回合[棋手] (让[玩家(当前玩家棋盘玩家)] (如果(=玩家:人类) (ttt板/转弯(人/选择空间)板) (ttt板/转弯板(随机计算机/选择空间板)板)))
- 用
board
呼叫single-turn
(按顺序移动的向量),并使用上述向量进行players
。 - 与
board
和players
呼叫current-player
players
,并将结果保存为player
。 当前的玩家检查已经进行了多少步-如果它是偶数,则使该玩家进入索引为零(’X’)的位置,否则为索引为1(’O’)的玩家。
(defn当前玩家[棋盘玩家] (如果(甚至?(计分板)) (让玩家0) (让玩家1)))
- 然后,我们将举动称为举动,而
board
唯一改变的是我们如何获得该举动。 - 我已尽我所能在这种方法调用中尽可能接近使用多态性-我对两种类型的播放器都有一个
take-turn
方法,并且已将其设置为调用human
或random-computer
的take-turn
功能可实现这一目标。
human
的样子是这样的:
(defn选择空间[] (输入/空间选择))(def转换 {“ A1” 0“ B1” 1“ C1” 2 “ A2” 3“ B2” 4“ C2” 5 “ A3” 6“ B3” 7“ C3” 8}) (defn space-selection [] (让[转换选择 (获取转化 (字符串/大写 (字符串/修剪 (阅读行)))) (如果(不是(非?转换选择)) 转换选择 (复发))))
random-computer
的外观如下:
(定义选择空间[板] (第n个(get-available-spaces board)))(defn get-available-spaces [board] (删除nil?(vec (对于[空格(范围9)] (如果(不是(部分(部分=空间)空间))空间)))))
最终,这花费了大约一个半点(一天的3/4),高于我的乐观和现实的估计,但低于我的悲观。 有趣的是,计算得出的估算值给了我1.5分-最终花了多长时间。