fun main() {
    fun part1(input: List<String>): Int {

        val cycleForSignalStrength = mutableListOf<Int>(20, 60, 100, 140, 180, 220)
        val register = Register()
        val clock = Clock().apply { addProcessors(register) }

        val signalStrength = buildList {
            input
                .forEach { instruction ->
                    register
                        .parseInstruction(instruction)

                    while (!register.isInstructionDone) {
                        clock.incrementCycle()
                        if (cycleForSignalStrength.isNotEmpty() && clock.cycle == cycleForSignalStrength.first()) {
                            add(Pair(cycleForSignalStrength.removeFirst(), register.value))
                        }
                    }
                    register.executeInstruction()
                }

        }

        clock.removeProcessor(register)

        return signalStrength
            .sumOf { it.first * it.second }
    }

    fun part2(input: List<String>): Int {
        val register = Register()
        val clock = Clock().apply { addProcessors(register) }

        val crtAllPixels = buildList {
            input
                .forEach { instruction ->
                    register
                        .parseInstruction(instruction)

                    while (!register.isInstructionDone) {
                        val crtCurrentPosition = (clock.cycle) % 40
                        val sprite = register.value - 1 .. register.value + 1

                        if (crtCurrentPosition in sprite)
                            add("#")
                        else add(".")

                        clock.incrementCycle()
                    }
                    register.executeInstruction()
                }

        }
        clock.removeProcessor(register)

        return crtAllPixels
            .also { drawCrtAllPixels(it) }
            .also { println() }
            .filter { it == "#" }
            .size
    }

//     test if implementation meets criteria from the description, like:
//    val testInput = readInput("Day10_test")
//    check(part1(testInput) == 13140)
//   check(part2(testInput) == 124)
//
//    val input = readInput("Day10")
//    println(part1(input))
//    println(part2(input))
}

interface Processor {
    fun process()
}
data class Clock(var cycle: Int = 0) {
    val processors = mutableListOf<Processor>()
    fun incrementCycle() {
        cycle++
        processors.forEach { processor -> processor.process() }
    }

    fun addProcessors(processor: Processor) {
        if (!processors.contains(processor))
            processors.add(processor)
    }

    fun removeProcessor(processor: Processor) {
        if (!processors.contains(processor))
            processors.remove(processor)
    }
}

class Register(var value: Int = 1) : Processor {
    sealed class Instruction(var cyclesLeft: Int, val valueToAdd: Int) {
        data class Noop(val value: Int = 0): Instruction(1, value)
        data class AddX(val value: Int): Instruction(2, value)

    }

    val isInstructionDone: Boolean
        get() = currentInstruction.cyclesLeft == 0

    lateinit var currentInstruction: Instruction
    override fun process() {
        currentInstruction.cyclesLeft--
    }

    fun executeInstruction() {
        value += currentInstruction.valueToAdd
    }
}

fun Register.parseInstruction(instruction: String) {
    val noopOrAddX = instruction.split(" ")
    when (noopOrAddX.first()) {
        "noop" -> currentInstruction = Register.Instruction.Noop()
        "addx" -> currentInstruction = Register.Instruction.AddX(noopOrAddX.last().toInt())
    }
}

fun drawCrtAllPixels(crtAllPixels: List<String>) {
    crtAllPixels.forEachIndexed { index, pixel ->
        if ((index) % 40 == 0)
            println()
        print(pixel)
    }
}

Compiled from "Day10.kt"
public final class Day10Kt {
  public static final void main();
    Code:
       0: return

  public static final void parseInstruction(Register, java.lang.String);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #19                 // String instruction
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_1
      13: checkcast     #21                 // class java/lang/CharSequence
      16: iconst_1
      17: anewarray     #23                 // class java/lang/String
      20: astore_3
      21: aload_3
      22: iconst_0
      23: ldc           #25                 // String
      25: aastore
      26: aload_3
      27: iconst_0
      28: iconst_0
      29: bipush        6
      31: aconst_null
      32: invokestatic  #31                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      35: astore_2
      36: aload_2
      37: invokestatic  #37                 // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
      40: checkcast     #23                 // class java/lang/String
      43: astore_3
      44: aload_3
      45: ldc           #39                 // String noop
      47: invokestatic  #43                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      50: ifeq          73
      53: aload_0
      54: new           #45                 // class Register$Instruction$Noop
      57: dup
      58: iconst_0
      59: iconst_1
      60: aconst_null
      61: invokespecial #49                 // Method Register$Instruction$Noop."<init>":(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
      64: checkcast     #51                 // class Register$Instruction
      67: invokevirtual #57                 // Method Register.setCurrentInstruction:(LRegister$Instruction;)V
      70: goto          106
      73: aload_3
      74: ldc           #59                 // String addx
      76: invokestatic  #43                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      79: ifeq          106
      82: aload_0
      83: new           #61                 // class Register$Instruction$AddX
      86: dup
      87: aload_2
      88: invokestatic  #64                 // Method kotlin/collections/CollectionsKt.last:(Ljava/util/List;)Ljava/lang/Object;
      91: checkcast     #23                 // class java/lang/String
      94: invokestatic  #70                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      97: invokespecial #73                 // Method Register$Instruction$AddX."<init>":(I)V
     100: checkcast     #51                 // class Register$Instruction
     103: invokevirtual #57                 // Method Register.setCurrentInstruction:(LRegister$Instruction;)V
     106: return

