-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
day 17 working, and day 18 not working
- Loading branch information
Showing
6 changed files
with
346 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package de.linkel.aoc | ||
|
||
import de.linkel.aoc.base.AbstractLinesAdventDay | ||
import de.linkel.aoc.base.QuizPart | ||
import de.linkel.aoc.utils.grid.Grid | ||
import de.linkel.aoc.utils.grid.Point | ||
import de.linkel.aoc.utils.grid.Vector | ||
import jakarta.inject.Singleton | ||
import java.util.PriorityQueue | ||
|
||
@Singleton | ||
class Day17: AbstractLinesAdventDay<Int>() { | ||
override val day = 17 | ||
|
||
override fun process(part: QuizPart, lines: Sequence<String>): Int { | ||
val grid = Grid.parse(lines) { pos, char -> | ||
char.digitToInt() | ||
} | ||
val dest = Point(grid.width - 1, grid.height - 1) | ||
val start = State(Point(0, 0), Direction.EAST, 0) | ||
return if (part == QuizPart.A) { | ||
dijkstra( | ||
start, | ||
{ state -> state.pos == dest }, | ||
{ state -> state.possibleNextStates(1, 3).filter { it.pos in grid } }, | ||
{ _, to -> grid[to.pos]!! } | ||
)!!.first | ||
} else { | ||
dijkstra( | ||
start, | ||
{ state -> state.pos == dest && state.straight >= 4 }, | ||
{ state -> state.possibleNextStates(4, 10).filter { it.pos in grid } }, | ||
{ _, to -> grid[to.pos]!! } | ||
)!!.first | ||
} | ||
} | ||
|
||
fun print(grid: Grid<Int>, path: Collection<Point>) { | ||
val points = path.toSet() | ||
println( | ||
buildString { | ||
(0 until grid.height).forEach { y -> | ||
(0 until grid.width).forEach { x -> | ||
val p = Point(x, y) | ||
if (p in points) { | ||
append('#') | ||
} else { | ||
append('.') | ||
} | ||
} | ||
append('\n') | ||
} | ||
} | ||
) | ||
} | ||
} | ||
|
||
enum class Direction( | ||
val vector: Vector | ||
) { | ||
NORTH(Vector(0, -1)) { | ||
override val left get() = WEST | ||
override val right get() = EAST | ||
override val opposite get() = SOUTH | ||
}, | ||
EAST(Vector(1, 0)) { | ||
override val left get() = NORTH | ||
override val right get() = SOUTH | ||
override val opposite get() = WEST | ||
}, | ||
SOUTH(Vector(0, 1)) { | ||
override val left get() = EAST | ||
override val right get() = WEST | ||
override val opposite get() = NORTH | ||
}, | ||
WEST(Vector(-1, 0)) { | ||
override val left get() = SOUTH | ||
override val right get() = NORTH | ||
override val opposite get() = EAST | ||
}; | ||
|
||
abstract val left: Direction | ||
abstract val right: Direction | ||
abstract val opposite: Direction | ||
} | ||
|
||
operator fun Point.plus(direction: Direction): Point = this + direction.vector | ||
|
||
data class State( | ||
val pos: Point, | ||
val direction: Direction, | ||
val straight: Int | ||
) { | ||
fun possibleNextStates(minStraight: Int = 1, maxStraight: Int = 100): List<State> { | ||
return buildList { | ||
if (straight < maxStraight) { | ||
add(State(pos + direction, direction, straight + 1)) | ||
} | ||
if (straight >= minStraight) { | ||
add(State(pos + direction.right, direction.right, 1)) | ||
add(State(pos + direction.left, direction.left, 1)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
fun <S> dijkstra( | ||
start: S, | ||
endLambda: (S) -> Boolean, | ||
nextLamba: (S) -> Iterable<S>, | ||
costLambda: (S, S) -> Int | ||
): Pair<Int, List<S>>? { | ||
data class Evaluated(val distance: Int, val prev: S?) | ||
|
||
data class Planned(val state: S, val distance: Int) : Comparable<Planned> { | ||
override fun compareTo(other: Planned): Int = distance.compareTo(other.distance) | ||
} | ||
|
||
val queue = PriorityQueue(listOf(Planned(start, 0))) | ||
val evaluated = mutableMapOf(start to Evaluated(0, null)) | ||
|
||
while (queue.isNotEmpty()) { | ||
val current = queue.remove() | ||
if (endLambda(current.state)) { | ||
val winningPath = mutableListOf<S>() | ||
var s: S? = current.state | ||
while (s != null) { | ||
winningPath.add(0, s) | ||
s = evaluated[s]!!.prev | ||
} | ||
return current.distance to winningPath | ||
} | ||
|
||
nextLamba(current.state) | ||
.filter { it !in evaluated } | ||
.forEach { state -> | ||
val distance = current.distance + costLambda(current.state, state) | ||
queue.add(Planned(state, distance)) | ||
evaluated[state] = Evaluated(distance, current.state) | ||
} | ||
} | ||
return null | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package de.linkel.aoc | ||
|
||
import de.linkel.aoc.base.AbstractLinesAdventDay | ||
import de.linkel.aoc.base.QuizPart | ||
import de.linkel.aoc.utils.grid.Grid | ||
import de.linkel.aoc.utils.grid.Point | ||
import jakarta.inject.Singleton | ||
import kotlin.math.max | ||
import kotlin.math.min | ||
|
||
@Singleton | ||
class Day18: AbstractLinesAdventDay<Long>() { | ||
override val day = 18 | ||
|
||
data class Cube( | ||
val dirIn: Char, | ||
val dirOut: Char | ||
) | ||
data class Point( | ||
val x: Long, | ||
val y: Long | ||
) | ||
interface Vector { | ||
val deltaX: Long | ||
val deltaY: Long | ||
} | ||
enum class Direction( | ||
override val deltaX: Long, | ||
override val deltaY: Long | ||
): Vector { | ||
R(1, 0), | ||
D(0, 1), | ||
L(-1, 0), | ||
U(0, -1) | ||
} | ||
data class GenericVector( | ||
override val deltaX: Long, | ||
override val deltaY: Long | ||
): Vector | ||
operator fun Point.plus(vector: Vector): Point = Point(this.x + vector.deltaX, this.y + vector.deltaY) | ||
operator fun Vector.times(factor: Long): Vector = GenericVector(this.deltaX * factor, this.deltaY * factor) | ||
|
||
override fun process(part: QuizPart, lines: Sequence<String>): Long { | ||
val origin = Point(0L,0L) | ||
val map = mutableMapOf<Point, Cube>() | ||
var minX = 0L | ||
var minY = 0L | ||
var maxX = 0L | ||
var maxY = 0L | ||
// val map = Grid<Cube>(origin, Dimension(1,1)) | ||
map[origin] = Cube('0','?') | ||
lines.fold(origin) { pos, line -> | ||
val (dir, len) = if (part == QuizPart.A) { | ||
val token = line.split(' ') | ||
val dir = Direction.valueOf(token[0]) | ||
val len = token[1].toLong() | ||
dir to len | ||
} else { | ||
val hex = line.substringAfter('#').substringBefore(')') | ||
val len = hex.substring(0, 5).toLong(16) | ||
val dir = Direction.entries[hex[5].digitToInt()] | ||
dir to len | ||
} | ||
val dest = pos + dir * len | ||
// map.stretchTo(dest) | ||
(1L..len).forEach { | ||
map[pos + dir * it] = Cube(line[0], line[0]) | ||
} | ||
minX = min(minX, dest.x) | ||
minY = min(minY, dest.y) | ||
maxX = max(maxX, dest.x) | ||
maxY = max(maxY, dest.y) | ||
map[pos] = map[pos]!!.copy(dirOut = line[0]) | ||
dest | ||
} | ||
|
||
var insides = 0L | ||
(minY..maxY) | ||
.forEach { y -> | ||
// var upIn = false | ||
// var downOut = false | ||
var inside = false | ||
(minX..maxX) | ||
.forEach { x -> | ||
val p = Point(x, y) | ||
if (map[p] != null) { | ||
// if (map[p]!!.dirIn == 'D' || map[p]!!.dirOut == 'U') | ||
if (map[p]!!.dirIn == 'U' || map[p]!!.dirOut == 'D') | ||
inside = !inside | ||
// if (map[p]!!.dirIn == 'U') | ||
// upIn = !upIn | ||
// if (map[p]!!.dirOut == 'D') | ||
// downOut = !downOut | ||
} else if (inside) { | ||
// } else if (upIn != downOut) { | ||
insides++ | ||
// map[p] = Cube('#', '#') | ||
} | ||
} | ||
} | ||
|
||
return insides + map.size | ||
} | ||
fun printMap(grid: Grid<Cube>) { | ||
println( | ||
buildString { | ||
(grid.area.y until (grid.area.y + grid.area.height)) | ||
.forEach { y -> | ||
(grid.area.x until (grid.area.x + grid.area.width)) | ||
.forEach { x -> | ||
val p = Point(x, y) | ||
if (grid[p] != null) { | ||
append(grid[p]!!.dirIn) | ||
} else { | ||
append('.') | ||
} | ||
} | ||
append('\n') | ||
} | ||
} | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package de.linkel.aoc | ||
|
||
import de.linkel.aoc.base.AbstractLinesAdventDay | ||
import de.linkel.aoc.base.QuizPart | ||
import jakarta.inject.Singleton | ||
|
||
@Singleton | ||
class Day19: AbstractLinesAdventDay<Int>() { | ||
override val day = 19 | ||
|
||
override fun process(part: QuizPart, lines: Sequence<String>): Int { | ||
return 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package de.linkel.aoc | ||
|
||
class Day17Test: AbstractDayTest<Int>() { | ||
override val exampleA = """ | ||
2413432311323 | ||
3215453535623 | ||
3255245654254 | ||
3446585845452 | ||
4546657867536 | ||
1438598798454 | ||
4457876987766 | ||
3637877979653 | ||
4654967986887 | ||
4564679986453 | ||
1224686865563 | ||
2546548887735 | ||
4322674655533 | ||
""".trimIndent() | ||
override val exampleSolutionA = 102 | ||
override val solutionA = 956 | ||
|
||
override val exampleSolutionB = 94 | ||
override val solutionB = 1106 | ||
|
||
override val implementation = Day17() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package de.linkel.aoc | ||
|
||
class Day18Test: AbstractDayTest<Long>() { | ||
override val exampleA = """ | ||
R 6 (#70c710) | ||
D 5 (#0dc571) | ||
L 2 (#5713f0) | ||
D 2 (#d2c081) | ||
R 2 (#59c680) | ||
D 2 (#411b91) | ||
L 5 (#8ceee2) | ||
U 2 (#caa173) | ||
L 1 (#1b58a2) | ||
U 2 (#caa171) | ||
R 2 (#7807d2) | ||
U 3 (#a77fa3) | ||
L 2 (#015232) | ||
U 2 (#7a21e3) | ||
""".trimIndent() | ||
override val exampleSolutionA = 62L | ||
override val solutionA = 35991L | ||
|
||
override val exampleSolutionB = 952408144115L | ||
override val solutionB = 0L | ||
|
||
override val implementation = Day18() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package de.linkel.aoc | ||
|
||
class Day19Test: AbstractDayTest<Int>() { | ||
override val exampleA = """ | ||
""".trimIndent() | ||
override val exampleSolutionA = 0 | ||
override val solutionA = 0 | ||
|
||
override val exampleSolutionB = 0 | ||
override val solutionB = 0 | ||
|
||
override val implementation = Day19() | ||
} |