finish day8 and refactor

This commit is contained in:
JasterV 2025-03-31 23:35:30 +02:00
parent 68f6a8e6f7
commit c081936a7d
6 changed files with 65 additions and 53 deletions

View file

@ -27,6 +27,7 @@ library
exposed-modules: exposed-modules:
Data.List.Extra Data.List.Extra
Data.Matrix Data.Matrix
Data.Point
Day1 Day1
Day2 Day2
Day3 Day3

View file

@ -3,7 +3,6 @@
module Data.Matrix module Data.Matrix
( Matrix, ( Matrix,
Position,
buildMatrix, buildMatrix,
lookupValue, lookupValue,
lookup, lookup,
@ -21,12 +20,11 @@ import Data.List (find)
import Data.Map.Lazy (Map) import Data.Map.Lazy (Map)
import qualified Data.Map.Lazy as Map import qualified Data.Map.Lazy as Map
import Data.Maybe import Data.Maybe
import Data.Point (Point)
import Prelude hiding (filter, lookup) import Prelude hiding (filter, lookup)
newtype Matrix v = Matrix (Map (Int, Int) v) newtype Matrix v = Matrix (Map (Int, Int) v)
type Position = (Int, Int)
buildMatrix :: [[a]] -> Matrix a buildMatrix :: [[a]] -> Matrix a
buildMatrix xs = Matrix (go xs 0 Map.empty) buildMatrix xs = Matrix (go xs 0 Map.empty)
where where
@ -43,22 +41,22 @@ buildMatrix xs = Matrix (go xs 0 Map.empty)
size :: Matrix v -> Int size :: Matrix v -> Int
size (Matrix hmap) = Map.size hmap size (Matrix hmap) = Map.size hmap
isInBounds :: Position -> Matrix v -> Bool isInBounds :: Point -> Matrix v -> Bool
isInBounds pos (Matrix hmap) = Map.member pos hmap isInBounds pos (Matrix hmap) = Map.member pos hmap
filterWithKey :: (Position -> v -> Bool) -> Matrix v -> Matrix v filterWithKey :: (Point -> v -> Bool) -> Matrix v -> Matrix v
filterWithKey f (Matrix hmap) = Matrix (Map.filterWithKey f hmap) filterWithKey f (Matrix hmap) = Matrix (Map.filterWithKey f hmap)
filter :: (v -> Bool) -> Matrix v -> Matrix v filter :: (v -> Bool) -> Matrix v -> Matrix v
filter f (Matrix hmap) = Matrix (Map.filter f hmap) filter f (Matrix hmap) = Matrix (Map.filter f hmap)
lookup :: Position -> Matrix v -> Maybe v lookup :: Point -> Matrix v -> Maybe v
lookup position (Matrix hmap) = Map.lookup position hmap lookup position (Matrix hmap) = Map.lookup position hmap
lookupMultiple :: [Position] -> Matrix v -> [v] lookupMultiple :: [Point] -> Matrix v -> [v]
lookupMultiple positions matrix = mapMaybe (`lookup` matrix) positions lookupMultiple positions matrix = mapMaybe (`lookup` matrix) positions
insert :: Position -> v -> Matrix v -> Matrix v insert :: Point -> v -> Matrix v -> Matrix v
insert position value (Matrix hmap) = insert position value (Matrix hmap) =
Matrix $ Matrix $
if Map.member position hmap if Map.member position hmap
@ -69,7 +67,7 @@ insert position value (Matrix hmap) =
Search for the given value on the matrix. Search for the given value on the matrix.
Return the position of the first match if found and nothing if it doens't exist. Return the position of the first match if found and nothing if it doens't exist.
--} --}
lookupValue :: (Eq v) => v -> Matrix v -> Maybe Position lookupValue :: (Eq v) => v -> Matrix v -> Maybe Point
lookupValue v (Matrix hmap) = lookupValue v (Matrix hmap) =
let entries = Map.toAscList hmap let entries = Map.toAscList hmap
mEntry = find ((== v) . snd) entries mEntry = find ((== v) . snd) entries
@ -80,7 +78,7 @@ Group elements given a function.
The function receives an entry of the matrix and returns a pair of key -> value. The function receives an entry of the matrix and returns a pair of key -> value.
The values are grouped in order. The values are grouped in order.
--} --}
groupByWith :: forall v a b. (Ord a) => ((Position, v) -> (a, b)) -> Matrix v -> Map a [b] groupByWith :: forall v a b. (Ord a) => ((Point, v) -> (a, b)) -> Matrix v -> Map a [b]
groupByWith f (Matrix hmap) = groupByWith f (Matrix hmap) =
let sortedEntries = Map.toAscList hmap let sortedEntries = Map.toAscList hmap
in foldr (insert' . f) Map.empty sortedEntries in foldr (insert' . f) Map.empty sortedEntries

18
src/Data/Point.hs Normal file
View file

@ -0,0 +1,18 @@
module Data.Point
( Point,
substract,
add,
distance,
)
where
type Point = (Int, Int)
substract :: Point -> (Int, Int) -> (Int, Int)
substract (x, y) (dx, dy) = (x - dx, y - dy)
add :: Point -> (Int, Int) -> (Int, Int)
add (x, y) (dx, dy) = (x + dx, y + dy)
distance :: Point -> Point -> (Int, Int)
distance (xrow, xcol) (yrow, ycol) = (xrow - yrow, xcol - ycol)

View file

