Skip to content

Commit 5a4aa5a

Browse files
committed
feat(2024/14): 2024 day 14
1 parent 93b2e39 commit 5a4aa5a

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

2024/day14.scala

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package `2024`.day14
2+
3+
import prelude.*
4+
import java.awt.image.BufferedImage
5+
import com.sksamuel.scrimage.ImmutableImage
6+
import com.sksamuel.scrimage.webp.WebpWriter
7+
8+
given size: Size = Size(101, 103)
9+
10+
case class Robot(p: Pos, v: Pos):
11+
def at(t: Int)(using size: Size): Pos =
12+
val x = {
13+
val x = (p.x + t * v.x) % size.width
14+
if x < 0 then size.width + x else x
15+
}
16+
val y = {
17+
val y = (p.y + t * v.y) % size.height
18+
if y < 0 then size.height + y else y
19+
}
20+
Pos(x, y)
21+
22+
object I:
23+
def unapply(s: String): Option[Int] = s.toIntOption
24+
25+
def parse(input: String) =
26+
input
27+
.split("\n")
28+
.toSeq
29+
.collect { case s"p=${I(x)},${I(y)} v=${I(vx)},${I(vy)}" =>
30+
Robot(Pos(x, y), Pos(vx, vy))
31+
}
32+
33+
enum Quadrant:
34+
case I, II, III, IV
35+
36+
def quadrant(p: Pos)(using size: Size): Option[Quadrant] =
37+
((p.x - size.width / 2).sign, (p.y - size.height / 2).sign) match
38+
case (1, 1) => Some(Quadrant.I)
39+
case (-1, 1) => Some(Quadrant.II)
40+
case (-1, -1) => Some(Quadrant.III)
41+
case (1, -1) => Some(Quadrant.IV)
42+
case _ => None
43+
44+
def asImage(xs: Set[Pos])(using size: Size) =
45+
val image = BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB)
46+
val g = image.createGraphics()
47+
for
48+
x <- 0 until size.width
49+
y <- 0 until size.height
50+
do
51+
g.setColor(
52+
if xs(Pos(x, y)) then java.awt.Color.BLACK else java.awt.Color.WHITE,
53+
)
54+
g.fillRect(x, y, 1, 1)
55+
g.dispose()
56+
57+
image
58+
59+
def part1(input: String) =
60+
val robots = parse(input)
61+
robots.map(_.at(100)).flatMap(quadrant).frequencies.values.reduce(_ * _)
62+
63+
def part2(input: String) =
64+
val robots = parse(input)
65+
66+
for t <- 6470 until 6480 do
67+
val pos = robots.map(_.at(t)).toSet
68+
69+
ImmutableImage
70+
.fromAwt(asImage(pos))
71+
.output(
72+
WebpWriter.MAX_LOSSLESS_COMPRESSION,
73+
f"img/2024/14/$t%05d.webp",
74+
)
75+
76+
@main def main =
77+
val input = fromFile(".cache/2024/14.txt").mkString
78+
79+
println(part1(input))
80+
81+
os.makeDir.all(os.pwd / "img" / "2024" / "14")
82+
println(part2(input))

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ $ scala-cli test .
2222

2323
## Images
2424

25-
| 2015 Day6 Part 1 | 2015 Day6 Part 2 |
26-
| :-------------------------------------------: | :---------------------------------------------: |
27-
| ![2015 Day6 Part 1](img/2015/day6.part1.webp) | ![2015 Day6 Part 2](./img/2015/day6.part2.webp) |
25+
| 2015 Day6 Part 1 | 2015 Day6 Part 2 |
26+
| :-----------------------------------: | :----------------------------------: |
27+
| <img width="100%" src="img/2015/day6.part1.webp"> | <img width="100%" src="img/2015/day6.part2.webp"> |
28+
| **2024 Day14 part 2** | |
29+
| <img width="100%" src="img/2024/day14.part2.webp"> | |

img/2024/day14.part2.webp

352 Bytes
Loading

0 commit comments

Comments
 (0)