Created
June 19, 2021 16:59
-
-
Save BalmungSan/34fe0f544fb38896ff035e954586b184 to your computer and use it in GitHub Desktop.
Ammonite script to play Rock-Paper-Scissors
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
// scala 2.13.6 | |
sealed trait RockPaperScissorsMove extends Product with Serializable | |
object RockPaperScissorsMove { | |
final case object Rock extends RockPaperScissorsMove | |
final case object Paper extends RockPaperScissorsMove | |
final case object Scissors extends RockPaperScissorsMove | |
} | |
trait Game { | |
def play(bestOf: Int): Game.State | |
} | |
object Game { | |
import RockPaperScissorsMove._ | |
final type Score = Int // Refined NonNegative | |
final type Round = Int // Refined Positive | |
final case class State(currentRound: Round, player1Score: Score, player2Score: Score) { | |
def playRound(player1Move: RockPaperScissorsMove, player2Move: RockPaperScissorsMove): State = | |
(player1Move, player2Move) match { | |
case (Rock, Scissors) | (Paper, Rock) | (Scissors, Paper) => | |
this.copy(currentRound = currentRound + 1, player1Score = this.player1Score + 1) | |
case (Scissors, Rock) | (Rock, Paper) | (Paper, Scissors) => | |
this.copy(currentRound = currentRound + 1, player2Score = this.player2Score + 1) | |
case _ => | |
this.copy(currentRound = currentRound + 1) | |
} | |
} | |
trait GameExecutor { | |
def newRound(): (RockPaperScissorsMove, RockPaperScissorsMove) | |
def reportRound(roundState: State, player1Move: RockPaperScissorsMove, player2Move: RockPaperScissorsMove): Unit | |
def reportEndGame(finalState: State): Unit | |
} | |
def apply(gameExecutor: GameExecutor): Game = new Game { | |
override def play(bestOf: Round): State = { | |
@annotation.tailrec | |
def loop(currentState: State): State = | |
if (currentState.currentRound >= bestOf) currentState | |
else { | |
val (player1Move, player2Move) = gameExecutor.newRound() | |
val newState = currentState.playRound(player1Move, player2Move) | |
gameExecutor.reportRound(roundState = newState, player1Move, player2Move) | |
loop(newState) | |
} | |
val finalState = loop(currentState = State(currentRound = 0, player1Score = 0, player2Score = 0)) | |
gameExecutor.reportEndGame(finalState) | |
finalState | |
} | |
} | |
def playerVsComputer(playerName: String): Game = | |
Game(new GameExecutor { | |
override final def newRound(): (RockPaperScissorsMove, RockPaperScissorsMove) = { | |
import scala.util.Random | |
import scala.io.StdIn | |
val computerMove = Random.shuffle(Rock :: Paper :: Scissors :: Nil).head | |
println(s"${playerName} pick an option!") | |
println("1: Rock") | |
println("2: Paper") | |
println("3: Scissors") | |
val playerMove = StdIn.readInt() match { | |
case 1 => Rock | |
case 2 => Paper | |
case 3 => Scissors | |
} | |
(playerMove, computerMove) | |
} | |
override final def reportRound(roundState: State, player1Move: RockPaperScissorsMove, player2Move: RockPaperScissorsMove): Unit = { | |
println(s"Player 1 move: ${player1Move}") | |
println(s"Player 2 move: ${player2Move}") | |
println(s"Round state: ${roundState}") | |
} | |
override final def reportEndGame(finalState: State): Unit = { | |
println(s"Final state: ${finalState}") | |
} | |
}) | |
} | |
object App { | |
def run(): Unit = { | |
Game.playerVsComputer(playerName = "BalmungSan").play(bestOf = 5) | |
} | |
} | |
@main | |
def main(): Unit = { | |
App.run() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment