Skip to content

Instantly share code, notes, and snippets.

@jayhutfles
Last active January 30, 2021 19:44
Show Gist options
  • Save jayhutfles/858ac79529e368d5922171026f5cc3ca to your computer and use it in GitHub Desktop.
Save jayhutfles/858ac79529e368d5922171026f5cc3ca to your computer and use it in GitHub Desktop.
war
case class Player(name: String, deck: List[Int]) {
def play(n: Int): (Player, List[Int]) = (Player(name, deck.drop(n)), deck.take(n).reverse)
def add(pile: List[Int]) = Player(name, deck ++ pile)
}
trait GameState { val turn: Int }
case class Idle(p1: Player, p2: Player, turn: Int) extends GameState
case class AtWar(p1: (Player, List[Int]), p2: (Player, List[Int]), pile: List[Int], turn: Int) extends GameState
case class Done(winner: Option[Player], turn: Int) extends GameState
object WarGame {
import scala.util.Random
def run(gs: GameState): GameState = gs match {
case Done(_, _) => gs
case Idle(p1, p2, t) if (p1.deck == Nil && p2.deck == Nil) => Done(None, t)
case Idle(p1, p2, t) if (p1.deck == Nil) => Done(Some(p2), t)
case Idle(p1, p2, t) if (p2.deck == Nil) => Done(Some(p1), t)
case Idle(p1, p2, t) => AtWar(p1.play(1), p2.play(1), Nil, t+1)
case AtWar((p1, f1), (p2, f2), pile, t) if (f1.size > f2.size) => Idle(p1.add(pile ++ f1 ++ f2), p2, t)
case AtWar((p1, f1), (p2, f2), pile, t) if (f1.size < f2.size) => Idle(p1, p2.add(pile ++ f1 ++ f2), t)
case AtWar((p1, f1), (p2, f2), pile, t) if (f1.head > f2.head) => Idle(p1.add(pile ++ f2 ++ f1), p2, t)
case AtWar((p1, f1), (p2, f2), pile, t) if (f1.head < f2.head) => Idle(p1, p2.add(pile ++ f1 ++ f2), t)
case AtWar((p1, f1), (p2, f2), pile, t) => AtWar(p1.play(4), p2.play(4), pile ++ f1 ++ f2, t+1)
}
def apply(p1Name: String, p2Name: String): GameState = {
val shuffledDeck = Random.shuffle((2 to 14).toList.flatMap(c => List.fill(4)(c)))
val p1 = Player(p1Name, shuffledDeck.take(26))
val p2 = Player(p2Name, shuffledDeck.drop(26))
def loop(gs: GameState): GameState = gs match {
case Done(_, _) => gs
case inProgress: GameState => loop(run(inProgress))
}
loop(Idle(p1, p2, 0))
}
}
@jayhutfles
Copy link
Author

jayhutfles commented Jan 30, 2021

List.fill(100000)(WarGame("P1", "P2")).map{ 
  case Done(Some(Player(name, _)), turns) => (name, turns) 
}.groupMap(_._1)(_._2).toSeq.map{
  case (name, turnsToWin) => (name, turnsToWin.size)
}

val res1: Seq[(String, Int)] = List((P1,50112), (P2,49888))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment