import java.io.File
import kotlin.math.max
import kotlin.math.min

fun readInput(name: String) = File("src", "$name.txt")
    .readLines()

fun <T> assert(actual: T, expected: T) {
    if (actual == expected) {
        return
    }

    throw Exception("Actual $actual Expected $expected")
}

data class Interval(val start: Int, val end: Int) {
    companion object {
        fun merge(intervals: List<Interval>): List<Interval> {
            var sorted = intervals.sortedBy { i -> i.start }
            var hasOverlap = true
            while (hasOverlap && sorted.size > 1) {
                hasOverlap = false
                val bucket = sorted.toMutableList<Interval?>()
                var i = 0
                while (i < bucket.size - 1) {
                    if (bucket[i] != null && bucket[i + 1] != null && bucket[i]!!.hasOverlap(bucket[i + 1]!!)) {
                        hasOverlap = true
                        val merged = bucket[i]!!.merge(bucket[i + 1]!!)
                        bucket[i] = null
                        bucket[i + 1] = merged
                    }

                    i += 1
                }

                sorted = bucket.filterNotNull()
            }

            return sorted
        }
    }

    fun hasFullOverlap(other: Interval): Boolean {
        return hasFullOverlap(this, other) || hasFullOverlap(other, this)
    }

    fun hasOverlap(other: Interval): Boolean {
        return hasOverlap(this, other) || hasOverlap(other, this)
    }

    fun merge(other: Interval): Interval {
        return Interval(min(this.start, other.start), max(this.end, other.end))
    }

    private fun hasFullOverlap(x: Interval, y: Interval): Boolean {
        return x.start >= y.start && x.end <= y.end
    }

    private fun hasOverlap(x: Interval, y: Interval): Boolean {
        return x.start >= y.start && x.start <= y.end
    }

    fun countPoints(excludePoints: Set<Int>? = null): Int {
        var count = end - start + 1
        if (excludePoints == null) {
            return count
        }

        for (p in excludePoints) {
            if (p in start..end) {
                --count
            }
        }

        return count
    }

    fun minStart(x: Int): Interval {
        if (x < start) {
            return Interval(x, end)
        }

        return this
    }

    fun maxEnd(x: Int): Interval {
        if (x > end) {
            return Interval(start, x)
        }

        return this
    }

    fun isInside(t: Int): Boolean {
        return t in start..end
    }
}

data class Point(val x: Int, val y: Int) {
    fun sum(other: Point): Point {
        return Point(this.x + other.x, this.y + other.y)
    }
}

enum class Direction {
    Up,
    Down,
    Left,
    Right
}

object DirectionManager {
    private val directions = arrayOf(Direction.Up, Direction.Right, Direction.Down, Direction.Left)

    fun turn(current: Direction, target: Direction): Direction {
        if (target == Direction.Down || target == Direction.Up) {
            throw RuntimeException("Illegal action $current -> $target")
        }

        val d = if (target == Direction.Left) -1 else 1
        val index = (directions.indexOf(current) + d + directions.size) % directions.size
        return directions[index]
    }
}

enum class Sign {
    Eq,
    Less,
    More
}

enum class ExecutionMode {
    Test1,
    Test2,
    Exec1,
    Exec2
}

