package day9

import java.lang.IllegalArgumentException

class Day9(val input: List<String>) {

    private val board = Board(Point(0, 0), Point(0, 0), Point(0, 0), mapOf())
    private val rope = (1..10).map { Point(0, 0) }.toMutableList()
    private val board2 = Board2(Point(0, 0), rope, mutableMapOf())

    private fun toCommandList(input: String): List<Command> {
        val direction = input.split(" ")[0]
        val repetitions = input.split(" ")[1].toInt()
        return when (direction) {
            "U" -> (1..repetitions).map { Command.Up(1) }
            "D" -> (1..repetitions).map { Command.Down(1) }
            "L" -> (1..repetitions).map { Command.Left(1) }
            "R" -> (1..repetitions).map { Command.Right(1) }
            else -> {
                throw IllegalArgumentException()
            }
        }
    }

    fun part1(): Int {
        val resultingBoard = input.flatMap { toCommandList(it) }
            .fold(board) { board, command -> board.handleCommand(command) }
        return resultingBoard.tailVisitationMap.size
    }

    fun part2(): Int {
        val resultingBoard = input.flatMap { toCommandList(it) }
            .fold(board2) { board2, command -> board2.handleCommand(command) }
        return resultingBoard.tailVisitationMap.size
    }
}

data class Board(val start: Point, val head: Point, val tail: Point, val tailVisitationMap: Map<Point, Int>) {
    fun handleCommand(command: Command): Board {
        when (command) {
            is Command.Down -> {
                val newHead = Point(head.x, head.y - 1)
                val newTail = calculateTail(newHead, tail)
                val count = tailVisitationMap[newTail] ?: 0
                return this.copy(
                    head = newHead,
                    tail = newTail,
                    tailVisitationMap = tailVisitationMap + (newTail to count + 1)
                )
            }

            is Command.Left -> {
                val newHead = Point(head.x - 1, head.y)
                val newTail = calculateTail(newHead, tail)
                val count = tailVisitationMap[newTail] ?: 0
                return this.copy(
                    head = newHead,
                    tail = newTail,
                    tailVisitationMap = tailVisitationMap + (newTail to count + 1)
                )
            }

            is Command.Right -> {
                val newHead = Point(head.x + 1, head.y)
                val newTail = calculateTail(newHead, tail)
                val count = tailVisitationMap[newTail] ?: 0
                return this.copy(
                    head = newHead,
                    tail = newTail,
                    tailVisitationMap = tailVisitationMap + (newTail to count + 1)
                )
            }

            is Command.Up -> {
                val newHead = Point(head.x, head.y + 1)
                val newTail = calculateTail(newHead, tail)
                val count = tailVisitationMap[newTail] ?: 0
                return this.copy(
                    head = newHead,
                    tail = newTail,
                    tailVisitationMap = tailVisitationMap + (newTail to count + 1)
                )
            }
        }
    }
}

data class Board2(val start: Point, val points: MutableList<Point>, val tailVisitationMap: MutableMap<Point, Int>) {

    fun handleCommand(command: Command): Board2 {
        when (command) {
            is Command.Down -> {
                points[0] = Point(points[0].x, points[0].y - 1)
                calculate()
                return this
            }

            is Command.Left -> {
                points[0] = Point(points[0].x - 1, points[0].y)
                calculate()
                return this
            }

            is Command.Right -> {
                points[0] = Point(points[0].x + 1, points[0].y)
                calculate()
                return this
            }

            is Command.Up -> {
                points[0] = Point(points[0].x, points[0].y + 1)
                calculate()
                return this
            }
        }
    }

    private fun calculate() {
        for (i in 1 until points.size) {
            points[i] = calculateTail(points[i - 1], points[i])
        }
        tailVisitationMap.compute(points.last()) { _, oldValue -> (oldValue ?: 0) + 1 }
    }
}

private fun calculateTail(newHead: Point, existingTail: Point): Point {
    if (newHead == existingTail) return existingTail
    if (newHead.x == existingTail.x + 1 && newHead.y == existingTail.y + 1) return existingTail
    if (newHead.x == existingTail.x + 1 && newHead.y == existingTail.y - 1) return existingTail
    if (newHead.x == existingTail.x - 1 && newHead.y == existingTail.y + 1) return existingTail
    if (newHead.x == existingTail.x - 1 && newHead.y == existingTail.y - 1) return existingTail
    if (newHead.x == existingTail.x && newHead.y == existingTail.y + 1) return existingTail
    if (newHead.x == existingTail.x && newHead.y == existingTail.y - 1) return existingTail
    if (newHead.x == existingTail.x + 1 && newHead.y == existingTail.y) return existingTail
    if (newHead.x == existingTail.x - 1 && newHead.y == existingTail.y) return existingTail

    // same column
    if (newHead.x == existingTail.x) {
        // Only one space apart
        if (newHead.y == existingTail.y + 1 || newHead.y == existingTail.y - 1) {
            return existingTail
        }
        return if (newHead.y > existingTail.y) {
            Point(existingTail.x, existingTail.y + 1)
        } else {
            Point(existingTail.x, existingTail.y - 1)
        }
    }
    if (newHead.y == existingTail.y) {
        // same row
        if (newHead.x == existingTail.x + 1 || newHead.x == existingTail.x - 1) {
            return existingTail
        }
        return if (newHead.x > existingTail.x) {
            Point(existingTail.x + 1, existingTail.y)
        } else {
            Point(existingTail.x - 1, existingTail.y)
        }
    }
    // neither on same row nor column
    /*
    .....    .....
    ...H.    ...H.
    ..... -> ...T.
    ..T..    .....
    .....    .....
     */
    if (newHead.x > existingTail.x && newHead.y > existingTail.y) return Point(existingTail.x + 1, existingTail.y + 1)
    if (newHead.x < existingTail.x && newHead.y > existingTail.y) return Point(existingTail.x - 1, existingTail.y + 1)
    return if (newHead.x > existingTail.x) {
        Point(existingTail.x + 1, existingTail.y - 1)
    } else {
        Point(existingTail.x - 1, existingTail.y - 1)
    }
}

sealed class Command {
    abstract val repetitions: Int

    data class Up(override val repetitions: Int) : Command()
    data class Down(override val repetitions: Int) : Command()
    data class Left(override val repetitions: Int) : Command()
    data class Right(override val repetitions: Int) : Command()
}

data class Point(val x: Int, val y: Int)

fun main() {
    val testInput = Day9::class.java.getResourceAsStream("/day9_test.txt").bufferedReader().readLines()
    val test2Input = Day9::class.java.getResourceAsStream("/day9_test2.txt").bufferedReader().readLines()
    val input = Day9::class.java.getResourceAsStream("/day9_input.txt").bufferedReader().readLines()

    val day9test = Day9(testInput)
    val day9test2 = Day9(test2Input)
    val day9input = Day9(input)

    println("Day9 part 1 test result: ${day9test.part1()}")
    println("Day9 part 1 result: ${day9input.part1()}")
    println("Day9 part 2 test result: ${day9test2.part2()}")
    println("Day9 part 2 result: ${day9input.part2()}")
}

Compiled from "Day9.kt"
public final class day9.Day9Kt {
  private static final day9.Point calculateTail(day9.Point, day9.Point);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #12                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
       5: ifeq          10
       8: aload_1
       9: areturn
      10: aload_0
      11: invokevirtual #18                 // Method day9/Point.getX:()I
      14: aload_1
      15: invokevirtual #18                 // Method day9/Point.getX:()I
      18: iconst_1
      19: iadd
      20: if_icmpne     38
      23: aload_0
      24: invokevirtual #21                 // Method day9/Point.getY:()I
      27: aload_1
      28: invokevirtual #21                 // Method day9/Point.getY:()I
      31: iconst_1
      32: iadd
      33: if_icmpne     38
      36: aload_1
      37: areturn
      38: aload_0
      39: invokevirtual #18                 // Method day9/Point.getX:()I
      42: aload_1
      43: invokevirtual #18                 // Method day9/Point.getX:()I
      46: iconst_1
      47: iadd
      48: if_icmpne     66
      51: aload_0
      52: invokevirtual #21                 // Method day9/Point.getY:()I
      55: aload_1
      56: invokevirtual #21                 // Method day9/Point.getY:()I
      59: iconst_1
      60: isub
      61: if_icmpne     66
      64: aload_1
      65: areturn
      66: aload_0
      67: invokevirtual #18                 // Method day9/Point.getX:()I
      70: aload_1
      71: invokevirtual #18                 // Method day9/Point.getX:()I
      74: iconst_1
      75: isub
      76: if_icmpne     94
      79: aload_0
      80: invokevirtual #21                 // Method day9/Point.getY:()I
      83: aload_1
      84: invokevirtual #21                 // Method day9/Point.getY:()I
      87: iconst_1
      88: iadd
      89: if_icmpne     94
      92: aload_1
      93: areturn
      94: aload_0
      95: invokevirtual #18                 // Method day9/Point.getX:()I
      98: aload_1
      99: invokevirtual #18                 // Method day9/Point.getX:()I
     102: iconst_1
     103: isub
     104: if_icmpne     122
     107: aload_0
     108: invokevirtual #21                 // Method day9/Point.getY:()I
     111: aload_1
     112: invokevirtual #21                 // Method day9/Point.getY:()I
     115: iconst_1
     116: isub
     117: if_icmpne     122
     120: aload_1
     121: areturn
     122: aload_0
     123: invokevirtual #18                 // Method day9/Point.getX:()I
     126: aload_1
     127: invokevirtual #18                 // Method day9/Point.getX:()I
     130: if_icmpne     148
     133: aload_0
     134: invokevirtual #21                 // Method day9/Point.getY:()I
     137: aload_1
     138: invokevirtual #21                 // Method day9/Point.getY:()I
     141: iconst_1
     142: iadd
     143: if_icmpne     148
     146: aload_1
     147: areturn
     148: aload_0
     149: invokevirtual #18                 // Method day9/Point.getX:()I
     152: aload_1
     153: invokevirtual #18                 // Method day9/Point.getX:()I
     156: if_icmpne     174
     159: aload_0
     160: invokevirtual #21                 // Method day9/Point.getY:()I
     163: aload_1
     164: invokevirtual #21                 // Method day9/Point.getY:()I
     167: iconst_1
     168: isub
     169: if_icmpne     174
     172: aload_1
     173: areturn
     174: aload_0
     175: invokevirtual #18                 // Method day9/Point.getX:()I
     178: aload_1
     179: invokevirtual #18                 // Method day9/Point.getX:()I
     182: iconst_1
     183: iadd
     184: if_icmpne     200
     187: aload_0
     188: invokevirtual #21                 // Method day9/Point.getY:()I
     191: aload_1
     192: invokevirtual #21                 // Method day9/Point.getY:()I
     195: if_icmpne     200
     198: aload_1
     199: areturn
     200: aload_0
     201: invokevirtual #18                 // Method day9/Point.getX:()I
     204: aload_1
     205: invokevirtual #18                 // Method day9/Point.getX:()I
     208: iconst_1
     209: isub
     210: if_icmpne     226
     213: aload_0
     214: invokevirtual #21                 // Method day9/Point.getY:()I
     217: aload_1
     218: invokevirtual #21                 // Method day9/Point.getY:()I
     221: if_icmpne     226
     224: aload_1
     225: areturn
     226: aload_0
     227: invokevirtual #18                 // Method day9/Point.getX:()I
     230: aload_1
     231: invokevirtual #18                 // Method day9/Point.getX:()I
     234: if_icmpne     314
     237: aload_0
     238: invokevirtual #21                 // Method day9/Point.getY:()I
     241: aload_1
     242: invokevirtual #21                 // Method day9/Point.getY:()I
     245: iconst_1
     246: iadd
     247: if_icmpeq     263
     250: aload_0
     251: invokevirtual #21                 // Method day9/Point.getY:()I
     254: aload_1
     255: invokevirtual #21                 // Method day9/Point.getY:()I
     258: iconst_1
     259: isub
     260: if_icmpne     265
     263: aload_1
     264: areturn
     265: aload_0
     266: invokevirtual #21                 // Method day9/Point.getY:()I
     269: aload_1
     270: invokevirtual #21                 // Method day9/Point.getY:()I
     273: if_icmple     296
     276: new           #14                 // class day9/Point
     279: dup
     280: aload_1
     281: invokevirtual #18                 // Method day9/Point.getX:()I
     284: aload_1
     285: invokevirtual #21                 // Method day9/Point.getY:()I
     288: iconst_1
     289: iadd
     290: invokespecial #25                 // Method day9/Point."<init>":(II)V
     293: goto          313
     296: new           #14                 // class day9/Point
     299: dup
     300: aload_1
     301: invokevirtual #18                 // Method day9/Point.getX:()I
     304: aload_1
     305: invokevirtual #21                 // Method day9/Point.getY:()I
     308: iconst_1
     309: isub
     310: invokespecial #25                 // Method day9/Point."<init>":(II)V
     313: areturn
     314: aload_0
     315: invokevirtual #21                 // Method day9/Point.getY:()I
     318: aload_1
     319: invokevirtual #21                 // Method day9/Point.getY:()I
     322: if_icmpne     402
     325: aload_0
     326: invokevirtual #18                 // Method day9/Point.getX:()I
     329: aload_1
     330: invokevirtual #18                 // Method day9/Point.getX:()I
     333: iconst_1
     334: iadd
     335: if_icmpeq     351
     338: aload_0
     339: invokevirtual #18                 // Method day9/Point.getX:()I
     342: aload_1
     343: invokevirtual #18                 // Method day9/Point.getX:()I
     346: iconst_1
     347: isub
     348: if_icmpne     353
     351: aload_1
     352: areturn
     353: aload_0
     354: invokevirtual #18                 // Method day9/Point.getX:()I
     357: aload_1
     358: invokevirtual #18                 // Method day9/Point.getX:()I
     361: if_icmple     384
     364: new           #14                 // class day9/Point
     367: dup
     368: aload_1
     369: invokevirtual #18                 // Method day9/Point.getX:()I
     372: iconst_1
     373: iadd
     374: aload_1
     375: invokevirtual #21                 // Method day9/Point.getY:()I
     378: invokespecial #25                 // Method day9/Point."<init>":(II)V
     381: goto          401
     384: new           #14                 // class day9/Point
     387: dup
     388: aload_1
     389: invokevirtual #18                 // Method day9/Point.getX:()I
     392: iconst_1
     393: isub
     394: aload_1
     395: invokevirtual #21                 // Method day9/Point.getY:()I
     398: invokespecial #25                 // Method day9/Point."<init>":(II)V
     401: areturn
     402: aload_0
     403: invokevirtual #18                 // Method day9/Point.getX:()I
     406: aload_1
     407: invokevirtual #18                 // Method day9/Point.getX:()I
     410: if_icmple     444
     413: aload_0
     414: invokevirtual #21                 // Method day9/Point.getY:()I
     417: aload_1
     418: invokevirtual #21                 // Method day9/Point.getY:()I
     421: if_icmple     444
     424: new           #14                 // class day9/Point
     427: dup
     428: aload_1
     429: invokevirtual #18                 // Method day9/Point.getX:()I
     432: iconst_1
     433: iadd
     434: aload_1
     435: invokevirtual #21                 // Method day9/Point.getY:()I
     438: iconst_1
     439: iadd
     440: invokespecial #25                 // Method day9/Point."<init>":(II)V
     443: areturn
     444: aload_0
     445: invokevirtual #18                 // Method day9/Point.getX:()I
     448: aload_1
     449: invokevirtual #18                 // Method day9/Point.getX:()I
     452: if_icmpge     486
     455: aload_0
     456: invokevirtual #21                 // Method day9/Point.getY:()I
     459: aload_1
     460: invokevirtual #21                 // Method day9/Point.getY:()I
     463: if_icmple     486
     466: new           #14                 // class day9/Point
     469: dup
     470: aload_1
     471: invokevirtual #18                 // Method day9/Point.getX:()I
     474: iconst_1
     475: isub
     476: aload_1
     477: invokevirtual #21                 // Method day9/Point.getY:()I
     480: iconst_1
     481: iadd
     482: invokespecial #25                 // Method day9/Point."<init>":(II)V
     485: areturn
     486: aload_0
     487: invokevirtual #18                 // Method day9/Point.getX:()I
     490: aload_1
     491: invokevirtual #18                 // Method day9/Point.getX:()I
     494: if_icmple     519
     497: new           #14                 // class day9/Point
     500: dup
     501: aload_1
     502: invokevirtual #18                 // Method day9/Point.getX:()I
     505: iconst_1
     506: iadd
     507: aload_1
     508: invokevirtual #21                 // Method day9/Point.getY:()I
     511: iconst_1
     512: isub
     513: invokespecial #25                 // Method day9/Point."<init>":(II)V
     516: goto          538
     519: new           #14                 // class day9/Point
     522: dup
     523: aload_1
     524: invokevirtual #18                 // Method day9/Point.getX:()I
     527: iconst_1
     528: isub
     529: aload_1
     530: invokevirtual #21                 // Method day9/Point.getY:()I
     533: iconst_1
     534: isub
     535: invokespecial #25                 // Method day9/Point."<init>":(II)V
     538: areturn

  public static final void main();
    Code:
       0: ldc           #32                 // class day9/Day9
       2: ldc           #34                 // String /day9_test.txt
       4: invokevirtual #40                 // Method java/lang/Class.getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream;
       7: dup
       8: ldc           #42                 // String getResourceAsStream(...)
      10: invokestatic  #46                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      13: astore_1
      14: getstatic     #52                 // Field kotlin/text/Charsets.UTF_8:Ljava/nio/charset/Charset;
      17: astore_2
      18: new           #54                 // class java/io/InputStreamReader
      21: dup
      22: aload_1
      23: aload_2
      24: invokespecial #57                 // Method java/io/InputStreamReader."<init>":(Ljava/io/InputStream;Ljava/nio/charset/Charset;)V
      27: checkcast     #59                 // class java/io/Reader
      30: astore_3
      31: sipush        8192
      34: istore        4
      36: aload_3
      37: instanceof    #61                 // class java/io/BufferedReader
      40: ifeq          50
      43: aload_3
      44: checkcast     #61                 // class java/io/BufferedReader
      47: goto          60
      50: new           #61                 // class java/io/BufferedReader
      53: dup
      54: aload_3
      55: iload         4
      57: invokespecial #64                 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;I)V
      60: checkcast     #59                 // class java/io/Reader
      63: invokestatic  #70                 // Method kotlin/io/TextStreamsKt.readLines:(Ljava/io/Reader;)Ljava/util/List;
      66: astore_0
      67: ldc           #32                 // class day9/Day9
      69: ldc           #72                 // String /day9_test2.txt
      71: invokevirtual #40                 // Method java/lang/Class.getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream;
      74: dup
      75: ldc           #42                 // String getResourceAsStream(...)
      77: invokestatic  #46                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      80: astore_2
      81: getstatic     #52                 // Field kotlin/text/Charsets.UTF_8:Ljava/nio/charset/Charset;
      84: astore_3
      85: new           #54                 // class java/io/InputStreamReader
      88: dup
      89: aload_2
      90: aload_3
      91: invokespecial #57                 // Method java/io/InputStreamReader."<init>":(Ljava/io/InputStream;Ljava/nio/charset/Charset;)V
      94: checkcast     #59                 // class java/io/Reader
      97: astore        4
      99: sipush        8192
     102: istore        5
     104: aload         4
     106: instanceof    #61                 // class java/io/BufferedReader
     109: ifeq          120
     112: aload         4
     114: checkcast     #61                 // class java/io/BufferedReader
     117: goto          131
     120: new           #61                 // class java/io/BufferedReader
     123: dup
     124: aload         4
     126: iload         5
     128: invokespecial #64                 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;I)V
     131: checkcast     #59                 // class java/io/Reader
     134: invokestatic  #70                 // Method kotlin/io/TextStreamsKt.readLines:(Ljava/io/Reader;)Ljava/util/List;
     137: astore_1
     138: ldc           #32                 // class day9/Day9
     140: ldc           #74                 // String /day9_input.txt
     142: invokevirtual #40                 // Method java/lang/Class.getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream;
     145: dup
     146: ldc           #42                 // String getResourceAsStream(...)
     148: invokestatic  #46                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     151: astore_3
     152: getstatic     #52                 // Field kotlin/text/Charsets.UTF_8:Ljava/nio/charset/Charset;
     155: astore        4
     157: new           #54                 // class java/io/InputStreamReader
     160: dup
     161: aload_3
     162: aload         4
     164: invokespecial #57                 // Method java/io/InputStreamReader."<init>":(Ljava/io/InputStream;Ljava/nio/charset/Charset;)V
     167: checkcast     #59                 // class java/io/Reader
     170: astore        5
     172: sipush        8192
     175: istore        6
     177: aload         5
     179: instanceof    #61                 // class java/io/BufferedReader
     182: ifeq          193
     185: aload         5
     187: checkcast     #61                 // class java/io/BufferedReader
     190: goto          204
     193: new           #61                 // class java/io/BufferedReader
     196: dup
     197: aload         5
     199: iload         6
     201: invokespecial #64                 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;I)V
     204: checkcast     #59                 // class java/io/Reader
     207: invokestatic  #70                 // Method kotlin/io/TextStreamsKt.readLines:(Ljava/io/Reader;)Ljava/util/List;
     210: astore_2
     211: new           #32                 // class day9/Day9
     214: dup
     215: aload_0
     216: invokespecial #77                 // Method day9/Day9."<init>":(Ljava/util/List;)V
     219: astore_3
     220: new           #32                 // class day9/Day9
     223: dup
     224: aload_1
     225: invokespecial #77                 // Method day9/Day9."<init>":(Ljava/util/List;)V
     228: astore        4
     230: new           #32                 // class day9/Day9
     233: dup
     234: aload_2
     235: invokespecial #77                 // Method day9/Day9."<init>":(Ljava/util/List;)V
     238: astore        5
     240: new           #79                 // class java/lang/StringBuilder
     243: dup
     244: invokespecial #81                 // Method java/lang/StringBuilder."<init>":()V
     247: ldc           #83                 // String Day9 part 1 test result:
     249: invokevirtual #87                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     252: aload_3
     253: invokevirtual #90                 // Method day9/Day9.part1:()I
     256: invokevirtual #93                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     259: invokevirtual #97                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     262: getstatic     #103                // Field java/lang/System.out:Ljava/io/PrintStream;
     265: swap
     266: invokevirtual #109                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     269: new           #79                 // class java/lang/StringBuilder
     272: dup
     273: invokespecial #81                 // Method java/lang/StringBuilder."<init>":()V
     276: ldc           #111                // String Day9 part 1 result:
     278: invokevirtual #87                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     281: aload         5
     283: invokevirtual #90                 // Method day9/Day9.part1:()I
     286: invokevirtual #93                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     289: invokevirtual #97                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     292: getstatic     #103                // Field java/lang/System.out:Ljava/io/PrintStream;
     295: swap
     296: invokevirtual #109                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     299: new           #79                 // class java/lang/StringBuilder
     302: dup
     303: invokespecial #81                 // Method java/lang/StringBuilder."<init>":()V
     306: ldc           #113                // String Day9 part 2 test result:
     308: invokevirtual #87                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     311: aload         4
     313: invokevirtual #116                // Method day9/Day9.part2:()I
     316: invokevirtual #93                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     319: invokevirtual #97                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     322: getstatic     #103                // Field java/lang/System.out:Ljava/io/PrintStream;
     325: swap
     326: invokevirtual #109                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     329: new           #79                 // class java/lang/StringBuilder
     332: dup
     333: invokespecial #81                 // Method java/lang/StringBuilder."<init>":()V
     336: ldc           #118                // String Day9 part 2 result:
     338: invokevirtual #87                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     341: aload         5
     343: invokevirtual #116                // Method day9/Day9.part2:()I
     346: invokevirtual #93                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     349: invokevirtual #97                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     352: getstatic     #103                // Field java/lang/System.out:Ljava/io/PrintStream;
     355: swap
     356: invokevirtual #109                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     359: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #135                // Method main:()V
       3: return

  public static final day9.Point access$calculateTail(day9.Point, day9.Point);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #140                // Method calculateTail:(Lday9/Point;Lday9/Point;)Lday9/Point;
       5: areturn
}

Compiled from "Day9.kt"
public final class day9.Day9 {
  private final java.util.List<java.lang.String> input;

  private final day9.Board board;

  private final java.util.List<day9.Point> rope;

  private final day9.Board2 board2;

  public day9.Day9(java.util.List<java.lang.String>);
    Code:
       0: aload_1
       1: ldc           #10                 // String input
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokespecial #19                 // Method java/lang/Object."<init>":()V
      10: aload_0
      11: aload_1
      12: putfield      #22                 // Field input:Ljava/util/List;
      15: aload_0
      16: new           #24                 // class day9/Board
      19: dup
      20: new           #26                 // class day9/Point
      23: dup
      24: iconst_0
      25: iconst_0
      26: invokespecial #29                 // Method day9/Point."<init>":(II)V
      29: new           #26                 // class day9/Point
      32: dup
      33: iconst_0
      34: iconst_0
      35: invokespecial #29                 // Method day9/Point."<init>":(II)V
      38: new           #26                 // class day9/Point
      41: dup
      42: iconst_0
      43: iconst_0
      44: invokespecial #29                 // Method day9/Point."<init>":(II)V
      47: invokestatic  #35                 // Method kotlin/collections/MapsKt.emptyMap:()Ljava/util/Map;
      50: invokespecial #38                 // Method day9/Board."<init>":(Lday9/Point;Lday9/Point;Lday9/Point;Ljava/util/Map;)V
      53: putfield      #42                 // Field board:Lday9/Board;
      56: aload_0
      57: new           #44                 // class kotlin/ranges/IntRange
      60: dup
      61: iconst_1
      62: bipush        10
      64: invokespecial #45                 // Method kotlin/ranges/IntRange."<init>":(II)V
      67: checkcast     #47                 // class java/lang/Iterable
      70: astore_2
      71: astore        11
      73: iconst_0
      74: istore_3
      75: aload_2
      76: astore        4
      78: new           #49                 // class java/util/ArrayList
      81: dup
      82: aload_2
      83: bipush        10
      85: invokestatic  #55                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      88: invokespecial #58                 // Method java/util/ArrayList."<init>":(I)V
      91: checkcast     #60                 // class java/util/Collection
      94: astore        5
      96: iconst_0
      97: istore        6
      99: aload         4
     101: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     106: astore        7
     108: aload         7
     110: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     115: ifeq          160
     118: aload         7
     120: checkcast     #72                 // class kotlin/collections/IntIterator
     123: invokevirtual #76                 // Method kotlin/collections/IntIterator.nextInt:()I
     126: istore        8
     128: aload         5
     130: iload         8
     132: istore        9
     134: astore        12
     136: iconst_0
     137: istore        10
     139: new           #26                 // class day9/Point
     142: dup
     143: iconst_0
     144: iconst_0
     145: invokespecial #29                 // Method day9/Point."<init>":(II)V
     148: aload         12
     150: swap
     151: invokeinterface #80,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     156: pop
     157: goto          108
     160: aload         5
     162: checkcast     #82                 // class java/util/List
     165: nop
     166: aload         11
     168: swap
     169: checkcast     #60                 // class java/util/Collection
     172: invokestatic  #86                 // Method kotlin/collections/CollectionsKt.toMutableList:(Ljava/util/Collection;)Ljava/util/List;
     175: putfield      #89                 // Field rope:Ljava/util/List;
     178: aload_0
     179: new           #91                 // class day9/Board2
     182: dup
     183: new           #26                 // class day9/Point
     186: dup
     187: iconst_0
     188: iconst_0
     189: invokespecial #29                 // Method day9/Point."<init>":(II)V
     192: aload_0
     193: getfield      #89                 // Field rope:Ljava/util/List;
     196: new           #93                 // class java/util/LinkedHashMap
     199: dup
     200: invokespecial #94                 // Method java/util/LinkedHashMap."<init>":()V
     203: checkcast     #96                 // class java/util/Map
     206: invokespecial #99                 // Method day9/Board2."<init>":(Lday9/Point;Ljava/util/List;Ljava/util/Map;)V
     209: putfield      #103                // Field board2:Lday9/Board2;
     212: return

  public final java.util.List<java.lang.String> getInput();
    Code:
       0: aload_0
       1: getfield      #22                 // Field input:Ljava/util/List;
       4: areturn

  private final java.util.List<day9.Command> toCommandList(java.lang.String);
    Code:
       0: aload_1
       1: checkcast     #124                // class java/lang/CharSequence
       4: iconst_1
       5: anewarray     #126                // class java/lang/String
       8: astore_3
       9: aload_3
      10: iconst_0
      11: ldc           #128                // String
      13: aastore
      14: aload_3
      15: iconst_0
      16: iconst_0
      17: bipush        6
      19: aconst_null
      20: invokestatic  #134                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      23: iconst_0
      24: invokeinterface #138,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      29: checkcast     #126                // class java/lang/String
      32: astore_2
      33: aload_1
      34: checkcast     #124                // class java/lang/CharSequence
      37: iconst_1
      38: anewarray     #126                // class java/lang/String
      41: astore        4
      43: aload         4
      45: iconst_0
      46: ldc           #128                // String
      48: aastore
      49: aload         4
      51: iconst_0
      52: iconst_0
      53: bipush        6
      55: aconst_null
      56: invokestatic  #134                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      59: iconst_1
      60: invokeinterface #138,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      65: checkcast     #126                // class java/lang/String
      68: invokestatic  #144                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      71: istore_3
      72: aload_2
      73: astore        4
      75: aload         4
      77: invokevirtual #147                // Method java/lang/String.hashCode:()I
      80: lookupswitch  { // 4
                    68: 137
                    76: 163
                    82: 124
                    85: 150
               default: 624
          }
     124: aload         4
     126: ldc           #149                // String R
     128: invokevirtual #152                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     131: ifne          512
     134: goto          624
     137: aload         4
     139: ldc           #154                // String D
     141: invokevirtual #152                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     144: ifne          288
     147: goto          624
     150: aload         4
     152: ldc           #156                // String U
     154: invokevirtual #152                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     157: ifne          176
     160: goto          624
     163: aload         4
     165: ldc           #158                // String L
     167: invokevirtual #152                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     170: ifne          400
     173: goto          624
     176: new           #44                 // class kotlin/ranges/IntRange
     179: dup
     180: iconst_1
     181: iload_3
     182: invokespecial #45                 // Method kotlin/ranges/IntRange."<init>":(II)V
     185: checkcast     #47                 // class java/lang/Iterable
     188: astore        5
     190: iconst_0
     191: istore        6
     193: aload         5
     195: astore        7
     197: new           #49                 // class java/util/ArrayList
     200: dup
     201: aload         5
     203: bipush        10
     205: invokestatic  #55                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     208: invokespecial #58                 // Method java/util/ArrayList."<init>":(I)V
     211: checkcast     #60                 // class java/util/Collection
     214: astore        8
     216: iconst_0
     217: istore        9
     219: aload         7
     221: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     226: astore        10
     228: aload         10
     230: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     235: ifeq          279
     238: aload         10
     240: checkcast     #72                 // class kotlin/collections/IntIterator
     243: invokevirtual #76                 // Method kotlin/collections/IntIterator.nextInt:()I
     246: istore        11
     248: aload         8
     250: iload         11
     252: istore        12
     254: astore        14
     256: iconst_0
     257: istore        13
     259: new           #160                // class day9/Command$Up
     262: dup
     263: iconst_1
     264: invokespecial #161                // Method day9/Command$Up."<init>":(I)V
     267: aload         14
     269: swap
     270: invokeinterface #80,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     275: pop
     276: goto          228
     279: aload         8
     281: checkcast     #82                 // class java/util/List
     284: nop
     285: goto          632
     288: new           #44                 // class kotlin/ranges/IntRange
     291: dup
     292: iconst_1
     293: iload_3
     294: invokespecial #45                 // Method kotlin/ranges/IntRange."<init>":(II)V
     297: checkcast     #47                 // class java/lang/Iterable
     300: astore        5
     302: iconst_0
     303: istore        6
     305: aload         5
     307: astore        7
     309: new           #49                 // class java/util/ArrayList
     312: dup
     313: aload         5
     315: bipush        10
     317: invokestatic  #55                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     320: invokespecial #58                 // Method java/util/ArrayList."<init>":(I)V
     323: checkcast     #60                 // class java/util/Collection
     326: astore        8
     328: iconst_0
     329: istore        9
     331: aload         7
     333: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     338: astore        10
     340: aload         10
     342: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     347: ifeq          391
     350: aload         10
     352: checkcast     #72                 // class kotlin/collections/IntIterator
     355: invokevirtual #76                 // Method kotlin/collections/IntIterator.nextInt:()I
     358: istore        11
     360: aload         8
     362: iload         11
     364: istore        12
     366: astore        14
     368: iconst_0
     369: istore        13
     371: new           #163                // class day9/Command$Down
     374: dup
     375: iconst_1
     376: invokespecial #164                // Method day9/Command$Down."<init>":(I)V
     379: aload         14
     381: swap
     382: invokeinterface #80,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     387: pop
     388: goto          340
     391: aload         8
     393: checkcast     #82                 // class java/util/List
     396: nop
     397: goto          632
     400: new           #44                 // class kotlin/ranges/IntRange
     403: dup
     404: iconst_1
     405: iload_3
     406: invokespecial #45                 // Method kotlin/ranges/IntRange."<init>":(II)V
     409: checkcast     #47                 // class java/lang/Iterable
     412: astore        5
     414: iconst_0
     415: istore        6
     417: aload         5
     419: astore        7
     421: new           #49                 // class java/util/ArrayList
     424: dup
     425: aload         5
     427: bipush        10
     429: invokestatic  #55                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     432: invokespecial #58                 // Method java/util/ArrayList."<init>":(I)V
     435: checkcast     #60                 // class java/util/Collection
     438: astore        8
     440: iconst_0
     441: istore        9
     443: aload         7
     445: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     450: astore        10
     452: aload         10
     454: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     459: ifeq          503
     462: aload         10
     464: checkcast     #72                 // class kotlin/collections/IntIterator
     467: invokevirtual #76                 // Method kotlin/collections/IntIterator.nextInt:()I
     470: istore        11
     472: aload         8
     474: iload         11
     476: istore        12
     478: astore        14
     480: iconst_0
     481: istore        13
     483: new           #166                // class day9/Command$Left
     486: dup
     487: iconst_1
     488: invokespecial #167                // Method day9/Command$Left."<init>":(I)V
     491: aload         14
     493: swap
     494: invokeinterface #80,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     499: pop
     500: goto          452
     503: aload         8
     505: checkcast     #82                 // class java/util/List
     508: nop
     509: goto          632
     512: new           #44                 // class kotlin/ranges/IntRange
     515: dup
     516: iconst_1
     517: iload_3
     518: invokespecial #45                 // Method kotlin/ranges/IntRange."<init>":(II)V
     521: checkcast     #47                 // class java/lang/Iterable
     524: astore        5
     526: iconst_0
     527: istore        6
     529: aload         5
     531: astore        7
     533: new           #49                 // class java/util/ArrayList
     536: dup
     537: aload         5
     539: bipush        10
     541: invokestatic  #55                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     544: invokespecial #58                 // Method java/util/ArrayList."<init>":(I)V
     547: checkcast     #60                 // class java/util/Collection
     550: astore        8
     552: iconst_0
     553: istore        9
     555: aload         7
     557: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     562: astore        10
     564: aload         10
     566: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     571: ifeq          615
     574: aload         10
     576: checkcast     #72                 // class kotlin/collections/IntIterator
     579: invokevirtual #76                 // Method kotlin/collections/IntIterator.nextInt:()I
     582: istore        11
     584: aload         8
     586: iload         11
     588: istore        12
     590: astore        14
     592: iconst_0
     593: istore        13
     595: new           #169                // class day9/Command$Right
     598: dup
     599: iconst_1
     600: invokespecial #170                // Method day9/Command$Right."<init>":(I)V
     603: aload         14
     605: swap
     606: invokeinterface #80,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     611: pop
     612: goto          564
     615: aload         8
     617: checkcast     #82                 // class java/util/List
     620: nop
     621: goto          632
     624: new           #172                // class java/lang/IllegalArgumentException
     627: dup
     628: invokespecial #173                // Method java/lang/IllegalArgumentException."<init>":()V
     631: athrow
     632: areturn

