aboutsummaryrefslogtreecommitdiffstats
path: root/day21/part1.hs
blob: 2c60e49b0323e71216b21005f779d58d725bd52c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
module Part1 (simulate1, makeState1) where

import Debug.Trace (traceShow)
import Utils

data State = State
  { positions :: [Int],
    scores :: [Int],
    die :: Int,
    dieRolledTotal :: Int
  }
  deriving (Show)

makeState1 = State

rollDie :: State -> (Int, State)
rollDie prevState = (die prevState, prevState {die = die prevState `mod` 100 + 1})

setAtIndex :: Int -> b -> [b] -> [b]
setAtIndex i value lst = zip [0 ..] lst $> map (\(i', value') -> if i == i' then value else value')

position player state = positions state !! player

score player state = scores state !! player

move player prevState =
  let (dieRoll1, state1) = rollDie prevState
      (dieRoll2, state2) = rollDie state1
      (dieRoll3, state3) = rollDie state2
      state = state3 {dieRolledTotal = dieRolledTotal state3 + 3}

      newPos = (position player state + dieRoll1 + dieRoll2 + dieRoll3 - 1) `mod` 10 + 1
      newScore = score player state + newPos
   in state
        { positions = setAtIndex player newPos (positions state),
          scores = setAtIndex player newScore (scores state)
        }

checkWinCondition state
  | (scores state !! 0) >= 1000 = Left (1, scores state !! 1, dieRolledTotal state)
  | (scores state !! 1) >= 1000 = Left (0, scores state !! 0, dieRolledTotal state)
  | otherwise = Right state

takeTurn :: Int -> State -> Either (Int, Int, Int) State
takeTurn player state = do
  let movedState = move player state
  checkWinCondition movedState

simulate1 state player =
  let turnTaken = takeTurn player state
      nextPlayer = (player + 1) `mod` 2
   in case turnTaken of
        Right newState -> simulate1 newState nextPlayer
        Left result -> result