Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- enum class Dir(val id: Long) {
- N(1L) {
- },
- S(2L) {
- },
- W(3L) {
- },
- E(4L) {
- };
- }
- fun reverse(d: Dir) = when (d) {
- Dir.N -> Dir.S
- Dir.S -> Dir.N
- Dir.W -> Dir.E
- Dir.E -> Dir.W
- }
- data class Point(val x: Int, val y: Int) {
- fun move(d: Dir) = when (d) {
- Dir.N -> Point(x, y - 1)
- Dir.S -> Point(x, y + 1)
- Dir.W -> Point(x - 1, y)
- Dir.E -> Point(x + 1, y)
- }
- fun manhattanDist(target: Point) = abs(x - target.x) + abs(y - target.y)
- }
- enum class Block(val id: Long) {
- EMPTY(1L),
- WALL(0L),
- OXYGEN(2L);
- companion object {
- fun of(id: Long) = Block.values().first { it.id == id }
- }
- }
- fun main() {
- val program = Program.read("input15")
- val readChannel = Channel<Long>()
- val writeChannel = Channel<Long>()
- val actionChannel = Channel<Action>()
- val computer = IntcodeComputer(
- DictMemory(),
- ChannelIO(writeChannel, readChannel),
- actionChannel = actionChannel
- )
- runBlocking {
- launch {
- computer.run(program)
- }
- launch {
- var isRunning = true
- var location = Point(0, 0)
- var triedLocation = Point(0, 0)
- var previousLocation = location
- var previousMove = Dir.N
- var oxygenLocation: Point? = null
- val map = mutableMapOf(location to Block.EMPTY)
- val cameFrom = mutableMapOf<Point, Pair<Point, Dir>>()
- while (isRunning) {
- select<Unit> {
- readChannel.onReceive {
- if (triedLocation in map) {
- location = triedLocation
- } else {
- val block = Block.of(it)
- map[triedLocation] = block
- if (block == Block.OXYGEN) {
- oxygenLocation = triedLocation
- }
- when (block) {
- // Block.OXYGEN -> {
- // println(triedLocation)
- // isRunning = false
- // }
- Block.OXYGEN, Block.EMPTY -> {
- cameFrom[triedLocation] = location to previousMove
- location = triedLocation
- println("$triedLocation $block")
- }
- else -> {
- println("$triedLocation $block")
- }
- }
- }
- // print map
- (-20..20).forEach { y ->
- (-20..20).forEach { x ->
- val p = Point(x, y)
- val b = map[p]
- if (p == location) {
- print("x")
- } else if (b != null) {
- print(
- when (b) {
- Block.EMPTY -> " "
- Block.WALL -> "#"
- Block.OXYGEN -> "O"
- }
- )
- } else {
- print("?")
- }
- }
- println()
- }
- }
- actionChannel.onReceive {
- when (it) {
- Action.AWAITING_INPUT -> {
- val neighbors = Dir.values().map {
- it to location.move(it)
- }.filter { it.second !in map }
- if (neighbors.isEmpty()) {
- // go back
- val target = cameFrom[location]
- if (target == null) {
- // TODO: find shortest path now
- println(findPath(Point(0,0), oxygenLocation!!, map)!!.size)
- println(fillOxygen(oxygenLocation!!, map))
- isRunning = false
- } else {
- val d = reverse(target.second)
- previousMove = d
- triedLocation = location.move(d)
- writeChannel.send(d.id)
- }
- } else {
- val selected = neighbors.first().first
- triedLocation = location.move(selected)
- previousMove = selected
- writeChannel.send(selected.id)
- }
- }
- Action.EXIT -> {
- isRunning = false
- }
- }
- }
- }
- }
- }
- }
- }
- data class DistancedPoint(
- val point: Point,
- val distance: Int
- )
- fun reconstructPath(cameFrom: Map<Point, Point>, to: Point): List<Point> {
- var current = to
- val path = mutableListOf<Point>(current)
- while (current in cameFrom) {
- current = cameFrom[current]!!
- path.add(current)
- }
- return path.reversed()
- }
- fun neighbors(current: Point, map: Map<Point, Block>): List<Point> {
- return Dir.values()
- .map { current.move(it) }
- .filter { it in map }
- .filter { map[it]!! != Block.WALL }
- }
- fun findPath(from: Point, target: Point, map: Map<Point, Block>): List<Point>? {
- val openSet = PriorityQueue(Comparator<DistancedPoint> { a, b -> a.distance - b.distance })
- openSet.add(DistancedPoint(from, 0))
- val cameFrom = mutableMapOf<Point, Point>()
- val gScore = mutableMapOf(from to 0)
- while (!openSet.isEmpty()) {
- val current = openSet.poll().point
- if (current == target) {
- return reconstructPath(cameFrom, current)
- }
- val neighbors = neighbors(current, map)
- for (n in neighbors) {
- val score = gScore.getOrDefault(current, Int.MAX_VALUE) + 1
- if (score < gScore.getOrDefault(n, Int.MAX_VALUE)) {
- cameFrom[n] = current
- gScore[n] = score
- openSet.find { it.point == n }?.let { openSet.remove(it) }
- openSet.add(DistancedPoint(n, score + n.manhattanDist(target)))
- }
- }
- }
- return null
- }
- fun fillOxygen(oxygenLocation: Point, map: Map<Point, Block>): Int {
- val hasOxy = mutableSetOf<Point>(oxygenLocation)
- val points = map.keys.filter { map[it]!! == Block.EMPTY }
- var counter = 0
- while (points.filter { it !in hasOxy }.isNotEmpty()) {
- counter += 1
- val newPoints = hasOxy.flatMap {point ->
- Dir.values().map { dir ->
- point.move(dir)
- }.filter { it in map && map[it]!! == Block.EMPTY }
- }
- hasOxy.addAll(newPoints)
- }
- return counter
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement