import java.util.*
import kotlin.math.max

fun main() {
    val testInput = readInput("Day16_test")
    check(part1(testInput) == 1651)
    check(part2(testInput) == 1707)

    val input = readInput("Day16")
    println(part1(input))
    println(part2(input))
}

private const val PART1_MINUTES = 30
private const val PART2_MINUTES = 26
private const val START_VALVE = "AA"

private fun part1(input: List<String>): Int {
    val valves = input.parseInputAndOptimize()
    val bitsMapper = valves.calcBitsMapper()

    return solve(
        minutesLeft = PART1_MINUTES,
        name = START_VALVE,
        openedBitmask = 0,
        valves = valves,
        bitsMapper = bitsMapper
    )
}

private fun part2(input: List<String>): Int {
    val valves = input.parseInputAndOptimize()
    val bitsMapper = valves.calcBitsMapper()

    val valvesToOpen = bitsMapper.keys.toList() - START_VALVE
    val allBits = valvesToOpen.fold(0L) { acc, valve -> acc or bitsMapper.getValue(valve) }

    val memo = mutableMapOf<Long, Int>()

    //Brut-force all possible variants where some valves will be opened by me and the rest - by elephant
    return valvesToOpen.allCombinations()
        .map { valves ->
            valves.fold(0L) { acc, valve -> acc or bitsMapper.getValue(valve) }
        }
        .maxOf { valveBits ->
            val otherBits = allBits and valveBits.inv()

            val first = memo.getOrPut(valveBits) {
                solve(
                    minutesLeft = PART2_MINUTES,
                    name = START_VALVE,
                    openedBitmask = valveBits,
                    valves = valves,
                    bitsMapper = bitsMapper
                )
            }

            val second = memo.getOrPut(otherBits) {
                solve(
                    minutesLeft = PART2_MINUTES,
                    name = START_VALVE,
                    openedBitmask = otherBits,
                    valves = valves,
                    bitsMapper = bitsMapper
                )
            }

            first + second
        }
}

private fun solve(
    minutesLeft: Int,
    name: String,
    openedBitmask: Long,
    valves: Map<String, Valve>,
    bitsMapper: Map<String, Long>,
    memo: MutableMap<String, Int> = mutableMapOf()
): Int {
    val key = "${minutesLeft}_${name}_$openedBitmask"
    if (key in memo) {
        return memo.getValue(key)
    }

    val valve = valves.getValue(name)

    val resultInc = valve.rate * minutesLeft
    var result = resultInc

    valve.destinations.forEach { (nextName, timeToReachAndOpen) ->
        val nextBit = bitsMapper.getValue(nextName)

        if (minutesLeft > timeToReachAndOpen && (openedBitmask and nextBit) == 0L) {
            result = max(
                result,
                resultInc + solve(
                    minutesLeft = minutesLeft - timeToReachAndOpen,
                    name = nextName,
                    openedBitmask = (openedBitmask or nextBit),
                    valves = valves,
                    bitsMapper = bitsMapper,
                    memo = memo
                )
            )
        }
    }

    memo[key] = result

    return result
}

private val ROW_FORMAT = Regex("Valve ([A-Z]+) has flow rate=(\\d+); tunnel[s]? lead[s]? to valve[s]? ([A-Z, ]+)")
private fun List<String>.parseInputAndOptimize(): Map<String, Valve> {
    val rates = mutableMapOf<String, Int>()
    val tunnelsFromValve = mutableMapOf<String, List<String>>()

    this.forEach {
        val match = ROW_FORMAT.find(it)
        val (valve, rate, tunnels) = requireNotNull(match).destructured

        rates[valve] = rate.toInt()
        tunnelsFromValve[valve] = tunnels.split(", ")
    }

    // Consider only valves with rate > 0
    // Don't forget to add START valve
    return rates.filter { it.value > 0 || it.key == START_VALVE }
        .mapValues { (name, rate) ->
            Valve(
                rate = rate,
                destinations = buildTunnelsChains(name, tunnelsFromValve, rates)
            )
        }
}

private fun buildTunnelsChains(
    start: String,
    tunnels: Map<String, List<String>>,
    rates: Map<String, Int>
): List<Destination> {
    return buildList {
        val queue = PriorityQueue<Pair<String, Int>> { a, b -> a.second - b.second }
        queue.offer(start to 0)

        val visited = mutableSetOf<String>()

        while (queue.isNotEmpty()) {
            val (name, time) = queue.poll()

            if (name in visited) {
                continue
            }
            visited.add(name)

            if (rates.getValue(name) > 0 && name != start) {
                add(Destination(name, time + 1)) //add 1 minute for opening
            }

            tunnels[name]?.forEach { next ->
                queue.offer(next to time + 1)
            }
        }
    }
}

private fun Map<String, Valve>.calcBitsMapper(): Map<String, Long> {
    var i = 1L
    return this.mapValues {
        val res = i
        i = i shl 1

        res
    }
}

private data class Valve(
    val rate: Int,
    val destinations: List<Destination>
)

private data class Destination(
    val name: String,
    val timeToReachAndOpen: Int
)

Compiled from "Day16.kt"
public final class Day16Kt {
  private static final int PART1_MINUTES;

  private static final int PART2_MINUTES;

  private static final java.lang.String START_VALVE;

  private static final kotlin.text.Regex ROW_FORMAT;

  public static final void main();
    Code:
       0: ldc           #8                  // String Day16_test
       2: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
       5: astore_0
       6: aload_0
       7: invokestatic  #18                 // Method part1:(Ljava/util/List;)I
      10: sipush        1651
      13: if_icmpne     20
      16: iconst_1
      17: goto          21
      20: iconst_0
      21: ifne          34
      24: new           #20                 // class java/lang/IllegalStateException
      27: dup
      28: ldc           #22                 // String Check failed.
      30: invokespecial #26                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
      33: athrow
      34: aload_0
      35: invokestatic  #29                 // Method part2:(Ljava/util/List;)I
      38: sipush        1707
      41: if_icmpne     48
      44: iconst_1
      45: goto          49
      48: iconst_0
      49: ifne          62
      52: new           #20                 // class java/lang/IllegalStateException
      55: dup
      56: ldc           #22                 // String Check failed.
      58: invokespecial #26                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
      61: athrow
      62: ldc           #31                 // String Day16
      64: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
      67: astore_1
      68: aload_1
      69: invokestatic  #18                 // Method part1:(Ljava/util/List;)I
      72: istore_2
      73: getstatic     #37                 // Field java/lang/System.out:Ljava/io/PrintStream;
      76: iload_2
      77: invokevirtual #43                 // Method java/io/PrintStream.println:(I)V
      80: aload_1
      81: invokestatic  #29                 // Method part2:(Ljava/util/List;)I
      84: istore_2
      85: getstatic     #37                 // Field java/lang/System.out:Ljava/io/PrintStream;
      88: iload_2
      89: invokevirtual #43                 // Method java/io/PrintStream.println:(I)V
      92: return

