所以我一直在研究托尼·莫里斯的Tic-Tac-Toe挑战。这些规则如下:
为玩编写一个API。不应该有任何副作用(或变量),在真正的。move函数将采用一个游戏状态,一个
Position,它将返回您自己编写的数据类型。必须支持以下函数(至少):move(如前所述)whoseTurn(返回哪个玩家的回合)whoWon(返回谁赢或如果平局)playerAt(如果有的话,返回处于给定位置的球员),以下必须是正确的:在游戏中调用move或whoseTurn是编译时错误,在尚未完成的游戏中调用whoWon是编译时错误,playerAt函数必须在完整游戏和游戏中都得到支持,祝您好运。
到目前为止,这就是我所得到的:
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 }
}到目前为止,我最关心的问题是:如何在不使用痛苦的排版/转换模式的情况下,作为客户来玩这个游戏?我的测试使用了这种方法:
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上显式地打印代码?也许用一个单字来理解?
发布于 2013-01-01 07:34:32
你为什么把胜利者的动作也延长了?
每一个移动对象与获胜状态之间的关系是什么?
sealed trait Move extends Winner发布于 2013-01-01 11:46:53
这不是对悬赏问题的回答。
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在董事会上是平等的。
https://codereview.stackexchange.com/questions/19940
复制相似问题