package com.oocode

fun pipesGridFrom(input: String): PipesGrid {
    val lines = input.split("\n")
    val tiles = lines.mapIndexed { y, line ->
        tilesFrom(y, line)
    }
    return PipesGrid(tiles)
}

data class PipesGrid(val tiles: List<List<Tile>>) {
    fun furthestDistanceFromStart() = path().size / 2

    fun path(): MutableList<Tile> {
        val path = mutableListOf<Tile>()
        var current: Tile? = start()
        while (current != null) {
            path.add(current)
            current = nextTile(current, path)
        }
        return path
    }

    fun start() = tiles.flatten().first { it.type == START }

    fun nextTile(current: Tile, path: List<Tile>): Tile? = neighbouringTiles(current.position)
        .filter { !path.contains(it.tile) }
        .filter { it.canBeReachedFrom(it.directionTowardsThis.opposite) }
        .filter { current.canBeReachedFrom(it.directionTowardsThis) }
        .map { it.tile }
        .firstOrNull()

    fun neighbouringTiles(sourcePosition: Position) = neighbouringPositions(sourcePosition)
        .map { NeighbouringTile(it.outwardDirection, tileAt(it.position)) }

    private fun tileAt(position: Position): Tile = tiles[position.y][position.x]

    override fun toString(): String = tiles
        .map { it.map { it.type.toString() }.joinToString("") }
        .joinToString("\n")

    private fun neighbouringPositions(position: Position): Set<NeighbouringPosition> =
        Compass.values()
            .map { NeighbouringPosition(position + it.relativePosition, it) }
            .filter { isInBounds(it) }
            .toSet()

    private fun isInBounds(neighbouringPosition: NeighbouringPosition) = neighbouringPosition.position.let { position ->
        position.x >= 0 && position.y >= 0 && position.x < width && position.y < height
    }

    val width: Int get() = tiles[0].size
    val height: Int get() = tiles.size
}

enum class Compass(val relativePosition: Position) {
    North(Position(0, -1)),
    South(Position(0, 1)),
    East(Position(1, 0)),
    West(Position(-1, 0));

    val opposite: Compass get() = when(this) {
        North -> South
        South -> North
        East -> West
        West -> East
    }
}
interface TileType {
    fun canBeReachedFrom(positionRelativeToMe: Compass): Boolean
}

data class ConnectingTileType(val representation: String, val outgoing1: Compass, val outgoing2: Compass) : TileType {
    override fun canBeReachedFrom(positionRelativeToMe: Compass) =
        outgoing1 == positionRelativeToMe || outgoing2 == positionRelativeToMe

    override fun toString() = representation
}
data class Ground(val representation: String) : TileType {
    override fun canBeReachedFrom(positionRelativeToMe: Compass) = false

    override fun toString() = representation
}

private data class NeighbouringPosition(val position: Position, val outwardDirection: Compass)
data class NeighbouringTile(val directionTowardsThis: Compass, val tile: Tile) {
    fun canBeReachedFrom(direction: Compass) = tile.canBeReachedFrom(direction)
}

data class Start(val representation: String) : TileType {
    override fun canBeReachedFrom(positionRelativeToMe: Compass) = true
    override fun toString() = representation
}

val NE = ConnectingTileType("L", Compass.North, Compass.East)
val NW = ConnectingTileType("J", Compass.North, Compass.West)
val NS = ConnectingTileType("|", Compass.North, Compass.South)
val EW = ConnectingTileType("-", Compass.East, Compass.West)
val SE = ConnectingTileType("F", Compass.South, Compass.East)
val SW = ConnectingTileType("7", Compass.South, Compass.West)

val GROUND = Ground(".")
val START = Start("S")

data class Position(val x: Int, val y: Int) {
    operator fun plus(other: Position): Position = Position(x + other.x, y + other.y)
}

data class Tile(val type: TileType, val position: Position) {
    fun canBeReachedFrom(direction: Compass): Boolean = direction.let { type.canBeReachedFrom(it) }
}

fun tilesFrom(y: Int, line: String): List<Tile> = line.mapIndexed { x, c ->
    tileFor(c.toString(), x, y)
}

fun tileFor(name: String, x: Int, y: Int) = Tile(tileTypeFor(name), Position(x, y))

fun tileTypeFor(name: String) = when (name) {
    "|" -> NS
    "-" -> EW
    "F" -> SE
    "7" -> SW
    "L" -> NE
    "J" -> NW
    "." -> GROUND
    "S" -> START
    else -> {
        throw RuntimeException("Unexpected name: $name")
    }
}

Compiled from "PipesGrid.kt"
public final class com.oocode.PipesGrid {
  private final java.util.List<java.util.List<com.oocode.Tile>> tiles;

  public com.oocode.PipesGrid(java.util.List<? extends java.util.List<com.oocode.Tile>>);
    Code:
       0: aload_1
       1: ldc           #10                 // String tiles
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokespecial #19                 // Method java/lang/Object."<init>":()V
      10: aload_0
      11: aload_1
      12: putfield      #22                 // Field tiles:Ljava/util/List;
      15: return

  public final java.util.List<java.util.List<com.oocode.Tile>> getTiles();
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: areturn

  public final int furthestDistanceFromStart();
    Code:
       0: aload_0
       1: invokevirtual #32                 // Method path:()Ljava/util/List;
       4: invokeinterface #37,  1           // InterfaceMethod java/util/List.size:()I
       9: iconst_2
      10: idiv
      11: ireturn

  public final java.util.List<com.oocode.Tile> path();
    Code:
       0: new           #40                 // class java/util/ArrayList
       3: dup
       4: invokespecial #41                 // Method java/util/ArrayList."<init>":()V
       7: checkcast     #34                 // class java/util/List
      10: astore_1
      11: aload_0
      12: invokevirtual #45                 // Method start:()Lcom/oocode/Tile;
      15: astore_2
      16: aload_2
      17: ifnull        38
      20: aload_1
      21: aload_2
      22: invokeinterface #49,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      27: pop
      28: aload_0
      29: aload_2
      30: aload_1
      31: invokevirtual #53                 // Method nextTile:(Lcom/oocode/Tile;Ljava/util/List;)Lcom/oocode/Tile;
      34: astore_2
      35: goto          16
      38: aload_1
      39: areturn

  public final com.oocode.Tile start();
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: checkcast     #59                 // class java/lang/Iterable
       7: invokestatic  #65                 // Method kotlin/collections/CollectionsKt.flatten:(Ljava/lang/Iterable;)Ljava/util/List;
      10: checkcast     #59                 // class java/lang/Iterable
      13: astore_1
      14: iconst_0
      15: istore_2
      16: aload_1
      17: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      22: astore_3
      23: aload_3
      24: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      29: ifeq          69
      32: aload_3
      33: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      38: astore        4
      40: aload         4
      42: checkcast     #57                 // class com/oocode/Tile
      45: astore        5
      47: iconst_0
      48: istore        6
      50: aload         5
      52: invokevirtual #83                 // Method com/oocode/Tile.getType:()Lcom/oocode/TileType;
      55: invokestatic  #89                 // Method com/oocode/PipesGridKt.getSTART:()Lcom/oocode/Start;
      58: invokestatic  #93                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      61: ifeq          23
      64: aload         4
      66: goto          79
      69: new           #95                 // class java/util/NoSuchElementException
      72: dup
      73: ldc           #97                 // String Collection contains no element matching the predicate.
      75: invokespecial #100                // Method java/util/NoSuchElementException."<init>":(Ljava/lang/String;)V
      78: athrow
      79: checkcast     #57                 // class com/oocode/Tile
      82: areturn

