5 import qualified Data.Text.IO as TIO
7 import qualified Data.Map.Strict as M
8 -- import Data.Map.Strict ((!))
10 import Data.List.Split
12 -- import Data.Function (on)
14 type Position = (Integer, Integer) -- x, y
15 data Cell = Empty | Wall | Block | Paddle | Ball deriving (Show, Eq, Ord)
17 type Screen = M.Map Position Cell
21 , _executionState :: ExecutionState
22 , _currentInput :: [Integer]
23 , _machineOutput :: [Integer]
24 , _currentScore :: Integer
29 instance Show Game where
30 show g = "Game {<m>, _executionState = " ++ show (_executionState g) ++
31 ", _currentInput = " ++ show (_currentInput g) ++
32 ", _machineOutput = " ++ show (_machineOutput g) ++
33 ", _currentScore = " ++ show (_currentScore g) ++
34 ", _paddleX = " ++ show (_paddleX g) ++
35 ", _ballX = " ++ show (_ballX g) ++
41 text <- TIO.readFile "data/advent13.txt"
42 let mem = parseMachineMemory text
48 part1 mem = M.size $ M.filter (== Block) screen
49 where (_halted, _machine, output) = runProgram [] mem
50 (screen, _score) = buildScreen output
52 part2 mem = _currentScore game
53 where mem' = [2] ++ (tail mem)
54 game0 = buildGame mem'
58 buildScreen :: [Integer] -> (Screen, Integer)
59 -- buildScreen output = foldl' addCell (M.empty, 0) $ chunksOf 3 output
60 buildScreen = foldl' addCell (M.empty, 0) . chunksOf 3
62 addCell :: (Screen, Integer) -> [Integer] -> (Screen, Integer)
63 addCell (screen, _s) [- 1 , 0, s] = (screen, s)
64 addCell (screen, score) [x, y, c] = (M.insert (x, y) (cellOf c) screen, score)
66 cellOf :: Integer -> Cell
75 { _machine = makeMachine mem
76 , _executionState = Runnable
84 runGame :: Game -> Game
85 -- runGame game | trace (show (_currentScore game) ++ " " ++ show (_executionState game)) False = undefined
87 where game1 = runGameStep game0
88 game = if (_executionState game1 == Terminated)
92 runGameStep :: Game -> Game
93 -- runGameStep game | trace (show (_currentScore game) ++ " " ++ show (_executionState game)) False = undefined
94 runGameStep game0 = game
95 where game1 = runGameMachine game0
96 output = _machineOutput game1
97 (screen, score) = buildScreen output
98 cs = _currentScore game0
99 score' = if score > cs then score else cs
100 game2 = game1 { _currentScore = score' }
101 game = joystick game2 screen
104 runGameMachine :: Game -> Game
105 runGameMachine g = g { _machine = machine'
106 , _executionState = halted
107 , _machineOutput = output
109 where machine = _machine g
110 input = _currentInput g
111 (halted, machine', output) = runMachine input machine
113 joystick :: Game -> Screen -> Game
114 joystick game screen = game {_currentInput = ci ++ [direction],
115 _paddleX = px, _ballX = bx,
116 _executionState = termination}
117 where knownBall = M.filter (== Ball) screen
118 bx = if M.null knownBall
120 else fst $ fst $ M.findMin knownBall
121 knownPaddle = M.filter (== Paddle) screen
122 px = if M.null knownPaddle
124 else fst $ fst $ M.findMin knownPaddle
125 termination = if _executionState game == Blocked
127 else _executionState game
128 ci = _currentInput game
129 direction = if bx > px
136 ghcisetup text = game0
137 where mem = parseMachineMemory text
138 mem' = [2] ++ (tail mem)
139 game0 = buildGame mem'
142 showScreen :: Screen -> String
143 showScreen screen = unlines rows
144 where minX = minimum $ map fst $ M.keys screen
145 minY = minimum $ map snd $ M.keys screen
146 maxX = maximum $ map fst $ M.keys screen
147 maxY = maximum $ map snd $ M.keys screen
148 rows = [showScreenRow screen minX maxX y | y <- [minY..maxY]]
150 showScreenRow :: Screen -> Integer -> Integer -> Integer -> String
151 showScreenRow screen minX maxX y = [showScreenCell screen x y | x <- [minX..maxX]]
153 showScreenCell :: Screen -> Integer -> Integer -> Char
154 showScreenCell screen x y =
155 case (M.findWithDefault Empty (x, y) screen) of