  public static final void drawCrtAllPixels(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: ldc           #85                 // String crtAllPixels
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #87                 // class java/lang/Iterable
      10: astore_1
      11: iconst_0
      12: istore_2
      13: iconst_0
      14: istore_3
      15: aload_1
      16: invokeinterface #91,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      21: astore        4
      23: aload         4
      25: invokeinterface #97,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      30: ifeq          97
      33: aload         4
      35: invokeinterface #101,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      40: astore        5
      42: iload_3
      43: iinc          3, 1
      46: istore        6
      48: iload         6
      50: ifge          56
      53: invokestatic  #104                // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
      56: iload         6
      58: aload         5
      60: checkcast     #23                 // class java/lang/String
      63: astore        7
      65: istore        8
      67: iconst_0
      68: istore        9
      70: iload         8
      72: bipush        40
      74: irem
      75: ifne          84
      78: getstatic     #110                // Field java/lang/System.out:Ljava/io/PrintStream;
      81: invokevirtual #115                // Method java/io/PrintStream.println:()V
      84: getstatic     #110                // Field java/lang/System.out:Ljava/io/PrintStream;
      87: aload         7
      89: invokevirtual #119                // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
      92: nop
      93: nop
      94: goto          23
      97: nop
      98: return

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

  private static final int main$part1(java.util.List<java.lang.String>);
    Code:
       0: bipush        6
       2: anewarray     #66                 // class java/lang/Integer
       5: astore_2
       6: aload_2
       7: iconst_0
       8: bipush        20
      10: invokestatic  #141                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      13: aastore
      14: aload_2
      15: iconst_1
      16: bipush        60
      18: invokestatic  #141                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      21: aastore
      22: aload_2
      23: iconst_2
      24: bipush        100
      26: invokestatic  #141                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      29: aastore
      30: aload_2
      31: iconst_3
      32: sipush        140
      35: invokestatic  #141                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      38: aastore
      39: aload_2
      40: iconst_4
      41: sipush        180
      44: invokestatic  #141                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      47: aastore
      48: aload_2
      49: iconst_5
      50: sipush        220
      53: invokestatic  #141                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      56: aastore
      57: aload_2
      58: invokestatic  #145                // Method kotlin/collections/CollectionsKt.mutableListOf:([Ljava/lang/Object;)Ljava/util/List;
      61: astore_1
      62: new           #53                 // class Register
      65: dup
      66: iconst_0
      67: iconst_1
      68: aconst_null
      69: invokespecial #146                // Method Register."<init>":(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
      72: astore_2
      73: new           #148                // class Clock
      76: dup
      77: iconst_0
      78: iconst_1
      79: aconst_null
      80: invokespecial #149                // Method Clock."<init>":(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
      83: astore        4
      85: aload         4
      87: astore        5
      89: iconst_0
      90: istore        6
      92: aload         5
      94: aload_2
      95: checkcast     #151                // class Processor
      98: invokevirtual #155                // Method Clock.addProcessors:(LProcessor;)V
     101: aload         4
     103: astore_3
     104: invokestatic  #159                // Method kotlin/collections/CollectionsKt.createListBuilder:()Ljava/util/List;
     107: astore        5
     109: aload         5
     111: astore        6
     113: iconst_0
     114: istore        7
     116: aload_0
     117: checkcast     #87                 // class java/lang/Iterable
     120: astore        8
     122: nop
     123: iconst_0
     124: istore        9
     126: aload         8
     128: invokeinterface #91,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     133: astore        10
     135: aload         10
     137: invokeinterface #97,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     142: ifeq          258
     145: aload         10
     147: invokeinterface #101,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     152: astore        11
     154: aload         11
     156: checkcast     #23                 // class java/lang/String
     159: astore        12
     161: iconst_0
     162: istore        13
     164: aload_2
     165: aload         12
     167: invokestatic  #161                // Method parseInstruction:(LRegister;Ljava/lang/String;)V
     170: aload_2
     171: invokevirtual #164                // Method Register.isInstructionDone:()Z
     174: ifne          249
     177: aload_3
     178: invokevirtual #167                // Method Clock.incrementCycle:()V
     181: aload_1
     182: checkcast     #169                // class java/util/Collection
     185: invokeinterface #172,  1          // InterfaceMethod java/util/Collection.isEmpty:()Z
     190: ifne          197
     193: iconst_1
     194: goto          198
     197: iconst_0
     198: ifeq          170
     201: aload_3
     202: invokevirtual #176                // Method Clock.getCycle:()I
     205: aload_1
     206: invokestatic  #37                 // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
     209: checkcast     #178                // class java/lang/Number
     212: invokevirtual #181                // Method java/lang/Number.intValue:()I
     215: if_icmpne     170
     218: aload         6
     220: new           #183                // class kotlin/Pair
     223: dup
     224: aload_1
     225: invokeinterface #186,  1          // InterfaceMethod java/util/List.removeFirst:()Ljava/lang/Object;
     230: aload_2
     231: invokevirtual #189                // Method Register.getValue:()I
     234: invokestatic  #141                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     237: invokespecial #192                // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
     240: invokeinterface #196,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     245: pop
     246: goto          170
     249: aload_2
     250: invokevirtual #199                // Method Register.executeInstruction:()V
     253: nop
     254: nop
     255: goto          135
     258: nop
     259: nop
     260: aload         5
     262: invokestatic  #203                // Method kotlin/collections/CollectionsKt.build:(Ljava/util/List;)Ljava/util/List;
     265: astore        4
     267: aload_3
     268: aload_2
     269: checkcast     #151                // class Processor
     272: invokevirtual #206                // Method Clock.removeProcessor:(LProcessor;)V
     275: aload         4
     277: checkcast     #87                 // class java/lang/Iterable
     280: astore        5
     282: iconst_0
     283: istore        6
     285: aload         5
     287: invokeinterface #91,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     292: astore        7
     294: aload         7
     296: invokeinterface #97,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     301: ifeq          362
     304: aload         7
     306: invokeinterface #101,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     311: astore        8
     313: iload         6
     315: aload         8
     317: checkcast     #183                // class kotlin/Pair
     320: astore        9
     322: istore        14
     324: iconst_0
     325: istore        10
     327: aload         9
     329: invokevirtual #209                // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     332: checkcast     #178                // class java/lang/Number
     335: invokevirtual #181                // Method java/lang/Number.intValue:()I
     338: aload         9
     340: invokevirtual #212                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     343: checkcast     #178                // class java/lang/Number
     346: invokevirtual #181                // Method java/lang/Number.intValue:()I
     349: imul
     350: istore        15
     352: iload         14
     354: iload         15
     356: iadd
     357: istore        6
     359: goto          294
     362: iload         6
     364: ireturn

  private static final int main$part2(java.util.List<java.lang.String>);
    Code:
       0: new           #53                 // class Register
       3: dup
       4: iconst_0
       5: iconst_1
       6: aconst_null
       7: invokespecial #146                // Method Register."<init>":(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
      10: astore_1
      11: new           #148                // class Clock
      14: dup
      15: iconst_0
      16: iconst_1
      17: aconst_null
      18: invokespecial #149                // Method Clock."<init>":(IILkotlin/jvm/internal/DefaultConstructorMarker;)V
      21: astore_3
      22: aload_3
      23: astore        4
      25: iconst_0
      26: istore        5
      28: aload         4
      30: aload_1
      31: checkcast     #151                // class Processor
      34: invokevirtual #155                // Method Clock.addProcessors:(LProcessor;)V
      37: aload_3
      38: astore_2
      39: invokestatic  #159                // Method kotlin/collections/CollectionsKt.createListBuilder:()Ljava/util/List;
      42: astore        4
      44: aload         4
      46: astore        5
      48: iconst_0
      49: istore        6
      51: aload_0
      52: checkcast     #87                 // class java/lang/Iterable
      55: astore        7
      57: nop
      58: iconst_0
      59: istore        8
      61: aload         7
      63: invokeinterface #91,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      68: astore        9
      70: aload         9
      72: invokeinterface #97,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      77: ifeq          216
      80: aload         9
      82: invokeinterface #101,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      87: astore        10
      89: aload         10
      91: checkcast     #23                 // class java/lang/String
      94: astore        11
      96: iconst_0
      97: istore        12
      99: aload_1
     100: aload         11
     102: invokestatic  #161                // Method parseInstruction:(LRegister;Ljava/lang/String;)V
     105: aload_1
     106: invokevirtual #164                // Method Register.isInstructionDone:()Z
     109: ifne          207
     112: aload_2
     113: invokevirtual #176                // Method Clock.getCycle:()I
     116: bipush        40
     118: irem
     119: istore        13
     121: new           #232                // class kotlin/ranges/IntRange
     124: dup
     125: aload_1
     126: invokevirtual #189                // Method Register.getValue:()I
     129: iconst_1
     130: isub
     131: aload_1
     132: invokevirtual #189                // Method Register.getValue:()I
     135: iconst_1
     136: iadd
     137: invokespecial #235                // Method kotlin/ranges/IntRange."<init>":(II)V
     140: astore        14
     142: aload         14
     144: invokevirtual #237                // Method kotlin/ranges/IntRange.getFirst:()I
     147: istore        15
     149: iload         13
     151: aload         14
     153: invokevirtual #240                // Method kotlin/ranges/IntRange.getLast:()I
     156: if_icmpgt     174
     159: iload         15
     161: iload         13
     163: if_icmpgt     170
     166: iconst_1
     167: goto          175
     170: iconst_0
     171: goto          175
     174: iconst_0
     175: ifeq          190
     178: aload         5
     180: ldc           #242                // String #
     182: invokeinterface #196,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     187: goto          199
     190: aload         5
     192: ldc           #244                // String .
     194: invokeinterface #196,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     199: pop
     200: aload_2
     201: invokevirtual #167                // Method Clock.incrementCycle:()V
     204: goto          105
     207: aload_1
     208: invokevirtual #199                // Method Register.executeInstruction:()V
     211: nop
     212: nop
     213: goto          70
     216: nop
     217: nop
     218: aload         4
     220: invokestatic  #203                // Method kotlin/collections/CollectionsKt.build:(Ljava/util/List;)Ljava/util/List;
     223: astore_3
     224: aload_2
     225: aload_1
     226: checkcast     #151                // class Processor
     229: invokevirtual #206                // Method Clock.removeProcessor:(LProcessor;)V
     232: aload_3
     233: astore        4
     235: aload         4
     237: astore        5
     239: iconst_0
     240: istore        6
     242: aload         5
     244: invokestatic  #246                // Method drawCrtAllPixels:(Ljava/util/List;)V
     247: aload         4
     249: astore        4
     251: aload         4
     253: astore        5
     255: iconst_0
     256: istore        6
     258: getstatic     #110                // Field java/lang/System.out:Ljava/io/PrintStream;
     261: invokevirtual #115                // Method java/io/PrintStream.println:()V
     264: nop
     265: aload         4
     267: checkcast     #87                 // class java/lang/Iterable
     270: astore        4
     272: nop
     273: iconst_0
     274: istore        5
     276: aload         4
     278: astore        6
     280: new           #248                // class java/util/ArrayList
     283: dup
     284: invokespecial #250                // Method java/util/ArrayList."<init>":()V
     287: checkcast     #169                // class java/util/Collection
     290: astore        7
     292: iconst_0
     293: istore        8
     295: aload         6
     297: invokeinterface #91,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     302: astore        9
     304: aload         9
     306: invokeinterface #97,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     311: ifeq          356
     314: aload         9
     316: invokeinterface #101,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     321: astore        10
     323: aload         10
     325: checkcast     #23                 // class java/lang/String
     328: astore        11
     330: iconst_0
     331: istore        12
     333: aload         11
     335: ldc           #242                // String #
     337: invokestatic  #43                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     340: ifeq          304
     343: aload         7
     345: aload         10
     347: invokeinterface #251,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     352: pop
     353: goto          304
     356: aload         7
     358: checkcast     #80                 // class java/util/List
     361: nop
     362: invokeinterface #254,  1          // InterfaceMethod java/util/List.size:()I
     367: ireturn
}


import java.lang.StrictMath.max

fun main() {
    fun part1(input: List<String>): Int {
        val treesGraph = AdjacencyList<Int>()
        val verticesOfTreeHeight = treesGraph.parseVertices(input)
        return verticesOfTreeHeight
            .fold(0) { acc, vertex ->
                if (vertex `is max in all directions of` treesGraph)
                    acc + 1
                  else
                    acc
            }
    }

    fun part2(input: List<String>): Int {
        val treesGraph = AdjacencyList<Int>()
        val verticesOfTreeHeight = treesGraph.parseVertices(input)
        return verticesOfTreeHeight
            .fold(Int.MIN_VALUE) { maxScenicScoreSoFar, vertex ->
                max(
                    maxScenicScoreSoFar,
                    vertex `scenic score` treesGraph
                )
            }
    }
    // test if implementation meets criteria from the description, like:
/*    val testInput = readInput("Day08_test")
    check(part1(testInput) == 21)
    check(part2(testInput) == 8)

    val input = readInput("Day08")
    println(part1(input))
    println(part2(input))*/
}

data class Vertex<T>(
    val index: Int,
    val data: T
)

data class Edge<T>(
    val source: Vertex<T>,
    val destination: Vertex<T>,
    val direction: Graph.EdgeType,
    val weight: Double?
)

interface Graph<T> {

