@@ -2,11 +2,10 @@ package com.willmolloy.adventofcode._2025
22
33import com.willmolloy.adventofcode.common.Day
44import com.willmolloy.adventofcode.common.Input
5- import com.willmolloy.adventofcode.common.extensions.debug
5+ import com.willmolloy.adventofcode.common.extensions.pairs
66import com.willmolloy.adventofcode.common.extensions.size
77import com.willmolloy.adventofcode.common.grid.Point
88import kotlin.collections.lastIndex
9- import kotlin.math.abs
109import kotlin.math.max
1110import kotlin.math.min
1211
@@ -16,106 +15,67 @@ object Day9 : Day(2025, 9) {
1615 override fun part1 (input : Input ): Any {
1716 val redTiles = getRedTiles(input)
1817
19- var max = 0L
20-
21- for ((i, p1) in redTiles.withIndex()) {
22- for (p2 in redTiles.drop(i + 1 )) {
23- val area = (abs(p2.y - p1.y) + 1 ) * (abs(p2.x - p1.x) + 1 )
24- max = max(max, area)
25- }
26- }
27-
28- return max
29- }
30-
31- private fun getRedTiles (input : Input ): List <Point > =
32- input.readLines().map {
33- val split = it.split(" ," )
34- Point (split[0 ], split[1 ])
35- }
36-
37- private fun getLoopOfGreenTiles (redTiles : List <Point >): List <Point > {
38- val greenTiles = mutableListOf<Point >()
39-
40- for (i in 0 until redTiles.size) {
41- val point = redTiles[i]
42- val adjPoint = if (i < redTiles.lastIndex) redTiles[i + 1 ] else redTiles[0 ]
43- // "Tiles that are adjacent will always be on either the same row or the same column."
44- if (point.x == adjPoint.x) {
45- // same col
46- for (y in min(point.y, adjPoint.y).. max(point.y, adjPoint.y)) {
47- greenTiles.add(Point (point.x, y))
48- }
49- } else {
50- // same row
51- for (x in min(point.x, adjPoint.x).. max(point.x, adjPoint.x)) {
52- greenTiles.add(Point (x, point.y))
53- }
54- }
18+ fun area (p1 : Point , p2 : Point ): Long {
19+ val cols = min(p1.x, p2.x).. max(p1.x, p2.x)
20+ val rows = min(p1.y, p2.y).. max(p1.y, p2.y)
21+ return cols.size * rows.size
5522 }
5623
57- return greenTiles
24+ return redTiles.pairs().maxOf { area(it.first, it.second) }
5825 }
5926
60- override fun part2 (input : Input ): Any {
27+ override fun part2 (input : Input ): Long {
6128 val redTiles = getRedTiles(input)
62- val greenTiles = getLoopOfGreenTiles (redTiles)
29+ val greenTiles = getGreenTilesLoop (redTiles)
6330 val redGreenTiles = redTiles.union(greenTiles)
6431
6532 // "In addition, all the tiles inside this loop of red and green tiles are also green."
66- val rowStart = redGreenTiles.minOf { it.y }
67- val rowEnd = redGreenTiles.maxOf { it.y }
68- println (" ROWS = $rowStart ..$rowEnd " )
69-
7033 // ROW -> COL RANGE
71- val tiledRanges = mutableMapOf<Long , LongRange >()
72-
73- for (row in rowStart.. rowEnd) {
74- val tilesInRow = redGreenTiles.filter { it.y == row }
75- if (tilesInRow.isEmpty()) {
76- continue
77- }
78-
79- val colStart = tilesInRow.minOf { it.x }
80- val colEnd = tilesInRow.maxOf { it.x }
81-
82- tiledRanges[row] = colStart.. colEnd
83- }
84-
85- tiledRanges.debug()
34+ val tiledRanges =
35+ redGreenTiles
36+ .groupBy { it.y }
37+ .mapValues { (_, tiles) -> tiles.minOf { it.x }.. tiles.maxOf { it.x } }
8638
8739 fun area (p1 : Point , p2 : Point ): Long {
88- // no need to filter for topLeft/bottomRight points because all the points in the rectangle
89- // are checked that they're tiled - so just force topLeft/bottomRight:
9040 val cols = min(p1.x, p2.x).. max(p1.x, p2.x)
9141 val rows = min(p1.y, p2.y).. max(p1.y, p2.y)
9242
9343 for (row in rows) {
9444 val tiledRange = tiledRanges[row] ? : return 0L
95- if (tiledRange.start > cols.start) {
96- return 0L
97- }
98- if (tiledRange.endInclusive < cols.endInclusive) {
45+ if (tiledRange.start > cols.start || tiledRange.endInclusive < cols.endInclusive) {
9946 return 0L
10047 }
10148 }
10249
10350 return cols.size * rows.size
10451 }
10552
106- // "The rectangle you choose still must have red tiles in opposite corners"
107- var max = 0L
53+ return redTiles.pairs().maxOf { area(it.first, it.second) }
54+ }
10855
109- for ((i, p1) in redTiles.withIndex()) {
110- for (p2 in redTiles.drop(i + 1 )) {
111- val area = area(p1, p2)
112- if (area > max) {
113- max = area
114- println (" NEW MAX: $p1 and $p2 = $area " )
56+ private fun getRedTiles (input : Input ): List <Point > =
57+ input.readLines().map {
58+ val split = it.split(" ," )
59+ Point (split[0 ], split[1 ])
60+ }
61+
62+ private fun getGreenTilesLoop (redTiles : List <Point >): List <Point > = buildList {
63+ for (i in 0 until redTiles.size) {
64+ val point = redTiles[i]
65+ val adjPoint = if (i < redTiles.lastIndex) redTiles[i + 1 ] else redTiles[0 ]
66+
67+ // "Tiles that are adjacent will always be on either the same row or the same column."
68+ if (point.x == adjPoint.x) {
69+ // same col
70+ for (y in min(point.y, adjPoint.y).. max(point.y, adjPoint.y)) {
71+ add(Point (point.x, y))
72+ }
73+ } else {
74+ // same row
75+ for (x in min(point.x, adjPoint.x).. max(point.x, adjPoint.x)) {
76+ add(Point (x, point.y))
11577 }
11678 }
11779 }
118-
119- return max
12080 }
12181}
0 commit comments