Compiled from "Utils.kt"
public final class UtilsKt {
  public static final java.util.List<java.lang.String> readInput(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #10                 // String name
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #18                 // class java/io/File
       9: dup
      10: ldc           #20                 // String src
      12: new           #22                 // class java/lang/StringBuilder
      15: dup
      16: invokespecial #26                 // Method java/lang/StringBuilder."<init>":()V
      19: aload_0
      20: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: ldc           #32                 // String .txt
      25: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #36                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: invokespecial #39                 // Method java/io/File."<init>":(Ljava/lang/String;Ljava/lang/String;)V
      34: aconst_null
      35: iconst_1
      36: aconst_null
      37: invokestatic  #45                 // Method kotlin/io/FilesKt.readLines$default:(Ljava/io/File;Ljava/nio/charset/Charset;ILjava/lang/Object;)Ljava/util/List;
      40: areturn

  public static final <T> void assert(T, T);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #53                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
       5: ifeq          9
       8: return
       9: new           #55                 // class java/lang/Exception
      12: dup
      13: new           #22                 // class java/lang/StringBuilder
      16: dup
      17: invokespecial #26                 // Method java/lang/StringBuilder."<init>":()V
      20: ldc           #57                 // String Actual
      22: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      25: aload_0
      26: invokevirtual #60                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      29: ldc           #62                 // String  Expected
      31: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      34: aload_1
      35: invokevirtual #60                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      38: invokevirtual #36                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      41: invokespecial #65                 // Method java/lang/Exception."<init>":(Ljava/lang/String;)V
      44: athrow
}


import kotlin.math.max
import kotlin.math.min

enum class CaveCell {
    Air,
    Rock,
    Sand
}

enum class SandFallResult {
    Stuck,
    Fall
}

val caveSize = 1000

fun main() {
    class Cave(val map: Array<Array<CaveCell>>) {
        fun getBounds(): Pair<Point, Point> {
            var minX = caveSize
            var minY = caveSize
            var maxX = 0
            var maxY = 0
            for (y in 0 until caveSize) {
                for (x in 0 until caveSize) {
                    if (map[x][y] != CaveCell.Air) {
                        minX = min(minX, x)
                        minY = min(minY, y)
                        maxX = max(maxX, x)
                        maxY = max(maxY, y)
                    }
                }
            }

            return Point(minX, minY) to Point(maxX, maxY)
        }
    }

    fun parse(input: List<String>): Cave {
        val cave = Cave(Array(caveSize) { _ -> Array(caveSize) { _ -> CaveCell.Air } })

        val pointBlocks = input.map { line ->
            line
                .split('-')
                .map { pair ->
                    val parts = pair.split(',')
                    Point(parts[0].toInt(), parts[1].toInt())
                }
        }

        for (pointBlock in pointBlocks) {
            for (i in 0..pointBlock.size - 2) {
                val left = pointBlock[i]
                val right = pointBlock[i + 1]
                if (left.x != right.x && left.y != right.y) {
                    println("Unexpected $left -> $right")
                    throw RuntimeException()
                }

                if (left.x == right.x) {
                    val x = left.x
                    for (dy in min(left.y, right.y)..max(left.y, right.y)) {
                        cave.map[x][dy] = CaveCell.Rock
                    }
                }

                if (left.y == right.y) {
                    val y = left.y
                    for (dx in min(left.x, right.x)..max(left.x, right.x)) {
                        cave.map[dx][y] = CaveCell.Rock
                    }
                }
            }
        }

        return cave
    }

    fun print(cave: Cave) {
        val window = 0
        val (minPoint, maxPoint) = cave.getBounds()
        for (y in (minPoint.y - window)..(maxPoint.y + window)) {
            for (x in (minPoint.x - window)..(maxPoint.x + window)) {
                val sign = when (cave.map[x][y]) {
                    CaveCell.Air -> '.'
                    CaveCell.Rock -> '#'
                    CaveCell.Sand -> 'o'
                }
                print(sign)
            }
            println()
        }
    }

    fun playSand(cave: Cave): SandFallResult {
        val (_, maxPoint) = cave.getBounds()
        var sx = 500
        var sy = 0

        while (sy < maxPoint.y) {
            if (cave.map[sx][sy + 1] == CaveCell.Air) {
                ++sy
            } else if (cave.map[sx - 1][sy + 1] == CaveCell.Air) {
                --sx
                ++sy
            } else if (cave.map[sx + 1][sy + 1] == CaveCell.Air) {
                ++sx
                ++sy
            } else {
                cave.map[sx][sy] = CaveCell.Sand
                return SandFallResult.Stuck
            }
        }

        return SandFallResult.Fall
    }

    fun play1(cave: Cave): Int {
        var counter = 0
        while (playSand(cave) != SandFallResult.Fall) {
            // print(cave)
            ++counter
        }

        return counter
    }

    fun play2(cave: Cave): Int {
        val (_, maxPoint) = cave.getBounds()
        for (x in 0 until caveSize) {
            cave.map[x][maxPoint.y + 2] = CaveCell.Rock
        }

        var counter = 0
        while (playSand(cave) != SandFallResult.Fall && cave.map[500][0] != CaveCell.Sand) {
            ++counter
        }

        return counter + 1
    }

    fun part1(input: List<String>): Int {
        val cave = parse(input)
        return play1(cave)
    }

    fun part2(input: List<String>): Int {
        val cave = parse(input)
        return play2(cave)
    }

    val testInput = readInput("Day14_test")
    assert(part1(testInput), 24)
    assert(part2(testInput), 93)

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

Compiled from "Day14.kt"
public final class Day14Kt {
  private static final int caveSize;

  public static final int getCaveSize();
    Code:
       0: getstatic     #10                 // Field caveSize:I
       3: ireturn

  public static final void main();
    Code:
       0: ldc           #14                 // String Day14_test
       2: invokestatic  #20                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
       5: astore_0
       6: aload_0
       7: invokestatic  #24                 // Method main$part1:(Ljava/util/List;)I
      10: invokestatic  #30                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      13: bipush        24
      15: invokestatic  #30                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      18: invokestatic  #34                 // Method UtilsKt.assert:(Ljava/lang/Object;Ljava/lang/Object;)V
      21: aload_0
      22: invokestatic  #37                 // Method main$part2:(Ljava/util/List;)I
      25: invokestatic  #30                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      28: bipush        93
      30: invokestatic  #30                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      33: invokestatic  #34                 // Method UtilsKt.assert:(Ljava/lang/Object;Ljava/lang/Object;)V
      36: ldc           #39                 // String Day14
      38: invokestatic  #20                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
      41: astore_1
      42: aload_1
      43: invokestatic  #24                 // Method main$part1:(Ljava/util/List;)I
      46: istore_2
      47: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
      50: iload_2
      51: invokevirtual #51                 // Method java/io/PrintStream.println:(I)V
      54: aload_1
      55: invokestatic  #37                 // Method main$part2:(Ljava/util/List;)I
      58: istore_2
      59: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
      62: iload_2
      63: invokevirtual #51                 // Method java/io/PrintStream.println:(I)V
      66: return

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

  private static final Day14Kt$main$Cave main$parse(java.util.List<java.lang.String>);
    Code:
       0: iconst_0
       1: istore_2
       2: getstatic     #10                 // Field caveSize:I
       5: istore_3
       6: iload_3
       7: anewarray     #64                 // class "[LCaveCell;"
      10: astore        4
      12: iload_2
      13: iload_3
      14: if_icmpge     81
      17: iload_2
      18: istore        5
      20: aload         4
      22: iload         5
      24: iconst_0
      25: istore        6
      27: getstatic     #10                 // Field caveSize:I
      30: istore        7
      32: iload         7
      34: anewarray     #66                 // class CaveCell
      37: astore        8
      39: istore        26
      41: astore        25
      43: iload         6
      45: iload         7
      47: if_icmpge     68
      50: iload         6
      52: istore        9
      54: aload         8
      56: iload         9
      58: getstatic     #70                 // Field CaveCell.Air:LCaveCell;
      61: aastore
      62: iinc          6, 1
      65: goto          43
      68: aload         25
      70: iload         26
      72: aload         8
      74: aastore
      75: iinc          2, 1
      78: goto          12
      81: aload         4
      83: astore        27
      85: new           #72                 // class Day14Kt$main$Cave
      88: dup
      89: aload         27
      91: invokespecial #76                 // Method Day14Kt$main$Cave."<init>":([[LCaveCell;)V
      94: astore_1
      95: aload_0
      96: checkcast     #78                 // class java/lang/Iterable
      99: astore_3
     100: iconst_0
     101: istore        4
     103: aload_3
     104: astore        5
     106: new           #80                 // class java/util/ArrayList
     109: dup
     110: aload_3
     111: bipush        10
     113: invokestatic  #86                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     116: invokespecial #88                 // Method java/util/ArrayList."<init>":(I)V
     119: checkcast     #90                 // class java/util/Collection
     122: astore        6
     124: iconst_0
     125: istore        7
     127: aload         5
     129: invokeinterface #94,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     134: astore        8
     136: aload         8
     138: invokeinterface #100,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     143: ifeq          366
     146: aload         8
     148: invokeinterface #104,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     153: astore        9
     155: aload         6
     157: aload         9
     159: checkcast     #106                // class java/lang/String
     162: astore        10
     164: astore        24
     166: iconst_0
     167: istore        11
     169: aload         10
     171: checkcast     #108                // class java/lang/CharSequence
     174: iconst_1
     175: newarray       char
     177: astore        12
     179: aload         12
     181: iconst_0
     182: bipush        45
     184: castore
     185: aload         12
     187: iconst_0
     188: iconst_0
     189: bipush        6
     191: aconst_null
     192: invokestatic  #114                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[CZIILjava/lang/Object;)Ljava/util/List;
     195: checkcast     #78                 // class java/lang/Iterable
     198: astore        12
     200: nop
     201: iconst_0
     202: istore        13
     204: aload         12
     206: astore        14
     208: new           #80                 // class java/util/ArrayList
     211: dup
     212: aload         12
     214: bipush        10
     216: invokestatic  #86                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     219: invokespecial #88                 // Method java/util/ArrayList."<init>":(I)V
     222: checkcast     #90                 // class java/util/Collection
     225: astore        15
     227: iconst_0
     228: istore        16
     230: aload         14
     232: invokeinterface #94,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     237: astore        17
     239: aload         17
     241: invokeinterface #100,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     246: ifeq          347
     249: aload         17
     251: invokeinterface #104,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     256: astore        18
     258: aload         15
     260: aload         18
     262: checkcast     #106                // class java/lang/String
     265: astore        19
     267: astore        20
     269: iconst_0
     270: istore        21
     272: aload         19
     274: checkcast     #108                // class java/lang/CharSequence
     277: iconst_1
     278: newarray       char
     280: astore        22
     282: aload         22
     284: iconst_0
     285: bipush        44
     287: castore
     288: aload         22
     290: iconst_0
     291: iconst_0
     292: bipush        6
     294: aconst_null
     295: invokestatic  #114                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[CZIILjava/lang/Object;)Ljava/util/List;
     298: astore        23
     300: new           #116                // class Point
     303: dup
     304: aload         23
     306: iconst_0
     307: invokeinterface #122,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     312: checkcast     #106                // class java/lang/String
     315: invokestatic  #126                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     318: aload         23
     320: iconst_1
     321: invokeinterface #122,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     326: checkcast     #106                // class java/lang/String
     329: invokestatic  #126                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     332: invokespecial #129                // Method Point."<init>":(II)V
     335: aload         20
     337: swap
     338: invokeinterface #133,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     343: pop
     344: goto          239
     347: aload         15
     349: checkcast     #118                // class java/util/List
     352: nop
     353: nop
     354: aload         24
     356: swap
     357: invokeinterface #133,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     362: pop
     363: goto          136
     366: aload         6
     368: checkcast     #118                // class java/util/List
     371: nop
     372: astore_2
     373: aload_2
     374: invokeinterface #134,  1          // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
     379: astore_3
     380: aload_3
     381: invokeinterface #100,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     386: ifeq          701
     389: aload_3
     390: invokeinterface #104,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     395: checkcast     #118                // class java/util/List
     398: astore        4
     400: iconst_0
     401: istore        5
     403: aload         4
     405: invokeinterface #137,  1          // InterfaceMethod java/util/List.size:()I
     410: iconst_2
     411: isub
     412: istore        6
     414: iload         5
     416: iload         6
     418: if_icmpgt     380
     421: aload         4
     423: iload         5
     425: invokeinterface #122,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     430: checkcast     #116                // class Point
     433: astore        7
     435: aload         4
     437: iload         5
     439: iconst_1
     440: iadd
     441: invokeinterface #122,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     446: checkcast     #116                // class Point
     449: astore        8
     451: aload         7
     453: invokevirtual #140                // Method Point.getX:()I
     456: aload         8
     458: invokevirtual #140                // Method Point.getX:()I
     461: if_icmpeq     522
     464: aload         7
     466: invokevirtual #143                // Method Point.getY:()I
     469: aload         8
     471: invokevirtual #143                // Method Point.getY:()I
     474: if_icmpeq     522
     477: new           #145                // class java/lang/StringBuilder
     480: dup
     481: invokespecial #147                // Method java/lang/StringBuilder."<init>":()V
     484: ldc           #149                // String Unexpected
     486: invokevirtual #153                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     489: aload         7
     491: invokevirtual #156                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
     494: ldc           #158                // String  ->
     496: invokevirtual #153                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     499: aload         8
     501: invokevirtual #156                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
     504: invokevirtual #162                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     507: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
     510: swap
     511: invokevirtual #165                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     514: new           #167                // class java/lang/RuntimeException
     517: dup
     518: invokespecial #168                // Method java/lang/RuntimeException."<init>":()V
     521: athrow
     522: aload         7
     524: invokevirtual #140                // Method Point.getX:()I
     527: aload         8
     529: invokevirtual #140                // Method Point.getX:()I
     532: if_icmpne     605
     535: aload         7
     537: invokevirtual #140                // Method Point.getX:()I
     540: istore        9
     542: aload         7
     544: invokevirtual #143                // Method Point.getY:()I
     547: aload         8
     549: invokevirtual #143                // Method Point.getY:()I
     552: invokestatic  #174                // Method java/lang/Math.min:(II)I
     555: istore        10
     557: aload         7
     559: invokevirtual #143                // Method Point.getY:()I
     562: aload         8
     564: invokevirtual #143                // Method Point.getY:()I
     567: invokestatic  #177                // Method java/lang/Math.max:(II)I
     570: istore        11
     572: iload         10
     574: iload         11
     576: if_icmpgt     605
     579: aload_1
     580: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
     583: iload         9
     585: aaload
     586: iload         10
     588: getstatic     #184                // Field CaveCell.Rock:LCaveCell;
     591: aastore
     592: iload         10
     594: iload         11
     596: if_icmpeq     605
     599: iinc          10, 1
     602: goto          579
     605: aload         7
     607: invokevirtual #143                // Method Point.getY:()I
     610: aload         8
     612: invokevirtual #143                // Method Point.getY:()I
     615: if_icmpne     688
     618: aload         7
     620: invokevirtual #143                // Method Point.getY:()I
     623: istore        9
     625: aload         7
     627: invokevirtual #140                // Method Point.getX:()I
     630: aload         8
     632: invokevirtual #140                // Method Point.getX:()I
     635: invokestatic  #174                // Method java/lang/Math.min:(II)I
     638: istore        10
     640: aload         7
     642: invokevirtual #140                // Method Point.getX:()I
     645: aload         8
     647: invokevirtual #140                // Method Point.getX:()I
     650: invokestatic  #177                // Method java/lang/Math.max:(II)I
     653: istore        11
     655: iload         10
     657: iload         11
     659: if_icmpgt     688
     662: aload_1
     663: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
     666: iload         10
     668: aaload
     669: iload         9
     671: getstatic     #184                // Field CaveCell.Rock:LCaveCell;
     674: aastore
     675: iload         10
     677: iload         11
     679: if_icmpeq     688
     682: iinc          10, 1
     685: goto          662
     688: iload         5
     690: iload         6
     692: if_icmpeq     380
     695: iinc          5, 1
     698: goto          421
     701: aload_1
     702: areturn

  private static final void main$print(Day14Kt$main$Cave);
    Code:
       0: iconst_0
       1: istore_1
       2: aload_0
       3: invokevirtual #219                // Method Day14Kt$main$Cave.getBounds:()Lkotlin/Pair;
       6: astore_2
       7: aload_2
       8: invokevirtual #224                // Method kotlin/Pair.component1:()Ljava/lang/Object;
      11: checkcast     #116                // class Point
      14: astore_3
      15: aload_2
      16: invokevirtual #227                // Method kotlin/Pair.component2:()Ljava/lang/Object;
      19: checkcast     #116                // class Point
      22: astore        4
      24: aload_3
      25: invokevirtual #143                // Method Point.getY:()I
      28: iload_1
      29: isub
      30: istore        5
      32: aload         4
      34: invokevirtual #143                // Method Point.getY:()I
      37: iload_1
      38: iadd
      39: istore        6
      41: iload         5
      43: iload         6
      45: if_icmpgt     181
      48: aload_3
      49: invokevirtual #140                // Method Point.getX:()I
      52: iload_1
      53: isub
      54: istore        7
      56: aload         4
      58: invokevirtual #140                // Method Point.getX:()I
      61: iload_1
      62: iadd
      63: istore        8
      65: iload         7
      67: iload         8
      69: if_icmpgt     162
      72: aload_0
      73: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
      76: iload         7
      78: aaload
      79: iload         5
      81: aaload
      82: getstatic     #233                // Field Day14Kt$WhenMappings.$EnumSwitchMapping$0:[I
      85: swap
      86: invokevirtual #236                // Method CaveCell.ordinal:()I
      89: iaload
      90: tableswitch   { // 1 to 3
                     1: 116
                     2: 121
                     3: 126
               default: 131
          }
     116: bipush        46
     118: goto          139
     121: bipush        35
     123: goto          139
     126: bipush        111
     128: goto          139
     131: new           #238                // class kotlin/NoWhenBranchMatchedException
     134: dup
     135: invokespecial #239                // Method kotlin/NoWhenBranchMatchedException."<init>":()V
     138: athrow
     139: istore        9
     141: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
     144: iload         9
     146: invokevirtual #243                // Method java/io/PrintStream.print:(C)V
     149: iload         7
     151: iload         8
     153: if_icmpeq     162
     156: iinc          7, 1
     159: goto          72
     162: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
     165: invokevirtual #245                // Method java/io/PrintStream.println:()V
     168: iload         5
     170: iload         6
     172: if_icmpeq     181
     175: iinc          5, 1
     178: goto          48
     181: return

  private static final SandFallResult main$playSand(Day14Kt$main$Cave);
    Code:
       0: aload_0
       1: invokevirtual #219                // Method Day14Kt$main$Cave.getBounds:()Lkotlin/Pair;
       4: invokevirtual #227                // Method kotlin/Pair.component2:()Ljava/lang/Object;
       7: checkcast     #116                // class Point
      10: astore_1
      11: sipush        500
      14: istore_2
      15: iconst_0
      16: istore_3
      17: iload_3
      18: aload_1
      19: invokevirtual #143                // Method Point.getY:()I
      22: if_icmpge     116
      25: aload_0
      26: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
      29: iload_2
      30: aaload
      31: iload_3
      32: iconst_1
      33: iadd
      34: aaload
      35: getstatic     #70                 // Field CaveCell.Air:LCaveCell;
      38: if_acmpne     47
      41: iinc          3, 1
      44: goto          17
      47: aload_0
      48: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
      51: iload_2
      52: iconst_1
      53: isub
      54: aaload
      55: iload_3
      56: iconst_1
      57: iadd
      58: aaload
      59: getstatic     #70                 // Field CaveCell.Air:LCaveCell;
      62: if_acmpne     74
      65: iinc          2, -1
      68: iinc          3, 1
      71: goto          17
      74: aload_0
      75: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
      78: iload_2
      79: iconst_1
      80: iadd
      81: aaload
      82: iload_3
      83: iconst_1
      84: iadd
      85: aaload
      86: getstatic     #70                 // Field CaveCell.Air:LCaveCell;
      89: if_acmpne     101
      92: iinc          2, 1
      95: iinc          3, 1
      98: goto          17
     101: aload_0
     102: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
     105: iload_2
     106: aaload
     107: iload_3
     108: getstatic     #255                // Field CaveCell.Sand:LCaveCell;
     111: aastore
     112: getstatic     #261                // Field SandFallResult.Stuck:LSandFallResult;
     115: areturn
     116: getstatic     #264                // Field SandFallResult.Fall:LSandFallResult;
     119: areturn

  private static final int main$play1(Day14Kt$main$Cave);
    Code:
       0: iconst_0
       1: istore_1
       2: aload_0
       3: invokestatic  #270                // Method main$playSand:(LDay14Kt$main$Cave;)LSandFallResult;
       6: getstatic     #264                // Field SandFallResult.Fall:LSandFallResult;
       9: if_acmpeq     18
      12: iinc          1, 1
      15: goto          2
      18: iload_1
      19: ireturn

  private static final int main$play2(Day14Kt$main$Cave);
    Code:
       0: aload_0
       1: invokevirtual #219                // Method Day14Kt$main$Cave.getBounds:()Lkotlin/Pair;
       4: invokevirtual #227                // Method kotlin/Pair.component2:()Ljava/lang/Object;
       7: checkcast     #116                // class Point
      10: astore_1
      11: iconst_0
      12: istore_2
      13: getstatic     #10                 // Field caveSize:I
      16: istore_3
      17: iload_2
      18: iload_3
      19: if_icmpge     44
      22: aload_0
      23: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
      26: iload_2
      27: aaload
      28: aload_1
      29: invokevirtual #143                // Method Point.getY:()I
      32: iconst_2
      33: iadd
      34: getstatic     #184                // Field CaveCell.Rock:LCaveCell;
      37: aastore
      38: iinc          2, 1
      41: goto          17
      44: iconst_0
      45: istore_2
      46: aload_0
      47: invokestatic  #270                // Method main$playSand:(LDay14Kt$main$Cave;)LSandFallResult;
      50: getstatic     #264                // Field SandFallResult.Fall:LSandFallResult;
      53: if_acmpeq     78
      56: aload_0
      57: invokevirtual #181                // Method Day14Kt$main$Cave.getMap:()[[LCaveCell;
      60: sipush        500
      63: aaload
      64: iconst_0
      65: aaload
      66: getstatic     #255                // Field CaveCell.Sand:LCaveCell;
      69: if_acmpeq     78
      72: iinc          2, 1
      75: goto          46
      78: iload_2
      79: iconst_1
      80: iadd
      81: ireturn

  private static final int main$part1(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: invokestatic  #275                // Method main$parse:(Ljava/util/List;)LDay14Kt$main$Cave;
       4: astore_1
       5: aload_1
       6: invokestatic  #277                // Method main$play1:(LDay14Kt$main$Cave;)I
       9: ireturn

  private static final int main$part2(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: invokestatic  #275                // Method main$parse:(Ljava/util/List;)LDay14Kt$main$Cave;
       4: astore_1
       5: aload_1
       6: invokestatic  #279                // Method main$play2:(LDay14Kt$main$Cave;)I
       9: ireturn

  static {};
    Code:
       0: sipush        1000
       3: putstatic     #10                 // Field caveSize:I
       6: return
}

Compiled from "Day14.kt"
public final class Day14Kt$main$Cave {
  private final CaveCell[][] map;

  public Day14Kt$main$Cave(CaveCell[][]);
    Code:
       0: aload_1
       1: ldc           #8                  // String map
       3: invokestatic  #14                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokespecial #17                 // Method java/lang/Object."<init>":()V
      10: aload_0
      11: aload_1
      12: putfield      #20                 // Field map:[[LCaveCell;
      15: return

  public final CaveCell[][] getMap();
    Code:
       0: aload_0
       1: getfield      #20                 // Field map:[[LCaveCell;
       4: areturn

  public final kotlin.Pair<Point, Point> getBounds();
    Code:
       0: invokestatic  #33                 // Method Day14Kt.getCaveSize:()I
       3: istore_1
       4: invokestatic  #33                 // Method Day14Kt.getCaveSize:()I
       7: istore_2
       8: iconst_0
       9: istore_3
      10: iconst_0
      11: istore        4
      13: iconst_0
      14: istore        5
      16: invokestatic  #33                 // Method Day14Kt.getCaveSize:()I
      19: istore        6
      21: iload         5
      23: iload         6
      25: if_icmpge     101
      28: iconst_0
      29: istore        7
      31: invokestatic  #33                 // Method Day14Kt.getCaveSize:()I
      34: istore        8
      36: iload         7
      38: iload         8
      40: if_icmpge     95
      43: aload_0
      44: getfield      #20                 // Field map:[[LCaveCell;
      47: iload         7
      49: aaload
      50: iload         5
      52: aaload
      53: getstatic     #39                 // Field CaveCell.Air:LCaveCell;
      56: if_acmpeq     89
      59: iload_1
      60: iload         7
      62: invokestatic  #45                 // Method java/lang/Math.min:(II)I
      65: istore_1
      66: iload_2
      67: iload         5
      69: invokestatic  #45                 // Method java/lang/Math.min:(II)I
      72: istore_2
      73: iload_3
      74: iload         7
      76: invokestatic  #48                 // Method java/lang/Math.max:(II)I
      79: istore_3
      80: iload         4
      82: iload         5
      84: invokestatic  #48                 // Method java/lang/Math.max:(II)I
      87: istore        4
      89: iinc          7, 1
      92: goto          36
      95: iinc          5, 1
      98: goto          21
     101: new           #50                 // class Point
     104: dup
     105: iload_1
     106: iload_2
     107: invokespecial #53                 // Method Point."<init>":(II)V
     110: new           #50                 // class Point
     113: dup
     114: iload_3
     115: iload         4
     117: invokespecial #53                 // Method Point."<init>":(II)V
     120: invokestatic  #59                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     123: areturn
}

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

  static {};
    Code:
       0: invokestatic  #14                 // Method CaveCell.values:()[LCaveCell;
       3: arraylength
       4: newarray       int
       6: astore_0
       7: nop
       8: aload_0
       9: getstatic     #18                 // Field CaveCell.Air:LCaveCell;
      12: invokevirtual #22                 // Method CaveCell.ordinal:()I
      15: iconst_1
      16: iastore
      17: goto          21
      20: astore_1
      21: nop
      22: aload_0
      23: getstatic     #25                 // Field CaveCell.Rock:LCaveCell;
      26: invokevirtual #22                 // Method CaveCell.ordinal:()I
      29: iconst_2
      30: iastore
      31: goto          35
      34: astore_1
      35: nop
      36: aload_0
      37: getstatic     #28                 // Field CaveCell.Sand:LCaveCell;
      40: invokevirtual #22                 // Method CaveCell.ordinal:()I
      43: iconst_3
      44: iastore
      45: goto          49
      48: astore_1
      49: aload_0
      50: putstatic     #32                 // Field $EnumSwitchMapping$0:[I
      53: 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
}


fun main() {
    fun parse(lines: List<String>): List<Pair<Interval, Interval>> {
        return lines.map { line ->
            val intervals = line
                .split(',')
                .map { range ->
                    val rangeParts = range.split('-')
                    Interval(rangeParts[0].toInt(), rangeParts[1].toInt())
                }
            intervals[0]to intervals[1]
        }
    }

    fun part1(input: List<String>): Int {
        return parse(input)
            .filter { (left, right) -> left.hasFullOverlap(right) }
            .size
    }

    fun part2(input: List<String>): Int {
        return parse(input)
            .filter { (left, right) -> left.hasOverlap(right) }
            .size
    }

    val testInput = readInput("Day04_test")
    assert(part1(testInput), 2)
    assert(part2(testInput), 4)

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

Compiled from "Day04.kt"
public final class Day04Kt {
  public static final void main();
    Code:
       0: ldc           #8                  // String Day04_test
       2: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
       5: astore_0
       6: aload_0
       7: invokestatic  #18                 // Method main$part1:(Ljava/util/List;)I
      10: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      13: iconst_2
      14: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      17: invokestatic  #28                 // Method UtilsKt.assert:(Ljava/lang/Object;Ljava/lang/Object;)V
      20: aload_0
      21: invokestatic  #31                 // Method main$part2:(Ljava/util/List;)I
      24: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      27: iconst_4
      28: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      31: invokestatic  #28                 // Method UtilsKt.assert:(Ljava/lang/Object;Ljava/lang/Object;)V
      34: ldc           #33                 // String Day04
      36: invokestatic  #14                 // Method UtilsKt.readInput:(Ljava/lang/String;)Ljava/util/List;
      39: astore_1
      40: aload_1
      41: invokestatic  #18                 // Method main$part1:(Ljava/util/List;)I
      44: istore_2
      45: getstatic     #39                 // Field java/lang/System.out:Ljava/io/PrintStream;
      48: iload_2
      49: invokevirtual #45                 // Method java/io/PrintStream.println:(I)V
      52: aload_1
      53: invokestatic  #31                 // Method main$part2:(Ljava/util/List;)I
      56: istore_2
      57: getstatic     #39                 // Field java/lang/System.out:Ljava/io/PrintStream;
      60: iload_2
      61: invokevirtual #45                 // Method java/io/PrintStream.println:(I)V
      64: return

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

  private static final java.util.List<kotlin.Pair<Interval, Interval>> main$parse(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: checkcast     #58                 // class java/lang/Iterable
       4: astore_1
       5: iconst_0
       6: istore_2
       7: aload_1
       8: astore_3
       9: new           #60                 // class java/util/ArrayList
      12: dup
      13: aload_1
      14: bipush        10
      16: invokestatic  #66                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      19: invokespecial #69                 // Method java/util/ArrayList."<init>":(I)V
      22: checkcast     #71                 // class java/util/Collection
      25: astore        4
      27: iconst_0
      28: istore        5
      30: aload_3
      31: invokeinterface #75,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      36: astore        6
      38: aload         6
      40: invokeinterface #81,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      45: ifeq          288
      48: aload         6
      50: invokeinterface #85,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      55: astore        7
      57: aload         4
      59: aload         7
      61: checkcast     #87                 // class java/lang/String
      64: astore        8
      66: astore        23
      68: iconst_0
      69: istore        9
      71: aload         8
      73: checkcast     #89                 // class java/lang/CharSequence
      76: iconst_1
      77: newarray       char
      79: astore        10
      81: aload         10
      83: iconst_0
      84: bipush        44
      86: castore
      87: aload         10
      89: iconst_0
      90: iconst_0
      91: bipush        6
      93: aconst_null
      94: invokestatic  #95                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[CZIILjava/lang/Object;)Ljava/util/List;
      97: checkcast     #58                 // class java/lang/Iterable
     100: astore        10
     102: nop
     103: iconst_0
     104: istore        11
     106: aload         10
     108: astore        12
     110: new           #60                 // class java/util/ArrayList
     113: dup
     114: aload         10
     116: bipush        10
     118: invokestatic  #66                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     121: invokespecial #69                 // Method java/util/ArrayList."<init>":(I)V
     124: checkcast     #71                 // class java/util/Collection
     127: astore        13
     129: iconst_0
     130: istore        14
     132: aload         12
     134: invokeinterface #75,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     139: astore        15
     141: aload         15
     143: invokeinterface #81,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     148: ifeq          249
     151: aload         15
     153: invokeinterface #85,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     158: astore        16
     160: aload         13
     162: aload         16
     164: checkcast     #87                 // class java/lang/String
     167: astore        17
     169: astore        18
     171: iconst_0
     172: istore        19
     174: aload         17
     176: checkcast     #89                 // class java/lang/CharSequence
     179: iconst_1
     180: newarray       char
     182: astore        20
     184: aload         20
     186: iconst_0
     187: bipush        45
     189: castore
     190: aload         20
     192: iconst_0
     193: iconst_0
     194: bipush        6
     196: aconst_null
     197: invokestatic  #95                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[CZIILjava/lang/Object;)Ljava/util/List;
     200: astore        21
     202: new           #97                 // class Interval
     205: dup
     206: aload         21
     208: iconst_0
     209: invokeinterface #103,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     214: checkcast     #87                 // class java/lang/String
     217: invokestatic  #107                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     220: aload         21
     222: iconst_1
     223: invokeinterface #103,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     228: checkcast     #87                 // class java/lang/String
     231: invokestatic  #107                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     234: invokespecial #110                // Method Interval."<init>":(II)V
     237: aload         18
     239: swap
     240: invokeinterface #114,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     245: pop
     246: goto          141
     249: aload         13
     251: checkcast     #99                 // class java/util/List
     254: nop
     255: astore        22
     257: aload         22
     259: iconst_0
     260: invokeinterface #103,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     265: aload         22
     267: iconst_1
     268: invokeinterface #103,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     273: invokestatic  #120                // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     276: aload         23
     278: swap
     279: invokeinterface #114,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     284: pop
     285: goto          38
     288: aload         4
     290: checkcast     #99                 // class java/util/List
     293: nop
     294: areturn

  private static final int main$part1(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: invokestatic  #141                // Method main$parse:(Ljava/util/List;)Ljava/util/List;
       4: checkcast     #58                 // class java/lang/Iterable
       7: astore_1
       8: nop
       9: iconst_0
      10: istore_2
      11: aload_1
      12: astore_3
      13: new           #60                 // class java/util/ArrayList
      16: dup
      17: invokespecial #143                // Method java/util/ArrayList."<init>":()V
      20: checkcast     #71                 // class java/util/Collection
      23: astore        4
      25: iconst_0
      26: istore        5
      28: aload_3
      29: invokeinterface #75,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      34: astore        6
      36: aload         6
      38: invokeinterface #81,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      43: ifeq          108
      46: aload         6
      48: invokeinterface #85,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      53: astore        7
      55: aload         7
      57: checkcast     #145                // class kotlin/Pair
      60: astore        8
      62: iconst_0
      63: istore        9
      65: aload         8
      67: invokevirtual #148                // Method kotlin/Pair.component1:()Ljava/lang/Object;
      70: checkcast     #97                 // class Interval
      73: astore        10
      75: aload         8
      77: invokevirtual #151                // Method kotlin/Pair.component2:()Ljava/lang/Object;
      80: checkcast     #97                 // class Interval
      83: astore        11
      85: aload         10
      87: aload         11
      89: invokevirtual #155                // Method Interval.hasFullOverlap:(LInterval;)Z
      92: ifeq          36
      95: aload         4
      97: aload         7
      99: invokeinterface #114,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     104: pop
     105: goto          36
     108: aload         4
     110: checkcast     #99                 // class java/util/List
     113: nop
     114: invokeinterface #159,  1          // InterfaceMethod java/util/List.size:()I
     119: ireturn

  private static final int main$part2(java.util.List<java.lang.String>);
    Code:
       0: aload_0
       1: invokestatic  #141                // Method main$parse:(Ljava/util/List;)Ljava/util/List;
       4: checkcast     #58                 // class java/lang/Iterable
       7: astore_1
       8: nop
       9: iconst_0
      10: istore_2
      11: aload_1
      12: astore_3
      13: new           #60                 // class java/util/ArrayList
      16: dup
      17: invokespecial #143                // Method java/util/ArrayList."<init>":()V
      20: checkcast     #71                 // class java/util/Collection
      23: astore        4
      25: iconst_0
      26: istore        5
      28: aload_3
      29: invokeinterface #75,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      34: astore        6
      36: aload         6
      38: invokeinterface #81,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      43: ifeq          108
      46: aload         6
      48: invokeinterface #85,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      53: astore        7
      55: aload         7
      57: checkcast     #145                // class kotlin/Pair
      60: astore        8
      62: iconst_0
      63: istore        9
      65: aload         8
      67: invokevirtual #148                // Method kotlin/Pair.component1:()Ljava/lang/Object;
      70: checkcast     #97                 // class Interval
      73: astore        10
      75: aload         8
      77: invokevirtual #151                // Method kotlin/Pair.component2:()Ljava/lang/Object;
      80: checkcast     #97                 // class Interval
      83: astore        11
      85: aload         10
      87: aload         11
      89: invokevirtual #171                // Method Interval.hasOverlap:(LInterval;)Z
      92: ifeq          36
      95: aload         4
      97: aload         7
      99: invokeinterface #114,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     104: pop
     105: goto          36
     108: aload         4
     110: checkcast     #99                 // class java/util/List
     113: nop
     114: invokeinterface #159,  1          // InterfaceMethod java/util/List.size:()I
     119: ireturn
}