Advertisement
Guest User

Untitled

a guest
Dec 15th, 2019
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 7.68 KB | None | 0 0
  1. enum class Dir(val id: Long) {
  2.     N(1L) {
  3.  
  4.     },
  5.     S(2L) {
  6.  
  7.     },
  8.     W(3L) {
  9.  
  10.     },
  11.     E(4L) {
  12.  
  13.     };
  14. }
  15.  
  16. fun reverse(d: Dir) = when (d) {
  17.     Dir.N -> Dir.S
  18.     Dir.S -> Dir.N
  19.     Dir.W -> Dir.E
  20.     Dir.E -> Dir.W
  21. }
  22.  
  23. data class Point(val x: Int, val y: Int) {
  24.  
  25.     fun move(d: Dir) = when (d) {
  26.         Dir.N -> Point(x, y - 1)
  27.         Dir.S -> Point(x, y + 1)
  28.         Dir.W -> Point(x - 1, y)
  29.         Dir.E -> Point(x + 1, y)
  30.     }
  31.  
  32.     fun manhattanDist(target: Point) = abs(x - target.x) + abs(y - target.y)
  33.  
  34. }
  35.  
  36. enum class Block(val id: Long) {
  37.     EMPTY(1L),
  38.     WALL(0L),
  39.     OXYGEN(2L);
  40.  
  41.     companion object {
  42.         fun of(id: Long) = Block.values().first { it.id == id }
  43.     }
  44. }
  45.  
  46. fun main() {
  47.     val program = Program.read("input15")
  48.     val readChannel = Channel<Long>()
  49.     val writeChannel = Channel<Long>()
  50.     val actionChannel = Channel<Action>()
  51.     val computer = IntcodeComputer(
  52.         DictMemory(),
  53.         ChannelIO(writeChannel, readChannel),
  54.         actionChannel = actionChannel
  55.     )
  56.     runBlocking {
  57.         launch {
  58.             computer.run(program)
  59.         }
  60.         launch {
  61.             var isRunning = true
  62.             var location = Point(0, 0)
  63.             var triedLocation = Point(0, 0)
  64.             var previousLocation = location
  65.             var previousMove = Dir.N
  66.             var oxygenLocation: Point? = null
  67.             val map = mutableMapOf(location to Block.EMPTY)
  68.             val cameFrom = mutableMapOf<Point, Pair<Point, Dir>>()
  69.             while (isRunning) {
  70.                 select<Unit> {
  71.                     readChannel.onReceive {
  72.                         if (triedLocation in map) {
  73.                             location = triedLocation
  74.                         } else {
  75.                             val block = Block.of(it)
  76.                             map[triedLocation] = block
  77.                             if (block == Block.OXYGEN) {
  78.                                 oxygenLocation = triedLocation
  79.                             }
  80.                             when (block) {
  81. //                                Block.OXYGEN -> {
  82. //                                    println(triedLocation)
  83. //                                    isRunning = false
  84. //                                }
  85.                                 Block.OXYGEN, Block.EMPTY -> {
  86.                                     cameFrom[triedLocation] = location to previousMove
  87.                                     location = triedLocation
  88.                                     println("$triedLocation $block")
  89.                                 }
  90.                                 else -> {
  91.                                     println("$triedLocation $block")
  92.                                 }
  93.                             }
  94.                         }
  95.  
  96.                         // print map
  97.                         (-20..20).forEach { y ->
  98.                             (-20..20).forEach { x ->
  99.                                 val p = Point(x, y)
  100.                                 val b = map[p]
  101.                                 if (p == location) {
  102.                                     print("x")
  103.                                 } else if (b != null) {
  104.                                     print(
  105.                                         when (b) {
  106.                                             Block.EMPTY -> " "
  107.                                             Block.WALL -> "#"
  108.                                             Block.OXYGEN -> "O"
  109.                                         }
  110.                                     )
  111.                                 } else {
  112.                                     print("?")
  113.                                 }
  114.                             }
  115.                             println()
  116.                         }
  117.                     }
  118.                     actionChannel.onReceive {
  119.                         when (it) {
  120.                             Action.AWAITING_INPUT -> {
  121.                                 val neighbors = Dir.values().map {
  122.                                     it to location.move(it)
  123.                                 }.filter { it.second !in map }
  124.                                 if (neighbors.isEmpty()) {
  125.                                     // go back
  126.                                     val target = cameFrom[location]
  127.                                     if (target == null) {
  128.                                         // TODO: find shortest path now
  129.                                         println(findPath(Point(0,0), oxygenLocation!!, map)!!.size)
  130.                                         println(fillOxygen(oxygenLocation!!, map))
  131.                                         isRunning = false
  132.                                     } else {
  133.                                         val d = reverse(target.second)
  134.                                         previousMove = d
  135.                                         triedLocation = location.move(d)
  136.                                         writeChannel.send(d.id)
  137.                                     }
  138.                                 } else {
  139.                                     val selected = neighbors.first().first
  140.                                     triedLocation = location.move(selected)
  141.                                     previousMove = selected
  142.                                     writeChannel.send(selected.id)
  143.                                 }
  144.                             }
  145.                             Action.EXIT -> {
  146.                                 isRunning = false
  147.                             }
  148.                         }
  149.                     }
  150.                 }
  151.             }
  152.         }
  153.     }
  154. }
  155.  
  156.  
  157. data class DistancedPoint(
  158.     val point: Point,
  159.     val distance: Int
  160. )
  161.  
  162. fun reconstructPath(cameFrom: Map<Point, Point>, to: Point): List<Point> {
  163.     var current = to
  164.     val path = mutableListOf<Point>(current)
  165.     while (current in cameFrom) {
  166.         current = cameFrom[current]!!
  167.         path.add(current)
  168.     }
  169.     return path.reversed()
  170. }
  171.  
  172. fun neighbors(current: Point, map: Map<Point, Block>): List<Point> {
  173.     return Dir.values()
  174.         .map { current.move(it) }
  175.         .filter { it in map }
  176.         .filter { map[it]!! != Block.WALL }
  177. }
  178.  
  179. fun findPath(from: Point, target: Point, map: Map<Point, Block>): List<Point>? {
  180.     val openSet = PriorityQueue(Comparator<DistancedPoint> { a, b -> a.distance - b.distance })
  181.     openSet.add(DistancedPoint(from, 0))
  182.     val cameFrom = mutableMapOf<Point, Point>()
  183.     val gScore = mutableMapOf(from to 0)
  184.  
  185.     while (!openSet.isEmpty()) {
  186.         val current = openSet.poll().point
  187.         if (current == target) {
  188.             return reconstructPath(cameFrom, current)
  189.         }
  190.  
  191.         val neighbors = neighbors(current, map)
  192.  
  193.         for (n in neighbors) {
  194.             val score = gScore.getOrDefault(current, Int.MAX_VALUE) + 1
  195.             if (score < gScore.getOrDefault(n, Int.MAX_VALUE)) {
  196.                 cameFrom[n] = current
  197.                 gScore[n] = score
  198.                 openSet.find { it.point == n }?.let { openSet.remove(it) }
  199.                 openSet.add(DistancedPoint(n, score + n.manhattanDist(target)))
  200.             }
  201.         }
  202.     }
  203.     return null
  204. }
  205.  
  206.  
  207. fun fillOxygen(oxygenLocation: Point, map: Map<Point, Block>): Int {
  208.     val hasOxy = mutableSetOf<Point>(oxygenLocation)
  209.     val points = map.keys.filter { map[it]!! == Block.EMPTY }
  210.     var counter = 0
  211.     while (points.filter { it !in hasOxy }.isNotEmpty()) {
  212.         counter += 1
  213.         val newPoints = hasOxy.flatMap {point ->
  214.             Dir.values().map { dir ->
  215.                 point.move(dir)
  216.             }.filter { it in map && map[it]!! == Block.EMPTY }
  217.         }
  218.         hasOxy.addAll(newPoints)
  219.     }
  220.     return counter
  221. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement