This commit is contained in:
Quinten Kock 2022-12-12 06:38:41 +01:00
parent f780e14dd7
commit ab9f771f6b
3 changed files with 172 additions and 0 deletions

90
2022/day11.hs Normal file
View File

@ -0,0 +1,90 @@
import Data.List.Split (splitOn)
import qualified Control.Monad.Trans.State as St
import qualified Data.Map as M
import Control.Monad (replicateM_)
import Data.List (sort)
data Expr = Old | Lit Int | Add Expr Expr | Mul Expr Expr
data Test = T Int Int Int
data Part = Part1 | Part2
data Monkey = M [Int] Expr Test
getFactor :: Monkey -> Int
getFactor (M _ _ (T x _ _)) = x
parseElem :: String -> Expr
parseElem "old" = Old
parseElem i = Lit (read i)
parseExpr :: [String] -> Expr
parseExpr s
| s !! 1 == "*" = Mul (parseElem $ s !! 0) (parseElem $ s !! 2)
| s !! 1 == "+" = Add (parseElem $ s !! 0) (parseElem $ s !! 2)
| otherwise = error $ "unknown expression: " ++ concat s
parseMonkey :: [String] -> Monkey
parseMonkey s = M startingItems expr test where
startingItems = read $ "[" ++ (splitOn ": " (s !! 1) !! 1) ++ "]"
expr = parseExpr $ last $ splitOn ["="] (words (s !! 2))
testFactor = read $ last $ words (s !! 3)
testTargetT = read $ last $ words (s !! 4)
testTargetF = read $ last $ words (s !! 5)
test = T testFactor testTargetT testTargetF
evalExpr :: Expr -> Int -> Int
evalExpr Old x = x
evalExpr (Lit i) x = i
evalExpr (Add a b) x = evalExpr a x + evalExpr b x
evalExpr (Mul a b) x = evalExpr a x * evalExpr b x
type Monkeys = M.Map Int (Monkey, Int)
steps :: Part -> Int -> Monkey -> St.State Monkeys (Int, Monkey)
steps part factor monkey@(M [] _ _) = do
pure (0, monkey)
steps part factor (M (item:items) op test@(T fac tr fa)) = do
let newItem' = evalExpr op item --`div` 3
let newItem = case part of
Part1 -> evalExpr op item `div` 3
Part2 -> evalExpr op item `mod` factor
let targetMonkey = if newItem `mod` fac == 0 then tr else fa
monkeys <- St.get
let (M items' op' test', count') = monkeys M.! targetMonkey
let updated = M (newItem:items') op' test'
St.put $ M.insert targetMonkey (updated, count') monkeys
(count, final) <- steps part factor $ M items op test
pure (count+1, final)
simulate :: Part -> Int -> Int -> St.State Monkeys ()
simulate part factor i = do
monkeys <- St.get
let (monkey, count) = monkeys M.! i
(iters, finished) <- steps part factor monkey
monkeys <- St.get
St.put $ M.insert i (finished, count + iters) monkeys
round :: Part -> Int -> St.State Monkeys ()
round part factor = do
monkeys <- St.get
mapM_ (simulate part factor . fst) (M.toAscList monkeys)
main :: IO ()
main = do
monkeys <- map parseMonkey . splitOn [""] . lines <$> getContents
let factor = foldr1 lcm $ map getFactor monkeys
let initialState = M.fromAscList $ zip [0..] (map (\x -> (x,0)) monkeys)
putStr "part 1: "
let action = replicateM_ 20 (Main.round Part1 factor)
let results = St.execState action initialState
let counts = map (snd . snd) (M.toAscList results)
print $ counts
print $ product $ take 2 $ reverse $ sort counts
putStr "part 2: "
let action = replicateM_ 10000 (Main.round Part2 factor)
let results = St.execState action initialState
let counts = map (snd . snd) (M.toAscList results)
print $ counts
print $ product $ take 2 $ reverse $ sort counts

55
2022/inputs/day11 Normal file
View File

@ -0,0 +1,55 @@
Monkey 0:
Starting items: 84, 66, 62, 69, 88, 91, 91
Operation: new = old * 11
Test: divisible by 2
If true: throw to monkey 4
If false: throw to monkey 7
Monkey 1:
Starting items: 98, 50, 76, 99
Operation: new = old * old
Test: divisible by 7
If true: throw to monkey 3
If false: throw to monkey 6
Monkey 2:
Starting items: 72, 56, 94
Operation: new = old + 1
Test: divisible by 13
If true: throw to monkey 4
If false: throw to monkey 0
Monkey 3:
Starting items: 55, 88, 90, 77, 60, 67
Operation: new = old + 2
Test: divisible by 3
If true: throw to monkey 6
If false: throw to monkey 5
Monkey 4:
Starting items: 69, 72, 63, 60, 72, 52, 63, 78
Operation: new = old * 13
Test: divisible by 19
If true: throw to monkey 1
If false: throw to monkey 7
Monkey 5:
Starting items: 89, 73
Operation: new = old + 5
Test: divisible by 17
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 6:
Starting items: 78, 68, 98, 88, 66
Operation: new = old + 6
Test: divisible by 11
If true: throw to monkey 2
If false: throw to monkey 5
Monkey 7:
Starting items: 70
Operation: new = old + 7
Test: divisible by 5
If true: throw to monkey 1
If false: throw to monkey 3

27
2022/inputs/day11.test Normal file
View File

@ -0,0 +1,27 @@
Monkey 0:
Starting items: 79, 98
Operation: new = old * 19
Test: divisible by 23
If true: throw to monkey 2
If false: throw to monkey 3
Monkey 1:
Starting items: 54, 65, 75, 74
Operation: new = old + 6
Test: divisible by 19
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 2:
Starting items: 79, 60, 97
Operation: new = old * old
Test: divisible by 13
If true: throw to monkey 1
If false: throw to monkey 3
Monkey 3:
Starting items: 74
Operation: new = old + 3
Test: divisible by 17
If true: throw to monkey 0
If false: throw to monkey 1