    fun createVertex(data: T): Vertex<T>

    fun addDirectedEdge(
        source: Vertex<T>,
        destination: Vertex<T>,
        direction: EdgeType,
        weight: Double?,
    )

    fun addUndirectedEdge(
        source: Vertex<T>,
        destination: Vertex<T>,
        direction: EdgeType,
        weight: Double?
    )

    fun add(
        edge: EdgeType,
        source: Vertex<T>,
        destination: Vertex<T>,
        weight: Double?
    )

    fun edges(source: Vertex<T>): Map<EdgeType,Edge<T>>

    fun weight(
        source: Vertex<T>,
        destination: Vertex<T>
    ) : Double?

    enum class EdgeType {
        RIGHT,
        LEFT,
        ABOVE,
        BELOW
    }

}

fun Graph.EdgeType.opposite(): Graph.EdgeType = when(this) {
    Graph.EdgeType.RIGHT -> Graph.EdgeType.LEFT
    Graph.EdgeType.LEFT -> Graph.EdgeType.RIGHT
    Graph.EdgeType.ABOVE -> Graph.EdgeType.BELOW
    Graph.EdgeType.BELOW -> Graph.EdgeType.ABOVE
}

class AdjacencyList <T> : Graph<T> {
    private val adjacencies: HashMap<Vertex<T>, MutableMap<Graph.EdgeType,Edge<T>>> = HashMap()

    override fun createVertex(data: T): Vertex<T> {
        val vertex = Vertex(adjacencies.count(), data)
        adjacencies[vertex] = mutableMapOf()
        return vertex
    }

    override fun addDirectedEdge(
        source: Vertex<T>,
        destination: Vertex<T>,
        direction: Graph.EdgeType,
        weight: Double?
    ) {
        val edge = Edge(source, destination, direction, weight)
        adjacencies[source]?.put(edge.direction, edge)
    }

    override fun addUndirectedEdge(
        source: Vertex<T>,
        destination: Vertex<T>,
        direction: Graph.EdgeType,
        weight: Double?
    ) {
        addDirectedEdge(source, destination, direction, weight)
        addDirectedEdge(destination, source, direction.opposite(), weight)
    }

    override fun add(edge: Graph.EdgeType, source: Vertex<T>, destination: Vertex<T>, weight: Double?) = addUndirectedEdge(source, destination, edge, weight)

    override fun edges(source: Vertex<T>): Map<Graph.EdgeType, Edge<T>>  = adjacencies[source] ?: mutableMapOf<Graph.EdgeType, Edge<T>>()

    override fun weight(source: Vertex<T>, destination: Vertex<T>): Double? {
        return edges(source).map { it.value }.firstOrNull { it.destination == destination }?.weight
    }

    override fun toString(): String {
        return buildString { // 1
            adjacencies.forEach { (vertex, edges) -> // 2
                val edgeString = edges
                    .map {Pair(it.key,it.value)}.joinToString { it.second.destination.data.toString() + " " + it.first.toString()} // 3
                append("${vertex.data} ---> [ $edgeString ]\n") // 4
            }
        }
    }
}

fun AdjacencyList<Int>.parseVertices(verticesData: List<String>): List<Vertex<Int>> {
    val verticesDataMatrix = verticesData.map { verticesDataRow ->
        verticesDataRow
            .chunked(1)
            .map { treeHeight ->
                treeHeight.toInt()
            }
    }

    val verticesDataRow = verticesDataMatrix.first().size
    val verticesDataColumn = verticesDataMatrix.size
    val verticesLastRow = verticesDataRow * verticesDataColumn + 1 - verticesDataRow .. verticesDataRow * verticesDataColumn

    val verticesList = verticesDataMatrix
        .flatten()
        .map {
            createVertex(it)
        }
    for (vertex in verticesList) {
        val vertexPosition = vertex.index + 1
        if (vertexPosition % verticesDataRow != 0) {
            add(Graph.EdgeType.RIGHT, vertex, verticesList[vertex.index + 1], null)
        }
        if (vertexPosition !in verticesLastRow) {
            add(Graph.EdgeType.BELOW, vertex, verticesList[vertex.index + verticesDataRow], null)
        }
    }
    return verticesList
}

fun Vertex<Int>.isMax(graph: Graph<Int>, direction: Graph.EdgeType): Boolean {
    tailrec fun go(direction: Graph.EdgeType, vert: Vertex< Int>, maxSoFar: Int): Int {
        val destinationVertex = graph.edges(vert)[direction]?.destination
        return if (destinationVertex == null)
            maxSoFar
        else go(direction, destinationVertex, max(maxSoFar, destinationVertex.data))
    }
    val isMaximum by lazy {
        this.data > go(direction, this, Integer.MIN_VALUE)
    }
    return isMaximum
}

infix fun Vertex<Int>.`is max in all directions of`(graph: Graph<Int>): Boolean = isMax(graph, Graph.EdgeType.RIGHT) ||
            isMax(graph, Graph.EdgeType.LEFT) ||
            isMax(graph, Graph.EdgeType.ABOVE) ||
            isMax(graph, Graph.EdgeType.BELOW)

fun Vertex<Int>.countToImmediateMax(graph: Graph<Int>, direction: Graph.EdgeType): Int {
    fun Int.go(direction: Graph.EdgeType, vert: Vertex<Int>, smallerImmediateVerticesCount: Int): Int {
        val destinationVertex = graph.edges(vert)[direction]?.destination
        return when {
            destinationVertex == null -> smallerImmediateVerticesCount
            destinationVertex.data >= this -> smallerImmediateVerticesCount + 1
            else -> go(direction, destinationVertex, smallerImmediateVerticesCount + 1)
        }

    }
    return data.go(direction, this, 0)
}

infix fun Vertex<Int>.`scenic score`(graph: Graph<Int>): Int = countToImmediateMax(graph, Graph.EdgeType.RIGHT) *
        countToImmediateMax(graph, Graph.EdgeType.LEFT) *
        countToImmediateMax(graph, Graph.EdgeType.ABOVE) *
        countToImmediateMax(graph, Graph.EdgeType.BELOW)

Compiled from "Day08.kt"
public final class Day08Kt$WhenMappings {
  public static final int[] $EnumSwitchMapping$0;

