refactor day6 part one

This commit is contained in:
JasterV 2025-03-30 20:59:08 +02:00
parent 1648683aa3
commit c27e24e063
5 changed files with 148 additions and 106 deletions

View file

@ -1,77 +1,78 @@
cabal-version: 2.2 cabal-version: 2.2
name: aoc2024
version: 0.1.0.0
license: BSD-3-Clause
license-file: LICENSE
copyright: 2025 Author name here
maintainer: example@example.com
author: Author name here
homepage: https://github.com/githubuser/aoc2024#readme
bug-reports: https://github.com/githubuser/aoc2024/issues
description:
Please see the README on GitHub at <https://github.com/githubuser/aoc2024#readme>
build-type: Simple -- This file has been generated from package.yaml by hpack version 0.37.0.
--
-- see: https://github.com/sol/hpack
name: aoc2024
version: 0.1.0.0
description: Please see the README on GitHub at <https://github.com/githubuser/aoc2024#readme>
homepage: https://github.com/githubuser/aoc2024#readme
bug-reports: https://github.com/githubuser/aoc2024/issues
author: Author name here
maintainer: example@example.com
copyright: 2025 Author name here
license: BSD-3-Clause
license-file: LICENSE
build-type: Simple
extra-source-files: extra-source-files:
README.md README.md
CHANGELOG.md CHANGELOG.md
source-repository head source-repository head
type: git type: git
location: https://github.com/githubuser/aoc2024 location: https://github.com/githubuser/aoc2024
library library
exposed-modules: exposed-modules:
Data.Matrix Data.Matrix
Day1 Day1
Day2 Day2
Day3 Day3
Day4 Day4
Day5 Day5
Day6 Day6
Day6.Guard
hs-source-dirs: src other-modules:
other-modules: Paths_aoc2024 Paths_aoc2024
autogen-modules: Paths_aoc2024 autogen-modules:
default-language: Haskell2010 Paths_aoc2024
ghc-options: hs-source-dirs:
-Wall -Wcompat -Widentities -Wincomplete-record-updates src
-Wincomplete-uni-patterns -Wmissing-export-lists ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
-Wmissing-home-modules -Wpartial-fields -Wredundant-constraints build-depends:
base >=4.7 && <5
build-depends: , containers
base >=4.7 && <5, , hashable
containers, , regex-tdfa >=1.3.2 && <1.4
regex-tdfa >=1.3.2 && <1.4, , text >=2.0.2
text >=2.0.2, , unordered-containers
unordered-containers default-language: Haskell2010
test-suite aoc2024-test test-suite aoc2024-test
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
main-is: Spec.hs main-is: Spec.hs
hs-source-dirs: test other-modules:
other-modules: Day1Spec
Day1Spec Day2Spec
Day2Spec Day3Spec
Day3Spec Day4Spec
Day4Spec Day5Spec
Day5Spec Day6Spec
Paths_aoc2024 Paths_aoc2024
autogen-modules:
autogen-modules: Paths_aoc2024 Paths_aoc2024
default-language: Haskell2010 hs-source-dirs:
ghc-options: test
-Wall -Wcompat -Widentities -Wincomplete-record-updates ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
-Wincomplete-uni-patterns -Wmissing-export-lists build-depends:
-Wmissing-home-modules -Wpartial-fields -Wredundant-constraints QuickCheck >=2.14.3 && <2.15
-threaded -rtsopts -with-rtsopts=-N , aoc2024
, base >=4.7 && <5
build-depends: , containers
QuickCheck >=2.14.3 && <2.15, , hashable
aoc2024, , hspec >=2.0.0
base >=4.7 && <5, , regex-tdfa >=1.3.2 && <1.4
containers, , text >=2.0.2
hspec >=2.0.0, , unordered-containers
regex-tdfa >=1.3.2 && <1.4, default-language: Haskell2010
text >=2.0.2,
unordered-containers

View file

@ -25,6 +25,7 @@ dependencies:
- text >= 2.0.2 - text >= 2.0.2
- containers - containers
- unordered-containers - unordered-containers
- hashable
ghc-options: ghc-options:
- -Wall - -Wall

View file

