X-Git-Url: https://git.njae.me.uk/?p=advent-of-code-19.git;a=blobdiff_plain;f=advent13%2Fsrc%2Fadvent13.hs;fp=advent13%2Fsrc%2Fadvent13.hs;h=37a17b21eedaef50aa4d86d1eef52d4dad5b4d79;hp=0000000000000000000000000000000000000000;hb=2ba79104daf3518414e60e8685b9eb2dc996bc56;hpb=dd188fd71f76bb33ace34b0886fa32a7145f6b2e diff --git a/advent13/src/advent13.hs b/advent13/src/advent13.hs new file mode 100644 index 0000000..37a17b2 --- /dev/null +++ b/advent13/src/advent13.hs @@ -0,0 +1,160 @@ +import Debug.Trace + +import Intcode + +import qualified Data.Text.IO as TIO + +import qualified Data.Map.Strict as M +-- import Data.Map.Strict ((!)) +import Data.List +import Data.List.Split +-- import Data.List +-- import Data.Function (on) + +type Position = (Integer, Integer) -- x, y +data Cell = Empty | Wall | Block | Paddle | Ball deriving (Show, Eq, Ord) +-- data Direction = North | East | South | West deriving (Show, Eq, Ord, Enum, Bounded) + +type Field = M.Map Position Cell + +data Game = Game + { _machine :: Machine + , _executionState :: ExecutionState + , _currentInput :: [Integer] + , _machineOutput :: [Integer] + , _currentScore :: Integer + , _paddleX :: Integer + , _ballX :: Integer + } deriving (Eq) + +instance Show Game where + show g = "Game {, _executionState = " ++ show (_executionState g) ++ + ", _currentInput = " ++ show (_currentInput g) ++ + ", _machineOutput = " ++ show (_machineOutput g) ++ + ", _currentScore = " ++ show (_currentScore g) ++ + ", _paddleX = " ++ show (_paddleX g) ++ + ", _ballX = " ++ show (_ballX g) ++ + " }" + + +main :: IO () +main = do + text <- TIO.readFile "data/advent13.txt" + let mem = parseMachineMemory text + -- print mem + print $ part1 mem + print $ part2 mem + + +part1 mem = M.size $ M.filter (== Block) screen + where (_halted, _machine, output) = runProgram [] mem + (screen, _score) = buildScreen output + +part2 mem = _currentScore game + where mem' = [2] ++ (tail mem) + game0 = buildGame mem' + game = runGame game0 + + +buildScreen :: [Integer] -> (Field, Integer) +buildScreen output = foldl' addCell (M.empty, 0) $ chunksOf 3 output + +addCell :: (Field, Integer) -> [Integer] -> (Field, Integer) +addCell (screen, _s) [- 1 , 0, s] = (screen, s) +addCell (screen, score) [x, y, c] = (M.insert (x, y) (cellOf c) screen, score) + +cellOf :: Integer -> Cell +cellOf 0 = Empty +cellOf 1 = Wall +cellOf 2 = Block +cellOf 3 = Paddle +cellOf 4 = Ball + + +buildGame mem = Game + { _machine = makeMachine mem + , _executionState = Runnable + , _currentInput = [] + , _machineOutput = [] + , _currentScore = 0 + , _paddleX = 0 + , _ballX = 0 + } + +runGame :: Game -> Game +-- runGame game | trace (show (_currentScore game) ++ " " ++ show (_executionState game)) False = undefined +runGame game0 = game + where game1 = runGameStep game0 + game = if (_executionState game1 == Terminated) + then game1 + else runGame game1 + +runGameStep :: Game -> Game +-- runGameStep game | trace (show (_currentScore game) ++ " " ++ show (_executionState game)) False = undefined +runGameStep game0 = game + where game1 = runGameMachine game0 + output = _machineOutput game1 + (screen, score) = buildScreen output + cs = _currentScore game0 + score' = if score > cs then score else cs + game2 = game1 { _currentScore = score' } + game = joystick game2 screen + + +runGameMachine :: Game -> Game +runGameMachine g = g { _machine = machine' + , _executionState = halted + , _machineOutput = output + } + where machine = _machine g + input = _currentInput g + (halted, machine', output) = runMachine input machine + +joystick :: Game -> Field -> Game +joystick game screen = game {_currentInput = ci ++ [direction], + _paddleX = px, _ballX = bx, + _executionState = termination} + where knownBall = M.filter (== Ball) screen + bx = if M.null knownBall + then _ballX game + else fst $ fst $ M.findMin knownBall + knownPaddle = M.filter (== Paddle) screen + px = if M.null knownPaddle + then _paddleX game + else fst $ fst $ M.findMin knownPaddle + termination = if _executionState game == Blocked + then Runnable + else _executionState game + ci = _currentInput game + direction = if bx > px + then 1 + else if bx < px + then -1 + else 0 + + +ghcisetup text = game0 + where mem = parseMachineMemory text + mem' = [2] ++ (tail mem) + game0 = buildGame mem' + + +showScreen :: Field -> String +showScreen screen = unlines rows + where minX = minimum $ map fst $ M.keys screen + minY = minimum $ map snd $ M.keys screen + maxX = maximum $ map fst $ M.keys screen + maxY = maximum $ map snd $ M.keys screen + rows = [showScreenRow screen minX maxX y | y <- [minY..maxY]] + +showScreenRow :: Field -> Integer -> Integer -> Integer -> String +showScreenRow screen minX maxX y = [showScreenCell screen x y | x <- [minX..maxX]] + +showScreenCell :: Field -> Integer -> Integer -> Char +showScreenCell screen x y = + case (M.findWithDefault Empty (x, y) screen) of + Empty -> ' ' + Wall -> '#' + Block -> '*' + Paddle -> '=' + Ball -> '+'