  static {};
    Code:
       0: invokestatic  #14                 // Method Graph$EdgeType.values:()[LGraph$EdgeType;
       3: arraylength
       4: newarray       int
       6: astore_0
       7: nop
       8: aload_0
       9: getstatic     #18                 // Field Graph$EdgeType.RIGHT:LGraph$EdgeType;
      12: invokevirtual #22                 // Method Graph$EdgeType.ordinal:()I
      15: iconst_1
      16: iastore
      17: goto          21
      20: astore_1
      21: nop
      22: aload_0
      23: getstatic     #25                 // Field Graph$EdgeType.LEFT:LGraph$EdgeType;
      26: invokevirtual #22                 // Method Graph$EdgeType.ordinal:()I
      29: iconst_2
      30: iastore
      31: goto          35
      34: astore_1
      35: nop
      36: aload_0
      37: getstatic     #28                 // Field Graph$EdgeType.ABOVE:LGraph$EdgeType;
      40: invokevirtual #22                 // Method Graph$EdgeType.ordinal:()I
      43: iconst_3
      44: iastore
      45: goto          49
      48: astore_1
      49: nop
      50: aload_0
      51: getstatic     #31                 // Field Graph$EdgeType.BELOW:LGraph$EdgeType;
      54: invokevirtual #22                 // Method Graph$EdgeType.ordinal:()I
      57: iconst_4
      58: iastore
      59: goto          63
      62: astore_1
      63: aload_0
      64: putstatic     #35                 // Field $EnumSwitchMapping$0:[I
      67: return
    Exception table:
       from    to  target type
           7    17    20   Class java/lang/NoSuchFieldError
          21    31    34   Class java/lang/NoSuchFieldError
          35    45    48   Class java/lang/NoSuchFieldError
          49    59    62   Class java/lang/NoSuchFieldError
}

Compiled from "Day08.kt"
public final class Day08Kt {
  public static final void main();
    Code:
       0: return

  public static final Graph$EdgeType opposite(Graph$EdgeType);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: getstatic     #23                 // Field Day08Kt$WhenMappings.$EnumSwitchMapping$0:[I
      10: swap
      11: invokevirtual #29                 // Method Graph$EdgeType.ordinal:()I
      14: iaload
      15: tableswitch   { // 1 to 4
                     1: 44
                     2: 50
                     3: 56
                     4: 62
               default: 68
          }
      44: getstatic     #33                 // Field Graph$EdgeType.LEFT:LGraph$EdgeType;
      47: goto          76
      50: getstatic     #36                 // Field Graph$EdgeType.RIGHT:LGraph$EdgeType;
      53: goto          76
      56: getstatic     #39                 // Field Graph$EdgeType.BELOW:LGraph$EdgeType;
      59: goto          76
      62: getstatic     #42                 // Field Graph$EdgeType.ABOVE:LGraph$EdgeType;
      65: goto          76
      68: new           #44                 // class kotlin/NoWhenBranchMatchedException
      71: dup
      72: invokespecial #47                 // Method kotlin/NoWhenBranchMatchedException."<init>":()V
      75: athrow
      76: areturn