@ -4,75 +4,59 @@ import Data.HashSet (HashSet)
import qualified Data.HashSet as HashSet import qualified Data.HashSet as HashSet
import Data.Matrix (Matrix, Position) import Data.Matrix (Matrix, Position)
import qualified Data.Matrix as M import qualified Data.Matrix as M
import Data.Maybe import Day6.Guard (Guard (..))
import Prelude hiding (Left, Right) import qualified Day6.Guard as G
partOne :: String -> Maybe Int data Error = GuardNotFoundError
deriving (Eq, Show)
partOne :: String -> Either Error Int
partOne input = length <$> predictGuardsRoute (parseLabMap input) partOne input = length <$> predictGuardsRoute (parseLabMap input)
partTwo :: String -> Int partTwo :: String -> Either Error Int
partTwo _input = 0 partTwo _input = Right 0
-- Laboratory Map -- Laboratory Map
--
type LabMap = Matrix Char type LabMap = Matrix Char
type Direction = Char type Visited = HashSet Guard
type Guard = (Position, Direction)
type Visited = HashSet (Position, Direction)
parseLabMap :: String -> LabMap parseLabMap :: String -> LabMap
parseLabMap = M.buildMatrix . lines parseLabMap = M.buildMatrix . lines
findGuard :: LabMap -> Maybe Guard findGuard :: LabMap -> Either Error Guard
findGuard matrix = findGuard matrix =
let mUp = M.lookupValue '^' matrix let mUp = M.lookupValue '^' matrix
mDown = M.lookupValue 'v' matrix mDown = M.lookupValue 'v' matrix
mRight = M.lookupValue '>' matrix mRight = M.lookupValue '>' matrix
mLeft = M.lookupValue '<' matrix mLeft = M.lookupValue '<' matrix
in case [mUp, mDown, mRight, mLeft] of in case [mUp, mDown, mRight, mLeft] of
[Just pos, _, _, _] -> Just (pos, '^') [Just pos, _, _, _] -> Right (Guard pos G.Up)
[_, Just pos, _, _] -> Just (pos, 'v') [_, Just pos, _, _] -> Right (Guard pos G.Down)
[_, _, Just pos, _] -> Just (pos, '>') [_, _, Just pos, _] -> Right (Guard pos G.Right)
[_, _, _, Just pos] -> Just (pos, '<') [_, _, _, Just pos] -> Right (Guard pos G.Left)
_ -> Nothing _ -> Left GuardNotFoundError
predictGuardsRoute :: LabMap -> Maybe [Position] predictGuardsRoute :: LabMap -> Either Error [Position]
predictGuardsRoute labMap = do predictGuardsRoute labMap = do
guard <- findGuard labMap guard <- findGuard labMap
return (go guard HashSet.empty HashSet.empty) return $ go guard HashSet.empty HashSet.empty
where where
go :: Guard -> Visited -> HashSet Position -> [Position] go :: Guard -> Visited -> HashSet Position -> [Position]
go guard@(position, _) visited acc = go guard visited acc =
let guard' = moveGuard guard let guard' = moveGuard guard
acc' = HashSet.insert position acc acc' = HashSet.insert (position guard) acc
visited' = HashSet.insert guard visited visited' = HashSet.insert guard visited
in -- If we have hit a loop or if the guard can't move anymore, finish prediction in -- If we have hit a loop or if the guard can't move anymore, finish prediction
if HashSet.member guard visited || guard == guard' if HashSet.member guard visited || (guard == guard')
then HashSet.toList acc' then HashSet.toList acc'
else go guard' visited' acc' else go guard' visited' acc'
moveGuard :: Guard -> Guard moveGuard :: Guard -> Guard
moveGuard guard = moveGuard guard =
let guard'@(position', _) = moveForward guard let guard' = G.moveForward guard
mObstacle = M.lookup position' labMap mObstacle = M.lookup (position guard') labMap
in case mObstacle of in case mObstacle of
Nothing -> guard Nothing -> guard
Just '#' -> turnRight guard Just '#' -> G.turnRight guard
Just _ -> guard' Just _ -> guard'
moveForward :: Guard -> Guard
moveForward ((row, col), '^') = ((row - 1, col), '^')
moveForward ((row, col), 'v') = ((row + 1, col), 'v')
moveForward ((row, col), '>') = ((row, col + 1), '>')
moveForward ((row, col), '<') = ((row, col - 1), '<')
moveForward guard = guard
turnRight :: Guard -> Guard
turnRight (pos, '^') = (pos, '>')
turnRight (pos, '>') = (pos, 'v')
turnRight (pos, 'v') = (pos, '<')
turnRight (pos, '<') = (pos, '^')
turnRight guard = guard

30
src/Day6/Guard.hs Normal file
View file

@ -0,0 +1,30 @@
{-# LANGUAGE DeriveGeneric #-}
module Day6.Guard (Guard (..), Direction (..), moveForward, turnRight) where
import Data.Hashable
import Data.Matrix (Position)
import GHC.Generics (Generic)
import Prelude hiding (Left, Right)
data Direction = Up | Down | Left | Right
deriving (Eq, Generic)
instance Hashable Direction
data Guard = Guard {position :: Position, directon :: Direction}
deriving (Eq, Generic)
instance Hashable Guard
moveForward :: Guard -> Guard
moveForward (Guard (row, col) Up) = Guard (row - 1, col) Up
moveForward (Guard (row, col) Down) = Guard (row + 1, col) Down
moveForward (Guard (row, col) Right) = Guard (row, col + 1) Right
moveForward (Guard (row, col) Left) = Guard (row, col - 1) Left
turnRight :: Guard -> Guard
turnRight (Guard pos Up) = Guard pos Right
turnRight (Guard pos Right) = Guard pos Down
turnRight (Guard pos Down) = Guard pos Left
turnRight (Guard pos Left) = Guard pos Up

26
test/Day6Spec.hs Normal file
View file

@ -0,0 +1,26 @@
module Day6Spec (spec) where
import Day6 (partOne, partTwo)
import Test.Hspec
spec :: Spec
spec = do
describe "PartOne" $ do
it "works" $ do
partOne input `shouldBe` Right 41
describe "PartTwo" $ do
it "works" $ do
partTwo input `shouldBe` Right 6
where
input =
"....#.....\n\
\.........#\n\
\..........\n\
\..#.......\n\
\.......#..\n\
\..........\n\
\.#..^.....\n\
\........#.\n\
\#.........\n\
\......#..."