  public final com.oocode.Tile nextTile(com.oocode.Tile, java.util.List<com.oocode.Tile>);
    Code:
       0: aload_1
       1: ldc           #111                // String current
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_2
       7: ldc           #112                // String path
       9: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: aload_1
      14: invokevirtual #116                // Method com/oocode/Tile.getPosition:()Lcom/oocode/Position;
      17: invokevirtual #120                // Method neighbouringTiles:(Lcom/oocode/Position;)Ljava/util/List;
      20: checkcast     #59                 // class java/lang/Iterable
      23: astore_3
      24: nop
      25: iconst_0
      26: istore        4
      28: aload_3
      29: astore        5
      31: new           #40                 // class java/util/ArrayList
      34: dup
      35: invokespecial #41                 // Method java/util/ArrayList."<init>":()V
      38: checkcast     #122                // class java/util/Collection
      41: astore        6
      43: iconst_0
      44: istore        7
      46: aload         5
      48: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      53: astore        8
      55: aload         8
      57: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      62: ifeq          119
      65: aload         8
      67: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      72: astore        9
      74: aload         9
      76: checkcast     #124                // class com/oocode/NeighbouringTile
      79: astore        10
      81: iconst_0
      82: istore        11
      84: aload_2
      85: aload         10
      87: invokevirtual #127                // Method com/oocode/NeighbouringTile.getTile:()Lcom/oocode/Tile;
      90: invokeinterface #130,  2          // InterfaceMethod java/util/List.contains:(Ljava/lang/Object;)Z
      95: ifne          102
      98: iconst_1
      99: goto          103
     102: iconst_0
     103: ifeq          55
     106: aload         6
     108: aload         9
     110: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     115: pop
     116: goto          55
     119: aload         6
     121: checkcast     #34                 // class java/util/List
     124: nop
     125: checkcast     #59                 // class java/lang/Iterable
     128: astore_3
     129: nop
     130: iconst_0
     131: istore        4
     133: aload_3
     134: astore        5
     136: new           #40                 // class java/util/ArrayList
     139: dup
     140: invokespecial #41                 // Method java/util/ArrayList."<init>":()V
     143: checkcast     #122                // class java/util/Collection
     146: astore        6
     148: iconst_0
     149: istore        7
     151: aload         5
     153: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     158: astore        8
     160: aload         8
     162: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     167: ifeq          218
     170: aload         8
     172: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     177: astore        9
     179: aload         9
     181: checkcast     #124                // class com/oocode/NeighbouringTile
     184: astore        10
     186: iconst_0
     187: istore        11
     189: aload         10
     191: aload         10
     193: invokevirtual #135                // Method com/oocode/NeighbouringTile.getDirectionTowardsThis:()Lcom/oocode/Compass;
     196: invokevirtual #140                // Method com/oocode/Compass.getOpposite:()Lcom/oocode/Compass;
     199: invokevirtual #144                // Method com/oocode/NeighbouringTile.canBeReachedFrom:(Lcom/oocode/Compass;)Z
     202: ifeq          160
     205: aload         6
     207: aload         9
     209: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     214: pop
     215: goto          160
     218: aload         6
     220: checkcast     #34                 // class java/util/List
     223: nop
     224: checkcast     #59                 // class java/lang/Iterable
     227: astore_3
     228: nop
     229: iconst_0
     230: istore        4
     232: aload_3
     233: astore        5
     235: new           #40                 // class java/util/ArrayList
     238: dup
     239: invokespecial #41                 // Method java/util/ArrayList."<init>":()V
     242: checkcast     #122                // class java/util/Collection
     245: astore        6
     247: iconst_0
     248: istore        7
     250: aload         5
     252: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     257: astore        8
     259: aload         8
     261: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     266: ifeq          313
     269: aload         8
     271: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     276: astore        9
     278: aload         9
     280: checkcast     #124                // class com/oocode/NeighbouringTile
     283: astore        10
     285: iconst_0
     286: istore        11
     288: aload_1
     289: aload         10
     291: invokevirtual #135                // Method com/oocode/NeighbouringTile.getDirectionTowardsThis:()Lcom/oocode/Compass;
     294: invokevirtual #145                // Method com/oocode/Tile.canBeReachedFrom:(Lcom/oocode/Compass;)Z
     297: ifeq          259
     300: aload         6
     302: aload         9
     304: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     309: pop
     310: goto          259
     313: aload         6
     315: checkcast     #34                 // class java/util/List
     318: nop
     319: checkcast     #59                 // class java/lang/Iterable
     322: astore_3
     323: nop
     324: iconst_0
     325: istore        4
     327: aload_3
     328: astore        5
     330: new           #40                 // class java/util/ArrayList
     333: dup
     334: aload_3
     335: bipush        10
     337: invokestatic  #149                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     340: invokespecial #152                // Method java/util/ArrayList."<init>":(I)V
     343: checkcast     #122                // class java/util/Collection
     346: astore        6
     348: iconst_0
     349: istore        7
     351: aload         5
     353: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     358: astore        8
     360: aload         8
     362: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     367: ifeq          410
     370: aload         8
     372: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     377: astore        9
     379: aload         6
     381: aload         9
     383: checkcast     #124                // class com/oocode/NeighbouringTile
     386: astore        10
     388: astore        12
     390: iconst_0
     391: istore        11
     393: aload         10
     395: invokevirtual #127                // Method com/oocode/NeighbouringTile.getTile:()Lcom/oocode/Tile;
     398: aload         12
     400: swap
     401: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     406: pop
     407: goto          360
     410: aload         6
     412: checkcast     #34                 // class java/util/List
     415: nop
     416: invokestatic  #156                // Method kotlin/collections/CollectionsKt.firstOrNull:(Ljava/util/List;)Ljava/lang/Object;
     419: checkcast     #57                 // class com/oocode/Tile
     422: areturn

  public final java.util.List<com.oocode.NeighbouringTile> neighbouringTiles(com.oocode.Position);
    Code:
       0: aload_1
       1: ldc           #176                // String sourcePosition
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_1
       8: invokespecial #180                // Method neighbouringPositions:(Lcom/oocode/Position;)Ljava/util/Set;
      11: checkcast     #59                 // class java/lang/Iterable
      14: astore_2
      15: nop
      16: iconst_0
      17: istore_3
      18: aload_2
      19: astore        4
      21: new           #40                 // class java/util/ArrayList
      24: dup
      25: aload_2
      26: bipush        10
      28: invokestatic  #149                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      31: invokespecial #152                // Method java/util/ArrayList."<init>":(I)V
      34: checkcast     #122                // class java/util/Collection
      37: astore        5
      39: iconst_0
      40: istore        6
      42: aload         4
      44: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      49: astore        7
      51: aload         7
      53: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      58: ifeq          117
      61: aload         7
      63: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      68: astore        8
      70: aload         5
      72: aload         8
      74: checkcast     #182                // class com/oocode/NeighbouringPosition
      77: astore        9
      79: astore        11
      81: iconst_0
      82: istore        10
      84: new           #124                // class com/oocode/NeighbouringTile
      87: dup
      88: aload         9
      90: invokevirtual #185                // Method com/oocode/NeighbouringPosition.getOutwardDirection:()Lcom/oocode/Compass;
      93: aload_0
      94: aload         9
      96: invokevirtual #186                // Method com/oocode/NeighbouringPosition.getPosition:()Lcom/oocode/Position;
      99: invokespecial #190                // Method tileAt:(Lcom/oocode/Position;)Lcom/oocode/Tile;
     102: invokespecial #193                // Method com/oocode/NeighbouringTile."<init>":(Lcom/oocode/Compass;Lcom/oocode/Tile;)V
     105: aload         11
     107: swap
     108: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     113: pop
     114: goto          51
     117: aload         5
     119: checkcast     #34                 // class java/util/List
     122: nop
     123: areturn

  private final com.oocode.Tile tileAt(com.oocode.Position);
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: aload_1
       5: invokevirtual #201                // Method com/oocode/Position.getY:()I
       8: invokeinterface #205,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      13: checkcast     #34                 // class java/util/List
      16: aload_1
      17: invokevirtual #208                // Method com/oocode/Position.getX:()I
      20: invokeinterface #205,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      25: checkcast     #57                 // class com/oocode/Tile
      28: areturn