  public static final java.util.List<Vertex<java.lang.Integer>> parseVertices(AdjacencyList<java.lang.Integer>, java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #53                 // String verticesData
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_1
      13: checkcast     #55                 // class java/lang/Iterable
      16: astore_3
      17: iconst_0
      18: istore        4
      20: aload_3
      21: astore        5
      23: new           #57                 // class java/util/ArrayList
      26: dup
      27: aload_3
      28: bipush        10
      30: invokestatic  #63                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      33: invokespecial #66                 // Method java/util/ArrayList."<init>":(I)V
      36: checkcast     #68                 // class java/util/Collection
      39: astore        6
      41: iconst_0
      42: istore        7
      44: aload         5
      46: invokeinterface #72,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      51: astore        8
      53: aload         8
      55: invokeinterface #78,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      60: ifeq          212
      63: aload         8
      65: invokeinterface #82,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      70: astore        9
      72: aload         6
      74: aload         9
      76: checkcast     #84                 // class java/lang/String
      79: astore        10
      81: astore        22
      83: iconst_0
      84: istore        11
      86: aload         10
      88: checkcast     #86                 // class java/lang/CharSequence
      91: iconst_1
      92: invokestatic  #92                 // Method kotlin/text/StringsKt.chunked:(Ljava/lang/CharSequence;I)Ljava/util/List;
      95: checkcast     #55                 // class java/lang/Iterable
      98: astore        12
     100: nop
     101: iconst_0
     102: istore        13
     104: aload         12
     106: astore        14
     108: new           #57                 // class java/util/ArrayList
     111: dup
     112: aload         12
     114: bipush        10
     116: invokestatic  #63                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     119: invokespecial #66                 // Method java/util/ArrayList."<init>":(I)V
     122: checkcast     #68                 // class java/util/Collection
     125: astore        15
     127: iconst_0
     128: istore        16
     130: aload         14
     132: invokeinterface #72,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     137: astore        17
     139: aload         17
     141: invokeinterface #78,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     146: ifeq          193
     149: aload         17
     151: invokeinterface #82,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     156: astore        18
     158: aload         15
     160: aload         18
     162: checkcast     #84                 // class java/lang/String
     165: astore        19
     167: astore        20
     169: iconst_0
     170: istore        21
     172: aload         19
     174: invokestatic  #98                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     177: nop
     178: invokestatic  #102                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     181: aload         20
     183: swap
     184: invokeinterface #106,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     189: pop
     190: goto          139
     193: aload         15
     195: checkcast     #108                // class java/util/List
     198: nop
     199: nop
     200: aload         22
     202: swap
     203: invokeinterface #106,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     208: pop
     209: goto          53
     212: aload         6
     214: checkcast     #108                // class java/util/List
     217: nop
     218: astore_2
     219: aload_2
     220: invokestatic  #112                // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
     223: checkcast     #108                // class java/util/List
     226: invokeinterface #115,  1          // InterfaceMethod java/util/List.size:()I
     231: istore_3
     232: aload_2
     233: invokeinterface #115,  1          // InterfaceMethod java/util/List.size:()I
     238: istore        4
     240: new           #117                // class kotlin/ranges/IntRange
     243: dup
     244: iload_3
     245: iload         4
     247: imul
     248: iconst_1
     249: iadd
     250: iload_3
     251: isub
     252: iload_3
     253: iload         4
     255: imul
     256: invokespecial #120                // Method kotlin/ranges/IntRange."<init>":(II)V
     259: astore        5
     261: aload_2
     262: checkcast     #55                 // class java/lang/Iterable
     265: invokestatic  #124                // Method kotlin/collections/CollectionsKt.flatten:(Ljava/lang/Iterable;)Ljava/util/List;
     268: checkcast     #55                 // class java/lang/Iterable
     271: astore        7
     273: nop
     274: iconst_0
     275: istore        8
     277: aload         7
     279: astore        9
     281: new           #57                 // class java/util/ArrayList
     284: dup
     285: aload         7
     287: bipush        10
     289: invokestatic  #63                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     292: invokespecial #66                 // Method java/util/ArrayList."<init>":(I)V
     295: checkcast     #68                 // class java/util/Collection
     298: astore        10
     300: iconst_0
     301: istore        11
     303: aload         9
     305: invokeinterface #72,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     310: astore        12
     312: aload         12
     314: invokeinterface #78,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     319: ifeq          369
     322: aload         12
     324: invokeinterface #82,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     329: astore        13
     331: aload         10
     333: aload         13
     335: checkcast     #126                // class java/lang/Number
     338: invokevirtual #129                // Method java/lang/Number.intValue:()I
     341: istore        14
     343: astore        22
     345: iconst_0
     346: istore        15
     348: aload_0
     349: iload         14
     351: invokestatic  #102                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     354: invokevirtual #135                // Method AdjacencyList.createVertex:(Ljava/lang/Object;)LVertex;
     357: aload         22
     359: swap
     360: invokeinterface #106,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     365: pop
     366: goto          312
     369: aload         10
     371: checkcast     #108                // class java/util/List
     374: nop
     375: astore        6
     377: aload         6
     379: invokeinterface #136,  1          // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
     384: astore        7
     386: aload         7
     388: invokeinterface #78,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     393: ifeq          517
     396: aload         7
     398: invokeinterface #82,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     403: checkcast     #138                // class Vertex
     406: astore        8
     408: aload         8
     410: invokevirtual #141                // Method Vertex.getIndex:()I
     413: iconst_1
     414: iadd
     415: istore        9
     417: iload         9
     419: iload_3
     420: irem
     421: ifeq          451
     424: aload_0
     425: getstatic     #36                 // Field Graph$EdgeType.RIGHT:LGraph$EdgeType;
     428: aload         8
     430: aload         6
     432: aload         8
     434: invokevirtual #141                // Method Vertex.getIndex:()I
     437: iconst_1
     438: iadd
     439: invokeinterface #145,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     444: checkcast     #138                // class Vertex
     447: aconst_null
     448: invokevirtual #148                // Method AdjacencyList.add:(LGraph$EdgeType;LVertex;LVertex;Ljava/lang/Double;)V
     451: aload         5
     453: invokevirtual #151                // Method kotlin/ranges/IntRange.getFirst:()I
     456: istore        10
     458: iload         9
     460: aload         5
     462: invokevirtual #154                // Method kotlin/ranges/IntRange.getLast:()I
     465: if_icmpgt     483
     468: iload         10
     470: iload         9
     472: if_icmpgt     479
     475: iconst_1
     476: goto          484
     479: iconst_0
     480: goto          484
     483: iconst_0
     484: ifne          386
     487: aload_0
     488: getstatic     #39                 // Field Graph$EdgeType.BELOW:LGraph$EdgeType;
     491: aload         8
     493: aload         6
     495: aload         8
     497: invokevirtual #141                // Method Vertex.getIndex:()I
     500: iload_3
     501: iadd
     502: invokeinterface #145,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     507: checkcast     #138                // class Vertex
     510: aconst_null
     511: invokevirtual #148                // Method AdjacencyList.add:(LGraph$EdgeType;LVertex;LVertex;Ljava/lang/Double;)V
     514: goto          386
     517: aload         6
     519: areturn

  public static final boolean isMax(Vertex<java.lang.Integer>, Graph<java.lang.Integer>, Graph$EdgeType);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #187                // String graph
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_2
      13: ldc           #189                // String direction
      15: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      18: aload_0
      19: aload_2
      20: aload_1
      21: invokedynamic #208,  0            // InvokeDynamic #0:invoke:(LVertex;LGraph$EdgeType;LGraph;)Lkotlin/jvm/functions/Function0;
      26: invokestatic  #214                // Method kotlin/LazyKt.lazy:(Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
      29: astore_3
      30: aload_3
      31: invokestatic  #218                // Method isMax$lambda$6:(Lkotlin/Lazy;)Z
      34: ireturn

  public static final boolean is max in all directions of(Vertex<java.lang.Integer>, Graph<java.lang.Integer>);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #187                // String graph
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: aload_1
      14: getstatic     #36                 // Field Graph$EdgeType.RIGHT:LGraph$EdgeType;
      17: invokestatic  #227                // Method isMax:(LVertex;LGraph;LGraph$EdgeType;)Z
      20: ifne          56
      23: aload_0
      24: aload_1
      25: getstatic     #33                 // Field Graph$EdgeType.LEFT:LGraph$EdgeType;
      28: invokestatic  #227                // Method isMax:(LVertex;LGraph;LGraph$EdgeType;)Z
      31: ifne          56
      34: aload_0
      35: aload_1
      36: getstatic     #42                 // Field Graph$EdgeType.ABOVE:LGraph$EdgeType;
      39: invokestatic  #227                // Method isMax:(LVertex;LGraph;LGraph$EdgeType;)Z
      42: ifne          56
      45: aload_0
      46: aload_1
      47: getstatic     #39                 // Field Graph$EdgeType.BELOW:LGraph$EdgeType;
      50: invokestatic  #227                // Method isMax:(LVertex;LGraph;LGraph$EdgeType;)Z
      53: ifeq          60
      56: iconst_1
      57: goto          61
      60: iconst_0
      61: ireturn

  public static final int countToImmediateMax(Vertex<java.lang.Integer>, Graph<java.lang.Integer>, Graph$EdgeType);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #187                // String graph
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_2
      13: ldc           #189                // String direction
      15: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      18: aload_0
      19: invokevirtual #234                // Method Vertex.getData:()Ljava/lang/Object;
      22: checkcast     #126                // class java/lang/Number
      25: invokevirtual #129                // Method java/lang/Number.intValue:()I
      28: aload_1
      29: aload_2
      30: aload_0
      31: iconst_0
      32: invokestatic  #238                // Method countToImmediateMax$go$7:(ILGraph;LGraph$EdgeType;LVertex;I)I
      35: ireturn

  public static final int scenic score(Vertex<java.lang.Integer>, Graph<java.lang.Integer>);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #187                // String graph
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: aload_1
      14: getstatic     #36                 // Field Graph$EdgeType.RIGHT:LGraph$EdgeType;
      17: invokestatic  #244                // Method countToImmediateMax:(LVertex;LGraph;LGraph$EdgeType;)I
      20: aload_0
      21: aload_1
      22: getstatic     #33                 // Field Graph$EdgeType.LEFT:LGraph$EdgeType;
      25: invokestatic  #244                // Method countToImmediateMax:(LVertex;LGraph;LGraph$EdgeType;)I
      28: imul
      29: aload_0
      30: aload_1
      31: getstatic     #42                 // Field Graph$EdgeType.ABOVE:LGraph$EdgeType;
      34: invokestatic  #244                // Method countToImmediateMax:(LVertex;LGraph;LGraph$EdgeType;)I
      37: imul
      38: aload_0
      39: aload_1
      40: getstatic     #39                 // Field Graph$EdgeType.BELOW:LGraph$EdgeType;
      43: invokestatic  #244                // Method countToImmediateMax:(LVertex;LGraph;LGraph$EdgeType;)I
      46: imul
      47: ireturn

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

  private static final int main$part1(java.util.List<java.lang.String>);
    Code:
       0: new           #131                // class AdjacencyList
       3: dup
       4: invokespecial #254                // Method AdjacencyList."<init>":()V
       7: astore_1
       8: aload_1
       9: aload_0
      10: invokestatic  #256                // Method parseVertices:(LAdjacencyList;Ljava/util/List;)Ljava/util/List;
      13: astore_2
      14: aload_2
      15: checkcast     #55                 // class java/lang/Iterable
      18: astore_3
      19: iconst_0
      20: istore        4
      22: iconst_0
      23: istore        5
      25: iload         4
      27: istore        6
      29: aload_3
      30: invokeinterface #72,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      35: astore        7
      37: aload         7
      39: invokeinterface #78,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      44: ifeq          96
      47: aload         7
      49: invokeinterface #82,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      54: astore        8
      56: iload         6
      58: aload         8
      60: checkcast     #138                // class Vertex
      63: astore        9
      65: istore        10
      67: iconst_0
      68: istore        11
      70: aload         9
      72: aload_1
      73: checkcast     #258                // class Graph
      76: invokestatic  #260                // Method "is max in all directions of":(LVertex;LGraph;)Z
      79: ifeq          89
      82: iload         10
      84: iconst_1
      85: iadd
      86: goto          91
      89: iload         10
      91: istore        6
      93: goto          37
      96: iload         6
      98: ireturn

  private static final int main$part2(java.util.List<java.lang.String>);
    Code:
       0: new           #131                // class AdjacencyList
       3: dup
       4: invokespecial #254                // Method AdjacencyList."<init>":()V
       7: astore_1
       8: aload_1
       9: aload_0
      10: invokestatic  #256                // Method parseVertices:(LAdjacencyList;Ljava/util/List;)Ljava/util/List;
      13: astore_2
      14: aload_2
      15: checkcast     #55                 // class java/lang/Iterable
      18: astore_3
      19: ldc_w         #272                // int -2147483648
      22: istore        4
      24: iconst_0
      25: istore        5
      27: iload         4
      29: istore        6
      31: aload_3
      32: invokeinterface #72,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      37: astore        7
      39: aload         7
      41: invokeinterface #78,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      46: ifeq          92
      49: aload         7
      51: invokeinterface #82,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      56: astore        8
      58: iload         6
      60: aload         8
      62: checkcast     #138                // class Vertex
      65: astore        9
      67: istore        10
      69: iconst_0
      70: istore        11
      72: iload         10
      74: aload         9
      76: aload_1
      77: checkcast     #258                // class Graph
      80: invokestatic  #274                // Method "scenic score":(LVertex;LGraph;)I
      83: invokestatic  #280                // Method java/lang/StrictMath.max:(II)I
      86: nop
      87: istore        6
      89: goto          39
      92: iload         6
      94: ireturn

  private static final int isMax$go(Graph<java.lang.Integer>, Graph$EdgeType, Vertex<java.lang.Integer>, int);
    Code:
       0: aload_0
       1: aload_2
       2: invokeinterface #289,  2          // InterfaceMethod Graph.edges:(LVertex;)Ljava/util/Map;
       7: aload_1
       8: invokeinterface #294,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
      13: checkcast     #296                // class Edge
      16: dup
      17: ifnull        26
      20: invokevirtual #300                // Method Edge.getDestination:()LVertex;
      23: goto          28
      26: pop
      27: aconst_null
      28: astore        4
      30: aload         4
      32: ifnonnull     39
      35: iload_3
      36: goto          71
      39: aload_1
      40: astore        5
      42: iload_3
      43: aload         4
      45: invokevirtual #234                // Method Vertex.getData:()Ljava/lang/Object;
      48: checkcast     #126                // class java/lang/Number
      51: invokevirtual #129                // Method java/lang/Number.intValue:()I
      54: invokestatic  #280                // Method java/lang/StrictMath.max:(II)I
      57: istore        6
      59: aload         5
      61: astore_1
      62: aload         4
      64: astore_2
      65: iload         6
      67: istore_3
      68: goto          0
      71: ireturn

  private static final boolean isMax$lambda$5(Vertex, Graph$EdgeType, Graph);
    Code:
       0: aload_0
       1: invokevirtual #234                // Method Vertex.getData:()Ljava/lang/Object;
       4: checkcast     #126                // class java/lang/Number
       7: invokevirtual #129                // Method java/lang/Number.intValue:()I
      10: aload_2
      11: aload_1
      12: aload_0
      13: ldc_w         #272                // int -2147483648
      16: invokestatic  #306                // Method isMax$go:(LGraph;LGraph$EdgeType;LVertex;I)I
      19: if_icmple     26
      22: iconst_1
      23: goto          27
      26: iconst_0
      27: ireturn

  private static final boolean isMax$lambda$6(kotlin.Lazy<java.lang.Boolean>);
    Code:
       0: aload_0
       1: astore_1
       2: aload_1
       3: invokeinterface #314,  1          // InterfaceMethod kotlin/Lazy.getValue:()Ljava/lang/Object;
       8: checkcast     #316                // class java/lang/Boolean
      11: invokevirtual #319                // Method java/lang/Boolean.booleanValue:()Z
      14: ireturn

  private static final int countToImmediateMax$go$7(int, Graph<java.lang.Integer>, Graph$EdgeType, Vertex<java.lang.Integer>, int);
    Code:
       0: aload_1
       1: aload_3
       2: invokeinterface #289,  2          // InterfaceMethod Graph.edges:(LVertex;)Ljava/util/Map;
       7: aload_2
       8: invokeinterface #294,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
      13: checkcast     #296                // class Edge
      16: dup
      17: ifnull        26
      20: invokevirtual #300                // Method Edge.getDestination:()LVertex;
      23: goto          28
      26: pop
      27: aconst_null
      28: astore        5
      30: nop
      31: aload         5
      33: ifnonnull     41
      36: iload         4
      38: goto          75
      41: aload         5
      43: invokevirtual #234                // Method Vertex.getData:()Ljava/lang/Object;
      46: checkcast     #126                // class java/lang/Number
      49: invokevirtual #129                // Method java/lang/Number.intValue:()I
      52: iload_0
      53: if_icmplt     63
      56: iload         4
      58: iconst_1
      59: iadd
      60: goto          75
      63: iload_0
      64: aload_1
      65: aload_2
      66: aload         5
      68: iload         4
      70: iconst_1
      71: iadd
      72: invokestatic  #238                // Method countToImmediateMax$go$7:(ILGraph;LGraph$EdgeType;LVertex;I)I
      75: ireturn
}


import java.lang.Math.abs

fun main() {
    fun part1(headKnotMotionsData: List<String>): Int {
        val tail = Knot("tail")
        val head = Knot("head")
        tail `join to follow` head

        headKnotMotionsData
            .map { it.split(" ") }
            .forEach {
                val direction = it.first()
                val magnitude = it.last().toInt()
                head
                    .appendMove(direction, magnitude)
                head.execute()
            }

        tail `unjoin so as not to follow` head
        return tail
            .positions
            .distinct()
            .also {
                it.map(::println)
            }
            .size
    }

    fun part2(headKnotMotionsData: List<String>): Int {
        val head = Knot("head")
        val tailOne = Knot("tailOne")
        val tailTwo = Knot("tailTwo")
        val tailThree = Knot("tailThree")
        val tailFour = Knot("tailFour")
        val tailFive = Knot("tailFive")
        val tailSix = Knot("tailSix")
        val tailSeven = Knot("tailSeven")
        val tailEight = Knot("tailEight")
        val tailNine = Knot("tailNine")

        tailOne `join to follow` head
        tailTwo `join to follow` tailOne
        tailThree `join to follow` tailTwo
        tailFour `join to follow` tailThree
        tailFive `join to follow` tailFour
        tailSix `join to follow` tailFive
        tailSeven `join to follow` tailSix
        tailEight `join to follow` tailSeven
        tailNine `join to follow` tailEight

        headKnotMotionsData
            .map { it.split(" ") }
            .forEach {
                val direction = it.first()
                val magnitude = it.last().toInt()
                head
                    .appendMove(direction, magnitude)
            }
        head.execute()

        tailOne `unjoin so as not to follow` head
        tailTwo `unjoin so as not to follow` tailOne
        tailThree `unjoin so as not to follow` tailTwo
        tailFour `unjoin so as not to follow` tailThree
        tailFive `unjoin so as not to follow` tailFour
        tailSix `unjoin so as not to follow` tailFive
        tailSeven `unjoin so as not to follow` tailSix
        tailEight `unjoin so as not to follow` tailSeven
        tailNine `unjoin so as not to follow` tailEight

        return tailNine
            .positions
            .distinct()
            .also {
                it.map(::println)
            }
            .size
    }

    // test if implementation meets criteria from the description, like:
/*    val testInput = readInput("Day09_test")
    check(part1(testInput) == 13)

    // testInputTwo is the larger example on the AOC website day 09 challenge of 2022

    val testInputTwo = readInput("Day09_test_two")
    check(part2(testInputTwo) == 36)
    check(part2(testInput) == 1)

    val input = readInput("Day09")
    println(part1(input))
    println(part2(input))*/
}

typealias Command = () -> Unit

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

class Knot(
    val name: String,
    var _xPosition: Int = 0,
    var _yPosition: Int = 0
) {
    private val orders = mutableListOf<Command>()
    private val _positions = mutableListOf<Position>()
    val positions
        get() = _positions.toList()
    val followers: HashMap<String, Knot> = HashMap()
    val moveGenerator = fun(
        knot: Knot,
        direction: String,
        qnty: Int
    ): Command {
        return fun() {
            when (direction) {
                "R" -> repeat(qnty) { knot.toRight() }
                "L" -> repeat(qnty) { knot.toLeft() }
                "U" -> repeat(qnty) { knot.toUp() }
                "D" -> repeat(qnty) { knot.toDown() }
                else -> {}
            }
        }
    }

    init {
        appendOrigin()
    }

    fun xPosition(xPosition: Int) { _xPosition = xPosition }
    fun yPosition(yPosition: Int) { _yPosition = yPosition }

    fun appendMove(direction: String, qnty: Int) = apply {
        orders.add(moveGenerator(this, direction, qnty))
    }

    fun appendOrigin() {
        _positions.add(Position(0, 0))
    }

    private fun toLeft() {
        _xPosition--
        moved()
    }
    private fun toRight() {
        _xPosition++
        moved()
    }
    private fun toDown() {
        _yPosition--
        moved()
    }
    private fun toUp() {
        _yPosition++
        moved()
    }

    fun moved() {
        _positions.add(Position(_xPosition, _yPosition))
        for ((_, follower) in followers) {
            follower.follow(this)
        }
    }

    fun execute() {
        while (!orders.isEmpty()) {
            val order = orders.removeAt(0)
            order.invoke()
            println("$name x -> $_xPosition y -> $_yPosition")
        }
    }

    fun follow(leader: Knot) {
        val deltaX = abs(leader._xPosition - this._xPosition)
        val deltaY = abs(leader._yPosition - this._yPosition)

        val xDirection = if (leader._xPosition - _xPosition > 0) "R" else "L"
        val yDirection = if (leader._yPosition - _yPosition > 0) "U" else "D"
        when {
            deltaX > 1 && deltaY > 0 || deltaY > 1 && deltaX > 0 -> {
                moveDiagonally(xDirection, yDirection)
                moved()
            }
            deltaX > 1 -> appendMove(xDirection, deltaX - 1).execute()
            deltaY > 1 -> appendMove(yDirection, deltaY - 1).execute()
        }
    }

    fun moveDiagonally(xDirection: String, yDirection: String) {
        when {
            xDirection == "L" -> _xPosition--
            xDirection == "R" -> _xPosition++
        }
        when {
            yDirection == "U" -> _yPosition++
            yDirection == "D" -> _yPosition--
        }
        /*
        appendMove(xDirection, 1)
            .appendMove(yDirection, 1)
            .execute()*/
    }
}

infix fun Knot.`join to follow`(head: Knot) {
    head.followers.put(this.name, this)
    println("${head.name} has a new follower $name")
}

infix fun Knot.`unjoin so as not to follow`(head: Knot) {
    head.followers.remove(name)
    println("${head.name} has been unfollowed by $name")
}

Compiled from "Day09.kt"
public final class Day09Kt {
  public static final void main();
    Code:
       0: return

