f505ff024a24c6f3204574497a0a6c450a8ee02d
[advent-of-code-19.git] / advent13 / src / advent13.hs
1 import Debug.Trace
2
3 import Intcode
4
5 import qualified Data.Text.IO as TIO
6
7 import qualified Data.Map.Strict as M
8 -- import Data.Map.Strict ((!))
9 import Data.List
10 import Data.List.Split
11 -- import Data.List
12 -- import Data.Function (on)
13
14 type Position = (Integer, Integer) -- x, y
15 data Cell = Empty | Wall | Block | Paddle | Ball deriving (Show, Eq, Ord)
16
17 type Screen = M.Map Position Cell
18
19 data Game = Game
20 { _machine :: Machine
21 , _executionState :: ExecutionState
22 , _currentInput :: [Integer]
23 , _machineOutput :: [Integer]
24 , _currentScore :: Integer
25 , _paddleX :: Integer
26 , _ballX :: Integer
27 } deriving (Eq)
28
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) ++
36 " }"
37
38
39 main :: IO ()
40 main = do
41 text <- TIO.readFile "data/advent13.txt"
42 let mem = parseMachineMemory text
43 -- print mem
44 print $ part1 mem
45 print $ part2 mem
46
47
48 part1 mem = M.size $ M.filter (== Block) screen
49 where (_halted, _machine, output) = runProgram [] mem
50 (screen, _score) = buildScreen output
51
52 part2 mem = _currentScore game
53 where mem' = [2] ++ (tail mem)
54 game0 = buildGame mem'
55 game = runGame game0
56
57
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
61
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)
65
66 cellOf :: Integer -> Cell
67 cellOf 0 = Empty
68 cellOf 1 = Wall
69 cellOf 2 = Block
70 cellOf 3 = Paddle
71 cellOf 4 = Ball
72
73
74 buildGame mem = Game
75 { _machine = makeMachine mem
76 , _executionState = Runnable
77 , _currentInput = []
78 , _machineOutput = []
79 , _currentScore = 0
80 , _paddleX = 0
81 , _ballX = 0
82 }
83
84 runGame :: Game -> Game
85 -- runGame game | trace (show (_currentScore game) ++ " " ++ show (_executionState game)) False = undefined
86 runGame game0 = game
87 where game1 = runGameStep game0
88 game = if (_executionState game1 == Terminated)
89 then game1
90 else runGame game1
91
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
102
103
104 runGameMachine :: Game -> Game
105 runGameMachine g = g { _machine = machine'
106 , _executionState = halted
107 , _machineOutput = output
108 }
109 where machine = _machine g
110 input = _currentInput g
111 (halted, machine', output) = runMachine input machine
112
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
119 then _ballX game
120 else fst $ fst $ M.findMin knownBall
121 knownPaddle = M.filter (== Paddle) screen
122 px = if M.null knownPaddle
123 then _paddleX game
124 else fst $ fst $ M.findMin knownPaddle
125 termination = if _executionState game == Blocked
126 then Runnable
127 else _executionState game
128 ci = _currentInput game
129 direction = if bx > px
130 then 1
131 else if bx < px
132 then -1
133 else 0
134
135
136 ghcisetup text = game0
137 where mem = parseMachineMemory text
138 mem' = [2] ++ (tail mem)
139 game0 = buildGame mem'
140
141
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]]
149
150 showScreenRow :: Screen -> Integer -> Integer -> Integer -> String
151 showScreenRow screen minX maxX y = [showScreenCell screen x y | x <- [minX..maxX]]
152
153 showScreenCell :: Screen -> Integer -> Integer -> Char
154 showScreenCell screen x y =
155 case (M.findWithDefault Empty (x, y) screen) of
156 Empty -> ' '
157 Wall -> '#'
158 Block -> '*'
159 Paddle -> '='
160 Ball -> '+'