  public java.lang.String toString();
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: checkcast     #59                 // class java/lang/Iterable
       7: astore_1
       8: nop
       9: iconst_0
      10: istore_2
      11: aload_1
      12: astore_3
      13: new           #40                 // class java/util/ArrayList
      16: dup
      17: aload_1
      18: bipush        10
      20: invokestatic  #149                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      23: invokespecial #152                // Method java/util/ArrayList."<init>":(I)V
      26: checkcast     #122                // class java/util/Collection
      29: astore        4
      31: iconst_0
      32: istore        5
      34: aload_3
      35: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      40: astore        6
      42: aload         6
      44: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      49: ifeq          210
      52: aload         6
      54: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      59: astore        7
      61: aload         4
      63: aload         7
      65: checkcast     #34                 // class java/util/List
      68: astore        8
      70: astore        20
      72: iconst_0
      73: istore        9
      75: aload         8
      77: checkcast     #59                 // class java/lang/Iterable
      80: astore        10
      82: iconst_0
      83: istore        11
      85: aload         10
      87: astore        12
      89: new           #40                 // class java/util/ArrayList
      92: dup
      93: aload         10
      95: bipush        10
      97: invokestatic  #149                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     100: invokespecial #152                // Method java/util/ArrayList."<init>":(I)V
     103: checkcast     #122                // class java/util/Collection
     106: astore        13
     108: iconst_0
     109: istore        14
     111: aload         12
     113: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     118: astore        15
     120: aload         15
     122: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     127: ifeq          173
     130: aload         15
     132: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     137: astore        16
     139: aload         13
     141: aload         16
     143: checkcast     #57                 // class com/oocode/Tile
     146: astore        17
     148: astore        18
     150: iconst_0
     151: istore        19
     153: aload         17
     155: invokevirtual #83                 // Method com/oocode/Tile.getType:()Lcom/oocode/TileType;
     158: invokevirtual #213                // Method java/lang/Object.toString:()Ljava/lang/String;
     161: aload         18
     163: swap
     164: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     169: pop
     170: goto          120
     173: aload         13
     175: checkcast     #34                 // class java/util/List
     178: nop
     179: checkcast     #59                 // class java/lang/Iterable
     182: ldc           #215                // String
     184: checkcast     #217                // class java/lang/CharSequence
     187: aconst_null
     188: aconst_null
     189: iconst_0
     190: aconst_null
     191: aconst_null
     192: bipush        62
     194: aconst_null
     195: invokestatic  #221                // Method kotlin/collections/CollectionsKt.joinToString$default:(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
     198: aload         20
     200: swap
     201: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     206: pop
     207: goto          42
     210: aload         4
     212: checkcast     #34                 // class java/util/List
     215: nop
     216: checkcast     #59                 // class java/lang/Iterable
     219: ldc           #223                // String \n
     221: checkcast     #217                // class java/lang/CharSequence
     224: aconst_null
     225: aconst_null
     226: iconst_0
     227: aconst_null
     228: aconst_null
     229: bipush        62
     231: aconst_null
     232: invokestatic  #221                // Method kotlin/collections/CollectionsKt.joinToString$default:(Ljava/lang/Iterable;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Ljava/lang/CharSequence;ILjava/lang/CharSequence;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/String;
     235: areturn

  private final java.util.Set<com.oocode.NeighbouringPosition> neighbouringPositions(com.oocode.Position);
    Code:
       0: invokestatic  #230                // Method com/oocode/Compass.values:()[Lcom/oocode/Compass;
       3: astore_2
       4: nop
       5: iconst_0
       6: istore_3
       7: aload_2
       8: astore        4
      10: new           #40                 // class java/util/ArrayList
      13: dup
      14: aload_2
      15: arraylength
      16: invokespecial #152                // Method java/util/ArrayList."<init>":(I)V
      19: checkcast     #122                // class java/util/Collection
      22: astore        5
      24: iconst_0
      25: istore        6
      27: iconst_0
      28: istore        7
      30: aload         4
      32: arraylength
      33: istore        8
      35: iload         7
      37: iload         8
      39: if_icmpge     93
      42: aload         4
      44: iload         7
      46: aaload
      47: astore        9
      49: aload         5
      51: aload         9
      53: astore        10
      55: astore        12
      57: iconst_0
      58: istore        11
      60: new           #182                // class com/oocode/NeighbouringPosition
      63: dup
      64: aload_1
      65: aload         10
      67: invokevirtual #233                // Method com/oocode/Compass.getRelativePosition:()Lcom/oocode/Position;
      70: invokevirtual #237                // Method com/oocode/Position.plus:(Lcom/oocode/Position;)Lcom/oocode/Position;
      73: aload         10
      75: invokespecial #240                // Method com/oocode/NeighbouringPosition."<init>":(Lcom/oocode/Position;Lcom/oocode/Compass;)V
      78: aload         12
      80: swap
      81: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
      86: pop
      87: iinc          7, 1
      90: goto          35
      93: aload         5
      95: checkcast     #34                 // class java/util/List
      98: nop
      99: checkcast     #59                 // class java/lang/Iterable
     102: astore_2
     103: nop
     104: iconst_0
     105: istore_3
     106: aload_2
     107: astore        4
     109: new           #40                 // class java/util/ArrayList
     112: dup
     113: invokespecial #41                 // Method java/util/ArrayList."<init>":()V
     116: checkcast     #122                // class java/util/Collection
     119: astore        5
     121: iconst_0
     122: istore        6
     124: aload         4
     126: invokeinterface #69,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     131: astore        7
     133: aload         7
     135: invokeinterface #75,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     140: ifeq          184
     143: aload         7
     145: invokeinterface #79,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     150: astore        8
     152: aload         8
     154: checkcast     #182                // class com/oocode/NeighbouringPosition
     157: astore        9
     159: iconst_0
     160: istore        10
     162: aload_0
     163: aload         9
     165: invokespecial #244                // Method isInBounds:(Lcom/oocode/NeighbouringPosition;)Z
     168: ifeq          133
     171: aload         5
     173: aload         8
     175: invokeinterface #131,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     180: pop
     181: goto          133
     184: aload         5
     186: checkcast     #34                 // class java/util/List
     189: nop
     190: checkcast     #59                 // class java/lang/Iterable
     193: invokestatic  #248                // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     196: areturn

  private final boolean isInBounds(com.oocode.NeighbouringPosition);
    Code:
       0: aload_1
       1: invokevirtual #186                // Method com/oocode/NeighbouringPosition.getPosition:()Lcom/oocode/Position;
       4: astore_2
       5: iconst_0
       6: istore_3
       7: aload_2
       8: invokevirtual #208                // Method com/oocode/Position.getX:()I
      11: iflt          47
      14: aload_2
      15: invokevirtual #201                // Method com/oocode/Position.getY:()I
      18: iflt          47
      21: aload_2
      22: invokevirtual #208                // Method com/oocode/Position.getX:()I
      25: aload_0
      26: invokevirtual #257                // Method getWidth:()I
      29: if_icmpge     47
      32: aload_2
      33: invokevirtual #201                // Method com/oocode/Position.getY:()I
      36: aload_0
      37: invokevirtual #260                // Method getHeight:()I
      40: if_icmpge     47
      43: iconst_1
      44: goto          48
      47: iconst_0
      48: nop
      49: ireturn

  public final int getWidth();
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: iconst_0
       5: invokeinterface #205,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      10: checkcast     #34                 // class java/util/List
      13: invokeinterface #37,  1           // InterfaceMethod java/util/List.size:()I
      18: ireturn

  public final int getHeight();
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: invokeinterface #37,  1           // InterfaceMethod java/util/List.size:()I
       9: ireturn

  public final java.util.List<java.util.List<com.oocode.Tile>> component1();
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: areturn

  public final com.oocode.PipesGrid copy(java.util.List<? extends java.util.List<com.oocode.Tile>>);
    Code:
       0: aload_1
       1: ldc           #10                 // String tiles
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #2                  // class com/oocode/PipesGrid
       9: dup
      10: aload_1
      11: invokespecial #268                // Method "<init>":(Ljava/util/List;)V
      14: areturn

  public static com.oocode.PipesGrid copy$default(com.oocode.PipesGrid, java.util.List, int, java.lang.Object);
    Code:
       0: iload_2
       1: iconst_1
       2: iand
       3: ifeq          11
       6: aload_0
       7: getfield      #22                 // Field tiles:Ljava/util/List;
      10: astore_1
      11: aload_0
      12: aload_1
      13: invokevirtual #272                // Method copy:(Ljava/util/List;)Lcom/oocode/PipesGrid;
      16: areturn

  public int hashCode();
    Code:
       0: aload_0
       1: getfield      #22                 // Field tiles:Ljava/util/List;
       4: invokevirtual #275                // Method java/lang/Object.hashCode:()I
       7: ireturn