  public static final void join to follow(Knot, Knot);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #19                 // String head
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_1
      13: invokevirtual #25                 // Method Knot.getFollowers:()Ljava/util/HashMap;
      16: aload_0
      17: invokevirtual #29                 // Method Knot.getName:()Ljava/lang/String;
      20: aload_0
      21: invokevirtual #35                 // Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      24: pop
      25: new           #37                 // class java/lang/StringBuilder
      28: dup
      29: invokespecial #40                 // Method java/lang/StringBuilder."<init>":()V
      32: aload_1
      33: invokevirtual #29                 // Method Knot.getName:()Ljava/lang/String;
      36: invokevirtual #44                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      39: ldc           #46                 // String  has a new follower
      41: invokevirtual #44                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      44: aload_0
      45: invokevirtual #29                 // Method Knot.getName:()Ljava/lang/String;
      48: invokevirtual #44                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      51: invokevirtual #49                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      54: getstatic     #55                 // Field java/lang/System.out:Ljava/io/PrintStream;
      57: swap
      58: invokevirtual #61                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      61: return

  public static final void unjoin so as not to follow(Knot, Knot);
    Code:
       0: aload_0
       1: ldc           #11                 // String <this>
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #19                 // String head
       9: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_1
      13: invokevirtual #25                 // Method Knot.getFollowers:()Ljava/util/HashMap;
      16: aload_0
      17: invokevirtual #29                 // Method Knot.getName:()Ljava/lang/String;
      20: invokevirtual #68                 // Method java/util/HashMap.remove:(Ljava/lang/Object;)Ljava/lang/Object;
      23: pop
      24: new           #37                 // class java/lang/StringBuilder
      27: dup
      28: invokespecial #40                 // Method java/lang/StringBuilder."<init>":()V
      31: aload_1
      32: invokevirtual #29                 // Method Knot.getName:()Ljava/lang/String;
      35: invokevirtual #44                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      38: ldc           #70                 // String  has been unfollowed by
      40: invokevirtual #44                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: aload_0
      44: invokevirtual #29                 // Method Knot.getName:()Ljava/lang/String;
      47: invokevirtual #44                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      50: invokevirtual #49                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      53: getstatic     #55                 // Field java/lang/System.out:Ljava/io/PrintStream;
      56: swap
      57: invokevirtual #61                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      60: return

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