  private static final int part1(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: invokestatic  #53                 // Method parseInputAndOptimize:(Ljava/util/List;)Ljava/util/Map;
       4: astore_1
       5: aload_1
       6: invokestatic  #57                 // Method calcBitsMapper:(Ljava/util/Map;)Ljava/util/Map;
       9: astore_2
      10: bipush        30
      12: ldc           #59                 // String AA
      14: lconst_0
      15: aload_1
      16: aload_2
      17: aconst_null
      18: bipush        32
      20: aconst_null
      21: invokestatic  #63                 // Method solve$default:(ILjava/lang/String;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)I
      24: ireturn

  private static final int part2(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: invokestatic  #53                 // Method parseInputAndOptimize:(Ljava/util/List;)Ljava/util/Map;
       4: astore_1
       5: aload_1
       6: invokestatic  #57                 // Method calcBitsMapper:(Ljava/util/Map;)Ljava/util/Map;
       9: astore_2
      10: aload_2
      11: invokeinterface #72,  1           // InterfaceMethod java/util/Map.keySet:()Ljava/util/Set;
      16: checkcast     #74                 // class java/lang/Iterable
      19: invokestatic  #80                 // Method kotlin/collections/CollectionsKt.toList:(Ljava/lang/Iterable;)Ljava/util/List;
      22: checkcast     #74                 // class java/lang/Iterable
      25: ldc           #59                 // String AA
      27: invokestatic  #84                 // Method kotlin/collections/CollectionsKt.minus:(Ljava/lang/Iterable;Ljava/lang/Object;)Ljava/util/List;
      30: astore_3
      31: aload_3
      32: checkcast     #74                 // class java/lang/Iterable
      35: astore        6
      37: lconst_0
      38: lstore        7
      40: iconst_0
      41: istore        9
      43: lload         7
      45: lstore        10
      47: aload         6
      49: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      54: astore        12
      56: aload         12
      58: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      63: ifeq          109
      66: aload         12
      68: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      73: astore        13
      75: lload         10
      77: aload         13
      79: checkcast     #100                // class java/lang/String
      82: astore        14
      84: lstore        15
      86: iconst_0
      87: istore        17
      89: lload         15
      91: aload_2
      92: aload         14
      94: invokestatic  #106                // Method kotlin/collections/MapsKt.getValue:(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
      97: checkcast     #108                // class java/lang/Number
     100: invokevirtual #112                // Method java/lang/Number.longValue:()J
     103: lor
     104: lstore        10
     106: goto          56
     109: lload         10
     111: lstore        4
     113: new           #114                // class java/util/LinkedHashMap
     116: dup
     117: invokespecial #116                // Method java/util/LinkedHashMap."<init>":()V
     120: checkcast     #68                 // class java/util/Map
     123: astore        6
     125: aload_3
     126: invokestatic  #120                // Method UtilsKt.allCombinations:(Ljava/util/List;)Ljava/util/List;
     129: checkcast     #74                 // class java/lang/Iterable
     132: astore        7
     134: nop
     135: iconst_0
     136: istore        9
     138: aload         7
     140: astore        10
     142: new           #122                // class java/util/ArrayList
     145: dup
     146: aload         7
     148: bipush        10
     150: invokestatic  #126                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     153: invokespecial #128                // Method java/util/ArrayList."<init>":(I)V
     156: checkcast     #130                // class java/util/Collection
     159: astore        12
     161: iconst_0
     162: istore        13
     164: aload         10
     166: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     171: astore        14
     173: aload         14
     175: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     180: ifeq          303
     183: aload         14
     185: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     190: astore        15
     192: aload         12
     194: aload         15
     196: checkcast     #48                 // class java/util/List
     199: astore        16
     201: astore        34
     203: iconst_0
     204: istore        17
     206: aload         16
     208: checkcast     #74                 // class java/lang/Iterable
     211: astore        18
     213: lconst_0
     214: lstore        19
     216: iconst_0
     217: istore        21
     219: lload         19
     221: lstore        22
     223: aload         18
     225: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     230: astore        24
     232: aload         24
     234: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     239: ifeq          285
     242: aload         24
     244: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     249: astore        25
     251: lload         22
     253: aload         25
     255: checkcast     #100                // class java/lang/String
     258: astore        26
     260: lstore        27
     262: iconst_0
     263: istore        29
     265: lload         27
     267: aload_2
     268: aload         26
     270: invokestatic  #106                // Method kotlin/collections/MapsKt.getValue:(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
     273: checkcast     #108                // class java/lang/Number
     276: invokevirtual #112                // Method java/lang/Number.longValue:()J
     279: lor
     280: lstore        22
     282: goto          232
     285: lload         22
     287: nop
     288: invokestatic  #136                // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     291: aload         34
     293: swap
     294: invokeinterface #140,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     299: pop
     300: goto          173
     303: aload         12
     305: checkcast     #48                 // class java/util/List
     308: nop
     309: checkcast     #74                 // class java/lang/Iterable
     312: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     317: astore        9
     319: aload         9
     321: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     326: ifne          337
     329: new           #142                // class java/util/NoSuchElementException
     332: dup
     333: invokespecial #143                // Method java/util/NoSuchElementException."<init>":()V
     336: athrow
     337: aload         9
     339: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     344: checkcast     #108                // class java/lang/Number
     347: invokevirtual #112                // Method java/lang/Number.longValue:()J
     350: lstore        10
     352: iconst_0
     353: istore        13
     355: lload         4
     357: lload         10
     359: ldc2_w        #144                // long -1l
     362: lxor
     363: land
     364: lstore        14
     366: aload         6
     368: astore        16
     370: lload         10
     372: invokestatic  #136                // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     375: astore        17
     377: iconst_0
     378: istore        18
     380: aload         16
     382: aload         17
     384: invokeinterface #149,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     389: astore        19
     391: aload         19
     393: ifnonnull     437
     396: iconst_0
     397: istore        21
     399: bipush        26
     401: ldc           #59                 // String AA
     403: lload         10
     405: aload_1
     406: aload_2
     407: aconst_null
     408: bipush        32
     410: aconst_null
     411: invokestatic  #63                 // Method solve$default:(ILjava/lang/String;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)I
     414: nop
     415: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     418: astore        22
     420: aload         16
     422: aload         17
     424: aload         22
     426: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     431: pop
     432: aload         22
     434: goto          439
     437: aload         19
     439: nop
     440: checkcast     #108                // class java/lang/Number
     443: invokevirtual #162                // Method java/lang/Number.intValue:()I
     446: istore        24
     448: aload         6
     450: astore        17
     452: lload         14
     454: invokestatic  #136                // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     457: astore        18
     459: iconst_0
     460: istore        19
     462: aload         17
     464: aload         18
     466: invokeinterface #149,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     471: astore        21
     473: aload         21
     475: ifnonnull     519
     478: iconst_0
     479: istore        22
     481: bipush        26
     483: ldc           #59                 // String AA
     485: lload         14
     487: aload_1
     488: aload_2
     489: aconst_null
     490: bipush        32
     492: aconst_null
     493: invokestatic  #63                 // Method solve$default:(ILjava/lang/String;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)I
     496: nop
     497: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     500: astore        25
     502: aload         17
     504: aload         18
     506: aload         25
     508: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     513: pop
     514: aload         25
     516: goto          521
     519: aload         21
     521: nop
     522: checkcast     #108                // class java/lang/Number
     525: invokevirtual #162                // Method java/lang/Number.intValue:()I
     528: istore        16
     530: iload         24
     532: iload         16
     534: iadd
     535: istore        26
     537: aload         9
     539: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     544: ifeq          761
     547: aload         9
     549: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     554: checkcast     #108                // class java/lang/Number
     557: invokevirtual #112                // Method java/lang/Number.longValue:()J
     560: lstore        27
     562: iconst_0
     563: istore        29
     565: lload         4
     567: lload         27
     569: ldc2_w        #144                // long -1l
     572: lxor
     573: land
     574: lstore        30
     576: aload         6
     578: astore        17
     580: lload         27
     582: invokestatic  #136                // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     585: astore        18
     587: iconst_0
     588: istore        19
     590: aload         17
     592: aload         18
     594: invokeinterface #149,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     599: astore        21
     601: aload         21
     603: ifnonnull     647
     606: iconst_0
     607: istore        22
     609: bipush        26
     611: ldc           #59                 // String AA
     613: lload         27
     615: aload_1
     616: aload_2
     617: aconst_null
     618: bipush        32
     620: aconst_null
     621: invokestatic  #63                 // Method solve$default:(ILjava/lang/String;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)I
     624: nop
     625: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     628: astore        24
     630: aload         17
     632: aload         18
     634: aload         24
     636: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     641: pop
     642: aload         24
     644: goto          649
     647: aload         21
     649: nop
     650: checkcast     #108                // class java/lang/Number
     653: invokevirtual #162                // Method java/lang/Number.intValue:()I
     656: istore        25
     658: aload         6
     660: astore        18
     662: lload         30
     664: invokestatic  #136                // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     667: astore        19
     669: iconst_0
     670: istore        21
     672: aload         18
     674: aload         19
     676: invokeinterface #149,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     681: astore        22
     683: aload         22
     685: ifnonnull     729
     688: iconst_0
     689: istore        24
     691: bipush        26
     693: ldc           #59                 // String AA
     695: lload         30
     697: aload_1
     698: aload_2
     699: aconst_null
     700: bipush        32
     702: aconst_null
     703: invokestatic  #63                 // Method solve$default:(ILjava/lang/String;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)I
     706: nop
     707: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     710: astore        32
     712: aload         18
     714: aload         19
     716: aload         32
     718: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     723: pop
     724: aload         32
     726: goto          731
     729: aload         22
     731: nop
     732: checkcast     #108                // class java/lang/Number
     735: invokevirtual #162                // Method java/lang/Number.intValue:()I
     738: istore        17
     740: iload         25
     742: iload         17
     744: iadd
     745: istore        33
     747: iload         26
     749: iload         33
     751: if_icmpge     537
     754: iload         33
     756: istore        26
     758: goto          537
     761: iload         26
     763: ireturn

  private static final int solve(int, java.lang.String, long, java.util.Map<java.lang.String, Valve>, java.util.Map<java.lang.String, java.lang.Long>, java.util.Map<java.lang.String, java.lang.Integer>);
    Code:
       0: new           #204                // class java/lang/StringBuilder
       3: dup
       4: invokespecial #205                // Method java/lang/StringBuilder."<init>":()V
       7: iload_0
       8: invokevirtual #209                // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      11: bipush        95
      13: invokevirtual #212                // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      16: aload_1
      17: invokevirtual #215                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      20: bipush        95
      22: invokevirtual #212                // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      25: lload_2
      26: invokevirtual #218                // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      29: invokevirtual #222                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore        7
      34: aload         6
      36: aload         7
      38: invokeinterface #225,  2          // InterfaceMethod java/util/Map.containsKey:(Ljava/lang/Object;)Z
      43: ifeq          60
      46: aload         6
      48: aload         7
      50: invokestatic  #106                // Method kotlin/collections/MapsKt.getValue:(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
      53: checkcast     #108                // class java/lang/Number
      56: invokevirtual #162                // Method java/lang/Number.intValue:()I
      59: ireturn
      60: aload         4
      62: aload_1
      63: invokestatic  #106                // Method kotlin/collections/MapsKt.getValue:(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
      66: checkcast     #227                // class Valve
      69: astore        8
      71: aload         8
      73: invokevirtual #230                // Method Valve.getRate:()I
      76: iload_0
      77: imul
      78: istore        9
      80: iconst_0
      81: istore        10
      83: iload         9
      85: istore        10
      87: aload         8
      89: invokevirtual #234                // Method Valve.getDestinations:()Ljava/util/List;
      92: checkcast     #74                 // class java/lang/Iterable
      95: astore        11
      97: iconst_0
      98: istore        12
     100: aload         11
     102: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     107: astore        13
     109: aload         13
     111: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     116: ifeq          218
     119: aload         13
     121: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     126: astore        14
     128: aload         14
     130: checkcast     #236                // class Destination
     133: astore        15
     135: iconst_0
     136: istore        16
     138: aload         15
     140: invokevirtual #239                // Method Destination.component1:()Ljava/lang/String;
     143: astore        17
     145: aload         15
     147: invokevirtual #242                // Method Destination.component2:()I
     150: istore        18
     152: aload         5
     154: aload         17
     156: invokestatic  #106                // Method kotlin/collections/MapsKt.getValue:(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
     159: checkcast     #108                // class java/lang/Number
     162: invokevirtual #112                // Method java/lang/Number.longValue:()J
     165: lstore        19
     167: iload_0
     168: iload         18
     170: if_icmple     213
     173: lload_2
     174: lload         19
     176: land
     177: lconst_0
     178: lcmp
     179: ifne          213
     182: nop
     183: nop
     184: iload         10
     186: iload         9
     188: iload_0
     189: iload         18
     191: isub
     192: aload         17
     194: lload_2
     195: lload         19
     197: lor
     198: aload         4
     200: aload         5
     202: aload         6
     204: invokestatic  #244                // Method solve:(ILjava/lang/String;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;)I
     207: iadd
     208: invokestatic  #250                // Method java/lang/Math.max:(II)I
     211: istore        10
     213: nop
     214: nop
     215: goto          109
     218: nop
     219: aload         6
     221: aload         7
     223: iload         10
     225: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     228: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     233: pop
     234: iload         10
     236: ireturn

  static int solve$default(int, java.lang.String, long, java.util.Map, java.util.Map, java.util.Map, int, java.lang.Object);
    Code:
       0: iload         7
       2: bipush        32
       4: iand
       5: ifeq          20
       8: new           #114                // class java/util/LinkedHashMap
      11: dup
      12: invokespecial #116                // Method java/util/LinkedHashMap."<init>":()V
      15: checkcast     #68                 // class java/util/Map
      18: astore        6
      20: iload_0
      21: aload_1
      22: lload_2
      23: aload         4
      25: aload         5
      27: aload         6
      29: invokestatic  #244                // Method solve:(ILjava/lang/String;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;)I
      32: ireturn

  private static final java.util.Map<java.lang.String, Valve> parseInputAndOptimize(java.util.List<java.lang.String>);
    Code:
       0: new           #114                // class java/util/LinkedHashMap
       3: dup
       4: invokespecial #116                // Method java/util/LinkedHashMap."<init>":()V
       7: checkcast     #68                 // class java/util/Map
      10: astore_1
      11: new           #114                // class java/util/LinkedHashMap
      14: dup
      15: invokespecial #116                // Method java/util/LinkedHashMap."<init>":()V
      18: checkcast     #68                 // class java/util/Map
      21: astore_2
      22: aload_0
      23: checkcast     #74                 // class java/lang/Iterable
      26: astore_3
      27: iconst_0
      28: istore        4
      30: aload_3
      31: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      36: astore        5
      38: aload         5
      40: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      45: ifeq          246
      48: aload         5
      50: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      55: astore        6
      57: aload         6
      59: checkcast     #100                // class java/lang/String
      62: astore        7
      64: iconst_0
      65: istore        8
      67: getstatic     #268                // Field ROW_FORMAT:Lkotlin/text/Regex;
      70: aload         7
      72: checkcast     #270                // class java/lang/CharSequence
      75: iconst_0
      76: iconst_2
      77: aconst_null
      78: invokestatic  #276                // Method kotlin/text/Regex.find$default:(Lkotlin/text/Regex;Ljava/lang/CharSequence;IILjava/lang/Object;)Lkotlin/text/MatchResult;
      81: astore        9
      83: aload         9
      85: dup
      86: ifnonnull     108
      89: pop
      90: ldc_w         #278                // String Required value was null.
      93: astore        10
      95: new           #280                // class java/lang/IllegalArgumentException
      98: dup
      99: aload         10
     101: invokevirtual #281                // Method java/lang/Object.toString:()Ljava/lang/String;
     104: invokespecial #282                // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
     107: athrow
     108: invokeinterface #288,  1          // InterfaceMethod kotlin/text/MatchResult.getDestructured:()Lkotlin/text/MatchResult$Destructured;
     113: astore        11
     115: aload         11
     117: invokevirtual #294                // Method kotlin/text/MatchResult$Destructured.getMatch:()Lkotlin/text/MatchResult;
     120: invokeinterface #297,  1          // InterfaceMethod kotlin/text/MatchResult.getGroupValues:()Ljava/util/List;
     125: iconst_1
     126: invokeinterface #300,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     131: checkcast     #100                // class java/lang/String
     134: astore        10
     136: aload         11
     138: invokevirtual #294                // Method kotlin/text/MatchResult$Destructured.getMatch:()Lkotlin/text/MatchResult;
     141: invokeinterface #297,  1          // InterfaceMethod kotlin/text/MatchResult.getGroupValues:()Ljava/util/List;
     146: iconst_2
     147: invokeinterface #300,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     152: checkcast     #100                // class java/lang/String
     155: astore        12
     157: aload         11
     159: invokevirtual #294                // Method kotlin/text/MatchResult$Destructured.getMatch:()Lkotlin/text/MatchResult;
     162: invokeinterface #297,  1          // InterfaceMethod kotlin/text/MatchResult.getGroupValues:()Ljava/util/List;
     167: iconst_3
     168: invokeinterface #300,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     173: checkcast     #100                // class java/lang/String
     176: astore        13
     178: nop
     179: aload_1
     180: aload         10
     182: aload         12
     184: invokestatic  #304                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     187: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     190: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     195: pop
     196: aload_2
     197: astore        14
     199: aload         13
     201: checkcast     #270                // class java/lang/CharSequence
     204: iconst_1
     205: anewarray     #100                // class java/lang/String
     208: astore        15
     210: aload         15
     212: iconst_0
     213: ldc_w         #306                // String ,
     216: aastore
     217: aload         15
     219: iconst_0
     220: iconst_0
     221: bipush        6
     223: aconst_null
     224: invokestatic  #312                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
     227: astore        15
     229: aload         14
     231: aload         10
     233: aload         15
     235: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     240: pop
     241: nop
     242: nop
     243: goto          38
     246: nop
     247: aload_1
     248: astore_3
     249: iconst_0
     250: istore        4
     252: aload_3
     253: astore        5
     255: new           #114                // class java/util/LinkedHashMap
     258: dup
     259: invokespecial #116                // Method java/util/LinkedHashMap."<init>":()V
     262: checkcast     #68                 // class java/util/Map
     265: astore        6
     267: iconst_0
     268: istore        7
     270: aload         5
     272: invokeinterface #315,  1          // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set;
     277: invokeinterface #318,  1          // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator;
     282: astore        8
     284: aload         8
     286: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     291: ifeq          377
     294: aload         8
     296: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     301: checkcast     #320                // class java/util/Map$Entry
     304: astore        9
     306: aload         9
     308: astore        10
     310: iconst_0
     311: istore        11
     313: aload         10
     315: invokeinterface #322,  1          // InterfaceMethod java/util/Map$Entry.getValue:()Ljava/lang/Object;
     320: checkcast     #108                // class java/lang/Number
     323: invokevirtual #162                // Method java/lang/Number.intValue:()I
     326: ifgt          344
     329: aload         10
     331: invokeinterface #325,  1          // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
     336: ldc           #59                 // String AA
     338: invokestatic  #331                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     341: ifeq          348
     344: iconst_1
     345: goto          349
     348: iconst_0
     349: ifeq          284
     352: aload         6
     354: aload         9
     356: invokeinterface #325,  1          // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
     361: aload         9
     363: invokeinterface #322,  1          // InterfaceMethod java/util/Map$Entry.getValue:()Ljava/lang/Object;
     368: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     373: pop
     374: goto          284
     377: aload         6
     379: nop
     380: astore_3
     381: nop
     382: iconst_0
     383: istore        4
     385: aload_3
     386: astore        5
     388: new           #114                // class java/util/LinkedHashMap
     391: dup
     392: aload_3
     393: invokeinterface #334,  1          // InterfaceMethod java/util/Map.size:()I
     398: invokestatic  #338                // Method kotlin/collections/MapsKt.mapCapacity:(I)I
     401: invokespecial #339                // Method java/util/LinkedHashMap."<init>":(I)V
     404: checkcast     #68                 // class java/util/Map
     407: astore        6
     409: iconst_0
     410: istore        7
     412: aload         5
     414: invokeinterface #315,  1          // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set;
     419: checkcast     #74                 // class java/lang/Iterable
     422: astore        8
     424: iconst_0
     425: istore        9
     427: aload         8
     429: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     434: astore        10
     436: aload         10
     438: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     443: ifeq          554
     446: aload         10
     448: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     453: astore        11
     455: aload         6
     457: aload         11
     459: checkcast     #320                // class java/util/Map$Entry
     462: astore        12
     464: astore        13
     466: iconst_0
     467: istore        14
     469: aload         12
     471: invokeinterface #325,  1          // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
     476: aload         13
     478: swap
     479: aload         11
     481: checkcast     #320                // class java/util/Map$Entry
     484: astore        15
     486: astore        20
     488: astore        19
     490: iconst_0
     491: istore        16
     493: aload         15
     495: invokeinterface #325,  1          // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
     500: checkcast     #100                // class java/lang/String
     503: astore        17
     505: aload         15
     507: invokeinterface #322,  1          // InterfaceMethod java/util/Map$Entry.getValue:()Ljava/lang/Object;
     512: checkcast     #108                // class java/lang/Number
     515: invokevirtual #162                // Method java/lang/Number.intValue:()I
     518: istore        18
     520: new           #227                // class Valve
     523: dup
     524: iload         18
     526: aload         17
     528: aload_2
     529: aload_1
     530: invokestatic  #343                // Method buildTunnelsChains:(Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)Ljava/util/List;
     533: invokespecial #346                // Method Valve."<init>":(ILjava/util/List;)V
     536: nop
     537: astore        21
     539: aload         19
     541: aload         20
     543: aload         21
     545: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     550: pop
     551: goto          436
     554: aload         6
     556: nop
     557: nop
     558: areturn

  private static final java.util.List<Destination> buildTunnelsChains(java.lang.String, java.util.Map<java.lang.String, ? extends java.util.List<java.lang.String>>, java.util.Map<java.lang.String, java.lang.Integer>);
    Code:
       0: invokestatic  #376                // Method kotlin/collections/CollectionsKt.createListBuilder:()Ljava/util/List;
       3: astore_3
       4: aload_3
       5: astore        4
       7: iconst_0
       8: istore        5
      10: new           #378                // class java/util/PriorityQueue
      13: dup
      14: invokedynamic #397,  0            // InvokeDynamic #0:invoke:()Lkotlin/jvm/functions/Function2;
      19: invokedynamic #408,  0            // InvokeDynamic #1:compare:(Lkotlin/jvm/functions/Function2;)Ljava/util/Comparator;
      24: invokespecial #411                // Method java/util/PriorityQueue."<init>":(Ljava/util/Comparator;)V
      27: astore        6
      29: aload         6
      31: aload_0
      32: iconst_0
      33: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      36: invokestatic  #417                // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      39: invokevirtual #420                // Method java/util/PriorityQueue.offer:(Ljava/lang/Object;)Z
      42: pop
      43: new           #422                // class java/util/LinkedHashSet
      46: dup
      47: invokespecial #423                // Method java/util/LinkedHashSet."<init>":()V
      50: checkcast     #317                // class java/util/Set
      53: astore        7
      55: aload         6
      57: checkcast     #130                // class java/util/Collection
      60: invokeinterface #426,  1          // InterfaceMethod java/util/Collection.isEmpty:()Z
      65: ifne          72
      68: iconst_1
      69: goto          73
      72: iconst_0
      73: ifeq          272
      76: aload         6
      78: invokevirtual #429                // Method java/util/PriorityQueue.poll:()Ljava/lang/Object;
      81: checkcast     #431                // class kotlin/Pair
      84: astore        8
      86: aload         8
      88: invokevirtual #433                // Method kotlin/Pair.component1:()Ljava/lang/Object;
      91: checkcast     #100                // class java/lang/String
      94: astore        9
      96: aload         8
      98: invokevirtual #435                // Method kotlin/Pair.component2:()Ljava/lang/Object;
     101: checkcast     #108                // class java/lang/Number
     104: invokevirtual #162                // Method java/lang/Number.intValue:()I
     107: istore        10
     109: aload         7
     111: aload         9
     113: invokeinterface #438,  2          // InterfaceMethod java/util/Set.contains:(Ljava/lang/Object;)Z
     118: ifeq          124
     121: goto          55
     124: aload         7
     126: aload         9
     128: invokeinterface #439,  2          // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
     133: pop
     134: aload_2
     135: aload         9
     137: invokestatic  #106                // Method kotlin/collections/MapsKt.getValue:(Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object;
     140: checkcast     #108                // class java/lang/Number
     143: invokevirtual #162                // Method java/lang/Number.intValue:()I
     146: ifle          179
     149: aload         9
     151: aload_0
     152: invokestatic  #331                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     155: ifne          179
     158: aload         4
     160: new           #236                // class Destination
     163: dup
     164: aload         9
     166: iload         10
     168: iconst_1
     169: iadd
     170: invokespecial #442                // Method Destination."<init>":(Ljava/lang/String;I)V
     173: invokeinterface #443,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     178: pop
     179: aload_1
     180: aload         9
     182: invokeinterface #149,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     187: checkcast     #48                 // class java/util/List
     190: dup
     191: ifnull        267
     194: checkcast     #74                 // class java/lang/Iterable
     197: astore        11
     199: iconst_0
     200: istore        12
     202: aload         11
     204: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     209: astore        13
     211: aload         13
     213: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     218: ifeq          263
     221: aload         13
     223: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     228: astore        14
     230: aload         14
     232: checkcast     #100                // class java/lang/String
     235: astore        15
     237: iconst_0
     238: istore        16
     240: aload         6
     242: aload         15
     244: iload         10
     246: iconst_1
     247: iadd
     248: invokestatic  #154                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     251: invokestatic  #417                // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     254: invokevirtual #420                // Method java/util/PriorityQueue.offer:(Ljava/lang/Object;)Z
     257: pop
     258: nop
     259: nop
     260: goto          211
     263: nop
     264: goto          55
     267: pop
     268: nop
     269: goto          55
     272: nop
     273: aload_3
     274: invokestatic  #446                // Method kotlin/collections/CollectionsKt.build:(Ljava/util/List;)Ljava/util/List;
     277: areturn

  private static final java.util.Map<java.lang.String, java.lang.Long> calcBitsMapper(java.util.Map<java.lang.String, Valve>);
    Code:
       0: lconst_0
       1: lstore        20
       3: lconst_1
       4: lstore        20
       6: aload_0
       7: astore_1
       8: iconst_0
       9: istore_2
      10: aload_1
      11: astore_3
      12: new           #114                // class java/util/LinkedHashMap
      15: dup
      16: aload_1
      17: invokeinterface #334,  1          // InterfaceMethod java/util/Map.size:()I
      22: invokestatic  #338                // Method kotlin/collections/MapsKt.mapCapacity:(I)I
      25: invokespecial #339                // Method java/util/LinkedHashMap."<init>":(I)V
      28: checkcast     #68                 // class java/util/Map
      31: astore        4
      33: iconst_0
      34: istore        5
      36: aload_3
      37: invokeinterface #315,  1          // InterfaceMethod java/util/Map.entrySet:()Ljava/util/Set;
      42: checkcast     #74                 // class java/lang/Iterable
      45: astore        6
      47: iconst_0
      48: istore        7
      50: aload         6
      52: invokeinterface #88,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      57: astore        8
      59: aload         8
      61: invokeinterface #94,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      66: ifeq          148
      69: aload         8
      71: invokeinterface #98,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      76: astore        9
      78: aload         4
      80: aload         9
      82: checkcast     #320                // class java/util/Map$Entry
      85: astore        10
      87: astore        11
      89: iconst_0
      90: istore        12
      92: aload         10
      94: invokeinterface #325,  1          // InterfaceMethod java/util/Map$Entry.getKey:()Ljava/lang/Object;
      99: aload         11
     101: swap
     102: aload         9
     104: checkcast     #320                // class java/util/Map$Entry
     107: astore        13
     109: astore        18
     111: astore        17
     113: iconst_0
     114: istore        14
     116: lload         20
     118: lstore        15
     120: lload         20
     122: iconst_1
     123: lshl
     124: lstore        20
     126: lload         15
     128: invokestatic  #136                // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     131: astore        19
     133: aload         17
     135: aload         18
     137: aload         19
     139: invokeinterface #158,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     144: pop
     145: goto          59
     148: aload         4
     150: nop
     151: nop
     152: areturn

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

  private static final int buildTunnelsChains$lambda$13$lambda$10(kotlin.Pair, kotlin.Pair);
    Code:
       0: aload_0
       1: invokevirtual #468                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
       4: checkcast     #108                // class java/lang/Number
       7: invokevirtual #162                // Method java/lang/Number.intValue:()I
      10: aload_1
      11: invokevirtual #468                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
      14: checkcast     #108                // class java/lang/Number
      17: invokevirtual #162                // Method java/lang/Number.intValue:()I
      20: isub
      21: ireturn

  private static final int buildTunnelsChains$lambda$13$lambda$11(kotlin.jvm.functions.Function2, java.lang.Object, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: aload_2
       3: invokeinterface #475,  3          // InterfaceMethod kotlin/jvm/functions/Function2.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
       8: checkcast     #108                // class java/lang/Number
      11: invokevirtual #162                // Method java/lang/Number.intValue:()I
      14: ireturn

  static {};
    Code:
       0: new           #272                // class kotlin/text/Regex
       3: dup
       4: ldc_w         #482                // String Valve ([A-Z]+) has flow rate=(\\d+); tunnel[s]? lead[s]? to valve[s]? ([A-Z, ]+)
       7: invokespecial #483                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
      10: putstatic     #268                // Field ROW_FORMAT:Lkotlin/text/Regex;
      13: return
}


fun main() {
    val testInput = readInput("Day20_test")
    check(part1(testInput) == 3L)
    check(part2(testInput) == 1623178306L)

    val input = readInput("Day20")
    println(part1(input))
    println(part2(input))
}

private fun part1(input: List<String>): Long = solve(input, String::toLong, mixesCount = 1)
private fun part2(input: List<String>): Long = solve(input, String::part2Converter, mixesCount = 10)

private fun String.part2Converter(): Long = this.toLong() * 811589153L

private fun solve(input: List<String>, converter: String.() -> Long, mixesCount: Int): Long {
    val nodes = input.map { LinkedNode(it.converter()) }

    var zeroIndex = -1
    for (i in nodes.indices) {
        nodes[i].next = if (i < nodes.lastIndex) nodes[i + 1] else nodes.first()
        nodes[i].prev = if (i > 0) nodes[i - 1] else nodes.last()

        if (nodes[i].value == 0L) {
            zeroIndex = i
        }
    }

    repeat(mixesCount) {
        nodes.forEach { node ->
            val count = correctMovesCount(node.value, nodes.size)

            if (count > 0) {
                var target = node
                repeat(count) {
                    target = target.next
                }

                //delete node from chain
                node.prev.next = node.next
                node.next.prev = node.prev

                //insert node to the new position
                node.next = target.next
                target.next.prev = node
                target.next = node
                node.prev = target
            }
        }
    }

    var node = nodes[zeroIndex]
    var result = 0L
    repeat(3_001) {
        if (it == 1_000 || it == 2_000 || it == 3_000) {
            result += node.value
        }

        node = node.next
    }

    return result
}

private fun correctMovesCount(count: Long, size: Int): Int {
    return if (count > 0) {
        //reduce the full cycles
        (count % (size - 1)).toInt()
    } else {
        //(size + (count % (size - 1)) - 1) - this converts negative steps to positive steps
        // % (size - 1) - this reduce the full cycles when the steps count is more than the items in the chain
        ((size + (count % (size - 1)) - 1) % (size - 1)).toInt()
    }
}

private class LinkedNode(val value: Long) {
    lateinit var next: LinkedNode
    lateinit var prev: LinkedNode
}

Compiled from "Day20.kt"
public final class Day20Kt {
  public static final void main();
    Code:
       0: ldc           #8                  // String Day20_test
       2: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
       5: astore_0
       6: aload_0
       7: invokestatic  #18                 // Method part1:(Ljava/util/List;)J
      10: ldc2_w        #19                 // long 3l
      13: lcmp
      14: ifne          21
      17: iconst_1
      18: goto          22
      21: iconst_0
      22: ifne          35
      25: new           #22                 // class java/lang/IllegalStateException
      28: dup
      29: ldc           #24                 // String Check failed.
      31: invokespecial #28                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
      34: athrow
      35: aload_0
      36: invokestatic  #31                 // Method part2:(Ljava/util/List;)J
      39: ldc2_w        #32                 // long 1623178306l
      42: lcmp
      43: ifne          50
      46: iconst_1
      47: goto          51
      50: iconst_0
      51: ifne          64
      54: new           #22                 // class java/lang/IllegalStateException
      57: dup
      58: ldc           #24                 // String Check failed.
      60: invokespecial #28                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
      63: athrow
      64: ldc           #35                 // String Day20
      66: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
      69: astore_1
      70: aload_1
      71: invokestatic  #18                 // Method part1:(Ljava/util/List;)J
      74: lstore_2
      75: getstatic     #41                 // Field java/lang/System.out:Ljava/io/PrintStream;
      78: lload_2
      79: invokevirtual #47                 // Method java/io/PrintStream.println:(J)V
      82: aload_1
      83: invokestatic  #31                 // Method part2:(Ljava/util/List;)J
      86: lstore_2
      87: getstatic     #41                 // Field java/lang/System.out:Ljava/io/PrintStream;
      90: lload_2
      91: invokevirtual #47                 // Method java/io/PrintStream.println:(J)V
      94: return

  private static final long part1(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: getstatic     #59                 // Field Day20Kt$part1$1.INSTANCE:LDay20Kt$part1$1;
       4: checkcast     #61                 // class kotlin/jvm/functions/Function1
       7: iconst_1
       8: invokestatic  #65                 // Method solve:(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)J
      11: lreturn

  private static final long part2(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: getstatic     #70                 // Field Day20Kt$part2$1.INSTANCE:LDay20Kt$part2$1;
       4: checkcast     #61                 // class kotlin/jvm/functions/Function1
       7: bipush        10
       9: invokestatic  #65                 // Method solve:(Ljava/util/List;Lkotlin/jvm/functions/Function1;I)J
      12: lreturn

  private static final long part2Converter(java.lang.String);
    Code:
       0: aload_0
       1: invokestatic  #77                 // Method java/lang/Long.parseLong:(Ljava/lang/String;)J
       4: ldc2_w        #78                 // long 811589153l
       7: lmul
       8: lreturn

  private static final long solve(java.util.List<java.lang.String>, kotlin.jvm.functions.Function1<? super java.lang.String, java.lang.Long>, int);
    Code:
       0: aload_0
       1: checkcast     #84                 // class java/lang/Iterable
       4: astore        4
       6: iconst_0
       7: istore        5
       9: aload         4
      11: astore        6
      13: new           #86                 // class java/util/ArrayList
      16: dup
      17: aload         4
      19: bipush        10
      21: invokestatic  #92                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      24: invokespecial #95                 // Method java/util/ArrayList."<init>":(I)V
      27: checkcast     #97                 // class java/util/Collection
      30: astore        7
      32: iconst_0
      33: istore        8
      35: aload         6
      37: invokeinterface #101,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      42: astore        9
      44: aload         9
      46: invokeinterface #107,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
      51: ifeq          110
      54: aload         9
      56: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      61: astore        10
      63: aload         7
      65: aload         10
      67: checkcast     #113                // class java/lang/String
      70: astore        11
      72: astore        19
      74: iconst_0
      75: istore        12
      77: new           #115                // class LinkedNode
      80: dup
      81: aload_1
      82: aload         11
      84: invokeinterface #119,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
      89: checkcast     #121                // class java/lang/Number
      92: invokevirtual #125                // Method java/lang/Number.longValue:()J
      95: invokespecial #127                // Method LinkedNode."<init>":(J)V
      98: aload         19
     100: swap
     101: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     106: pop
     107: goto          44
     110: aload         7
     112: checkcast     #52                 // class java/util/List
     115: nop
     116: astore_3
     117: iconst_m1
     118: istore        4
     120: iconst_0
     121: istore        5
     123: aload_3
     124: checkcast     #97                 // class java/util/Collection
     127: invokeinterface #135,  1          // InterfaceMethod java/util/Collection.size:()I
     132: istore        6
     134: iload         5
     136: iload         6
     138: if_icmpge     258
     141: aload_3
     142: iload         5
     144: invokeinterface #139,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     149: checkcast     #115                // class LinkedNode
     152: iload         5
     154: aload_3
     155: invokestatic  #143                // Method kotlin/collections/CollectionsKt.getLastIndex:(Ljava/util/List;)I
     158: if_icmpge     177
     161: aload_3
     162: iload         5
     164: iconst_1
     165: iadd
     166: invokeinterface #139,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     171: checkcast     #115                // class LinkedNode
     174: goto          184
     177: aload_3
     178: invokestatic  #147                // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
     181: checkcast     #115                // class LinkedNode
     184: invokevirtual #151                // Method LinkedNode.setNext:(LLinkedNode;)V
     187: aload_3
     188: iload         5
     190: invokeinterface #139,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     195: checkcast     #115                // class LinkedNode
     198: iload         5
     200: ifle          219
     203: aload_3
     204: iload         5
     206: iconst_1
     207: isub
     208: invokeinterface #139,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     213: checkcast     #115                // class LinkedNode
     216: goto          226
     219: aload_3
     220: invokestatic  #154                // Method kotlin/collections/CollectionsKt.last:(Ljava/util/List;)Ljava/lang/Object;
     223: checkcast     #115                // class LinkedNode
     226: invokevirtual #157                // Method LinkedNode.setPrev:(LLinkedNode;)V
     229: aload_3
     230: iload         5
     232: invokeinterface #139,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     237: checkcast     #115                // class LinkedNode
     240: invokevirtual #160                // Method LinkedNode.getValue:()J
     243: lconst_0
     244: lcmp
     245: ifne          252
     248: iload         5
     250: istore        4
     252: iinc          5, 1
     255: goto          134
     258: iconst_0
     259: istore        5
     261: iload         5
     263: iload_2
     264: if_icmpge     453
     267: iload         5
     269: istore        6
     271: iconst_0
     272: istore        7
     274: aload_3
     275: checkcast     #84                 // class java/lang/Iterable
     278: astore        8
     280: iconst_0
     281: istore        9
     283: aload         8
     285: invokeinterface #101,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     290: astore        10
     292: aload         10
     294: invokeinterface #107,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     299: ifeq          445
     302: aload         10
     304: invokeinterface #111,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     309: astore        11
     311: aload         11
     313: checkcast     #115                // class LinkedNode
     316: astore        12
     318: iconst_0
     319: istore        13
     321: aload         12
     323: invokevirtual #160                // Method LinkedNode.getValue:()J
     326: aload_3
     327: invokeinterface #161,  1          // InterfaceMethod java/util/List.size:()I
     332: invokestatic  #165                // Method correctMovesCount:(JI)I
     335: istore        14
     337: iload         14
     339: ifle          440
     342: aconst_null
     343: astore        15
     345: aload         12
     347: astore        15
     349: iconst_0
     350: istore        16
     352: iload         16
     354: iload         14
     356: if_icmpge     380
     359: iload         16
     361: istore        17
     363: iconst_0
     364: istore        18
     366: aload         15
     368: invokevirtual #169                // Method LinkedNode.getNext:()LLinkedNode;
     371: astore        15
     373: nop
     374: iinc          16, 1
     377: goto          352
     380: aload         12
     382: invokevirtual #172                // Method LinkedNode.getPrev:()LLinkedNode;
     385: aload         12
     387: invokevirtual #169                // Method LinkedNode.getNext:()LLinkedNode;
     390: invokevirtual #151                // Method LinkedNode.setNext:(LLinkedNode;)V
     393: aload         12
     395: invokevirtual #169                // Method LinkedNode.getNext:()LLinkedNode;
     398: aload         12
     400: invokevirtual #172                // Method LinkedNode.getPrev:()LLinkedNode;
     403: invokevirtual #157                // Method LinkedNode.setPrev:(LLinkedNode;)V
     406: aload         12
     408: aload         15
     410: invokevirtual #169                // Method LinkedNode.getNext:()LLinkedNode;
     413: invokevirtual #151                // Method LinkedNode.setNext:(LLinkedNode;)V
     416: aload         15
     418: invokevirtual #169                // Method LinkedNode.getNext:()LLinkedNode;
     421: aload         12
     423: invokevirtual #157                // Method LinkedNode.setPrev:(LLinkedNode;)V
     426: aload         15
     428: aload         12
     430: invokevirtual #151                // Method LinkedNode.setNext:(LLinkedNode;)V
     433: aload         12
     435: aload         15
     437: invokevirtual #157                // Method LinkedNode.setPrev:(LLinkedNode;)V
     440: nop
     441: nop
     442: goto          292
     445: nop
     446: nop
     447: iinc          5, 1
     450: goto          261
     453: aconst_null
     454: astore        5
     456: aload_3
     457: iload         4
     459: invokeinterface #139,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     464: astore        5
     466: lconst_0
     467: lstore        20
     469: sipush        3001
     472: istore        7
     474: iconst_0
     475: istore        8
     477: iload         8
     479: iload         7
     481: if_icmpge     558
     484: iload         8
     486: istore        9
     488: iconst_0
     489: istore        10
     491: iload         9
     493: lookupswitch  { // 3
                  1000: 528
                  2000: 528
                  3000: 528
               default: 541
          }
     528: lload         20
     530: aload         5
     532: checkcast     #115                // class LinkedNode
     535: invokevirtual #160                // Method LinkedNode.getValue:()J
     538: ladd
     539: lstore        20
     541: aload         5
     543: checkcast     #115                // class LinkedNode
     546: invokevirtual #169                // Method LinkedNode.getNext:()LLinkedNode;
     549: astore        5
     551: nop
     552: iinc          8, 1
     555: goto          477
     558: lload         20
     560: lreturn

  private static final int correctMovesCount(long, int);
    Code:
       0: lload_0
       1: lconst_0
       2: lcmp
       3: ifle          16
       6: lload_0
       7: iload_2
       8: iconst_1
       9: isub
      10: i2l
      11: lrem
      12: l2i
      13: goto          33
      16: iload_2
      17: i2l
      18: lload_0
      19: iload_2
      20: iconst_1
      21: isub
      22: i2l
      23: lrem
      24: ladd
      25: lconst_1
      26: lsub
      27: iload_2
      28: iconst_1
      29: isub
      30: i2l
      31: lrem
      32: l2i
      33: ireturn

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

  public static final long access$part2Converter(java.lang.String);
    Code:
       0: aload_0
       1: invokestatic  #211                // Method part2Converter:(Ljava/lang/String;)J
       4: lreturn
}

Compiled from "Day20.kt"
final class Day20Kt$part1$1 extends kotlin.jvm.internal.FunctionReferenceImpl implements kotlin.jvm.functions.Function1<java.lang.String, java.lang.Long> {
  public static final Day20Kt$part1$1 INSTANCE;

  Day20Kt$part1$1();
    Code:
       0: aload_0
       1: iconst_1
       2: ldc           #11                 // class kotlin/text/StringsKt
       4: ldc           #13                 // String toLong
       6: ldc           #15                 // String toLong(Ljava/lang/String;)J
       8: iconst_1
       9: invokespecial #18                 // Method kotlin/jvm/internal/FunctionReferenceImpl."<init>":(ILjava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
      12: return

  public final java.lang.Long invoke(java.lang.String);
    Code:
       0: aload_1
       1: ldc           #24                 // String p0
       3: invokestatic  #30                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: invokestatic  #36                 // Method java/lang/Long.parseLong:(Ljava/lang/String;)J
      10: invokestatic  #40                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
      13: areturn

  public java.lang.Object invoke(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #44                 // class java/lang/String
       5: invokevirtual #46                 // Method invoke:(Ljava/lang/String;)Ljava/lang/Long;
       8: areturn

  static {};
    Code:
       0: new           #2                  // class Day20Kt$part1$1
       3: dup
       4: invokespecial #51                 // Method "<init>":()V
       7: putstatic     #54                 // Field INSTANCE:LDay20Kt$part1$1;
      10: return
}

Compiled from "Day20.kt"
final class Day20Kt$part2$1 extends kotlin.jvm.internal.FunctionReferenceImpl implements kotlin.jvm.functions.Function1<java.lang.String, java.lang.Long> {
  public static final Day20Kt$part2$1 INSTANCE;

  Day20Kt$part2$1();
    Code:
       0: aload_0
       1: iconst_1
       2: ldc           #11                 // class Day20Kt
       4: ldc           #13                 // String part2Converter
       6: ldc           #15                 // String part2Converter(Ljava/lang/String;)J
       8: iconst_1
       9: invokespecial #18                 // Method kotlin/jvm/internal/FunctionReferenceImpl."<init>":(ILjava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
      12: return

  public final java.lang.Long invoke(java.lang.String);
    Code:
       0: aload_1
       1: ldc           #24                 // String p0
       3: invokestatic  #30                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: invokestatic  #34                 // Method Day20Kt.access$part2Converter:(Ljava/lang/String;)J
      10: invokestatic  #40                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
      13: areturn

  public java.lang.Object invoke(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #44                 // class java/lang/String
       5: invokevirtual #46                 // Method invoke:(Ljava/lang/String;)Ljava/lang/Long;
       8: areturn

  static {};
    Code:
       0: new           #2                  // class Day20Kt$part2$1
       3: dup
       4: invokespecial #51                 // Method "<init>":()V
       7: putstatic     #54                 // Field INSTANCE:LDay20Kt$part2$1;
      10: return
}


fun main() {
    val testInput = readInput("Day25_test")
    check(part1(testInput) == "2=-1=0")

    val input = readInput("Day25")
    println(part1(input))
}

private fun part1(input: List<String>): String {
    val sum = input.sumOf(String::SNAFUToInt)

    return sum.toSNAFU()
}

private fun String.SNAFUToInt(): Long {
    var result = 0L
    var pow = 1L

    for (i in this.lastIndex downTo 0) {
        result += when (this[i]) {
            '-' -> -pow
            '=' -> -2L * pow
            else -> this[i].digitToInt() * pow
        }

        pow *= 5L
    }

    return result
}

private fun Long.toSNAFU(): String {
    var tmp = this
    var result = ""

    while (tmp != 0L) {
        val rem = tmp % 5L
        tmp /= 5L

        if (rem <= 2) {
            result = rem.toString() + result
        } else {
            ++tmp

            result = when (rem) {
                3L -> "="
                4L -> "-"
                else -> error(Unit)
            } + result
        }
    }

    return result
}

Compiled from "Day25.kt"
public final class Day25Kt {
  public static final void main();
    Code:
       0: ldc           #8                  // String Day25_test
       2: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
       5: astore_0
       6: aload_0
       7: invokestatic  #18                 // Method part1:(Ljava/util/List;)Ljava/lang/String;
      10: ldc           #20                 // String 2=-1=0
      12: invokestatic  #26                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      15: ifne          28
      18: new           #28                 // class java/lang/IllegalStateException
      21: dup
      22: ldc           #30                 // String Check failed.
      24: invokespecial #34                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
      27: athrow
      28: ldc           #36                 // String Day25
      30: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
      33: astore_1
      34: aload_1
      35: invokestatic  #18                 // Method part1:(Ljava/util/List;)Ljava/lang/String;
      38: getstatic     #42                 // Field java/lang/System.out:Ljava/io/PrintStream;
      41: swap
      42: invokevirtual #48                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      45: return

  private static final java.lang.String part1(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: checkcast     #56                 // class java/lang/Iterable
       4: astore_3
       5: lconst_0
       6: lstore        4
       8: aload_3
       9: invokeinterface #60,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      14: astore        6
      16: aload         6
      18: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      23: ifeq          66
      26: aload         6
      28: invokeinterface #70,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      33: astore        7
      35: lload         4
      37: aload         7
      39: checkcast     #72                 // class java/lang/String
      42: astore        8
      44: lstore        10
      46: iconst_0
      47: istore        9
      49: aload         8
      51: invokestatic  #76                 // Method SNAFUToInt:(Ljava/lang/String;)J
      54: lstore        12
      56: lload         10
      58: lload         12
      60: ladd
      61: lstore        4
      63: goto          16
      66: lload         4
      68: lstore_1
      69: lload_1
      70: invokestatic  #80                 // Method toSNAFU:(J)Ljava/lang/String;
      73: areturn

  private static final long SNAFUToInt(java.lang.String);
    Code:
       0: lconst_0
       1: lstore_1
       2: lconst_1
       3: lstore_3
       4: aload_0
       5: checkcast     #88                 // class java/lang/CharSequence
       8: invokestatic  #94                 // Method kotlin/text/StringsKt.getLastIndex:(Ljava/lang/CharSequence;)I
      11: istore        5
      13: iconst_m1
      14: iload         5
      16: if_icmpge     91
      19: lload_1
      20: aload_0
      21: iload         5
      23: invokevirtual #98                 // Method java/lang/String.charAt:(I)C
      26: lookupswitch  { // 2
                    45: 52
                    61: 57
               default: 65
          }
      52: lload_3
      53: lneg
      54: goto          77
      57: ldc2_w        #99                 // long -2l
      60: lload_3
      61: lmul
      62: goto          77
      65: aload_0
      66: iload         5
      68: invokevirtual #98                 // Method java/lang/String.charAt:(I)C
      71: invokestatic  #106                // Method kotlin/text/CharsKt.digitToInt:(C)I
      74: i2l
      75: lload_3
      76: lmul
      77: ladd
      78: lstore_1
      79: lload_3
      80: ldc2_w        #107                // long 5l
      83: lmul
      84: lstore_3
      85: iinc          5, -1
      88: goto          13
      91: lload_1
      92: lreturn

  private static final java.lang.String toSNAFU(long);
    Code:
       0: lload_0
       1: lstore_2
       2: ldc           #114                // String
       4: astore        4
       6: lload_2
       7: lconst_0
       8: lcmp
       9: ifeq          132
      12: lload_2
      13: ldc2_w        #107                // long 5l
      16: lrem
      17: lstore        5
      19: lload_2
      20: ldc2_w        #107                // long 5l
      23: ldiv
      24: lstore_2
      25: lload         5
      27: ldc2_w        #115                // long 2l
      30: lcmp
      31: ifgt          59
      34: new           #118                // class java/lang/StringBuilder
      37: dup
      38: invokespecial #120                // Method java/lang/StringBuilder."<init>":()V
      41: lload         5
      43: invokevirtual #124                // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      46: aload         4
      48: invokevirtual #127                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      51: invokevirtual #131                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      54: astore        4
      56: goto          6
      59: lload_2
      60: lconst_1
      61: ladd
      62: lstore_2
      63: new           #118                // class java/lang/StringBuilder
      66: dup
      67: invokespecial #120                // Method java/lang/StringBuilder."<init>":()V
      70: lload         5
      72: lstore        7
      74: lload         7
      76: ldc2_w        #132                // long 3l
      79: lcmp
      80: ifne          88
      83: ldc           #135                // String =
      85: goto          116
      88: lload         7
      90: ldc2_w        #136                // long 4l
      93: lcmp
      94: ifne          102
      97: ldc           #139                // String -
      99: goto          116
     102: new           #28                 // class java/lang/IllegalStateException
     105: dup
     106: getstatic     #145                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
     109: invokevirtual #146                // Method java/lang/Object.toString:()Ljava/lang/String;
     112: invokespecial #34                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
     115: athrow
     116: invokevirtual #127                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     119: aload         4
     121: invokevirtual #127                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     124: invokevirtual #131                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     127: astore        4
     129: goto          6
     132: aload         4
     134: areturn

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