  public boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: if_acmpne     7
       5: iconst_1
       6: ireturn
       7: aload_1
       8: instanceof    #2                  // class com/oocode/PipesGrid
      11: ifne          16
      14: iconst_0
      15: ireturn
      16: aload_1
      17: checkcast     #2                  // class com/oocode/PipesGrid
      20: astore_2
      21: aload_0
      22: getfield      #22                 // Field tiles:Ljava/util/List;
      25: aload_2
      26: getfield      #22                 // Field tiles:Ljava/util/List;
      29: invokestatic  #93                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      32: ifne          37
      35: iconst_0
      36: ireturn
      37: iconst_1
      38: ireturn
}

Compiled from "PipesGrid.kt"
public final class com.oocode.PipesGridKt {
  private static final com.oocode.ConnectingTileType NE;

  private static final com.oocode.ConnectingTileType NW;

  private static final com.oocode.ConnectingTileType NS;

  private static final com.oocode.ConnectingTileType EW;

  private static final com.oocode.ConnectingTileType SE;

  private static final com.oocode.ConnectingTileType SW;

  private static final com.oocode.Ground GROUND;

  private static final com.oocode.Start START;

  public static final com.oocode.PipesGrid pipesGridFrom(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #9                  // String input
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #17                 // class java/lang/CharSequence
      10: iconst_1
      11: anewarray     #19                 // class java/lang/String
      14: astore_2
      15: aload_2
      16: iconst_0
      17: ldc           #21                 // String \n
      19: aastore
      20: aload_2
      21: iconst_0
      22: iconst_0
      23: bipush        6
      25: aconst_null
      26: invokestatic  #27                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      29: astore_1
      30: aload_1
      31: checkcast     #29                 // class java/lang/Iterable
      34: astore_3
      35: iconst_0
      36: istore        4
      38: aload_3
      39: astore        5
      41: new           #31                 // class java/util/ArrayList
      44: dup
      45: aload_3
      46: bipush        10
      48: invokestatic  #37                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      51: invokespecial #41                 // Method java/util/ArrayList."<init>":(I)V
      54: checkcast     #43                 // class java/util/Collection
      57: astore        6
      59: iconst_0
      60: istore        7
      62: iconst_0
      63: istore        8
      65: aload         5
      67: invokeinterface #47,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      72: astore        9
      74: aload         9
      76: invokeinterface #53,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      81: ifeq          145
      84: aload         9
      86: invokeinterface #57,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      91: astore        10
      93: aload         6
      95: iload         8
      97: iinc          8, 1
     100: istore        11
     102: iload         11
     104: ifge          110
     107: invokestatic  #61                 // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
     110: iload         11
     112: aload         10
     114: checkcast     #19                 // class java/lang/String
     117: astore        12
     119: istore        13
     121: astore        15
     123: iconst_0
     124: istore        14
     126: iload         13
     128: aload         12
     130: invokestatic  #65                 // Method tilesFrom:(ILjava/lang/String;)Ljava/util/List;
     133: aload         15
     135: swap
     136: invokeinterface #69,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     141: pop
     142: goto          74
     145: aload         6
     147: checkcast     #71                 // class java/util/List
     150: nop
     151: astore_2
     152: new           #73                 // class com/oocode/PipesGrid
     155: dup
     156: aload_2
     157: invokespecial #76                 // Method com/oocode/PipesGrid."<init>":(Ljava/util/List;)V
     160: areturn

  public static final com.oocode.ConnectingTileType getNE();
    Code:
       0: getstatic     #102                // Field NE:Lcom/oocode/ConnectingTileType;
       3: areturn

  public static final com.oocode.ConnectingTileType getNW();
    Code:
       0: getstatic     #106                // Field NW:Lcom/oocode/ConnectingTileType;
       3: areturn

  public static final com.oocode.ConnectingTileType getNS();
    Code:
       0: getstatic     #110                // Field NS:Lcom/oocode/ConnectingTileType;
       3: areturn

  public static final com.oocode.ConnectingTileType getEW();
    Code:
       0: getstatic     #114                // Field EW:Lcom/oocode/ConnectingTileType;
       3: areturn

  public static final com.oocode.ConnectingTileType getSE();
    Code:
       0: getstatic     #118                // Field SE:Lcom/oocode/ConnectingTileType;
       3: areturn

  public static final com.oocode.ConnectingTileType getSW();
    Code:
       0: getstatic     #122                // Field SW:Lcom/oocode/ConnectingTileType;
       3: areturn

  public static final com.oocode.Ground getGROUND();
    Code:
       0: getstatic     #128                // Field GROUND:Lcom/oocode/Ground;
       3: areturn

  public static final com.oocode.Start getSTART();
    Code:
       0: getstatic     #134                // Field START:Lcom/oocode/Start;
       3: areturn

  public static final java.util.List<com.oocode.Tile> tilesFrom(int, java.lang.String);
    Code:
       0: aload_1
       1: ldc           #136                // String line
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: checkcast     #17                 // class java/lang/CharSequence
      10: astore_2
      11: iconst_0
      12: istore_3
      13: aload_2
      14: astore        4
      16: new           #31                 // class java/util/ArrayList
      19: dup
      20: aload_2
      21: invokeinterface #140,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      26: invokespecial #41                 // Method java/util/ArrayList."<init>":(I)V
      29: checkcast     #43                 // class java/util/Collection
      32: astore        5
      34: iconst_0
      35: istore        6
      37: iconst_0
      38: istore        7
      40: iconst_0
      41: istore        8
      43: iload         8
      45: aload         4
      47: invokeinterface #140,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      52: if_icmpge     110
      55: aload         4
      57: iload         8
      59: invokeinterface #144,  2          // InterfaceMethod java/lang/CharSequence.charAt:(I)C
      64: istore        9
      66: aload         5
      68: iload         7
      70: iinc          7, 1
      73: iload         9
      75: istore        10
      77: istore        11
      79: astore        13
      81: iconst_0
      82: istore        12
      84: iload         10
      86: invokestatic  #148                // Method java/lang/String.valueOf:(C)Ljava/lang/String;
      89: iload         11
      91: iload_0
      92: invokestatic  #152                // Method tileFor:(Ljava/lang/String;II)Lcom/oocode/Tile;
      95: aload         13
      97: swap
      98: invokeinterface #69,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     103: pop
     104: iinc          8, 1
     107: goto          43
     110: aload         5
     112: checkcast     #71                 // class java/util/List
     115: nop
     116: areturn

  public static final com.oocode.Tile tileFor(java.lang.String, int, int);
    Code:
       0: aload_0
       1: ldc           #159                // String name
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #161                // class com/oocode/Tile
       9: dup
      10: aload_0
      11: invokestatic  #165                // Method tileTypeFor:(Ljava/lang/String;)Lcom/oocode/TileType;
      14: new           #167                // class com/oocode/Position
      17: dup
      18: iload_1
      19: iload_2
      20: invokespecial #170                // Method com/oocode/Position."<init>":(II)V
      23: invokespecial #173                // Method com/oocode/Tile."<init>":(Lcom/oocode/TileType;Lcom/oocode/Position;)V
      26: areturn

  public static final com.oocode.TileType tileTypeFor(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #159                // String name
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: astore_1
       8: aload_1
       9: invokevirtual #176                // Method java/lang/String.hashCode:()I
      12: lookupswitch  { // 8
                    45: 160
                    46: 172
                    55: 112
                    70: 100
                    74: 124
                    76: 148
                    83: 88
                   124: 136
               default: 256
          }
      88: aload_1
      89: ldc           #178                // String S
      91: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      94: ifne          247
      97: goto          256
     100: aload_1
     101: ldc           #183                // String F
     103: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     106: ifne          202
     109: goto          256
     112: aload_1
     113: ldc           #185                // String 7
     115: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     118: ifne          211
     121: goto          256
     124: aload_1
     125: ldc           #187                // String J
     127: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     130: ifne          229
     133: goto          256
     136: aload_1
     137: ldc           #189                // String |
     139: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     142: ifne          184
     145: goto          256
     148: aload_1
     149: ldc           #191                // String L
     151: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     154: ifne          220
     157: goto          256
     160: aload_1
     161: ldc           #193                // String -
     163: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     166: ifne          193
     169: goto          256
     172: aload_1
     173: ldc           #195                // String .
     175: invokevirtual #181                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     178: ifne          238
     181: goto          256
     184: getstatic     #110                // Field NS:Lcom/oocode/ConnectingTileType;
     187: checkcast     #197                // class com/oocode/TileType
     190: goto          283
     193: getstatic     #114                // Field EW:Lcom/oocode/ConnectingTileType;
     196: checkcast     #197                // class com/oocode/TileType
     199: goto          283
     202: getstatic     #118                // Field SE:Lcom/oocode/ConnectingTileType;
     205: checkcast     #197                // class com/oocode/TileType
     208: goto          283
     211: getstatic     #122                // Field SW:Lcom/oocode/ConnectingTileType;
     214: checkcast     #197                // class com/oocode/TileType
     217: goto          283
     220: getstatic     #102                // Field NE:Lcom/oocode/ConnectingTileType;
     223: checkcast     #197                // class com/oocode/TileType
     226: goto          283
     229: getstatic     #106                // Field NW:Lcom/oocode/ConnectingTileType;
     232: checkcast     #197                // class com/oocode/TileType
     235: goto          283
     238: getstatic     #128                // Field GROUND:Lcom/oocode/Ground;
     241: checkcast     #197                // class com/oocode/TileType
     244: goto          283
     247: getstatic     #134                // Field START:Lcom/oocode/Start;
     250: checkcast     #197                // class com/oocode/TileType
     253: goto          283
     256: new           #199                // class java/lang/RuntimeException
     259: dup
     260: new           #201                // class java/lang/StringBuilder
     263: dup
     264: invokespecial #203                // Method java/lang/StringBuilder."<init>":()V
     267: ldc           #205                // String Unexpected name:
     269: invokevirtual #209                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     272: aload_0
     273: invokevirtual #209                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     276: invokevirtual #213                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     279: invokespecial #216                // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
     282: athrow
     283: areturn

  static {};
    Code:
       0: new           #219                // class com/oocode/ConnectingTileType
       3: dup
       4: ldc           #191                // String L
       6: getstatic     #225                // Field com/oocode/Compass.North:Lcom/oocode/Compass;
       9: getstatic     #228                // Field com/oocode/Compass.East:Lcom/oocode/Compass;
      12: invokespecial #231                // Method com/oocode/ConnectingTileType."<init>":(Ljava/lang/String;Lcom/oocode/Compass;Lcom/oocode/Compass;)V
      15: putstatic     #102                // Field NE:Lcom/oocode/ConnectingTileType;
      18: new           #219                // class com/oocode/ConnectingTileType
      21: dup
      22: ldc           #187                // String J
      24: getstatic     #225                // Field com/oocode/Compass.North:Lcom/oocode/Compass;
      27: getstatic     #234                // Field com/oocode/Compass.West:Lcom/oocode/Compass;
      30: invokespecial #231                // Method com/oocode/ConnectingTileType."<init>":(Ljava/lang/String;Lcom/oocode/Compass;Lcom/oocode/Compass;)V
      33: putstatic     #106                // Field NW:Lcom/oocode/ConnectingTileType;
      36: new           #219                // class com/oocode/ConnectingTileType
      39: dup
      40: ldc           #189                // String |
      42: getstatic     #225                // Field com/oocode/Compass.North:Lcom/oocode/Compass;
      45: getstatic     #237                // Field com/oocode/Compass.South:Lcom/oocode/Compass;
      48: invokespecial #231                // Method com/oocode/ConnectingTileType."<init>":(Ljava/lang/String;Lcom/oocode/Compass;Lcom/oocode/Compass;)V
      51: putstatic     #110                // Field NS:Lcom/oocode/ConnectingTileType;
      54: new           #219                // class com/oocode/ConnectingTileType
      57: dup
      58: ldc           #193                // String -
      60: getstatic     #228                // Field com/oocode/Compass.East:Lcom/oocode/Compass;
      63: getstatic     #234                // Field com/oocode/Compass.West:Lcom/oocode/Compass;
      66: invokespecial #231                // Method com/oocode/ConnectingTileType."<init>":(Ljava/lang/String;Lcom/oocode/Compass;Lcom/oocode/Compass;)V
      69: putstatic     #114                // Field EW:Lcom/oocode/ConnectingTileType;
      72: new           #219                // class com/oocode/ConnectingTileType
      75: dup
      76: ldc           #183                // String F
      78: getstatic     #237                // Field com/oocode/Compass.South:Lcom/oocode/Compass;
      81: getstatic     #228                // Field com/oocode/Compass.East:Lcom/oocode/Compass;
      84: invokespecial #231                // Method com/oocode/ConnectingTileType."<init>":(Ljava/lang/String;Lcom/oocode/Compass;Lcom/oocode/Compass;)V
      87: putstatic     #118                // Field SE:Lcom/oocode/ConnectingTileType;
      90: new           #219                // class com/oocode/ConnectingTileType
      93: dup
      94: ldc           #185                // String 7
      96: getstatic     #237                // Field com/oocode/Compass.South:Lcom/oocode/Compass;
      99: getstatic     #234                // Field com/oocode/Compass.West:Lcom/oocode/Compass;
     102: invokespecial #231                // Method com/oocode/ConnectingTileType."<init>":(Ljava/lang/String;Lcom/oocode/Compass;Lcom/oocode/Compass;)V
     105: putstatic     #122                // Field SW:Lcom/oocode/ConnectingTileType;
     108: new           #239                // class com/oocode/Ground
     111: dup
     112: ldc           #195                // String .
     114: invokespecial #240                // Method com/oocode/Ground."<init>":(Ljava/lang/String;)V
     117: putstatic     #128                // Field GROUND:Lcom/oocode/Ground;
     120: new           #242                // class com/oocode/Start
     123: dup
     124: ldc           #178                // String S
     126: invokespecial #243                // Method com/oocode/Start."<init>":(Ljava/lang/String;)V
     129: putstatic     #134                // Field START:Lcom/oocode/Start;
     132: return
}


package com.oocode

fun engineSchematicFrom(input: String): EngineSchematic {
    val lines = input.split("\n")
    val numbers = lines.flatMapIndexed { index, line -> numbersFrom(line, index) }.toSet()
    val symbols = lines.flatMapIndexed { index, line -> symbolsFrom(line, index) }.toSet()
    val gearIndicators = lines.flatMapIndexed { index, line -> gearIndicatorsFrom(line, index) }.toSet()
    return EngineSchematic(numbers, symbols, gearIndicators)
}

private fun Number.isNextToASymbol(symbols: Set<Symbol>) = symbols.any { symbol -> isNextTo(symbol.position) }

private fun Pair<Int, Int>.isNextTo(position: Pair<Int, Int>) =
    Math.abs(first - position.first) <= 1 && Math.abs(second - position.second) <= 1

private fun numbersFrom(line: String, y: Int) =
    Regex("(\\d+)")
        .findAll(line)
        .map { Number(Pair(it.range.first, y), it.value) }
        .toSet()

private fun symbolsFrom(line: String, y: Int): Set<Symbol> =
    line.mapIndexedNotNull { x, c -> if (c.isSymbol()) Symbol(Pair(x, y)) else null }.toSet()

private fun gearIndicatorsFrom(line: String, y: Int): Set<GearIndicator> =
    line.mapIndexedNotNull { x, c -> if (c.isGearIndicator()) GearIndicator(Pair(x, y)) else null }.toSet()

private fun Char.isSymbol() = !isDigit() && this != '.'

private fun Char.isGearIndicator() = this == '*'

data class Number(val startPosition: Pair<Int, Int>, val value: String) {
    fun positions(): Set<Pair<Int, Int>> = value.mapIndexed { index, _ ->
        startPosition.copy(startPosition.first + index)
    }.toSet()

    fun isNextTo(position: Pair<Int, Int>) = positions().any { it.isNextTo(position) }
}

data class Symbol(val position: Pair<Int, Int>)
data class GearIndicator(val position: Pair<Int, Int>)

class EngineSchematic(
    private val numbers: Set<Number>,
    private val symbols: Set<Symbol>,
    private val gearIndicators: Set<GearIndicator>
) {
    fun total() = partNumbers().sumOf { it.value.toInt() }

    private fun partNumbers() = numbers.filter { number -> number.isNextToASymbol(symbols) }.toSet()
    fun gearRatiosTotal() =
        gearIndicators
            .map { gearIndicator ->
                numbers
                    .filter { number -> number.isNextTo(gearIndicator.position) }
                    .map { it.value.toInt() }
            }
            .filter { it.size == 2 }
            .sumOf { it[0] * it[1] }
}

Compiled from "EngineSchematic.kt"
public final class com.oocode.EngineSchematicKt {
  public static final com.oocode.EngineSchematic engineSchematicFrom(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #9                  // String input
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #17                 // class java/lang/CharSequence
      10: iconst_1
      11: anewarray     #19                 // class java/lang/String
      14: astore_2
      15: aload_2
      16: iconst_0
      17: ldc           #21                 // String \n
      19: aastore
      20: aload_2
      21: iconst_0
      22: iconst_0
      23: bipush        6
      25: aconst_null
      26: invokestatic  #27                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      29: astore_1
      30: aload_1
      31: checkcast     #29                 // class java/lang/Iterable
      34: astore        4
      36: new           #31                 // class java/util/ArrayList
      39: dup
      40: invokespecial #35                 // Method java/util/ArrayList."<init>":()V
      43: checkcast     #37                 // class java/util/Collection
      46: astore        5
      48: iconst_0
      49: istore        6
      51: aload         4
      53: invokeinterface #41,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      58: astore        7
      60: aload         7
      62: invokeinterface #47,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      67: ifeq          128
      70: aload         7
      72: invokeinterface #51,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      77: astore        8
      79: iload         6
      81: iinc          6, 1
      84: istore        9
      86: iload         9
      88: ifge          94
      91: invokestatic  #56                 // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
      94: iload         9
      96: aload         8
      98: checkcast     #19                 // class java/lang/String
     101: astore        10
     103: istore        11
     105: iconst_0
     106: istore        12
     108: aload         10
     110: iload         11
     112: invokestatic  #60                 // Method numbersFrom:(Ljava/lang/String;I)Ljava/util/Set;
     115: checkcast     #29                 // class java/lang/Iterable
     118: aload         5
     120: swap
     121: invokestatic  #64                 // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
     124: pop
     125: goto          60
     128: aload         5
     130: checkcast     #66                 // class java/util/List
     133: checkcast     #29                 // class java/lang/Iterable
     136: invokestatic  #70                 // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     139: astore_2
     140: aload_1
     141: checkcast     #29                 // class java/lang/Iterable
     144: astore        5
     146: new           #31                 // class java/util/ArrayList
     149: dup
     150: invokespecial #35                 // Method java/util/ArrayList."<init>":()V
     153: checkcast     #37                 // class java/util/Collection
     156: astore        6
     158: iconst_0
     159: istore        7
     161: aload         5
     163: invokeinterface #41,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     168: astore        8
     170: aload         8
     172: invokeinterface #47,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     177: ifeq          238
     180: aload         8
     182: invokeinterface #51,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     187: astore        9
     189: iload         7
     191: iinc          7, 1
     194: istore        10
     196: iload         10
     198: ifge          204
     201: invokestatic  #56                 // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
     204: iload         10
     206: aload         9
     208: checkcast     #19                 // class java/lang/String
     211: astore        11
     213: istore        12
     215: iconst_0
     216: istore        13
     218: aload         11
     220: iload         12
     222: invokestatic  #73                 // Method symbolsFrom:(Ljava/lang/String;I)Ljava/util/Set;
     225: checkcast     #29                 // class java/lang/Iterable
     228: aload         6
     230: swap
     231: invokestatic  #64                 // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
     234: pop
     235: goto          170
     238: aload         6
     240: checkcast     #66                 // class java/util/List
     243: checkcast     #29                 // class java/lang/Iterable
     246: invokestatic  #70                 // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     249: astore_3
     250: aload_1
     251: checkcast     #29                 // class java/lang/Iterable
     254: astore        6
     256: new           #31                 // class java/util/ArrayList
     259: dup
     260: invokespecial #35                 // Method java/util/ArrayList."<init>":()V
     263: checkcast     #37                 // class java/util/Collection
     266: astore        7
     268: iconst_0
     269: istore        8
     271: aload         6
     273: invokeinterface #41,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     278: astore        9
     280: aload         9
     282: invokeinterface #47,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     287: ifeq          348
     290: aload         9
     292: invokeinterface #51,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     297: astore        10
     299: iload         8
     301: iinc          8, 1
     304: istore        11
     306: iload         11
     308: ifge          314
     311: invokestatic  #56                 // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
     314: iload         11
     316: aload         10
     318: checkcast     #19                 // class java/lang/String
     321: astore        12
     323: istore        13
     325: iconst_0
     326: istore        14
     328: aload         12
     330: iload         13
     332: invokestatic  #76                 // Method gearIndicatorsFrom:(Ljava/lang/String;I)Ljava/util/Set;
     335: checkcast     #29                 // class java/lang/Iterable
     338: aload         7
     340: swap
     341: invokestatic  #64                 // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
     344: pop
     345: goto          280
     348: aload         7
     350: checkcast     #66                 // class java/util/List
     353: checkcast     #29                 // class java/lang/Iterable
     356: invokestatic  #70                 // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     359: astore        4
     361: new           #78                 // class com/oocode/EngineSchematic
     364: dup
     365: aload_2
     366: aload_3
     367: aload         4
     369: invokespecial #81                 // Method com/oocode/EngineSchematic."<init>":(Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V
     372: areturn

  private static final boolean isNextToASymbol(com.oocode.Number, java.util.Set<com.oocode.Symbol>);
    Code:
       0: aload_1
       1: checkcast     #29                 // class java/lang/Iterable
       4: astore_2
       5: iconst_0
       6: istore_3
       7: aload_2
       8: instanceof    #37                 // class java/util/Collection
      11: ifeq          30
      14: aload_2
      15: checkcast     #37                 // class java/util/Collection
      18: invokeinterface #104,  1          // InterfaceMethod java/util/Collection.isEmpty:()Z
      23: ifeq          30
      26: iconst_0
      27: goto          84
      30: aload_2
      31: invokeinterface #41,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      36: astore        4
      38: aload         4
      40: invokeinterface #47,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      45: ifeq          83
      48: aload         4
      50: invokeinterface #51,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      55: astore        5
      57: aload         5
      59: checkcast     #106                // class com/oocode/Symbol
      62: astore        6
      64: iconst_0
      65: istore        7
      67: aload_0
      68: aload         6
      70: invokevirtual #110                // Method com/oocode/Symbol.getPosition:()Lkotlin/Pair;
      73: invokevirtual #116                // Method com/oocode/Number.isNextTo:(Lkotlin/Pair;)Z
      76: ifeq          38
      79: iconst_1
      80: goto          84
      83: iconst_0
      84: ireturn

  private static final boolean isNextTo(kotlin.Pair<java.lang.Integer, java.lang.Integer>, kotlin.Pair<java.lang.Integer, java.lang.Integer>);
    Code:
       0: aload_0
       1: invokevirtual #133                // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
       4: checkcast     #135                // class java/lang/Number
       7: invokevirtual #139                // Method java/lang/Number.intValue:()I
      10: aload_1
      11: invokevirtual #133                // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
      14: checkcast     #135                // class java/lang/Number
      17: invokevirtual #139                // Method java/lang/Number.intValue:()I
      20: isub
      21: invokestatic  #145                // Method java/lang/Math.abs:(I)I
      24: iconst_1
      25: if_icmpgt     60
      28: aload_0
      29: invokevirtual #148                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
      32: checkcast     #135                // class java/lang/Number
      35: invokevirtual #139                // Method java/lang/Number.intValue:()I
      38: aload_1
      39: invokevirtual #148                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
      42: checkcast     #135                // class java/lang/Number
      45: invokevirtual #139                // Method java/lang/Number.intValue:()I
      48: isub
      49: invokestatic  #145                // Method java/lang/Math.abs:(I)I
      52: iconst_1
      53: if_icmpgt     60
      56: iconst_1
      57: goto          61
      60: iconst_0
      61: ireturn

  private static final java.util.Set<com.oocode.Number> numbersFrom(java.lang.String, int);
    Code:
       0: new           #154                // class kotlin/text/Regex
       3: dup
       4: ldc           #156                // String (\\d+)
       6: invokespecial #159                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
       9: aload_0
      10: checkcast     #17                 // class java/lang/CharSequence
      13: iconst_0
      14: iconst_2
      15: aconst_null
      16: invokestatic  #163                // Method kotlin/text/Regex.findAll$default:(Lkotlin/text/Regex;Ljava/lang/CharSequence;IILjava/lang/Object;)Lkotlin/sequences/Sequence;
      19: iload_1
      20: invokedynamic #183,  0            // InvokeDynamic #0:invoke:(I)Lkotlin/jvm/functions/Function1;
      25: invokestatic  #189                // Method kotlin/sequences/SequencesKt.map:(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
      28: invokestatic  #192                // Method kotlin/sequences/SequencesKt.toSet:(Lkotlin/sequences/Sequence;)Ljava/util/Set;
      31: areturn

  private static final java.util.Set<com.oocode.Symbol> symbolsFrom(java.lang.String, int);
    Code:
       0: aload_0
       1: checkcast     #17                 // class java/lang/CharSequence
       4: astore_2
       5: iconst_0
       6: istore_3
       7: aload_2
       8: astore        4
      10: new           #31                 // class java/util/ArrayList
      13: dup
      14: invokespecial #35                 // Method java/util/ArrayList."<init>":()V
      17: checkcast     #37                 // class java/util/Collection
      20: astore        5
      22: iconst_0
      23: istore        6
      25: aload         4
      27: astore        7
      29: iconst_0
      30: istore        8
      32: iconst_0
      33: istore        9
      35: iconst_0
      36: istore        10
      38: iload         10
      40: aload         7
      42: invokeinterface #197,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      47: if_icmpge     151
      50: aload         7
      52: iload         10
      54: invokeinterface #201,  2          // InterfaceMethod java/lang/CharSequence.charAt:(I)C
      59: istore        11
      61: iload         9
      63: iinc          9, 1
      66: iload         11
      68: istore        12
      70: istore        13
      72: iconst_0
      73: istore        14
      75: iload         13
      77: iload         12
      79: istore        15
      81: istore        16
      83: iconst_0
      84: istore        17
      86: iload         15
      88: invokestatic  #205                // Method isSymbol:(C)Z
      91: ifeq          120
      94: new           #106                // class com/oocode/Symbol
      97: dup
      98: new           #130                // class kotlin/Pair
     101: dup
     102: iload         16
     104: invokestatic  #211                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     107: iload_1
     108: invokestatic  #211                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     111: invokespecial #214                // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
     114: invokespecial #217                // Method com/oocode/Symbol."<init>":(Lkotlin/Pair;)V
     117: goto          121
     120: aconst_null
     121: dup
     122: ifnull        143
     125: astore        18
     127: iconst_0
     128: istore        19
     130: aload         5
     132: aload         18
     134: invokeinterface #221,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     139: pop
     140: goto          144
     143: pop
     144: nop
     145: iinc          10, 1
     148: goto          38
     151: nop
     152: aload         5
     154: checkcast     #66                 // class java/util/List
     157: nop
     158: checkcast     #29                 // class java/lang/Iterable
     161: invokestatic  #70                 // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     164: areturn

  private static final java.util.Set<com.oocode.GearIndicator> gearIndicatorsFrom(java.lang.String, int);
    Code:
       0: aload_0
       1: checkcast     #17                 // class java/lang/CharSequence
       4: astore_2
       5: iconst_0
       6: istore_3
       7: aload_2
       8: astore        4
      10: new           #31                 // class java/util/ArrayList
      13: dup
      14: invokespecial #35                 // Method java/util/ArrayList."<init>":()V
      17: checkcast     #37                 // class java/util/Collection
      20: astore        5
      22: iconst_0
      23: istore        6
      25: aload         4
      27: astore        7
      29: iconst_0
      30: istore        8
      32: iconst_0
      33: istore        9
      35: iconst_0
      36: istore        10
      38: iload         10
      40: aload         7
      42: invokeinterface #197,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      47: if_icmpge     151
      50: aload         7
      52: iload         10
      54: invokeinterface #201,  2          // InterfaceMethod java/lang/CharSequence.charAt:(I)C
      59: istore        11
      61: iload         9
      63: iinc          9, 1
      66: iload         11
      68: istore        12
      70: istore        13
      72: iconst_0
      73: istore        14
      75: iload         13
      77: iload         12
      79: istore        15
      81: istore        16
      83: iconst_0
      84: istore        17
      86: iload         15
      88: invokestatic  #245                // Method isGearIndicator:(C)Z
      91: ifeq          120
      94: new           #247                // class com/oocode/GearIndicator
      97: dup
      98: new           #130                // class kotlin/Pair
     101: dup
     102: iload         16
     104: invokestatic  #211                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     107: iload_1
     108: invokestatic  #211                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     111: invokespecial #214                // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
     114: invokespecial #248                // Method com/oocode/GearIndicator."<init>":(Lkotlin/Pair;)V
     117: goto          121
     120: aconst_null
     121: dup
     122: ifnull        143
     125: astore        18
     127: iconst_0
     128: istore        19
     130: aload         5
     132: aload         18
     134: invokeinterface #221,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     139: pop
     140: goto          144
     143: pop
     144: nop
     145: iinc          10, 1
     148: goto          38
     151: nop
     152: aload         5
     154: checkcast     #66                 // class java/util/List
     157: nop
     158: checkcast     #29                 // class java/lang/Iterable
     161: invokestatic  #70                 // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     164: areturn

  private static final boolean isSymbol(char);
    Code:
       0: iload_0
       1: invokestatic  #254                // Method java/lang/Character.isDigit:(C)Z
       4: ifne          17
       7: iload_0
       8: bipush        46
      10: if_icmpeq     17
      13: iconst_1
      14: goto          18
      17: iconst_0
      18: ireturn

  private static final boolean isGearIndicator(char);
    Code:
       0: iload_0
       1: bipush        42
       3: if_icmpne     10
       6: iconst_1
       7: goto          11
      10: iconst_0
      11: ireturn

  private static final com.oocode.Number numbersFrom$lambda$4(int, kotlin.text.MatchResult);
    Code:
       0: aload_1
       1: ldc_w         #258                // String it
       4: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       7: new           #112                // class com/oocode/Number
      10: dup
      11: new           #130                // class kotlin/Pair
      14: dup
      15: aload_1
      16: invokeinterface #264,  1          // InterfaceMethod kotlin/text/MatchResult.getRange:()Lkotlin/ranges/IntRange;
      21: invokevirtual #268                // Method kotlin/ranges/IntRange.getFirst:()I
      24: invokestatic  #211                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      27: iload_0
      28: invokestatic  #211                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      31: invokespecial #214                // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
      34: aload_1
      35: invokeinterface #272,  1          // InterfaceMethod kotlin/text/MatchResult.getValue:()Ljava/lang/String;
      40: invokespecial #275                // Method com/oocode/Number."<init>":(Lkotlin/Pair;Ljava/lang/String;)V
      43: areturn

  public static final boolean access$isNextTo(kotlin.Pair, kotlin.Pair);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #280                // Method isNextTo:(Lkotlin/Pair;Lkotlin/Pair;)Z
       5: ireturn

  public static final boolean access$isNextToASymbol(com.oocode.Number, java.util.Set);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #284                // Method isNextToASymbol:(Lcom/oocode/Number;Ljava/util/Set;)Z
       5: ireturn
}

Compiled from "EngineSchematic.kt"
public final class com.oocode.EngineSchematic {
  private final java.util.Set<com.oocode.Number> numbers;

  private final java.util.Set<com.oocode.Symbol> symbols;

  private final java.util.Set<com.oocode.GearIndicator> gearIndicators;

  public com.oocode.EngineSchematic(java.util.Set<com.oocode.Number>, java.util.Set<com.oocode.Symbol>, java.util.Set<com.oocode.GearIndicator>);
    Code:
       0: aload_1
       1: ldc           #10                 // String numbers
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_2
       7: ldc           #18                 // String symbols
       9: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_3
      13: ldc           #20                 // String gearIndicators
      15: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      18: aload_0
      19: invokespecial #23                 // Method java/lang/Object."<init>":()V
      22: aload_0
      23: aload_1
      24: putfield      #26                 // Field numbers:Ljava/util/Set;
      27: aload_0
      28: aload_2
      29: putfield      #28                 // Field symbols:Ljava/util/Set;
      32: aload_0
      33: aload_3
      34: putfield      #30                 // Field gearIndicators:Ljava/util/Set;
      37: return

  public final int total();
    Code:
       0: aload_0
       1: invokespecial #38                 // Method partNumbers:()Ljava/util/Set;
       4: checkcast     #40                 // class java/lang/Iterable
       7: astore_1
       8: iconst_0
       9: istore_2
      10: aload_1
      11: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      16: astore_3
      17: aload_3
      18: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      23: ifeq          67
      26: aload_3
      27: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      32: astore        4
      34: iload_2
      35: aload         4
      37: checkcast     #56                 // class com/oocode/Number
      40: astore        5
      42: istore        7
      44: iconst_0
      45: istore        6
      47: aload         5
      49: invokevirtual #60                 // Method com/oocode/Number.getValue:()Ljava/lang/String;
      52: invokestatic  #66                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      55: nop
      56: istore        8
      58: iload         7
      60: iload         8
      62: iadd
      63: istore_2
      64: goto          17
      67: iload_2
      68: ireturn

  private final java.util.Set<com.oocode.Number> partNumbers();
    Code:
       0: aload_0
       1: getfield      #26                 // Field numbers:Ljava/util/Set;
       4: checkcast     #40                 // class java/lang/Iterable
       7: astore_1
       8: iconst_0
       9: istore_2
      10: aload_1
      11: astore_3
      12: new           #73                 // class java/util/ArrayList
      15: dup
      16: invokespecial #74                 // Method java/util/ArrayList."<init>":()V
      19: checkcast     #76                 // class java/util/Collection
      22: astore        4
      24: iconst_0
      25: istore        5
      27: aload_3
      28: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      33: astore        6
      35: aload         6
      37: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      42: ifeq          89
      45: aload         6
      47: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      52: astore        7
      54: aload         7
      56: checkcast     #56                 // class com/oocode/Number
      59: astore        8
      61: iconst_0
      62: istore        9
      64: aload         8
      66: aload_0
      67: getfield      #28                 // Field symbols:Ljava/util/Set;
      70: invokestatic  #82                 // Method com/oocode/EngineSchematicKt.access$isNextToASymbol:(Lcom/oocode/Number;Ljava/util/Set;)Z
      73: ifeq          35
      76: aload         4
      78: aload         7
      80: invokeinterface #86,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
      85: pop
      86: goto          35
      89: aload         4
      91: checkcast     #88                 // class java/util/List
      94: nop
      95: checkcast     #40                 // class java/lang/Iterable
      98: invokestatic  #94                 // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     101: areturn

  public final int gearRatiosTotal();
    Code:
       0: aload_0
       1: getfield      #30                 // Field gearIndicators:Ljava/util/Set;
       4: checkcast     #40                 // class java/lang/Iterable
       7: astore_1
       8: nop
       9: iconst_0
      10: istore_2
      11: aload_1
      12: astore_3
      13: new           #73                 // class java/util/ArrayList
      16: dup
      17: aload_1
      18: bipush        10
      20: invokestatic  #110                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      23: invokespecial #113                // Method java/util/ArrayList."<init>":(I)V
      26: checkcast     #76                 // class java/util/Collection
      29: astore        4
      31: iconst_0
      32: istore        5
      34: aload_3
      35: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      40: astore        6
      42: aload         6
      44: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      49: ifeq          297
      52: aload         6
      54: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      59: astore        7
      61: aload         4
      63: aload         7
      65: checkcast     #115                // class com/oocode/GearIndicator
      68: astore        8
      70: astore        20
      72: iconst_0
      73: istore        9
      75: aload_0
      76: getfield      #26                 // Field numbers:Ljava/util/Set;
      79: checkcast     #40                 // class java/lang/Iterable
      82: astore        10
      84: nop
      85: iconst_0
      86: istore        11
      88: aload         10
      90: astore        12
      92: new           #73                 // class java/util/ArrayList
      95: dup
      96: invokespecial #74                 // Method java/util/ArrayList."<init>":()V
      99: checkcast     #76                 // class java/util/Collection
     102: astore        13
     104: iconst_0
     105: istore        14
     107: aload         12
     109: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     114: astore        15
     116: aload         15
     118: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     123: ifeq          171
     126: aload         15
     128: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     133: astore        16
     135: aload         16
     137: checkcast     #56                 // class com/oocode/Number
     140: astore        17
     142: iconst_0
     143: istore        18
     145: aload         17
     147: aload         8
     149: invokevirtual #119                // Method com/oocode/GearIndicator.getPosition:()Lkotlin/Pair;
     152: invokevirtual #123                // Method com/oocode/Number.isNextTo:(Lkotlin/Pair;)Z
     155: ifeq          116
     158: aload         13
     160: aload         16
     162: invokeinterface #86,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     167: pop
     168: goto          116
     171: aload         13
     173: checkcast     #88                 // class java/util/List
     176: nop
     177: checkcast     #40                 // class java/lang/Iterable
     180: astore        10
     182: nop
     183: iconst_0
     184: istore        11
     186: aload         10
     188: astore        12
     190: new           #73                 // class java/util/ArrayList
     193: dup
     194: aload         10
     196: bipush        10
     198: invokestatic  #110                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     201: invokespecial #113                // Method java/util/ArrayList."<init>":(I)V
     204: checkcast     #76                 // class java/util/Collection
     207: astore        13
     209: iconst_0
     210: istore        14
     212: aload         12
     214: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     219: astore        15
     221: aload         15
     223: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     228: ifeq          278
     231: aload         15
     233: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     238: astore        16
     240: aload         13
     242: aload         16
     244: checkcast     #56                 // class com/oocode/Number
     247: astore        17
     249: astore        19
     251: iconst_0
     252: istore        18
     254: aload         17
     256: invokevirtual #60                 // Method com/oocode/Number.getValue:()Ljava/lang/String;
     259: invokestatic  #66                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     262: nop
     263: invokestatic  #127                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     266: aload         19
     268: swap
     269: invokeinterface #86,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     274: pop
     275: goto          221
     278: aload         13
     280: checkcast     #88                 // class java/util/List
     283: nop
     284: nop
     285: aload         20
     287: swap
     288: invokeinterface #86,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     293: pop
     294: goto          42
     297: aload         4
     299: checkcast     #88                 // class java/util/List
     302: nop
     303: checkcast     #40                 // class java/lang/Iterable
     306: astore_1
     307: nop
     308: iconst_0
     309: istore_2
     310: aload_1
     311: astore_3
     312: new           #73                 // class java/util/ArrayList
     315: dup
     316: invokespecial #74                 // Method java/util/ArrayList."<init>":()V
     319: checkcast     #76                 // class java/util/Collection
     322: astore        4
     324: iconst_0
     325: istore        5
     327: aload_3
     328: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     333: astore        6
     335: aload         6
     337: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     342: ifeq          396
     345: aload         6
     347: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     352: astore        7
     354: aload         7
     356: checkcast     #88                 // class java/util/List
     359: astore        8
     361: iconst_0
     362: istore        9
     364: aload         8
     366: invokeinterface #130,  1          // InterfaceMethod java/util/List.size:()I
     371: iconst_2
     372: if_icmpne     379
     375: iconst_1
     376: goto          380
     379: iconst_0
     380: ifeq          335
     383: aload         4
     385: aload         7
     387: invokeinterface #86,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     392: pop
     393: goto          335
     396: aload         4
     398: checkcast     #88                 // class java/util/List
     401: nop
     402: checkcast     #40                 // class java/lang/Iterable
     405: astore_1
     406: iconst_0
     407: istore_2
     408: aload_1
     409: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     414: astore_3
     415: aload_3
     416: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     421: ifeq          485
     424: aload_3
     425: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     430: astore        4
     432: iload_2
     433: aload         4
     435: checkcast     #88                 // class java/util/List
     438: astore        5
     440: istore        20
     442: iconst_0
     443: istore        6
     445: aload         5
     447: iconst_0
     448: invokeinterface #134,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     453: checkcast     #136                // class java/lang/Number
     456: invokevirtual #139                // Method java/lang/Number.intValue:()I
     459: aload         5
     461: iconst_1
     462: invokeinterface #134,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     467: checkcast     #136                // class java/lang/Number
     470: invokevirtual #139                // Method java/lang/Number.intValue:()I
     473: imul
     474: istore        21
     476: iload         20
     478: iload         21
     480: iadd
     481: istore_2
     482: goto          415
     485: iload_2
     486: ireturn
}