Skip to content

Commit 11c69da

Browse files
authored
Added Solution for Puzzle 10 in Haskell
1 parent 15f6e81 commit 11c69da

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

10/Main.hs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
module Main where
2+
3+
import System.IO
4+
import Data.List (elemIndex, find)
5+
import Data.Maybe (catMaybes, fromMaybe)
6+
import qualified Data.Set as Set
7+
8+
parseFile :: FilePath -> IO [[Char]]
9+
parseFile path = do
10+
content <- readFile path
11+
return $ lines content
12+
13+
findPositions :: Char -> [[Char]] -> [(Int, Int)]
14+
findPositions char arr = catMaybes [findPositionInLine char line row | (line, row) <- zip arr [0..]]
15+
16+
findPositionInLine :: Char -> [Char] -> Int -> Maybe (Int, Int)
17+
findPositionInLine char line row = case elemIndex char line of
18+
Just col -> Just (row, col)
19+
Nothing -> Nothing
20+
21+
getCharAtPosition :: [[Char]] -> (Int, Int) -> Char
22+
getCharAtPosition arr (row, col) = (arr !! row) !! col
23+
24+
nextPositions :: Char -> (Int, Int) -> [(Int, Int)]
25+
nextPositions char (row, col) = case char of
26+
'|' -> [(row + 1, col), (row - 1, col)]
27+
'-' -> [(row, col + 1), (row, col - 1)]
28+
'L' -> [(row - 1, col), (row, col + 1)]
29+
'J' -> [(row - 1, col), (row, col - 1)]
30+
'7' -> [(row, col - 1), (row + 1, col)]
31+
'F' -> [(row + 1, col), (row, col + 1)]
32+
'.' -> []
33+
_ -> []
34+
35+
nextPosition :: [[Char]] -> (Int, Int) -> Char -> (Int, Int) -> Maybe (Int, Int)
36+
nextPosition arr prevPos curChar curPos =
37+
find (/= prevPos) (nextPositions curChar curPos)
38+
39+
areConnected :: [[Char]] -> (Int, Int) -> (Int, Int) -> Bool
40+
areConnected arr (row1, col1) (row2, col2) =
41+
(row1, col1) `elem` nextPositions (getCharAtPosition arr (row2, col2)) (row2, col2)
42+
43+
traverseLoop :: [[Char]] -> [(Int, Int)] -> (Int, Int) -> ((Int, Int), [(Int, Int)])
44+
traverseLoop arr path curPos =
45+
let curChar = getCharAtPosition arr curPos
46+
in case curChar of
47+
'S' -> (curPos, path)
48+
_ -> case nextPosition arr (last path) curChar curPos of
49+
Just nextPos -> traverseLoop arr (path ++ [curPos]) nextPos
50+
Nothing -> (curPos, path)
51+
52+
isInBounds :: (Int, Int) -> [[a]] -> Bool
53+
isInBounds (row, col) arr = row >= 0 && row < length arr && col >= 0 && col < length (arr !! row)
54+
55+
findPath :: [[Char]] -> [(Int, Int)]
56+
findPath arr =
57+
let (row, col) = head (findPositions 'S' arr) in
58+
let possibleNextPositions = [(row, col-1), (row, col+1), (row-1, col), (row-1, col-1), (row-1, col+1), (row+1, col), (row+1, col+1), (row+1, col-1)] in
59+
let inBoundsPos = filter (`isInBounds` arr) possibleNextPositions in
60+
let connectedPositions = filter (areConnected arr (row, col)) inBoundsPos in
61+
let firstPipePos = head connectedPositions in
62+
let (targetPos, path) = traverseLoop arr [(row, col)] firstPipePos in
63+
path
64+
65+
closesLoop :: Char -> Char -> Bool
66+
closesLoop startChar endChar = case startChar of
67+
'7' -> endChar == 'F'
68+
'J' -> endChar == 'L'
69+
_ -> False
70+
71+
countPathHits :: Set.Set(Int,Int) -> [[Char]] -> Int -> Maybe Char -> (Int, Int) -> Int
72+
countPathHits pathPositions arr hits lastHit (row, col) = case col-1 of
73+
-2 -> hits
74+
x ->
75+
if (row, col) `elem` pathPositions
76+
then let curChar = arr !! row !! col in
77+
if (row, col+1) `elem` pathPositions && areConnected arr (row, col) (row, col+1 )
78+
then
79+
if closesLoop (fromMaybe '.' lastHit) curChar
80+
then countPathHits pathPositions arr (hits - 1) Nothing (row, col-1)
81+
else countPathHits pathPositions arr hits lastHit (row, col-1)
82+
else countPathHits pathPositions arr (hits + 1) (Just curChar) (row, col-1)
83+
else countPathHits pathPositions arr hits Nothing (row, col-1)
84+
85+
solve :: [[Char]] -> IO ()
86+
solve arr = do
87+
let path = findPath arr
88+
print $ length path `div` 2
89+
90+
solve2 :: [[Char]] -> IO ()
91+
solve2 arr = do
92+
let path = findPath arr
93+
let m = length arr
94+
let n = length (head arr)
95+
let pathPositions = Set.fromList path
96+
let allPossiblePositions = [(i, j) | i <- [0..m-1], j <- [0..n-1], not (Set.member (i, j) pathPositions)]
97+
let oddPositions = filter (\x -> odd (countPathHits pathPositions arr 0 Nothing x) ) allPossiblePositions
98+
print $ length $ oddPositions
99+
100+
main :: IO ()
101+
main = do
102+
arr <- parseFile "input"
103+
solve arr
104+
solve2 arr

0 commit comments

Comments
 (0)