  public final int part1();
    Code:
       0: aload_0
       1: getfield      #22                 // Field input:Ljava/util/List;
       4: checkcast     #47                 // class java/lang/Iterable
       7: astore_2
       8: iconst_0
       9: istore_3
      10: aload_2
      11: astore        4
      13: new           #49                 // class java/util/ArrayList
      16: dup
      17: invokespecial #182                // Method java/util/ArrayList."<init>":()V
      20: checkcast     #60                 // class java/util/Collection
      23: astore        5
      25: iconst_0
      26: istore        6
      28: aload         4
      30: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      35: astore        7
      37: aload         7
      39: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      44: ifeq          88
      47: aload         7
      49: invokeinterface #186,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      54: astore        8
      56: aload         8
      58: checkcast     #126                // class java/lang/String
      61: astore        9
      63: iconst_0
      64: istore        10
      66: aload_0
      67: aload         9
      69: invokespecial #188                // Method toCommandList:(Ljava/lang/String;)Ljava/util/List;
      72: checkcast     #47                 // class java/lang/Iterable
      75: astore        9
      77: aload         5
      79: aload         9
      81: invokestatic  #192                // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
      84: pop
      85: goto          37
      88: aload         5
      90: checkcast     #82                 // class java/util/List
      93: nop
      94: checkcast     #47                 // class java/lang/Iterable
      97: astore_2
      98: aload_0
      99: getfield      #42                 // Field board:Lday9/Board;
     102: astore_3
     103: iconst_0
     104: istore        4
     106: aload_3
     107: astore        5
     109: aload_2
     110: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     115: astore        6
     117: aload         6
     119: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     124: ifeq          162
     127: aload         6
     129: invokeinterface #186,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     134: astore        7
     136: aload         5
     138: aload         7
     140: checkcast     #194                // class day9/Command
     143: astore        8
     145: astore        9
     147: iconst_0
     148: istore        10
     150: aload         9
     152: aload         8
     154: invokevirtual #198                // Method day9/Board.handleCommand:(Lday9/Command;)Lday9/Board;
     157: astore        5
     159: goto          117
     162: aload         5
     164: astore_1
     165: aload_1
     166: invokevirtual #201                // Method day9/Board.getTailVisitationMap:()Ljava/util/Map;
     169: invokeinterface #204,  1          // InterfaceMethod java/util/Map.size:()I
     174: ireturn