  private static final int main$part1(java.util.List<java.lang.String>);
    Code:
       0: new           #21                 // class Knot
       3: dup
       4: ldc           #81                 // String tail
       6: iconst_0
       7: iconst_0
       8: bipush        6
      10: aconst_null
      11: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      14: astore_1
      15: new           #21                 // class Knot
      18: dup
      19: ldc           #19                 // String head
      21: iconst_0
      22: iconst_0
      23: bipush        6
      25: aconst_null
      26: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      29: astore_2
      30: aload_1
      31: aload_2
      32: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
      35: aload_0
      36: checkcast     #88                 // class java/lang/Iterable
      39: astore_3
      40: nop
      41: iconst_0
      42: istore        4
      44: aload_3
      45: astore        5
      47: new           #90                 // class java/util/ArrayList
      50: dup
      51: aload_3
      52: bipush        10
      54: invokestatic  #96                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      57: invokespecial #99                 // Method java/util/ArrayList."<init>":(I)V
      60: checkcast     #101                // class java/util/Collection
      63: astore        6
      65: iconst_0
      66: istore        7
      68: aload         5
      70: invokeinterface #105,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      75: astore        8
      77: aload         8
      79: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
      84: ifeq          149
      87: aload         8
      89: invokeinterface #115,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      94: astore        9
      96: aload         6
      98: aload         9
     100: checkcast     #117                // class java/lang/String
     103: astore        10
     105: astore        16
     107: iconst_0
     108: istore        11
     110: aload         10
     112: checkcast     #119                // class java/lang/CharSequence
     115: iconst_1
     116: anewarray     #117                // class java/lang/String
     119: astore        12
     121: aload         12
     123: iconst_0
     124: ldc           #121                // String
     126: aastore
     127: aload         12
     129: iconst_0
     130: iconst_0
     131: bipush        6
     133: aconst_null
     134: invokestatic  #127                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
     137: aload         16
     139: swap
     140: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     145: pop
     146: goto          77
     149: aload         6
     151: checkcast     #133                // class java/util/List
     154: nop
     155: checkcast     #88                 // class java/lang/Iterable
     158: astore_3
     159: nop
     160: iconst_0
     161: istore        4
     163: aload_3
     164: invokeinterface #105,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     169: astore        5
     171: aload         5
     173: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     178: ifeq          241
     181: aload         5
     183: invokeinterface #115,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     188: astore        6
     190: aload         6
     192: checkcast     #133                // class java/util/List
     195: astore        7
     197: iconst_0
     198: istore        8
     200: aload         7
     202: invokestatic  #137                // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
     205: checkcast     #117                // class java/lang/String
     208: astore        9
     210: aload         7
     212: invokestatic  #140                // Method kotlin/collections/CollectionsKt.last:(Ljava/util/List;)Ljava/lang/Object;
     215: checkcast     #117                // class java/lang/String
     218: invokestatic  #146                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     221: istore        10
     223: aload_2
     224: aload         9
     226: iload         10
     228: invokevirtual #150                // Method Knot.appendMove:(Ljava/lang/String;I)LKnot;
     231: pop
     232: aload_2
     233: invokevirtual #153                // Method Knot.execute:()V
     236: nop
     237: nop
     238: goto          171
     241: nop
     242: aload_1
     243: aload_2
     244: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     247: aload_1
     248: invokevirtual #159                // Method Knot.getPositions:()Ljava/util/List;
     251: checkcast     #88                 // class java/lang/Iterable
     254: invokestatic  #163                // Method kotlin/collections/CollectionsKt.distinct:(Ljava/lang/Iterable;)Ljava/util/List;
     257: astore_3
     258: aload_3
     259: astore        4
     261: iconst_0
     262: istore        5
     264: aload         4
     266: checkcast     #88                 // class java/lang/Iterable
     269: astore        6
     271: iconst_0
     272: istore        7
     274: aload         6
     276: astore        8
     278: new           #90                 // class java/util/ArrayList
     281: dup
     282: aload         6
     284: bipush        10
     286: invokestatic  #96                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     289: invokespecial #99                 // Method java/util/ArrayList."<init>":(I)V
     292: checkcast     #101                // class java/util/Collection
     295: astore        9
     297: iconst_0
     298: istore        10
     300: aload         8
     302: invokeinterface #105,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     307: astore        11
     309: aload         11
     311: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     316: ifeq          362
     319: aload         11
     321: invokeinterface #115,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     326: astore        12
     328: aload         9
     330: aload         12
     332: astore        13
     334: astore        14
     336: iconst_0
     337: istore        15
     339: getstatic     #55                 // Field java/lang/System.out:Ljava/io/PrintStream;
     342: aload         13
     344: invokevirtual #61                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     347: nop
     348: aload         14
     350: getstatic     #169                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
     353: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     358: pop
     359: goto          309
     362: aload         9
     364: checkcast     #133                // class java/util/List
     367: nop
     368: pop
     369: nop
     370: aload_3
     371: invokeinterface #173,  1          // InterfaceMethod java/util/List.size:()I
     376: ireturn

