Skip to content

Commit cc61010

Browse files
committed
Add solution for day 15
1 parent 14833eb commit cc61010

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

2022/input/day15

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Sensor at x=98246, y=1908027: closest beacon is at x=1076513, y=2000000
2+
Sensor at x=1339369, y=2083853: closest beacon is at x=1076513, y=2000000
3+
Sensor at x=679177, y=3007305: closest beacon is at x=1076513, y=2000000
4+
Sensor at x=20262, y=3978297: closest beacon is at x=13166, y=4136840
5+
Sensor at x=3260165, y=2268955: closest beacon is at x=4044141, y=2290104
6+
Sensor at x=2577675, y=3062584: closest beacon is at x=2141091, y=2828176
7+
Sensor at x=3683313, y=2729137: closest beacon is at x=4044141, y=2290104
8+
Sensor at x=1056412, y=370641: closest beacon is at x=1076513, y=2000000
9+
Sensor at x=2827280, y=1827095: closest beacon is at x=2757345, y=1800840
10+
Sensor at x=1640458, y=3954524: closest beacon is at x=2141091, y=2828176
11+
Sensor at x=2139884, y=1162189: closest beacon is at x=2757345, y=1800840
12+
Sensor at x=3777450, y=3714504: closest beacon is at x=3355953, y=3271922
13+
Sensor at x=1108884, y=2426713: closest beacon is at x=1076513, y=2000000
14+
Sensor at x=2364307, y=20668: closest beacon is at x=2972273, y=-494417
15+
Sensor at x=3226902, y=2838842: closest beacon is at x=3355953, y=3271922
16+
Sensor at x=22804, y=3803886: closest beacon is at x=13166, y=4136840
17+
Sensor at x=2216477, y=2547945: closest beacon is at x=2141091, y=2828176
18+
Sensor at x=1690953, y=2203555: closest beacon is at x=1076513, y=2000000
19+
Sensor at x=3055156, y=3386812: closest beacon is at x=3355953, y=3271922
20+
Sensor at x=3538996, y=719130: closest beacon is at x=2972273, y=-494417
21+
Sensor at x=2108918, y=2669413: closest beacon is at x=2141091, y=2828176
22+
Sensor at x=3999776, y=2044283: closest beacon is at x=4044141, y=2290104
23+
Sensor at x=2184714, y=2763072: closest beacon is at x=2141091, y=2828176
24+
Sensor at x=2615462, y=2273553: closest beacon is at x=2757345, y=1800840

2022/src/day15.scala

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package day15
2+
3+
import locations.Directory.currentDir
4+
import inputs.Input.loadFileSync
5+
6+
@main def part1: Unit =
7+
println(s"The solution is ${part1(loadInput())}")
8+
9+
@main def part2: Unit =
10+
println(s"The solution is ${part2(loadInput())}")
11+
12+
def loadInput(): String = loadFileSync(s"$currentDir/../input/day15")
13+
14+
case class Position(x: Int, y: Int)
15+
16+
def parse(input: String): List[(Position, Position)] =
17+
input.split("\n").toList.map{
18+
case s"Sensor at x=$sx, y=$sy: closest beacon is at x=$bx, y=$by" =>
19+
(Position(sx.toInt, sy.toInt), Position(bx.toInt, by.toInt))
20+
}
21+
22+
def distance(p1: Position, p2: Position): Int =
23+
Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y)
24+
25+
def distanceToLine(p: Position, y: Int): Int =
26+
Math.abs(p.y - y)
27+
28+
def lineCoverage(sensor: Position, radius: Int, lineY: Int): Range =
29+
val radiusInLine = radius - distanceToLine(sensor, lineY)
30+
31+
// if radiusInLine is smaller than 0, the range will be empty
32+
(sensor.x - radiusInLine) to (sensor.x + radiusInLine)
33+
34+
def coverOfLine(sensorsWithDistances: List[(Position, Int)], line: Int) =
35+
sensorsWithDistances.map( (sensor, radius) => lineCoverage(sensor, radius, line) ).filter(_.nonEmpty)
36+
37+
def smartDiff(r1: Range, r2: Range): List[Range] =
38+
val innit = r1.start to Math.min(r2.start - 1, r1.last)
39+
val tail = Math.max(r1.start, r2.last + 1) to r1.last
40+
val res = if innit == tail then
41+
List(innit)
42+
else
43+
List(innit, tail)
44+
res.filter(_.nonEmpty).toList
45+
46+
def remainingSpots(target: Range, cover: List[Range]): Set[Int] =
47+
48+
def rec(partialTarget: List[Range], remainingCover: List[Range]): List[Range] =
49+
if remainingCover.isEmpty then
50+
partialTarget
51+
else
52+
val (curr: Range) :: rest = remainingCover: @unchecked
53+
rec(
54+
partialTarget = partialTarget.flatMap( r => smartDiff(r, curr) ),
55+
remainingCover = rest
56+
)
57+
58+
rec(List(target), cover).flatten.toSet
59+
60+
def part1(input: String): Int =
61+
val parsed: List[(Position, Position)] = parse(input)
62+
val beacons: Set[Position] = parsed.map(_._2).toSet
63+
val sensorsWithDistances: List[(Position, Int)] =
64+
parsed.map( (sensor, beacon) => (sensor, distance(sensor, beacon)) )
65+
66+
val line = 2000000
67+
val cover: List[Range] = coverOfLine(sensorsWithDistances, line)
68+
val beaconsOnLine: Set[Position] = beacons.filter(_.y == line)
69+
val count: Int = cover.map(_.size).sum - beaconsOnLine.size
70+
count
71+
72+
def part2(input: String): Any =
73+
74+
val parsed: List[(Position, Position)] = parse(input)
75+
val beacons: Set[Position] = parsed.map(_._2).toSet
76+
val sensorsWithDistances: List[(Position, Int)] =
77+
parsed.map( (sensor, beacon) => (sensor, distance(sensor, beacon)) )
78+
79+
val target: Range = 0 until 4_000_000
80+
val spots: Seq[Position] = target.flatMap{
81+
line =>
82+
val cover: List[Range] = coverOfLine(sensorsWithDistances, line)
83+
val beaconsOnLine: Set[Position] = beacons.filter(_.y == line)
84+
85+
val remainingRanges: List[Range] = cover.foldLeft(List(target)){
86+
case (acc: List[Range], range: Range) =>
87+
acc.flatMap( r => smartDiff(r, range) )
88+
}
89+
val potential = remainingRanges.flatten.toSet
90+
91+
val spotsOnLine = potential diff beaconsOnLine.map( b => b.x )
92+
spotsOnLine.map( x => Position(x, line) )
93+
}
94+
def tuningFrequency(p: Position): BigInt = BigInt(p.x) * 4_000_000 + p.y
95+
96+
println(spots.mkString(", "))
97+
assert(spots.size == 1)
98+
tuningFrequency(spots.head)

0 commit comments

Comments
 (0)