diff --git a/day18.hs b/day18.hs new file mode 100644 index 0000000..bfeac5e --- /dev/null +++ b/day18.hs @@ -0,0 +1,140 @@ +import Data.List.Split +import Data.List.Unique +import Data.Char as Char +import Data.List as List +import Data.Either as Either +import Debug.Trace as Trace +import Data.Maybe + +main = do + mapIn <- lines <$> getContents + --let brain = Amplifier software 0 0 [] [0] + --let robot = Robot mapIn [((5,1),64)] (5,1) 1 + --let resultRobots = (runRobot robot ) + --let reachablePoints = getNextKey resultRobots + --let nextKey = head (sortBy sortLength reachablePoints) + --let newMap = openGate mapIn nextKey + let result = getAllKeys mapIn (15,1) [] + --let aRobotLength = List.minimum( map (length . points) $ aRobots) + --let aRobotWin = filter(\(Robot brain points position direction) -> length points == aRobotLength) aRobots + --let winRobots = filter(\(Robot br pts pos dir) -> elem 2 (map(\(p,c) -> c) pts))resultRobots + --let winRobotsLength = map(\(Robot br pts pos dir) -> length (filter(\(p,c) -> c == 1)pts))winRobots + --let winRobot = (map(\(Robot br pts pos dir) -> Robot br [] pos 1) winRobots) !! 0 + --let part2Robots = (runRobot winRobot) + --let part2Length = map(\(Robot br pts pos dir) -> length (filter(\(p,c) -> c == 1)pts))part2Robots + --putStrLn(show winRobotsLength) + --putStrLn(show $ List.maximum( part2Length)) + mapM putStrLn(map show mapIn) + putStrLn(show result) + + --putStrLn(printKey nextKey) + --mapM putStrLn(map show resultRobots) + +data Robot = Robot{ brain:: [[Char]] + ,points:: [((Int,Int),Int)] + ,position:: (Int,Int) + ,direction :: Int + } deriving Show + +data Key = Key { id :: Int, + pos :: (Int,Int), + way :: Int + } deriving (Show, Eq) + +getAllKeys :: [[Char]] -> (Int,Int) -> [Key] -> [[Key]] +getAllKeys mapIn (a,b) keys = do + let robot = Robot (Trace.traceShowId(mapIn)) [((a,b),64)] (a,b) 1 + let resultRobots = (runRobot robot ) + let reachablKeys = (Trace.traceShowId(getNextKey (resultRobots))) + if length reachablKeys /= 0 + then do + let nextKey = head (sortBy sortLength reachablKeys) + let newMap = openGate mapIn (Trace.traceShowId(nextKey)) + let newKeys = nextKey:keys + getAllKeys newMap (pos nextKey) newKeys + else keys + + +sortLength :: Key -> Key -> Ordering +sortLength (Key _ _ way1) (Key _ _ way2) + | way1 == way2 = EQ + | way1 < way2 = LT + | way1 > way2 = GT + +openGate :: [[Char]] -> Key -> [[Char]] +openGate mapIn (Key id (a,b) _) = result + where result' = map( map(\c -> if c==(chr id) then '.' else c)) mapIn + result = map( map(\c -> if c==(chr (id-32)) then '.' else c)) result' + +printKey :: Key -> [Char] +printKey (Key id pos way) = (show id)++" :"++(show pos)++(show way) + +getBrain :: Robot -> [[Char]] +getBrain (Robot brain points poisition direction) = brain + + +getNextKey :: [Robot] -> [Key] +getNextKey robots = nub minPts + where kPts = map(\(Robot brain points position direction) ->(Key (snd(last points)) (fst(last points)) (length points))) robots + minPts = map(\(Key id pos way) ->(Key id pos (min id))) keyWPr + min x = List.minimum $ map(\(Key id pos way) -> way) $ filter(\(Key id pos way) -> id == x) keyWPr + keys = filter(\(Key id pos way) -> id /= 46 && id /= 64 && between 97 id 122) kPts + keyWPr = keys + + +runRobot :: Robot -> [Robot] +runRobot robot + | (length move) == 0 = [robot] + | (length move) == 1 = do + let newRobot = stepRobot robot $ move!!0 + runRobot newRobot + | otherwise = do + let newRobots = map(\mv -> stepRobot robot mv) move + foldl (++) [] $ map(\robot -> runRobot robot) newRobots + where move = getNextMove robot + +stepRobot :: Robot -> Int -> Robot +stepRobot (Robot brain points position direction) newDirection = do + let newPos = move position newDirection + let statusResponse = ord ((brain!! (snd newPos))!! (fst newPos)) + let newPoints = (points) ++ [(newPos, statusResponse)] + if statusResponse == 35 || between 65 statusResponse 90 || between 97 statusResponse 122 + then Robot brain newPoints position newDirection + else Robot brain newPoints newPos newDirection + +between :: Int -> Int -> Int -> Bool +between x y z + |x <= y = y <= z + |otherwise = False + +move :: (Int,Int) -> Int -> (Int,Int) +move (x,y) direction + | direction == 1 = (x,y-1) + | direction == 2 = (x+1,y) + | direction == 3 = (x,y+1) + | direction == 4 = (x-1,y) + +getNextMove :: Robot -> [Int] +getNextMove (Robot brain points position direction) + |length points > 0 && (snd $ last points) == 2 = [] + |otherwise = do + filterMoves (Robot brain points position direction) [1,2,3,4] + +filterMoves :: Robot -> [Int] -> [Int] +filterMoves robot moves = filter(\x -> checkVisit robot x && checkWall robot x) moves + +checkVisit :: Robot -> Int -> Bool +checkVisit (Robot brain points position direction) mv = do + let newPos = move position mv + let visits = map(\(pos,c) -> pos) points + notElem newPos visits + +checkWall :: Robot -> Int -> Bool +checkWall (Robot brain points position direction) mv = do + let newPos = (move position mv) + let mvResult = ( ord ((brain!! (snd newPos))!! (fst newPos))) + not (mvResult == 35 ) + +getList :: String -> [Int] +getList = map Prelude.read . splitOn "," +