  private static final int main$part2(java.util.List<java.lang.String>);
    Code:
       0: new           #21                 // class Knot
       3: dup
       4: ldc           #19                 // String head
       6: iconst_0
       7: iconst_0
       8: bipush        6
      10: aconst_null
      11: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      14: astore_1
      15: new           #21                 // class Knot
      18: dup
      19: ldc           #200                // String tailOne
      21: iconst_0
      22: iconst_0
      23: bipush        6
      25: aconst_null
      26: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      29: astore_2
      30: new           #21                 // class Knot
      33: dup
      34: ldc           #202                // String tailTwo
      36: iconst_0
      37: iconst_0
      38: bipush        6
      40: aconst_null
      41: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      44: astore_3
      45: new           #21                 // class Knot
      48: dup
      49: ldc           #204                // String tailThree
      51: iconst_0
      52: iconst_0
      53: bipush        6
      55: aconst_null
      56: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      59: astore        4
      61: new           #21                 // class Knot
      64: dup
      65: ldc           #206                // String tailFour
      67: iconst_0
      68: iconst_0
      69: bipush        6
      71: aconst_null
      72: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      75: astore        5
      77: new           #21                 // class Knot
      80: dup
      81: ldc           #208                // String tailFive
      83: iconst_0
      84: iconst_0
      85: bipush        6
      87: aconst_null
      88: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
      91: astore        6
      93: new           #21                 // class Knot
      96: dup
      97: ldc           #210                // String tailSix
      99: iconst_0
     100: iconst_0
     101: bipush        6
     103: aconst_null
     104: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
     107: astore        7
     109: new           #21                 // class Knot
     112: dup
     113: ldc           #212                // String tailSeven
     115: iconst_0
     116: iconst_0
     117: bipush        6
     119: aconst_null
     120: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
     123: astore        8
     125: new           #21                 // class Knot
     128: dup
     129: ldc           #214                // String tailEight
     131: iconst_0
     132: iconst_0
     133: bipush        6
     135: aconst_null
     136: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
     139: astore        9
     141: new           #21                 // class Knot
     144: dup
     145: ldc           #216                // String tailNine
     147: iconst_0
     148: iconst_0
     149: bipush        6
     151: aconst_null
     152: invokespecial #84                 // Method Knot."<init>":(Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V
     155: astore        10
     157: aload_2
     158: aload_1
     159: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     162: aload_3
     163: aload_2
     164: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     167: aload         4
     169: aload_3
     170: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     173: aload         5
     175: aload         4
     177: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     180: aload         6
     182: aload         5
     184: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     187: aload         7
     189: aload         6
     191: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     194: aload         8
     196: aload         7
     198: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     201: aload         9
     203: aload         8
     205: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     208: aload         10
     210: aload         9
     212: invokestatic  #86                 // Method "join to follow":(LKnot;LKnot;)V
     215: aload_0
     216: checkcast     #88                 // class java/lang/Iterable
     219: astore        11
     221: nop
     222: iconst_0
     223: istore        12
     225: aload         11
     227: astore        13
     229: new           #90                 // class java/util/ArrayList
     232: dup
     233: aload         11
     235: bipush        10
     237: invokestatic  #96                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     240: invokespecial #99                 // Method java/util/ArrayList."<init>":(I)V
     243: checkcast     #101                // class java/util/Collection
     246: astore        14
     248: iconst_0
     249: istore        15
     251: aload         13
     253: invokeinterface #105,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     258: astore        16
     260: aload         16
     262: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     267: ifeq          332
     270: aload         16
     272: invokeinterface #115,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     277: astore        17
     279: aload         14
     281: aload         17
     283: checkcast     #117                // class java/lang/String
     286: astore        18
     288: astore        24
     290: iconst_0
     291: istore        19
     293: aload         18
     295: checkcast     #119                // class java/lang/CharSequence
     298: iconst_1
     299: anewarray     #117                // class java/lang/String
     302: astore        20
     304: aload         20
     306: iconst_0
     307: ldc           #121                // String
     309: aastore
     310: aload         20
     312: iconst_0
     313: iconst_0
     314: bipush        6
     316: aconst_null
     317: invokestatic  #127                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
     320: aload         24
     322: swap
     323: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     328: pop
     329: goto          260
     332: aload         14
     334: checkcast     #133                // class java/util/List
     337: nop
     338: checkcast     #88                 // class java/lang/Iterable
     341: astore        11
     343: nop
     344: iconst_0
     345: istore        12
     347: aload         11
     349: invokeinterface #105,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     354: astore        13
     356: aload         13
     358: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     363: ifeq          422
     366: aload         13
     368: invokeinterface #115,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     373: astore        14
     375: aload         14
     377: checkcast     #133                // class java/util/List
     380: astore        15
     382: iconst_0
     383: istore        16
     385: aload         15
     387: invokestatic  #137                // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
     390: checkcast     #117                // class java/lang/String
     393: astore        17
     395: aload         15
     397: invokestatic  #140                // Method kotlin/collections/CollectionsKt.last:(Ljava/util/List;)Ljava/lang/Object;
     400: checkcast     #117                // class java/lang/String
     403: invokestatic  #146                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     406: istore        18
     408: aload_1
     409: aload         17
     411: iload         18
     413: invokevirtual #150                // Method Knot.appendMove:(Ljava/lang/String;I)LKnot;
     416: pop
     417: nop
     418: nop
     419: goto          356
     422: nop
     423: aload_1
     424: invokevirtual #153                // Method Knot.execute:()V
     427: aload_2
     428: aload_1
     429: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     432: aload_3
     433: aload_2
     434: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     437: aload         4
     439: aload_3
     440: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     443: aload         5
     445: aload         4
     447: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     450: aload         6
     452: aload         5
     454: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     457: aload         7
     459: aload         6
     461: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     464: aload         8
     466: aload         7
     468: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     471: aload         9
     473: aload         8
     475: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     478: aload         10
     480: aload         9
     482: invokestatic  #155                // Method "unjoin so as not to follow":(LKnot;LKnot;)V
     485: aload         10
     487: invokevirtual #159                // Method Knot.getPositions:()Ljava/util/List;
     490: checkcast     #88                 // class java/lang/Iterable
     493: invokestatic  #163                // Method kotlin/collections/CollectionsKt.distinct:(Ljava/lang/Iterable;)Ljava/util/List;
     496: astore        11
     498: aload         11
     500: astore        12
     502: iconst_0
     503: istore        13
     505: aload         12
     507: checkcast     #88                 // class java/lang/Iterable
     510: astore        14
     512: iconst_0
     513: istore        15
     515: aload         14
     517: astore        16
     519: new           #90                 // class java/util/ArrayList
     522: dup
     523: aload         14
     525: bipush        10
     527: invokestatic  #96                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     530: invokespecial #99                 // Method java/util/ArrayList."<init>":(I)V
     533: checkcast     #101                // class java/util/Collection
     536: astore        17
     538: iconst_0
     539: istore        18
     541: aload         16
     543: invokeinterface #105,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     548: astore        19
     550: aload         19
     552: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     557: ifeq          603
     560: aload         19
     562: invokeinterface #115,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     567: astore        20
     569: aload         17
     571: aload         20
     573: astore        21
     575: astore        22
     577: iconst_0
     578: istore        23
     580: getstatic     #55                 // Field java/lang/System.out:Ljava/io/PrintStream;
     583: aload         21
     585: invokevirtual #61                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     588: nop
     589: aload         22
     591: getstatic     #169                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
     594: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     599: pop
     600: goto          550
     603: aload         17
     605: checkcast     #133                // class java/util/List
     608: nop
     609: pop
     610: nop
     611: aload         11
     613: invokeinterface #173,  1          // InterfaceMethod java/util/List.size:()I
     618: ireturn
}