package playground import scala.annotation.tailrec import scala.io.StdIn import scala.util.Random trait Action { def actionType(): String } case class GuessAction(wasRight: Boolean, result: String) extends Action { override def actionType(): String = "GUESS" } case class GameState(tries: Int, wins: Int, lastResult: String, continue: Boolean = true) object GameState { def update(state: GameState, action: Action): GameState = action match { case GuessAction(true, result) => state.copy(tries = state.tries + 1, wins = state.wins + 1, lastResult = result) case GuessAction(false, result) => state.copy(tries = state.tries + 1, lastResult = result) case _ => state } } object PlayerInteraction { def inputOption(): String = StdIn.readLine.toUpperCase } object GameInterface { def showPrompt() = print("\n(h)eads, (t)ails or (q)quit? ") def showState(state: GameState) = println(s"tries: ${state.tries}, wins: ${state.wins}") def showAttemptResult(wasRight: Boolean) = if(wasRight) println("Yes! You guessed it!") else println("Sorry! You're wrong") def showGameOver(state: GameState) = { println("================") println("Game Over") println("================") } } object Game extends App { def start = gameLoop(GameState(0, 0, "", true), Random) @tailrec def gameLoop(state: GameState, random: Random): Unit = { // Shows the prompt GameInterface.showPrompt() // get user input (heads, tails or quit) val userOption = PlayerInteraction.inputOption() // Check user input userOption match { case "H" | "T" => { val side = flipCoin(random.nextInt(2)) val rightGuess = isGuessRight(userOption, side) val action = if(rightGuess) new GuessAction(true, side) else new GuessAction(false, side) val nextState = GameState.update(state, action) guessResult(nextState, rightGuess) gameLoop(nextState, random) } case "Q" => endGame(state) case _ => gameLoop(state, random) } } def isGuessRight(playerGuess: String, side: String) = playerGuess == side def guessResult(state: GameState, wasRight: Boolean) = { GameInterface.showAttemptResult(wasRight) GameInterface.showState(state) } def endGame(state: GameState) = { GameInterface.showGameOver(state) GameInterface.showState(state) } def flipCoin(value: Int): String = value match { case 0 => "H" case 1 => "T" case _ => "?" } Game.start }