Clojure —随机计算机播放器

昨天我在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
  • boardplayers呼叫current-player players ,并将结果保存为player 。 当前的玩家检查已经进行了多少步-如果它是偶数,则使该玩家进入索引为零(’X’)的位置,否则为索引为1(’O’)的玩家。
  (defn当前玩家[棋盘玩家]
   (如果(甚至?(计分板))
     (让玩家0)
     (让玩家1))) 
  • 然后,我们将举动称为举动,而board唯一改变的是我们如何获得该举动。
  • 我已尽我所能在这种方法调用中尽可能接近使用多态性-我对两种类型的播放器都有一个take-turn方法,并且已将其设置为调用humanrandom-computertake-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分-最终花了多长时间。