Really ugly kotlin solution.
I did this without state, and this caused me some wacky problems. I'll reply with a cleaner version later.
import arrow.core.Either import arrow.core.None import arrow.core.Option import arrow.core.Some import arrow.core.left import arrow.core.right import arrow.core.some import intcode.CurrentState import intcode.handleCodePoint import intcode.toIntCodeProgram import java.util.LinkedList sealed class ShipTile { object Empty : ShipTile() object Oxygen : ShipTile() object Wall : ShipTile() } data class RepairRobot( val code: MutableMap<Long, Long>, val position: PointL = PointL(0, 0), val map: MutableMap<PointL, ShipTile> = mutableMapOf(PointL(0, 0) to ShipTile.Empty), val lastInstruction: Option<Direction> = Option.empty(), val state: Either<String, CurrentState> = CurrentState().right(), val instructions: LinkedList<Direction> = LinkedList() ) object Day15 { private const val FILENAME = "src/main/resources/day15.txt" private val fileData = FILENAME.toIntCodeProgram() private tailrec fun RepairRobot.move(): RepairRobot { return when { instructions.size > 2500 -> this.copy(state = "reached mapping limit".left()) state is Either.Left<String> -> this state is Either.Right<CurrentState> -> when (state.b.pointer) { is None -> this is Some<Long> -> { val nRobot = this.processReturn().sendDirection(instructions) nRobot.copy(state = handleCodePoint(code, nRobot.state)) .move() } else -> this } else -> this } } fun part1() { val r = RepairRobot( code = fileData.toMutableMap(), instructions = LinkedList(allDirections()) ) .move() println(r.state) val path = r.map.path(r.position, listOf(PointL(0, 0) to 0)) println(path) println(r.map.size) r.printScreen() println( fillWithOxygen( r.map.filter { it.key != r.position && it.value == ShipTile.Empty }.map { it.key }.toSet(), setOf(r.position) ) ) } private tailrec fun fillWithOxygen( map: Set<PointL>, position: Set<PointL>, minutes: Int = 0, filled: Int = 0 ): Int { println("map:${map.size}") println("position:${position.size}") println("minutes:$minutes") println("filled:$filled") println() return when { map.isEmpty() -> minutes else -> { val filling = position.flatMap { p -> allDirections().map(p::inDirection).filter { it in map } }.toSet() val unfilled = map - filling fillWithOxygen(unfilled, filling, minutes + 1, filled + filling.size) } } } } private tailrec fun MutableMap<PointL, ShipTile>.path( end: PointL, queue: List<Pair<PointL, Int>>, seen: Set<PointL> = emptySet() ): Int { return when { queue.isEmpty() -> throw Error("not found") queue.first().first == end -> queue.first().second else -> { val (p, dist) = queue.first() val candidates = listOf( p.inDirection(Direction.Up()), p.inDirection(Direction.Left()), p.inDirection(Direction.Down()), p.inDirection(Direction.Right()) ).filter { it !in seen && this[it] != null && this[it] != ShipTile.Wall } .map { it to dist + 1 } path( end, queue.drop(1) + candidates, seen + queue.first().first ) } } } fun main() { Day15.part1() } private fun RepairRobot.sendDirection( instructions: LinkedList<Direction> ): RepairRobot { return when { state is Either.Right<CurrentState> && state.b.waitingForInput && instructions.isNotEmpty() -> { val nInstr = instructions.pop() state.b.inputs.add(nInstr.toLong()) copy(state = state, lastInstruction = nInstr.some()) } state is Either.Right<CurrentState> && state.b.waitingForInput -> copy(state = "No more instructions".left()) else -> this } } fun PointL.inDirection(direction: Direction): PointL = when (direction) { is Direction.Up -> PointL.y.set(this, this.y - 1) is Direction.Down -> PointL.y.set(this, this.y + 1) is Direction.Left -> PointL.x.set(this, this.x - 1) is Direction.Right -> PointL.x.set(this, this.x + 1) } private tailrec fun RepairRobot.processReturn(): RepairRobot { return when (state) { is Either.Left<String> -> this is Either.Right<CurrentState> -> { if (state.b.output.isNotEmpty()) { val rNext = when (state.b.output.pop()) { 0L -> { lastInstruction.map { dir -> map[position.inDirection(dir)] = ShipTile.Wall } this.copy( lastInstruction = Option.empty(), position = position ) } 1L -> { lastInstruction.map { dir -> map[position.inDirection(dir)] = ShipTile.Empty instructions.push(dir.reverse().turnLeft()) instructions.push(dir) instructions.push(dir.turnLeft()) } this.copy( lastInstruction = Option.empty(), position = lastInstruction.fold({ position }, { position.inDirection(it) }) ) } 2L -> { lastInstruction.map { dir -> map[position.inDirection(dir)] = ShipTile.Oxygen instructions.push(dir.reverse().turnLeft()) instructions.push(dir) instructions.push(dir.turnLeft()) } this.copy( lastInstruction = Option.empty(), position = lastInstruction.fold({ position }, { position.inDirection(it) }) // state = "Found Oxygen ${lastInstruction.fold( { position }, { position.inDirection(it) })}".left() ) } else -> this } rNext.processReturn() } else { this } } } } fun allDirections(): Collection<Direction> { return listOf( Direction.Left(), Direction.Up(), Direction.Right(), Direction.Down() ) } private fun Direction.reverse(): Direction { return this.turnLeft().turnLeft() } fun RepairRobot.printScreen() { println(instructions.size) val toConsider = map + (position to ShipTile.Empty) val topLeft = PointL( toConsider.keys.map(PointL::x).min() ?: 0L, toConsider.keys.map(PointL::y).min() ?: 0L ) val bottomRight = PointL( toConsider.keys.map(PointL::x).max() ?: 0L, toConsider.keys.map(PointL::y).max() ?: 0L ) println( (topLeft.y..bottomRight.y).joinToString("\n") { y -> (topLeft.x..bottomRight.x).joinToString("") { x -> when (val p = PointL(x, y)) { position -> lastInstruction.fold({ "B" }, { it.glyph }) else -> map[p].toGlyph() } } } ) println("---") } private fun ShipTile?.toGlyph(): String { return when (this) { is ShipTile.Empty -> "." is ShipTile.Oxygen -> "O" is ShipTile.Wall -> "#" null -> " " } }
Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink.
Hide child comments as well
Confirm
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Really ugly kotlin solution.
I did this without state, and this caused me some wacky problems. I'll reply with a cleaner version later.