首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tic-Tac-Toe API

Tic-Tac-Toe API
EN

Code Review用户
提问于 2012-12-26 12:34:48
回答 2查看 814关注 0票数 5

所以我一直在研究托尼·莫里斯的Tic-Tac-Toe挑战。这些规则如下:

为玩编写一个API。不应该有任何副作用(或变量),在真正的。move函数将采用一个游戏状态,一个Position,它将返回您自己编写的数据类型。必须支持以下函数(至少):move (如前所述) whoseTurn (返回哪个玩家的回合) whoWon (返回谁赢或如果平局) playerAt (如果有的话,返回处于给定位置的球员),以下必须是正确的:在游戏中调用move或whoseTurn是编译时错误,在尚未完成的游戏中调用whoWon是编译时错误,playerAt函数必须在完整游戏和游戏中都得到支持,祝您好运。

到目前为止,这就是我所得到的:

代码语言:javascript
复制
object TicTacToe2 {

  type Board = Map[Position, Option[Move]]

  sealed trait Winner
  case object Draw extends Winner

  sealed trait Move extends Winner
  case object X extends Move
  case object O extends Move

  sealed trait Position
  case object TL extends Position
  case object TM extends Position
  case object TR extends Position
  case object ML extends Position
  case object MM extends Position
  case object MR extends Position
  case object BL extends Position
  case object BM extends Position
  case object BR extends Position

  case class InProgress(override val board: Board) extends GameState(board) 
  case class Finished(override val board: Board) extends GameState(board) 

  sealed abstract class GameState(val board: Board) {
    override def toString = this.board.mkString("\n")
  }

  private val winningPatterns: Set[Set[Position]] = Set(Set(TL,TM, TR), Set(ML, MM, MR), Set(BL, BM, BR), 
  Set(TL, ML, BL), Set(TM, MM, BM), Set(TR, MR, BR), Set(TL, MM, BR), Set(TR, MM, BL))

  def whoseTurn(gameState: InProgress): Option[Move] = {
    val xs = gameState.board.count{ case (k, v) => v == Some(X) }
    val os = gameState.board.count{ case (k, v) => v == Some(O) }
    if (xs > os) Some(O) else if (xs < os) Some(X) else None
  }

  private def checkPlayerHasWon(gameState: GameState): Option[Winner] = {
    def hasPlayerWon(player: Move) = { 
      val playerPositions = gameState.board.filter { case (k, v) => v == Some(player) }.keys.toSet 
      winningPatterns.exists(wp => wp.subsetOf(playerPositions))
    }
    if (hasPlayerWon(X)) Some(X) 
    else if (hasPlayerWon(O)) Some(O)
    else if(gameState.board.count{ case (k, v) => v == None } == 0) Some(Draw) 
    else None 
  }

  def move(gameState: InProgress, position: Position, player: Move): GameState = {
    val tempGame = InProgress { gameState.board.updated(position, Some(player)) }
    checkPlayerHasWon(tempGame) match {
      case None => InProgress { tempGame.board }
      case Some(winner) => Finished { gameState.board }
    }
  }

  def playerAt(gameState: GameState, position: Position): Option[Move] = gameState.board.get(position).get

  def whoWonOrDraw(finishedGame: Finished): Winner = checkPlayerHasWon(finishedGame).get
}

object TicTacToeApplication2 {
  import TicTacToe2._

  def createGame = InProgress { List(TL, TM, TR, ML, MM, MR, BL, BM, BR).map((_, None)).toMap }
}

到目前为止,我最关心的问题是:如何在不使用痛苦的排版/转换模式的情况下,作为客户来玩这个游戏?我的测试使用了这种方法:

代码语言:javascript
复制
new BlankBoardTest {
  val newGameState: InProgress = move(gameState, TR, O).asInstanceOf[InProgress]
  val newGameState2 = move(newGameState, BM, X)
  newGameState2 match {
    case game @ InProgress(_) => {
      assert(playerAt(game, TR) === Some(O))
      assert(playerAt(game, BM) === Some(X))
    }
    case _ => fail
  }
}

看到那种类型的模式匹配了吗?是否有一种方法可以避免这样做,并将它们链接在一起,这样客户端就可以播放它们,而不必在gameState上显式地打印代码?也许用一个单字来理解?

EN

回答 2

Code Review用户

发布于 2013-01-01 07:34:32

你为什么把胜利者的动作也延长了?

每一个移动对象与获胜状态之间的关系是什么?

代码语言:javascript
复制
 sealed trait Move extends Winner
票数 2
EN

Code Review用户

发布于 2013-01-01 11:46:53

这不是对悬赏问题的回答。

代码语言:javascript
复制
 def whoseTurn(gameState: InProgress): Option[Move] = {
    val xs = gameState.board.count{ case (k, v) => v == Some(X) }
    val os = gameState.board.count{ case (k, v) => v == Some(O) }
    if (xs > os) Some(O) else if (xs < os) Some(X) else None
  }

对于一个正在进行中的游戏来说,它总是可以确定的。此方法不应返回可选类型。最后一行有个错误。这是第一个球员(X,我认为)转,如果没有X S和O S在董事会上是平等的。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/19940

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档