1
+ import common .loadPackets
2
+
3
+ import scala .annotation .tailrec
4
+
5
+ val input = loadPackets(List (" day21.txt" )).map(_.split(" : " )(1 ).toInt)
6
+
7
+ val threeThrows =
8
+ (for (x <- Range .inclusive(1 , 3 );
9
+ y <- Range .inclusive(1 , 3 );
10
+ z <- Range .inclusive(1 , 3 )) yield (x + y + z, 1 )).groupMapReduce(_._1)(_._2)(_ + _)
11
+
12
+ case class State (player1Position : Int = input.head,
13
+ player2Position : Int = input(1 ),
14
+ player1Score : Int = 0 ,
15
+ player2Score : Int = 0 ,
16
+ player1Turn : Boolean = true ) {
17
+ def wrap (v : Int ): Int = (v - 1 ) % 10 + 1
18
+
19
+ def won : Boolean = player1Score >= 21 | player2Score >= 21
20
+
21
+ def winner : Option [Int ] =
22
+ if (player1Score >= 21 ) Some (1 )
23
+ else if (player2Score >= 21 ) Some (2 )
24
+ else None
25
+
26
+ def next (): Map [State , Int ] = {
27
+ if (won) Map (this -> 1 )
28
+ else threeThrows.map { case (roll, count) =>
29
+ if (player1Turn) {
30
+ val newPos = wrap(player1Position + roll)
31
+ copy(player1Position = newPos,
32
+ player1Score = player1Score + newPos,
33
+ player1Turn = ! player1Turn) -> count
34
+ } else {
35
+ val newPos = wrap(player2Position + roll)
36
+ copy(player2Position = newPos,
37
+ player2Score = player2Score + newPos,
38
+ player1Turn = ! player1Turn) -> count
39
+ }
40
+ }
41
+ }
42
+ }
43
+
44
+ val initial : Map [State , Long ] = Map (State (input.head, input(1 )) -> 1L )
45
+ def nextState (universes : Map [State , Long ]): Map [State , Long ] =
46
+ universes.toList.flatMap {
47
+ case (universe : State , count : Long ) => universe.next().view.mapValues(_ * count)
48
+ }.groupMapReduce(_._1)(_._2)(_ + _)
49
+
50
+ @ tailrec
51
+ def part2 (universes : Map [State , Long ]): Long = {
52
+ if (universes.keySet.forall(_.won)) {
53
+ val counts : Map [Int , Long ] = universes.groupMapReduce(_._1.winner.get)(_._2)(_ + _)
54
+ counts.values.max
55
+ } else part2(nextState(universes))
56
+ }
57
+
58
+ part2(initial)
0 commit comments