Skip to content

Instantly share code, notes, and snippets.

@BalmungSan
Created June 19, 2021 16:59
Show Gist options
  • Save BalmungSan/34fe0f544fb38896ff035e954586b184 to your computer and use it in GitHub Desktop.
Save BalmungSan/34fe0f544fb38896ff035e954586b184 to your computer and use it in GitHub Desktop.
Ammonite script to play Rock-Paper-Scissors
// 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