@ -1,8 +1,9 @@
module Day6 (partOne, partTwo) where module Day6 (partOne, partTwo) where
import qualified Data.HashSet as HashSet import qualified Data.HashSet as HashSet
import Data.Matrix (Matrix, Position) import Data.Matrix (Matrix)
import qualified Data.Matrix as M import qualified Data.Matrix as M
import Data.Point (Point)
import Day6.Guard (Guard (..)) import Day6.Guard (Guard (..))
import qualified Day6.Guard as G import qualified Day6.Guard as G
@ -21,8 +22,8 @@ partTwo input = do
let labMap = parseLabMap input let labMap = parseLabMap input
guard <- findGuard labMap guard <- findGuard labMap
route <- predictGuardsRoute guard labMap route <- predictGuardsRoute guard labMap
let initialPosition = position guard let initialPoint = position guard
candidates = filter (/= initialPosition) route candidates = filter (/= initialPoint) route
return $ return $
length $ length $
@ -52,7 +53,7 @@ findGuard matrix =
[_, _, _, Just pos] -> Right (Guard pos G.Left) [_, _, _, Just pos] -> Right (Guard pos G.Left)
_ -> Left GuardNotFoundError _ -> Left GuardNotFoundError
predictGuardsRoute :: Guard -> LabMap -> Either Error [Position] predictGuardsRoute :: Guard -> LabMap -> Either Error [Point]
predictGuardsRoute initialGuard labMap = go initialGuard HashSet.empty HashSet.empty predictGuardsRoute initialGuard labMap = go initialGuard HashSet.empty HashSet.empty
where where
go guard visited acc = go guard visited acc =

View file

@ -3,7 +3,7 @@
module Day6.Guard (Guard (..), Direction (..), moveForward, turnRight) where module Day6.Guard (Guard (..), Direction (..), moveForward, turnRight) where
import Data.Hashable import Data.Hashable
import Data.Matrix (Position) import Data.Point (Point)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Prelude hiding (Left, Right) import Prelude hiding (Left, Right)
@ -12,7 +12,7 @@ data Direction = Up | Down | Left | Right
instance Hashable Direction instance Hashable Direction
data Guard = Guard {position :: Position, directon :: Direction} data Guard = Guard {position :: Point, directon :: Direction}
deriving (Eq, Generic) deriving (Eq, Generic)
instance Hashable Guard instance Hashable Guard

View file

@ -1,51 +1,45 @@
module Day8 (partOne, partTwo) where module Day8 (partOne, partTwo) where
import Data.List (nub) import Data.List (nub)
import Data.List.Extra (pairs) import qualified Data.List.Extra as LE
import qualified Data.Map.Lazy as Map import qualified Data.Map.Lazy as Map
import Data.Matrix (Matrix, Position) import Data.Matrix (Matrix)
import qualified Data.Matrix as M import qualified Data.Matrix as M
import Data.Point (Point)
type Node = (Int, Int) import qualified Data.Point as P
partOne :: String -> Int partOne :: String -> Int
partOne input = length $ filter (`M.isInBounds` grid) $ nub antiNodes partOne input = length $ filter (`M.isInBounds` matrix) $ nub antiNodes
where
grid = M.buildMatrix (lines input)
antiNodes = concatMap (uncurry getAntiNodes) $ nodePairs grid
getAntiNodes x y = case distance x y of
(0, 0) -> []
d -> [add x d, substract y d]
partTwo :: String -> Int
partTwo input = length antiNodes
where where
matrix = M.buildMatrix (lines input) matrix = M.buildMatrix (lines input)
combinations = nodePairs matrix pairs = pairNodes matrix
antiNodes = nub $ concatMap (uncurry getAntiNodes) combinations antiNodes = concatMap (uncurry getAntiNodes) pairs
getAntiNodes x y = case distance x y of getAntiNodes x y =
(0, 0) -> [] case P.distance x y of
d -> computePointsAtDistance x d add ++ computePointsAtDistance y d substract (0, 0) -> []
d -> [P.add x d, P.substract y d]
computePointsAtDistance point dist f = partTwo :: String -> Int
let point' = f point dist partTwo input = length (nub antiNodes)
in if M.isInBounds point matrix where
then point : computePointsAtDistance point' dist f matrix = M.buildMatrix (lines input)
else [] pairs = pairNodes matrix
antiNodes = concatMap (uncurry getAntiNodes) pairs
nodePairs :: Matrix Char -> [(Node, Node)] getAntiNodes x y =
nodePairs matrix = let distance = P.distance x y
in go x distance P.add ++ go y distance P.substract
where
go _ (0, 0) _ = []
go point distance f =
let point' = f point distance
in if M.isInBounds point matrix
then point : go point' distance f
else []
pairNodes :: Matrix Char -> [(Point, Point)]
pairNodes matrix =
let noDotsMatrix = M.filter (/= '.') matrix let noDotsMatrix = M.filter (/= '.') matrix
pointGroups = Map.elems $ M.groupByWith (\(position, value) -> (value, position)) noDotsMatrix pointGroups = Map.elems $ M.groupByWith (\(position, value) -> (value, position)) noDotsMatrix
in concatMap pairs pointGroups in concatMap LE.pairs pointGroups
substract :: Position -> (Int, Int) -> (Int, Int)
substract (x, y) (dx, dy) = (x - dx, y - dy)
add :: Position -> (Int, Int) -> (Int, Int)
add (x, y) (dx, dy) = (x + dx, y + dy)
distance :: Position -> Position -> (Int, Int)
distance (xrow, xcol) (yrow, ycol) = (xrow - yrow, xcol - ycol)