  public final int part2();
    Code:
       0: aload_0
       1: getfield      #22                 // Field input:Ljava/util/List;
       4: checkcast     #47                 // class java/lang/Iterable
       7: astore_2
       8: iconst_0
       9: istore_3
      10: aload_2
      11: astore        4
      13: new           #49                 // class java/util/ArrayList
      16: dup
      17: invokespecial #182                // Method java/util/ArrayList."<init>":()V
      20: checkcast     #60                 // class java/util/Collection
      23: astore        5
      25: iconst_0
      26: istore        6
      28: aload         4
      30: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      35: astore        7
      37: aload         7
      39: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      44: ifeq          88
      47: aload         7
      49: invokeinterface #186,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      54: astore        8
      56: aload         8
      58: checkcast     #126                // class java/lang/String
      61: astore        9
      63: iconst_0
      64: istore        10
      66: aload_0
      67: aload         9
      69: invokespecial #188                // Method toCommandList:(Ljava/lang/String;)Ljava/util/List;
      72: checkcast     #47                 // class java/lang/Iterable
      75: astore        9
      77: aload         5
      79: aload         9
      81: invokestatic  #192                // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
      84: pop
      85: goto          37
      88: aload         5
      90: checkcast     #82                 // class java/util/List
      93: nop
      94: checkcast     #47                 // class java/lang/Iterable
      97: astore_2
      98: aload_0
      99: getfield      #103                // Field board2:Lday9/Board2;
     102: astore_3
     103: iconst_0
     104: istore        4
     106: aload_3
     107: astore        5
     109: aload_2
     110: invokeinterface #64,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     115: astore        6
     117: aload         6
     119: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     124: ifeq          162
     127: aload         6
     129: invokeinterface #186,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     134: astore        7
     136: aload         5
     138: aload         7
     140: checkcast     #194                // class day9/Command
     143: astore        8
     145: astore        9
     147: iconst_0
     148: istore        10
     150: aload         9
     152: aload         8
     154: invokevirtual #225                // Method day9/Board2.handleCommand:(Lday9/Command;)Lday9/Board2;
     157: astore        5
     159: goto          117
     162: aload         5
     164: astore_1
     165: aload_1
     166: invokevirtual #226                // Method day9/Board2.getTailVisitationMap:()Ljava/util/Map;
     169: invokeinterface #204,  1          // InterfaceMethod java/util/Map.size:()I
     174: ireturn
}