Created
January 24, 2011 05:45
-
-
Save brianhsu/792885 to your computer and use it in GitHub Desktop.
[Scala] 剪刀石頭布猜拳大亂鬥
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Answer(val id: Int) | |
case object Rock extends Answer(0) {override def toString = "石頭"} | |
case object Paper extends Answer(1) {override def toString = "布"} | |
case object Scissor extends Answer(2) {override def toString = "剪刀"} | |
case class User(x: Int, score: Int = 20) | |
case class Turn(user: User, answer: Answer) | |
object Game { | |
val answers = Array(Rock, Paper, Scissor) | |
/** | |
* 開始進行某一局 | |
* | |
* @param turn 某一局所有人出的拳 | |
* @return 該局結束之後,存活下來的人 | |
*/ | |
def playTurn(turn: List[Turn]) = { | |
// 將所有人出的拳印出 | |
turn.foreach { x => println ("%s 出 %s" format(x.user, x.answer)) } | |
// 判定該局勝負 | |
judge(turn) | |
} | |
/** | |
* 判斷某一局的勝負 | |
* | |
* 判斷條件: | |
* | |
* - 如果該局出現的拳種數目為 1(大家都出一樣)、3(剪刀、石頭、布都有出現),則該局平手 | |
* - 如果該局出現的拳種數目為 2,以窮舉法判定輸贏 | |
* - 贏的人分數加 10 | |
* - 輸的人分數扣 10 | |
* - 該局結束後分數為 0 的人出局,不再列入參賽者清單 | |
* | |
* @param turn 某一局所有人出的拳 | |
* @return 該局結束之後,存活下來的人 | |
*/ | |
def judge (turn: List[Turn]) = turn.map(_.answer).toSet.size match { // 所有人的拳種數量如果 | |
// 是一或三就平手 | |
case 1 | 3 => | |
println ("全部平手") | |
turn.map(_.user) | |
// 是二就進行輸贏判定 | |
case 2 => | |
val group = turn.groupBy(_.answer).toList // 將使用者依他們出的拳種分組 | |
.sortWith(_._1.id < _._1.id) // 並依照拳種的 ID 排序 | |
// 用窮舉法找出贏的組別和輸的組別 | |
val (winner, loser) = group match { | |
// 石頭對布、石頭對剪刀 | |
case List((Rock, lose @ _), (Paper, win @ _)) => (win.map(_.user), lose.map(_.user)) | |
case List((Rock, win @ _), (Scissor, lose @ _)) => (win.map(_.user), lose.map(_.user)) | |
// 布對剪刀、布對石頭 | |
case List((Paper, lose @ _), (Scissor, win @ _)) => (win.map(_.user), lose.map(_.user)) | |
case List((Rock, lose @ _), (Paper, win @ _)) => (win.map(_.user), lose.map(_.user)) | |
// 剪刀對石頭、剪刀對布 | |
case List((Scissor, lose @ _), (Rock, win @ _)) => (win.map(_.user), lose.map(_.user)) | |
case List((Scissor, win @ _), (Paper, lose @ _)) => (win.map(_.user), lose.map(_.user)) | |
} | |
def forWin(user: User) = user copy (score = user.score + 10) // 加玩家十分 | |
def forLose(user: User) = user copy (score = user.score - 10) // 扣玩家十分 | |
val updateWinner = winner.map(forWin _) // 贏家全加十分 | |
val updateLoser = loser.map(forLose _) // 輸家全扣十分 | |
// 印出該局狀態 | |
updateWinner.foreach (user => println (user + " 贏了")) | |
updateLoser.foreach (user => println (user + " 輸了")) | |
updateLoser.filter(_.score <= 0).foreach (user => println (user + " 退場")) | |
// 存活的人:贏家再加上分數還沒被扣到 0 分的輸家 | |
updateWinner ++ updateLoser.filter(_.score > 0) | |
} | |
/** | |
* 遊戲結束 | |
*/ | |
def endGame(players: List[User]) = { | |
println ("=============") | |
println ("遊戲結束,以下為存活者及其積分:") | |
// 依分數排序後印出 | |
players.sortWith(_.score > _.score).foreach {println _} | |
} | |
/** | |
* 亂數取他某使用者出的拳 | |
* | |
* @param user 哪個使用者 | |
* @return 該使用者那一局的策略 | |
*/ | |
def getUserAnswer(user: User) = { | |
val answerIndex = ((scala.math.random * 10) % 3).toInt | |
Turn(user, answers(answerIndex)) | |
} | |
/** | |
* 開始遊戲 | |
* | |
* @param n 倒數第 n 次 | |
* @param players 此局參與的玩家 | |
*/ | |
def startGame(n: Int, players: List[User]): Unit = n match { | |
case 0 => endGame(players) // 時間到 | |
case x if players.length == 1 => endGame(players) // 只剩一個,冠軍產生 | |
case x => | |
println ("============ 倒數第 %d/%d 次 =========" format(x, turnNumber)) | |
// 取得每一個人出的拳 | |
val turn = players.map {user => getUserAnswer(user)} | |
// 進行此局,並取得下一局仍然存活的玩家 | |
val nextTurnPlayers = playTurn(turn) | |
startGame (n-1, nextTurnPlayers) | |
} | |
} | |
val turnNumber = 50 // 玩幾輪 | |
val playerNumber = 5 // 幾個玩家 | |
val players = (1 to playerNumber).map(User(_)).toList // 初始化玩家 | |
Game.startGame(turnNumber, players) // 開始猜拳大亂鬥 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment