Skip to content

Instantly share code, notes, and snippets.

@skatenerd
Created December 15, 2022 21:27
Show Gist options
  • Save skatenerd/cabfcd6bf07697854c1b69be0ceba0bf to your computer and use it in GitHub Desktop.
Save skatenerd/cabfcd6bf07697854c1b69be0ceba0bf to your computer and use it in GitHub Desktop.
day fifteen
{-# LANGUAGE OverloadedStrings #-}
module DayFifteen
( main
) where
import qualified Data.Maybe as M
import qualified Data.Ord as O
import qualified Data.Text as T
import qualified Data.Text.IO as TI
import qualified Data.List as L
import qualified Data.List.Split as LS
import qualified Data.Set as S
import qualified Data.Function as F
import Data.Range
import Debug.Trace
data Coordinate = Coordinate { x :: Int, y :: Int } deriving (Eq, Ord, Show)
data InputFact = InputFact { sensor :: Coordinate, beacon :: Coordinate } deriving (Eq, Show)
distanceToRow coordinate row = manhattan coordinate (Coordinate (x coordinate) row)
radius InputFact { sensor, beacon } = manhattan sensor beacon
parse line = InputFact { sensor=(Coordinate sensorX sensorY), beacon=(Coordinate beaconX beaconY)}
where splitted = T.split (`L.elem` splitters) line
splitters :: String = ",=:"
sensorX = readText (splitted !! 1)
sensorY = readText (splitted !! 3)
beaconX = readText (splitted !! 5)
beaconY = readText (splitted !! 7)
readText = read . T.unpack
manhattan Coordinate{x=fromX,y=fromY} Coordinate{x=toX,y=toY} = (abs (fromX - toX)) + (abs (fromY - toY))
testInput :: [T.Text]
testInput = [
"Sensor at x=2, y=18: closest beacon is at x=-2, y=15",
"Sensor at x=9, y=16: closest beacon is at x=10, y=16",
"Sensor at x=13, y=2: closest beacon is at x=15, y=3",
"Sensor at x=12, y=14: closest beacon is at x=10, y=16",
"Sensor at x=10, y=20: closest beacon is at x=10, y=16",
"Sensor at x=14, y=17: closest beacon is at x=10, y=16",
"Sensor at x=8, y=7: closest beacon is at x=2, y=10",
"Sensor at x=2, y=0: closest beacon is at x=2, y=10",
"Sensor at x=0, y=11: closest beacon is at x=2, y=10",
"Sensor at x=20, y=14: closest beacon is at x=25, y=17",
"Sensor at x=17, y=20: closest beacon is at x=21, y=22",
"Sensor at x=16, y=7: closest beacon is at x=15, y=3",
"Sensor at x=14, y=3: closest beacon is at x=15, y=3",
"Sensor at x=20, y=1: closest beacon is at x=15, y=3"
]
testFacts = map parse testInput
emptyRange = 1 *=* 1
getFootprintInTargetRow targetRow fact
| relativeRadius >= 1 = low +=+ high
| relativeRadius == 0 = SingletonRange (x theSensor)
| otherwise = emptyRange
where relativeRadius = (radius fact) - (distanceToRow theSensor targetRow)
theSensor = sensor fact
low = (x theSensor) - relativeRadius
high = ((x theSensor) + relativeRadius)
main targetRow facts = S.size realAnswer
where overcount = fromRanges $ mergeRanges $ map (getFootprintInTargetRow targetRow) facts
overcountCoordinates = S.fromList $ map (\x -> (Coordinate x targetRow)) overcount
realAnswer = S.difference overcountCoordinates beacons
beacons = S.fromList $ map beacon facts
rowIsInteresting minX maxX facts targetRow = [wholeRange] /= (intersection wholeFootprint [wholeRange])
where wholeRange = minX +=+ maxX
wholeFootprint = joinRanges $ map (getFootprintInTargetRow targetRow) facts
partTwo facts minX maxX minY maxY = filter (rowIsInteresting minX maxX facts) [minY..maxY]
getLines path = do
input <- TI.readFile path
return $ T.lines input
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment