package day3

import java.io.File

fun isSymbol(char: Char): Boolean = !char.isDigit() && char != '.'

fun isNextToASymbol(position: Pair<Int, Int>, engineSchematic: Map<Pair<Int, Int>, Char>): Boolean {
    val neighbourPositions = listOf(
        position.first to position.second -1,
        position.first + 1 to position.second -1,
        position.first - 1 to position.second -1,
        position.first to position.second +1,
        position.first + 1 to position.second +1,
        position.first - 1 to position.second +1,
        position.first + 1 to position.second,
        position.first - 1 to position.second
    )

    return neighbourPositions.mapNotNull { engineSchematic[it] }.any { isSymbol(it) }
}

fun main() {
    val inputFileName = "day3/input.txt"
    val engineSchematic: MutableMap<Pair<Int, Int>, Char> = mutableMapOf()
    val numbers: MutableList<Pair<Int, List<Pair<Int, Int>>>> = mutableListOf()
    var lineNumber = 0

    File(inputFileName).forEachLine {
        var number = ""
        var digitsIndices = mutableListOf<Pair<Int, Int>>()
        it.forEachIndexed { index, c ->
            engineSchematic[lineNumber to index] = c
            if (c.isDigit()) {
                number += c.toString()
                digitsIndices.add(lineNumber to index)
            } else if(number != "") {
                numbers.add(
                    number.toInt() to digitsIndices
                )
                number = ""
                digitsIndices = mutableListOf()
            }
        }

        if(number != "") {
            numbers.add(
                number.toInt() to digitsIndices
            )
            number = ""
            digitsIndices = mutableListOf()
        }

        ++lineNumber
    }

    println(numbers.filter {
        val nextToASymbol = it.second.any { digitsIndices -> isNextToASymbol(digitsIndices, engineSchematic) }
        println("number: ${it.first} indices: ${it.second} nextToASymbol: $nextToASymbol")
        nextToASymbol
    }.sumOf { it.first })
}

Compiled from "part1.kt"
public final class day3.Part1Kt {
  public static final boolean isSymbol(char);
    Code:
       0: iload_0
       1: invokestatic  #11                 // 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

  public static final boolean isNextToASymbol(kotlin.Pair<java.lang.Integer, java.lang.Integer>, java.util.Map<kotlin.Pair<java.lang.Integer, java.lang.Integer>, java.lang.Character>);
    Code:
       0: aload_0
       1: ldc           #19                 // String position
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #27                 // String engineSchematic
       9: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: bipush        8
      14: anewarray     #29                 // class kotlin/Pair
      17: astore_3
      18: aload_3
      19: iconst_0
      20: aload_0
      21: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
      24: aload_0
      25: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
      28: checkcast     #38                 // class java/lang/Number
      31: invokevirtual #42                 // Method java/lang/Number.intValue:()I
      34: iconst_1
      35: isub
      36: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      39: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      42: aastore
      43: aload_3
      44: iconst_1
      45: aload_0
      46: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
      49: checkcast     #38                 // class java/lang/Number
      52: invokevirtual #42                 // Method java/lang/Number.intValue:()I
      55: iconst_1
      56: iadd
      57: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      60: aload_0
      61: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
      64: checkcast     #38                 // class java/lang/Number
      67: invokevirtual #42                 // Method java/lang/Number.intValue:()I
      70: iconst_1
      71: isub
      72: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      75: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      78: aastore
      79: aload_3
      80: iconst_2
      81: aload_0
      82: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
      85: checkcast     #38                 // class java/lang/Number
      88: invokevirtual #42                 // Method java/lang/Number.intValue:()I
      91: iconst_1
      92: isub
      93: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      96: aload_0
      97: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     100: checkcast     #38                 // class java/lang/Number
     103: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     106: iconst_1
     107: isub
     108: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     111: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     114: aastore
     115: aload_3
     116: iconst_3
     117: aload_0
     118: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     121: aload_0
     122: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     125: checkcast     #38                 // class java/lang/Number
     128: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     131: iconst_1
     132: iadd
     133: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     136: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     139: aastore
     140: aload_3
     141: iconst_4
     142: aload_0
     143: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     146: checkcast     #38                 // class java/lang/Number
     149: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     152: iconst_1
     153: iadd
     154: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     157: aload_0
     158: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     161: checkcast     #38                 // class java/lang/Number
     164: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     167: iconst_1
     168: iadd
     169: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     172: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     175: aastore
     176: aload_3
     177: iconst_5
     178: aload_0
     179: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     182: checkcast     #38                 // class java/lang/Number
     185: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     188: iconst_1
     189: isub
     190: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     193: aload_0
     194: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     197: checkcast     #38                 // class java/lang/Number
     200: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     203: iconst_1
     204: iadd
     205: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     208: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     211: aastore
     212: aload_3
     213: bipush        6
     215: aload_0
     216: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     219: checkcast     #38                 // class java/lang/Number
     222: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     225: iconst_1
     226: iadd
     227: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     230: aload_0
     231: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     234: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     237: aastore
     238: aload_3
     239: bipush        7
     241: aload_0
     242: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     245: checkcast     #38                 // class java/lang/Number
     248: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     251: iconst_1
     252: isub
     253: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     256: aload_0
     257: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     260: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     263: aastore
     264: aload_3
     265: invokestatic  #60                 // Method kotlin/collections/CollectionsKt.listOf:([Ljava/lang/Object;)Ljava/util/List;
     268: astore_2
     269: aload_2
     270: checkcast     #62                 // class java/lang/Iterable
     273: astore_3
     274: iconst_0
     275: istore        4
     277: aload_3
     278: astore        5
     280: new           #64                 // class java/util/ArrayList
     283: dup
     284: invokespecial #68                 // Method java/util/ArrayList."<init>":()V
     287: checkcast     #70                 // class java/util/Collection
     290: astore        6
     292: iconst_0
     293: istore        7
     295: aload         5
     297: astore        8
     299: iconst_0
     300: istore        9
     302: aload         8
     304: invokeinterface #74,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     309: astore        10
     311: aload         10
     313: invokeinterface #80,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     318: ifeq          385
     321: aload         10
     323: invokeinterface #83,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     328: astore        11
     330: aload         11
     332: astore        12
     334: iconst_0
     335: istore        13
     337: aload         12
     339: checkcast     #29                 // class kotlin/Pair
     342: astore        14
     344: iconst_0
     345: istore        15
     347: aload_1
     348: aload         14
     350: invokeinterface #89,  2           // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     355: checkcast     #8                  // class java/lang/Character
     358: dup
     359: ifnull        380
     362: astore        16
     364: iconst_0
     365: istore        17
     367: aload         6
     369: aload         16
     371: invokeinterface #93,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     376: pop
     377: goto          381
     380: pop
     381: nop
     382: goto          311
     385: nop
     386: aload         6
     388: checkcast     #95                 // class java/util/List
     391: nop
     392: checkcast     #62                 // class java/lang/Iterable
     395: astore_3
     396: nop
     397: iconst_0
     398: istore        4
     400: aload_3
     401: instanceof    #70                 // class java/util/Collection
     404: ifeq          423
     407: aload_3
     408: checkcast     #70                 // class java/util/Collection
     411: invokeinterface #98,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
     416: ifeq          423
     419: iconst_0
     420: goto          476
     423: aload_3
     424: invokeinterface #74,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     429: astore        5
     431: aload         5
     433: invokeinterface #80,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     438: ifeq          475
     441: aload         5
     443: invokeinterface #83,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     448: astore        6
     450: aload         6
     452: checkcast     #8                  // class java/lang/Character
     455: invokevirtual #102                // Method java/lang/Character.charValue:()C
     458: istore        7
     460: iconst_0
     461: istore        8
     463: iload         7
     465: invokestatic  #104                // Method isSymbol:(C)Z
     468: ifeq          431
     471: iconst_1
     472: goto          476
     475: iconst_0
     476: ireturn

  public static final void main();
    Code:
       0: ldc           #133                // String day3/input.txt
       2: astore_0
       3: new           #135                // class java/util/LinkedHashMap
       6: dup
       7: invokespecial #136                // Method java/util/LinkedHashMap."<init>":()V
      10: checkcast     #85                 // class java/util/Map
      13: astore_1
      14: new           #64                 // class java/util/ArrayList
      17: dup
      18: invokespecial #68                 // Method java/util/ArrayList."<init>":()V
      21: checkcast     #95                 // class java/util/List
      24: astore_2
      25: new           #138                // class kotlin/jvm/internal/Ref$IntRef
      28: dup
      29: invokespecial #139                // Method kotlin/jvm/internal/Ref$IntRef."<init>":()V
      32: astore_3
      33: new           #141                // class java/io/File
      36: dup
      37: aload_0
      38: invokespecial #144                // Method java/io/File."<init>":(Ljava/lang/String;)V
      41: aconst_null
      42: aload_2
      43: aload_3
      44: aload_1
      45: invokedynamic #163,  0            // InvokeDynamic #0:invoke:(Ljava/util/List;Lkotlin/jvm/internal/Ref$IntRef;Ljava/util/Map;)Lkotlin/jvm/functions/Function1;
      50: iconst_1
      51: aconst_null
      52: invokestatic  #169                // Method kotlin/io/FilesKt.forEachLine$default:(Ljava/io/File;Ljava/nio/charset/Charset;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
      55: aload_2
      56: checkcast     #62                 // class java/lang/Iterable
      59: astore        4
      61: iconst_0
      62: istore        5
      64: aload         4
      66: astore        6
      68: new           #64                 // class java/util/ArrayList
      71: dup
      72: invokespecial #68                 // Method java/util/ArrayList."<init>":()V
      75: checkcast     #70                 // class java/util/Collection
      78: astore        7
      80: iconst_0
      81: istore        8
      83: aload         6
      85: invokeinterface #74,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      90: astore        9
      92: aload         9
      94: invokeinterface #80,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      99: ifeq          290
     102: aload         9
     104: invokeinterface #83,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     109: astore        10
     111: aload         10
     113: checkcast     #29                 // class kotlin/Pair
     116: astore        11
     118: iconst_0
     119: istore        12
     121: aload         11
     123: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     126: checkcast     #62                 // class java/lang/Iterable
     129: astore        13
     131: iconst_0
     132: istore        14
     134: aload         13
     136: instanceof    #70                 // class java/util/Collection
     139: ifeq          159
     142: aload         13
     144: checkcast     #70                 // class java/util/Collection
     147: invokeinterface #98,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
     152: ifeq          159
     155: iconst_0
     156: goto          211
     159: aload         13
     161: invokeinterface #74,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     166: astore        15
     168: aload         15
     170: invokeinterface #80,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     175: ifeq          210
     178: aload         15
     180: invokeinterface #83,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     185: astore        16
     187: aload         16
     189: checkcast     #29                 // class kotlin/Pair
     192: astore        17
     194: iconst_0
     195: istore        18
     197: aload         17
     199: aload_1
     200: invokestatic  #171                // Method isNextToASymbol:(Lkotlin/Pair;Ljava/util/Map;)Z
     203: ifeq          168
     206: iconst_1
     207: goto          211
     210: iconst_0
     211: istore        19
     213: new           #173                // class java/lang/StringBuilder
     216: dup
     217: invokespecial #174                // Method java/lang/StringBuilder."<init>":()V
     220: ldc           #176                // String number:
     222: invokevirtual #180                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     225: aload         11
     227: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     230: checkcast     #38                 // class java/lang/Number
     233: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     236: invokevirtual #183                // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
     239: ldc           #185                // String  indices:
     241: invokevirtual #180                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     244: aload         11
     246: invokevirtual #36                 // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     249: invokevirtual #188                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
     252: ldc           #190                // String  nextToASymbol:
     254: invokevirtual #180                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     257: iload         19
     259: invokevirtual #193                // Method java/lang/StringBuilder.append:(Z)Ljava/lang/StringBuilder;
     262: invokevirtual #197                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     265: getstatic     #203                // Field java/lang/System.out:Ljava/io/PrintStream;
     268: swap
     269: invokevirtual #209                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     272: iload         19
     274: ifeq          92
     277: aload         7
     279: aload         10
     281: invokeinterface #93,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     286: pop
     287: goto          92
     290: aload         7
     292: checkcast     #95                 // class java/util/List
     295: nop
     296: checkcast     #62                 // class java/lang/Iterable
     299: astore        4
     301: iconst_0
     302: istore        5
     304: aload         4
     306: invokeinterface #74,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     311: astore        6
     313: aload         6
     315: invokeinterface #80,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     320: ifeq          369
     323: aload         6
     325: invokeinterface #83,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     330: astore        7
     332: iload         5
     334: aload         7
     336: checkcast     #29                 // class kotlin/Pair
     339: astore        8
     341: istore        20
     343: iconst_0
     344: istore        9
     346: aload         8
     348: invokevirtual #33                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     351: checkcast     #38                 // class java/lang/Number
     354: invokevirtual #42                 // Method java/lang/Number.intValue:()I
     357: istore        21
     359: iload         20
     361: iload         21
     363: iadd
     364: istore        5
     366: goto          313
     369: iload         5
     371: istore        4
     373: getstatic     #203                // Field java/lang/System.out:Ljava/io/PrintStream;
     376: iload         4
     378: invokevirtual #212                // Method java/io/PrintStream.println:(I)V
     381: return

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

  private static final kotlin.Unit main$lambda$3(java.util.List, kotlin.jvm.internal.Ref$IntRef, java.util.Map, java.lang.String);
    Code:
       0: aload_3
       1: ldc           #235                // String it
       3: invokestatic  #25                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aconst_null
       7: astore        4
       9: ldc           #237                // String
      11: astore        4
      13: aconst_null
      14: astore        5
      16: new           #64                 // class java/util/ArrayList
      19: dup
      20: invokespecial #68                 // Method java/util/ArrayList."<init>":()V
      23: checkcast     #95                 // class java/util/List
      26: astore        5
      28: aload_3
      29: checkcast     #239                // class java/lang/CharSequence
      32: astore        6
      34: iconst_0
      35: istore        7
      37: iconst_0
      38: istore        8
      40: iconst_0
      41: istore        9
      43: iload         9
      45: aload         6
      47: invokeinterface #242,  1          // InterfaceMethod java/lang/CharSequence.length:()I
      52: if_icmpge     221
      55: aload         6
      57: iload         9
      59: invokeinterface #246,  2          // InterfaceMethod java/lang/CharSequence.charAt:(I)C
      64: istore        10
      66: iload         8
      68: iinc          8, 1
      71: iload         10
      73: istore        11
      75: istore        12
      77: iconst_0
      78: istore        13
      80: iload         11
      82: invokestatic  #249                // Method java/lang/Character.valueOf:(C)Ljava/lang/Character;
      85: astore        14
      87: aload_2
      88: aload_1
      89: getfield      #252                // Field kotlin/jvm/internal/Ref$IntRef.element:I
      92: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      95: iload         12
      97: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     100: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     103: aload         14
     105: invokeinterface #256,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     110: pop
     111: iload         11
     113: invokestatic  #11                 // Method java/lang/Character.isDigit:(C)Z
     116: ifeq          167
     119: new           #173                // class java/lang/StringBuilder
     122: dup
     123: invokespecial #174                // Method java/lang/StringBuilder."<init>":()V
     126: aload         4
     128: invokevirtual #180                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     131: iload         11
     133: invokevirtual #259                // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
     136: invokevirtual #197                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     139: astore        4
     141: aload         5
     143: aload_1
     144: getfield      #252                // Field kotlin/jvm/internal/Ref$IntRef.element:I
     147: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     150: iload         12
     152: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     155: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     158: invokeinterface #260,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     163: pop
     164: goto          213
     167: aload         4
     169: ldc           #237                // String
     171: invokestatic  #264                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     174: ifne          213
     177: aload_0
     178: aload         4
     180: invokestatic  #268                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     183: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     186: aload         5
     188: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     191: invokeinterface #260,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     196: pop
     197: ldc           #237                // String
     199: astore        4
     201: new           #64                 // class java/util/ArrayList
     204: dup
     205: invokespecial #68                 // Method java/util/ArrayList."<init>":()V
     208: checkcast     #95                 // class java/util/List
     211: astore        5
     213: nop
     214: nop
     215: iinc          9, 1
     218: goto          43
     221: nop
     222: aload         4
     224: ldc           #237                // String
     226: invokestatic  #264                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     229: ifne          268
     232: aload_0
     233: aload         4
     235: invokestatic  #268                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     238: invokestatic  #48                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     241: aload         5
     243: invokestatic  #54                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     246: invokeinterface #260,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     251: pop
     252: ldc           #237                // String
     254: astore        4
     256: new           #64                 // class java/util/ArrayList
     259: dup
     260: invokespecial #68                 // Method java/util/ArrayList."<init>":()V
     263: checkcast     #95                 // class java/util/List
     266: astore        5
     268: aload_1
     269: aload_1
     270: getfield      #252                // Field kotlin/jvm/internal/Ref$IntRef.element:I
     273: iconst_1
     274: iadd
     275: putfield      #252                // Field kotlin/jvm/internal/Ref$IntRef.element:I
     278: aload_1
     279: getfield      #252                // Field kotlin/jvm/internal/Ref$IntRef.element:I
     282: pop
     283: getstatic     #274                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
     286: areturn
}


package com.nickperov.stud.combinatorics

import java.math.BigInteger

object CombinatorialUtils {

    /**
     * Number of ordered samples of size m, without replacement, from n objects.
     */
    fun calculateNumberOfVariationsInt(n: Int, m: Int): Int {
        val number = calculateNumberOfVariations(n, m)
        if (number > BigInteger.valueOf(Int.MAX_VALUE.toLong())) {
            throw IllegalArgumentException("Value is too big")
        } else {
            return number.toInt()
        }
    }

    /**
     * Number of ordered samples of size m, without replacement, from n objects.
     */
    fun calculateNumberOfVariationsLong(n: Int, m: Int): Long {
        val number = calculateNumberOfVariations(n, m)
        if (number > BigInteger.valueOf(Long.MAX_VALUE)) {
            throw IllegalArgumentException("Value is too big")
        } else {
            return number.toLong()
        }
    }

    private fun calculateNumberOfVariations(n: Int, m: Int): BigInteger {
        val numerator = factorial(n)
        val denominator = factorial(n - m)
        return numerator.divide(denominator)
    }

    fun calculateNumberOfPermutationsInt(n: Int): Int {
        val f = factorial(n)
        if (f > BigInteger.valueOf(Int.MAX_VALUE.toLong())) {
            throw IllegalArgumentException("Value is too big")
        } else {
            return f.toInt()
        }
    }

    fun calculateNumberOfPermutationsLong(n: Int): Long {
        val f = factorial(n)
        if (f > BigInteger.valueOf(Long.MAX_VALUE)) {
            throw IllegalArgumentException("Value is too big")
        } else {
            return f.toLong()
        }
    }

    private fun factorial(n: Int): BigInteger {
        var result = BigInteger.ONE
        for (i in 1..n) {
            result = result.multiply(BigInteger.valueOf(i.toLong()))
        }
        return result
    }

    /**
     * Provides all permutations of the elements in the given array.
     * recursive implementation, uses list invariant
     * returns array of arrays
     */
    fun <T> getAllPermutations(elements: Array<T>): Array<List<T>> {
        if (elements.isEmpty()) {
            return arrayOf()
        }

        val result = MutableList(0) { listOf<T>() }
        val used = BooleanArray(elements.size)

        collectAllPermutations(result, used, elements, arrayListOf())

        return result.toTypedArray()
    }

    private fun <T> collectAllPermutations(result: MutableList<List<T>>, used: BooleanArray, elements: Array<T>, selection: MutableList<T>) {
        if (selection.size == elements.size) {
            result.add(selection.toList())
        } else {
            for (i in used.indices) {
                if (!used[i]) {
                    val usedCopy = used.clone()
                    usedCopy[i] = true
                    val selectionCopy = selection.toMutableList()
                    selectionCopy.add(elements[i])
                    collectAllPermutations(result, usedCopy, elements, selectionCopy)
                }
            }
        }
    }

    data class CombinationsInvariant<T>(val value: Array<List<T>>, var index: Int) {

        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as CombinationsInvariant<*>

            if (!value.contentEquals(other.value)) return false
            if (index != other.index) return false

            return true
        }

        override fun hashCode(): Int {
            var result = value.contentHashCode()
            result = 31 * result + index
            return result
        }
    }
}

Compiled from "CombinatorialUtils.kt"
public final class com.nickperov.stud.combinatorics.CombinatorialUtils$CombinationsInvariant<T> {
  private final java.util.List<T>[] value;

  private int index;

  public com.nickperov.stud.combinatorics.CombinatorialUtils$CombinationsInvariant(java.util.List<T>[], int);
    Code:
       0: aload_1
       1: ldc           #11                 // String value
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokespecial #20                 // Method java/lang/Object."<init>":()V
      10: aload_0
      11: aload_1
      12: putfield      #23                 // Field value:[Ljava/util/List;
      15: aload_0
      16: iload_2
      17: putfield      #27                 // Field index:I
      20: return

  public final java.util.List<T>[] getValue();
    Code:
       0: aload_0
       1: getfield      #23                 // Field value:[Ljava/util/List;
       4: areturn

  public final int getIndex();
    Code:
       0: aload_0
       1: getfield      #27                 // Field index:I
       4: ireturn

  public final void setIndex(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #27                 // Field index:I
       5: return

  public boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: if_acmpne     7
       5: iconst_1
       6: ireturn
       7: aload_0
       8: invokevirtual #44                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      11: aload_1
      12: dup
      13: ifnull        22
      16: invokevirtual #44                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      19: goto          24
      22: pop
      23: aconst_null
      24: invokestatic  #48                 // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
      27: ifne          32
      30: iconst_0
      31: ireturn
      32: aload_1
      33: ldc           #50                 // String null cannot be cast to non-null type com.nickperov.stud.combinatorics.CombinatorialUtils.CombinationsInvariant<*>
      35: invokestatic  #53                 // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
      38: aload_1
      39: checkcast     #2                  // class com/nickperov/stud/combinatorics/CombinatorialUtils$CombinationsInvariant
      42: pop
      43: aload_0
      44: getfield      #23                 // Field value:[Ljava/util/List;
      47: aload_1
      48: checkcast     #2                  // class com/nickperov/stud/combinatorics/CombinatorialUtils$CombinationsInvariant
      51: getfield      #23                 // Field value:[Ljava/util/List;
      54: invokestatic  #58                 // Method java/util/Arrays.equals:([Ljava/lang/Object;[Ljava/lang/Object;)Z
      57: ifne          62
      60: iconst_0
      61: ireturn
      62: aload_0
      63: getfield      #27                 // Field index:I
      66: aload_1
      67: checkcast     #2                  // class com/nickperov/stud/combinatorics/CombinatorialUtils$CombinationsInvariant
      70: getfield      #27                 // Field index:I
      73: if_icmpeq     78
      76: iconst_0
      77: ireturn
      78: iconst_1
      79: ireturn

  public int hashCode();
    Code:
       0: aload_0
       1: getfield      #23                 // Field value:[Ljava/util/List;
       4: invokestatic  #66                 // Method java/util/Arrays.hashCode:([Ljava/lang/Object;)I
       7: istore_1
       8: bipush        31
      10: iload_1
      11: imul
      12: aload_0
      13: getfield      #27                 // Field index:I
      16: iadd
      17: istore_1
      18: iload_1
      19: ireturn

  public final java.util.List<T>[] component1();
    Code:
       0: aload_0
       1: getfield      #23                 // Field value:[Ljava/util/List;
       4: areturn

  public final int component2();
    Code:
       0: aload_0
       1: getfield      #27                 // Field index:I
       4: ireturn

  public final com.nickperov.stud.combinatorics.CombinatorialUtils$CombinationsInvariant<T> copy(java.util.List<T>[], int);
    Code:
       0: aload_1
       1: ldc           #11                 // String value
       3: invokestatic  #17                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #2                  // class com/nickperov/stud/combinatorics/CombinatorialUtils$CombinationsInvariant
       9: dup
      10: aload_1
      11: iload_2
      12: invokespecial #74                 // Method "<init>":([Ljava/util/List;I)V
      15: areturn

  public static com.nickperov.stud.combinatorics.CombinatorialUtils$CombinationsInvariant copy$default(com.nickperov.stud.combinatorics.CombinatorialUtils$CombinationsInvariant, java.util.List[], int, int, java.lang.Object);
    Code:
       0: iload_3
       1: iconst_1
       2: iand
       3: ifeq          11
       6: aload_0
       7: getfield      #23                 // Field value:[Ljava/util/List;
      10: astore_1
      11: iload_3
      12: iconst_2
      13: iand
      14: ifeq          22
      17: aload_0
      18: getfield      #27                 // Field index:I
      21: istore_2
      22: aload_0
      23: aload_1
      24: iload_2
      25: invokevirtual #78                 // Method copy:([Ljava/util/List;I)Lcom/nickperov/stud/combinatorics/CombinatorialUtils$CombinationsInvariant;
      28: areturn

  public java.lang.String toString();
    Code:
       0: new           #82                 // class java/lang/StringBuilder
       3: dup
       4: invokespecial #83                 // Method java/lang/StringBuilder."<init>":()V
       7: ldc           #85                 // String CombinationsInvariant(value=
       9: invokevirtual #89                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      12: aload_0
      13: getfield      #23                 // Field value:[Ljava/util/List;
      16: invokestatic  #92                 // Method java/util/Arrays.toString:([Ljava/lang/Object;)Ljava/lang/String;
      19: invokevirtual #89                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: ldc           #94                 // String , index=
      24: invokevirtual #89                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: aload_0
      28: getfield      #27                 // Field index:I
      31: invokevirtual #97                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      34: bipush        41
      36: invokevirtual #100                // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      39: invokevirtual #102                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      42: areturn
}

Compiled from "CombinatorialUtils.kt"
public final class com.nickperov.stud.combinatorics.CombinatorialUtils {
  public static final com.nickperov.stud.combinatorics.CombinatorialUtils INSTANCE;

  private com.nickperov.stud.combinatorics.CombinatorialUtils();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final int calculateNumberOfVariationsInt(int, int);
    Code:
       0: aload_0
       1: iload_1
       2: iload_2
       3: invokespecial #16                 // Method calculateNumberOfVariations:(II)Ljava/math/BigInteger;
       6: astore_3
       7: aload_3
       8: ldc2_w        #17                 // long 2147483647l
      11: invokestatic  #24                 // Method java/math/BigInteger.valueOf:(J)Ljava/math/BigInteger;
      14: invokevirtual #28                 // Method java/math/BigInteger.compareTo:(Ljava/math/BigInteger;)I
      17: ifle          30
      20: new           #30                 // class java/lang/IllegalArgumentException
      23: dup
      24: ldc           #32                 // String Value is too big
      26: invokespecial #35                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
      29: athrow
      30: aload_3
      31: invokevirtual #39                 // Method java/math/BigInteger.intValue:()I
      34: ireturn

  public final long calculateNumberOfVariationsLong(int, int);
    Code:
       0: aload_0
       1: iload_1
       2: iload_2
       3: invokespecial #16                 // Method calculateNumberOfVariations:(II)Ljava/math/BigInteger;
       6: astore_3
       7: aload_3
       8: ldc2_w        #47                 // long 9223372036854775807l
      11: invokestatic  #24                 // Method java/math/BigInteger.valueOf:(J)Ljava/math/BigInteger;
      14: invokevirtual #28                 // Method java/math/BigInteger.compareTo:(Ljava/math/BigInteger;)I
      17: ifle          30
      20: new           #30                 // class java/lang/IllegalArgumentException
      23: dup
      24: ldc           #32                 // String Value is too big
      26: invokespecial #35                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
      29: athrow
      30: aload_3
      31: invokevirtual #52                 // Method java/math/BigInteger.longValue:()J
      34: lreturn

  private final java.math.BigInteger calculateNumberOfVariations(int, int);
    Code:
       0: aload_0
       1: iload_1
       2: invokespecial #56                 // Method factorial:(I)Ljava/math/BigInteger;
       5: astore_3
       6: aload_0
       7: iload_1
       8: iload_2
       9: isub
      10: invokespecial #56                 // Method factorial:(I)Ljava/math/BigInteger;
      13: astore        4
      15: aload_3
      16: aload         4
      18: invokevirtual #60                 // Method java/math/BigInteger.divide:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
      21: dup
      22: ldc           #62                 // String divide(...)
      24: invokestatic  #68                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      27: areturn

  public final int calculateNumberOfPermutationsInt(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokespecial #56                 // Method factorial:(I)Ljava/math/BigInteger;
       5: astore_2
       6: aload_2
       7: ldc2_w        #17                 // long 2147483647l
      10: invokestatic  #24                 // Method java/math/BigInteger.valueOf:(J)Ljava/math/BigInteger;
      13: invokevirtual #28                 // Method java/math/BigInteger.compareTo:(Ljava/math/BigInteger;)I
      16: ifle          29
      19: new           #30                 // class java/lang/IllegalArgumentException
      22: dup
      23: ldc           #32                 // String Value is too big
      25: invokespecial #35                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
      28: athrow
      29: aload_2
      30: invokevirtual #39                 // Method java/math/BigInteger.intValue:()I
      33: ireturn

  public final long calculateNumberOfPermutationsLong(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokespecial #56                 // Method factorial:(I)Ljava/math/BigInteger;
       5: astore_2
       6: aload_2
       7: ldc2_w        #47                 // long 9223372036854775807l
      10: invokestatic  #24                 // Method java/math/BigInteger.valueOf:(J)Ljava/math/BigInteger;
      13: invokevirtual #28                 // Method java/math/BigInteger.compareTo:(Ljava/math/BigInteger;)I
      16: ifle          29
      19: new           #30                 // class java/lang/IllegalArgumentException
      22: dup
      23: ldc           #32                 // String Value is too big
      25: invokespecial #35                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
      28: athrow
      29: aload_2
      30: invokevirtual #52                 // Method java/math/BigInteger.longValue:()J
      33: lreturn

  private final java.math.BigInteger factorial(int);
    Code:
       0: getstatic     #78                 // Field java/math/BigInteger.ONE:Ljava/math/BigInteger;
       3: astore_2
       4: iconst_1
       5: istore_3
       6: iload_3
       7: iload_1
       8: if_icmpgt     32
      11: aload_2
      12: iload_3
      13: i2l
      14: invokestatic  #24                 // Method java/math/BigInteger.valueOf:(J)Ljava/math/BigInteger;
      17: invokevirtual #81                 // Method java/math/BigInteger.multiply:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
      20: astore_2
      21: iload_3
      22: iload_1
      23: if_icmpeq     32
      26: iinc          3, 1
      29: goto          11
      32: aload_2
      33: astore_3
      34: aload_3
      35: invokestatic  #85                 // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
      38: aload_3
      39: areturn

  public final <T> java.util.List<T>[] getAllPermutations(T[]);
    Code:
       0: aload_1
       1: ldc           #93                 // String elements
       3: invokestatic  #96                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: arraylength
       8: ifne          15
      11: iconst_1
      12: goto          16
      15: iconst_0
      16: ifeq          24
      19: iconst_0
      20: anewarray     #98                 // class java/util/List
      23: areturn
      24: iconst_0
      25: istore_3
      26: new           #100                // class java/util/ArrayList
      29: dup
      30: iload_3
      31: invokespecial #103                // Method java/util/ArrayList."<init>":(I)V
      34: astore        4
      36: iconst_0
      37: istore        5
      39: iload         5
      41: ifge          76
      44: iload         5
      46: istore        6
      48: aload         4
      50: iload         6
      52: istore        7
      54: astore        9
      56: iconst_0
      57: istore        8
      59: invokestatic  #109                // Method kotlin/collections/CollectionsKt.emptyList:()Ljava/util/List;
      62: nop
      63: aload         9
      65: swap
      66: invokevirtual #113                // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      69: pop
      70: iinc          5, 1
      73: goto          39
      76: aload         4
      78: checkcast     #98                 // class java/util/List
      81: astore_2
      82: aload_1
      83: arraylength
      84: newarray       boolean
      86: astore_3
      87: aload_0
      88: aload_2
      89: aload_3
      90: aload_1
      91: new           #100                // class java/util/ArrayList
      94: dup
      95: invokespecial #114                // Method java/util/ArrayList."<init>":()V
      98: checkcast     #98                 // class java/util/List
     101: invokespecial #118                // Method collectAllPermutations:(Ljava/util/List;[Z[Ljava/lang/Object;Ljava/util/List;)V
     104: aload_2
     105: checkcast     #120                // class java/util/Collection
     108: astore        4
     110: iconst_0
     111: istore        5
     113: aload         4
     115: astore        6
     117: aload         6
     119: iconst_0
     120: anewarray     #98                 // class java/util/List
     123: invokeinterface #124,  2          // InterfaceMethod java/util/Collection.toArray:([Ljava/lang/Object;)[Ljava/lang/Object;
     128: checkcast     #126                // class "[Ljava/util/List;"
     131: areturn

  private final <T> void collectAllPermutations(java.util.List<java.util.List<T>>, boolean[], T[], java.util.List<T>);
    Code:
       0: aload         4
       2: invokeinterface #141,  1          // InterfaceMethod java/util/List.size:()I
       7: aload_3
       8: arraylength
       9: if_icmpne     30
      12: aload_1
      13: aload         4
      15: checkcast     #143                // class java/lang/Iterable
      18: invokestatic  #147                // Method kotlin/collections/CollectionsKt.toList:(Ljava/lang/Iterable;)Ljava/util/List;
      21: invokeinterface #148,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      26: pop
      27: goto          104
      30: iconst_0
      31: istore        5
      33: aload_2
      34: arraylength
      35: istore        6
      37: iload         5
      39: iload         6
      41: if_icmpge     104
      44: aload_2
      45: iload         5
      47: baload
      48: ifne          98
      51: aload_2
      52: invokevirtual #152                // Method java/lang/Object.clone:()Ljava/lang/Object;
      55: checkcast     #153                // class "[Z"
      58: astore        7
      60: aload         7
      62: iload         5
      64: iconst_1
      65: bastore
      66: aload         4
      68: checkcast     #120                // class java/util/Collection
      71: invokestatic  #157                // Method kotlin/collections/CollectionsKt.toMutableList:(Ljava/util/Collection;)Ljava/util/List;
      74: astore        8
      76: aload         8
      78: aload_3
      79: iload         5
      81: aaload
      82: invokeinterface #148,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      87: pop
      88: aload_0
      89: aload_1
      90: aload         7
      92: aload_3
      93: aload         8
      95: invokespecial #118                // Method collectAllPermutations:(Ljava/util/List;[Z[Ljava/lang/Object;Ljava/util/List;)V
      98: iinc          5, 1
     101: goto          37
     104: return

  static {};
    Code:
       0: new           #2                  // class com/nickperov/stud/combinatorics/CombinatorialUtils
       3: dup
       4: invokespecial #162                // Method "<init>":()V
       7: putstatic     #165                // Field INSTANCE:Lcom/nickperov/stud/combinatorics/CombinatorialUtils;
      10: return
}


package com.nickperov.stud.algorithms.knapsack

import kotlin.random.Random

data class KnapSack(val weightLimit: Int)

data class Item(val weight: Int, val price: Int)

data class ProblemParameters(val knapSackSize: Int, val itemListSize: Int, val itemWeightLimit: Int, val itemPriceLimit: Int)

data class Problem(val knapSack: KnapSack, val items: List<Item>)

// Default values
const val knapsackDefaultSize = 100
const val itemListDefaultSize = 50
const val itemWeightDefaultLimit = 10
const val itemPriceDefaultLimit = 20

fun main(args: Array<String>) {

    val problem = initProblemFromArgs(args)
    printItems(problem.items)
}

private fun initProblemFromArgs(args: Array<String>): Problem {
    println("Init from command line arguments")
    val (knapsackSize, itemListSize, itemWeightLimit, itemPriceLimit) = initParameters(args)
    println("Knapsack size: $knapsackSize; product list size: $itemListSize; product limits: (weight: $itemWeightLimit, price: $itemPriceLimit)")

    val knapSack = KnapSack(knapsackSize)
    val items = initItems(itemListSize, itemWeightLimit, itemPriceLimit)

    return Problem(knapSack, items)
}

private fun initParameters(args: Array<String>): ProblemParameters {
    return if (args.isNotEmpty()) {
        if (args.size != 4)
            throw RuntimeException("Wrong number of arguments")

        ProblemParameters(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt())
    } else {
        println("Command line arguments are empty, use default values")
        ProblemParameters(knapsackDefaultSize, itemListDefaultSize, itemWeightDefaultLimit, itemPriceDefaultLimit)
    }
}

private fun printItems(items: List<Item>) {
    val itemPrintFormat = "%5s %10s %10s"
    println("Items list")
    println("----------------------------------------------")
    print("|")
    println(itemPrintFormat.format("Number", "Weight", "Price"))
    println("----------------------------------------------")
    items.forEachIndexed { index, item -> print("|"); println(itemPrintFormat.format(index, item.weight, item.price)) }
}

private fun initItems(number: Int, weightLimit: Int, priceLimit: Int): List<Item> {
    return generateSequence(0) { i -> i + 1 }.take(number).map { initItem(weightLimit, priceLimit) }.toList()
}

private fun initItem(weightLimit: Int, priceLimit: Int) = Item(Random.nextInt(weightLimit) + 1, Random.nextInt(priceLimit) + 1)

Compiled from "KnapSackProblem.kt"
public final class com.nickperov.stud.algorithms.knapsack.KnapSackProblemKt {
  public static final int knapsackDefaultSize;

  public static final int itemListDefaultSize;

  public static final int itemWeightDefaultLimit;

  public static final int itemPriceDefaultLimit;

  public static final void main(java.lang.String[]);
    Code:
       0: aload_0
       1: ldc           #9                  // String args
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokestatic  #19                 // Method initProblemFromArgs:([Ljava/lang/String;)Lcom/nickperov/stud/algorithms/knapsack/Problem;
      10: astore_1
      11: aload_1
      12: invokevirtual #25                 // Method com/nickperov/stud/algorithms/knapsack/Problem.getItems:()Ljava/util/List;
      15: invokestatic  #29                 // Method printItems:(Ljava/util/List;)V
      18: return

  private static final com.nickperov.stud.algorithms.knapsack.Problem initProblemFromArgs(java.lang.String[]);
    Code:
       0: ldc           #34                 // String Init from command line arguments
       2: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
       5: swap
       6: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       9: aload_0
      10: invokestatic  #50                 // Method initParameters:([Ljava/lang/String;)Lcom/nickperov/stud/algorithms/knapsack/ProblemParameters;
      13: astore_1
      14: aload_1
      15: invokevirtual #56                 // Method com/nickperov/stud/algorithms/knapsack/ProblemParameters.component1:()I
      18: istore_2
      19: aload_1
      20: invokevirtual #59                 // Method com/nickperov/stud/algorithms/knapsack/ProblemParameters.component2:()I
      23: istore_3
      24: aload_1
      25: invokevirtual #62                 // Method com/nickperov/stud/algorithms/knapsack/ProblemParameters.component3:()I
      28: istore        4
      30: aload_1
      31: invokevirtual #65                 // Method com/nickperov/stud/algorithms/knapsack/ProblemParameters.component4:()I
      34: istore        5
      36: new           #67                 // class java/lang/StringBuilder
      39: dup
      40: invokespecial #71                 // Method java/lang/StringBuilder."<init>":()V
      43: ldc           #73                 // String Knapsack size:
      45: invokevirtual #77                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      48: iload_2
      49: invokevirtual #80                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      52: ldc           #82                 // String ; product list size:
      54: invokevirtual #77                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      57: iload_3
      58: invokevirtual #80                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      61: ldc           #84                 // String ; product limits: (weight:
      63: invokevirtual #77                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      66: iload         4
      68: invokevirtual #80                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      71: ldc           #86                 // String , price:
      73: invokevirtual #77                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      76: iload         5
      78: invokevirtual #80                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      81: bipush        41
      83: invokevirtual #89                 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      86: invokevirtual #93                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      89: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
      92: swap
      93: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      96: new           #95                 // class com/nickperov/stud/algorithms/knapsack/KnapSack
      99: dup
     100: iload_2
     101: invokespecial #98                 // Method com/nickperov/stud/algorithms/knapsack/KnapSack."<init>":(I)V
     104: astore        6
     106: iload_3
     107: iload         4
     109: iload         5
     111: invokestatic  #102                // Method initItems:(III)Ljava/util/List;
     114: astore        7
     116: new           #21                 // class com/nickperov/stud/algorithms/knapsack/Problem
     119: dup
     120: aload         6
     122: aload         7
     124: invokespecial #105                // Method com/nickperov/stud/algorithms/knapsack/Problem."<init>":(Lcom/nickperov/stud/algorithms/knapsack/KnapSack;Ljava/util/List;)V
     127: areturn

  private static final com.nickperov.stud.algorithms.knapsack.ProblemParameters initParameters(java.lang.String[]);
    Code:
       0: aload_0
       1: arraylength
       2: ifne          9
       5: iconst_1
       6: goto          10
       9: iconst_0
      10: ifne          17
      13: iconst_1
      14: goto          18
      17: iconst_0
      18: ifeq          71
      21: aload_0
      22: arraylength
      23: iconst_4
      24: if_icmpeq     37
      27: new           #116                // class java/lang/RuntimeException
      30: dup
      31: ldc           #118                // String Wrong number of arguments
      33: invokespecial #121                // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
      36: athrow
      37: new           #52                 // class com/nickperov/stud/algorithms/knapsack/ProblemParameters
      40: dup
      41: aload_0
      42: iconst_0
      43: aaload
      44: invokestatic  #127                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      47: aload_0
      48: iconst_1
      49: aaload
      50: invokestatic  #127                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      53: aload_0
      54: iconst_2
      55: aaload
      56: invokestatic  #127                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      59: aload_0
      60: iconst_3
      61: aaload
      62: invokestatic  #127                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      65: invokespecial #130                // Method com/nickperov/stud/algorithms/knapsack/ProblemParameters."<init>":(IIII)V
      68: goto          95
      71: ldc           #132                // String Command line arguments are empty, use default values
      73: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
      76: swap
      77: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      80: new           #52                 // class com/nickperov/stud/algorithms/knapsack/ProblemParameters
      83: dup
      84: bipush        100
      86: bipush        50
      88: bipush        10
      90: bipush        20
      92: invokespecial #130                // Method com/nickperov/stud/algorithms/knapsack/ProblemParameters."<init>":(IIII)V
      95: areturn

  private static final void printItems(java.util.List<com.nickperov.stud.algorithms.knapsack.Item>);
    Code:
       0: ldc           #135                // String %5s %10s %10s
       2: astore_1
       3: ldc           #137                // String Items list
       5: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
       8: swap
       9: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      12: ldc           #139                // String ----------------------------------------------
      14: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
      17: swap
      18: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      21: ldc           #141                // String |
      23: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
      26: swap
      27: invokevirtual #144                // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
      30: aload_1
      31: astore_2
      32: iconst_3
      33: anewarray     #4                  // class java/lang/Object
      36: astore_3
      37: aload_3
      38: iconst_0
      39: ldc           #146                // String Number
      41: aastore
      42: aload_3
      43: iconst_1
      44: ldc           #148                // String Weight
      46: aastore
      47: aload_3
      48: iconst_2
      49: ldc           #150                // String Price
      51: aastore
      52: aload_3
      53: astore_3
      54: aload_2
      55: aload_3
      56: aload_3
      57: arraylength
      58: invokestatic  #156                // Method java/util/Arrays.copyOf:([Ljava/lang/Object;I)[Ljava/lang/Object;
      61: invokestatic  #162                // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      64: dup
      65: ldc           #164                // String format(...)
      67: invokestatic  #167                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      70: astore_2
      71: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
      74: aload_2
      75: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      78: ldc           #139                // String ----------------------------------------------
      80: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
      83: swap
      84: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      87: aload_0
      88: checkcast     #169                // class java/lang/Iterable
      91: astore_2
      92: iconst_0
      93: istore_3
      94: iconst_0
      95: istore        4
      97: aload_2
      98: invokeinterface #173,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     103: astore        5
     105: aload         5
     107: invokeinterface #179,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     112: ifeq          242
     115: aload         5
     117: invokeinterface #183,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     122: astore        6
     124: iload         4
     126: iinc          4, 1
     129: istore        7
     131: iload         7
     133: ifge          139
     136: invokestatic  #188                // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
     139: iload         7
     141: aload         6
     143: checkcast     #190                // class com/nickperov/stud/algorithms/knapsack/Item
     146: astore        8
     148: istore        9
     150: iconst_0
     151: istore        10
     153: ldc           #141                // String |
     155: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
     158: swap
     159: invokevirtual #144                // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
     162: aload_1
     163: astore        11
     165: iconst_3
     166: anewarray     #4                  // class java/lang/Object
     169: astore        12
     171: aload         12
     173: iconst_0
     174: iload         9
     176: invokestatic  #194                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     179: aastore
     180: aload         12
     182: iconst_1
     183: aload         8
     185: invokevirtual #197                // Method com/nickperov/stud/algorithms/knapsack/Item.getWeight:()I
     188: invokestatic  #194                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     191: aastore
     192: aload         12
     194: iconst_2
     195: aload         8
     197: invokevirtual #200                // Method com/nickperov/stud/algorithms/knapsack/Item.getPrice:()I
     200: invokestatic  #194                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     203: aastore
     204: aload         12
     206: astore        12
     208: aload         11
     210: aload         12
     212: aload         12
     214: arraylength
     215: invokestatic  #156                // Method java/util/Arrays.copyOf:([Ljava/lang/Object;I)[Ljava/lang/Object;
     218: invokestatic  #162                // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
     221: dup
     222: ldc           #164                // String format(...)
     224: invokestatic  #167                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     227: astore        11
     229: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
     232: aload         11
     234: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     237: nop
     238: nop
     239: goto          105
     242: nop
     243: return

  private static final java.util.List<com.nickperov.stud.algorithms.knapsack.Item> initItems(int, int, int);
    Code:
       0: iconst_0
       1: invokestatic  #194                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4: invokedynamic #234,  0            // InvokeDynamic #0:invoke:()Lkotlin/jvm/functions/Function1;
       9: invokestatic  #240                // Method kotlin/sequences/SequencesKt.generateSequence:(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
      12: iload_0
      13: invokestatic  #244                // Method kotlin/sequences/SequencesKt.take:(Lkotlin/sequences/Sequence;I)Lkotlin/sequences/Sequence;
      16: iload_1
      17: iload_2
      18: invokedynamic #254,  0            // InvokeDynamic #1:invoke:(II)Lkotlin/jvm/functions/Function1;
      23: invokestatic  #258                // Method kotlin/sequences/SequencesKt.map:(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
      26: invokestatic  #262                // Method kotlin/sequences/SequencesKt.toList:(Lkotlin/sequences/Sequence;)Ljava/util/List;
      29: areturn

  private static final com.nickperov.stud.algorithms.knapsack.Item initItem(int, int);
    Code:
       0: new           #190                // class com/nickperov/stud/algorithms/knapsack/Item
       3: dup
       4: getstatic     #273                // Field kotlin/random/Random.Default:Lkotlin/random/Random$Default;
       7: iload_0
       8: invokevirtual #279                // Method kotlin/random/Random$Default.nextInt:(I)I
      11: iconst_1
      12: iadd
      13: getstatic     #273                // Field kotlin/random/Random.Default:Lkotlin/random/Random$Default;
      16: iload_1
      17: invokevirtual #279                // Method kotlin/random/Random$Default.nextInt:(I)I
      20: iconst_1
      21: iadd
      22: invokespecial #282                // Method com/nickperov/stud/algorithms/knapsack/Item."<init>":(II)V
      25: areturn

  private static final java.lang.Integer initItems$lambda$1(int);
    Code:
       0: iload_0
       1: iconst_1
       2: iadd
       3: invokestatic  #194                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       6: areturn

  private static final com.nickperov.stud.algorithms.knapsack.Item initItems$lambda$2(int, int, int);
    Code:
       0: iload_0
       1: iload_1
       2: invokestatic  #285                // Method initItem:(II)Lcom/nickperov/stud/algorithms/knapsack/Item;
       5: areturn
}


package com.nickperov.stud.algorithms.montyhall

import kotlin.random.Random

enum class Prize {
    GOAT, CAR
}

enum class Strategy {
    KEEP, CHANGE, GUESS
}

object MontyHallApp {
    @JvmStatic
    fun main(args: Array<String>) {
        println("Simulate monty hall game with different strategies")
        val rounds = generateRounds(1_000_000)
        /*println(rounds.contentDeepToString())*/
        Strategy.values().forEach { strategy ->
            val percentageWins = play(rounds, strategy)
            println("Strategy %{strategy.name} wins:$percentageWins%")
        }
    }
}

private fun play(rounds: Array<Array<Prize>>, strategy: Strategy): Double {
    val result = rounds.map { play(it, strategy) }.toTypedArray()
    val totalWins = result.filter { it }.count()
    return (totalWins / (rounds.size / 100).toDouble()).toDouble()
}

private fun play(round: Array<Prize>, strategy: Strategy): Boolean {
    val firstTry = Random.nextInt(3)
    val openedDoor = openDoor(round, firstTry)
    val secondTry = makeSecondTry(firstTry, openedDoor, strategy)
    return round[secondTry] == Prize.CAR
}

private fun makeSecondTry(firstTry: Int, openedDoor: Int, strategy: Strategy): Int {
    return when (strategy) {
        Strategy.KEEP -> firstTry
        Strategy.CHANGE -> nextDoor(firstTry, openedDoor)
        Strategy.GUESS -> if (Random.nextBoolean()) nextDoor(firstTry, openedDoor) else firstTry
    }
}

private fun nextDoor(currentDoor: Int, openedDoor: Int): Int {
    for (i in 0..2) {
        if (i != currentDoor && i != openedDoor) {
            return i;
        }
    }
    throw RuntimeException("Fatal error")
}

private fun openDoor(round: Array<Prize>, firstTry: Int): Int {
    round.forEachIndexed { index, prize ->
        if (index != firstTry && prize == Prize.GOAT) {
            return index
        }
    }
    throw RuntimeException("Fatal error")
}

private fun generateRounds(size: Int): Array<Array<Prize>> {
    return Array(size) { generateRound() }
}

private fun generateRound(): Array<Prize> {
    return when (Random.nextInt(3)) {
        0 -> {
            arrayOf(Prize.CAR, Prize.GOAT, Prize.GOAT)
        }
        1 -> {
            arrayOf(Prize.GOAT, Prize.CAR, Prize.GOAT)
        }
        else -> {
            arrayOf(Prize.GOAT, Prize.GOAT, Prize.CAR)
        }
    }
}

Compiled from "MontyHallSimulator.kt"
public final class com.nickperov.stud.algorithms.montyhall.MontyHallSimulatorKt$WhenMappings {
  public static final int[] $EnumSwitchMapping$0;

  static {};
    Code:
       0: invokestatic  #14                 // Method com/nickperov/stud/algorithms/montyhall/Strategy.values:()[Lcom/nickperov/stud/algorithms/montyhall/Strategy;
       3: arraylength
       4: newarray       int
       6: astore_0
       7: nop
       8: aload_0
       9: getstatic     #18                 // Field com/nickperov/stud/algorithms/montyhall/Strategy.KEEP:Lcom/nickperov/stud/algorithms/montyhall/Strategy;
      12: invokevirtual #22                 // Method com/nickperov/stud/algorithms/montyhall/Strategy.ordinal:()I
      15: iconst_1
      16: iastore
      17: goto          21
      20: astore_1
      21: nop
      22: aload_0
      23: getstatic     #25                 // Field com/nickperov/stud/algorithms/montyhall/Strategy.CHANGE:Lcom/nickperov/stud/algorithms/montyhall/Strategy;
      26: invokevirtual #22                 // Method com/nickperov/stud/algorithms/montyhall/Strategy.ordinal:()I
      29: iconst_2
      30: iastore
      31: goto          35
      34: astore_1
      35: nop
      36: aload_0
      37: getstatic     #28                 // Field com/nickperov/stud/algorithms/montyhall/Strategy.GUESS:Lcom/nickperov/stud/algorithms/montyhall/Strategy;
      40: invokevirtual #22                 // Method com/nickperov/stud/algorithms/montyhall/Strategy.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
}

Compiled from "MontyHallSimulator.kt"
public final class com.nickperov.stud.algorithms.montyhall.MontyHallSimulatorKt {
  private static final double play(com.nickperov.stud.algorithms.montyhall.Prize[][], com.nickperov.stud.algorithms.montyhall.Strategy);
    Code:
       0: aload_0
       1: checkcast     #8                  // class "[Ljava/lang/Object;"
       4: astore_3
       5: iconst_0
       6: istore        4
       8: aload_3
       9: astore        5
      11: new           #10                 // class java/util/ArrayList
      14: dup
      15: aload_3
      16: arraylength
      17: invokespecial #14                 // Method java/util/ArrayList."<init>":(I)V
      20: checkcast     #16                 // class java/util/Collection
      23: astore        6
      25: iconst_0
      26: istore        7
      28: iconst_0
      29: istore        8
      31: aload         5
      33: arraylength
      34: istore        9
      36: iload         8
      38: iload         9
      40: if_icmpge     88
      43: aload         5
      45: iload         8
      47: aaload
      48: astore        10
      50: aload         6
      52: aload         10
      54: checkcast     #18                 // class "[Lcom/nickperov/stud/algorithms/montyhall/Prize;"
      57: astore        11
      59: astore        14
      61: iconst_0
      62: istore        12
      64: aload         11
      66: aload_1
      67: invokestatic  #21                 // Method play:([Lcom/nickperov/stud/algorithms/montyhall/Prize;Lcom/nickperov/stud/algorithms/montyhall/Strategy;)Z
      70: invokestatic  #27                 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
      73: aload         14
      75: swap
      76: invokeinterface #31,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
      81: pop
      82: iinc          8, 1
      85: goto          36
      88: aload         6
      90: checkcast     #33                 // class java/util/List
      93: nop
      94: checkcast     #16                 // class java/util/Collection
      97: astore_3
      98: nop
      99: iconst_0
     100: istore        4
     102: aload_3
     103: astore        5
     105: aload         5
     107: iconst_0
     108: anewarray     #23                 // class java/lang/Boolean
     111: invokeinterface #37,  2           // InterfaceMethod java/util/Collection.toArray:([Ljava/lang/Object;)[Ljava/lang/Object;
     116: checkcast     #39                 // class "[Ljava/lang/Boolean;"
     119: astore_2
     120: aload_2
     121: astore        4
     123: iconst_0
     124: istore        5
     126: aload         4
     128: astore        6
     130: new           #10                 // class java/util/ArrayList
     133: dup
     134: invokespecial #42                 // Method java/util/ArrayList."<init>":()V
     137: checkcast     #16                 // class java/util/Collection
     140: astore        7
     142: iconst_0
     143: istore        8
     145: iconst_0
     146: istore        9
     148: aload         6
     150: arraylength
     151: istore        10
     153: iload         9
     155: iload         10
     157: if_icmpge     198
     160: aload         6
     162: iload         9
     164: aaload
     165: astore        11
     167: aload         11
     169: invokevirtual #46                 // Method java/lang/Boolean.booleanValue:()Z
     172: istore        12
     174: iconst_0
     175: istore        13
     177: iload         12
     179: ifeq          192
     182: aload         7
     184: aload         11
     186: invokeinterface #31,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     191: pop
     192: iinc          9, 1
     195: goto          153
     198: aload         7
     200: checkcast     #33                 // class java/util/List
     203: nop
     204: checkcast     #16                 // class java/util/Collection
     207: invokeinterface #50,  1           // InterfaceMethod java/util/Collection.size:()I
     212: istore_3
     213: iload_3
     214: i2d
     215: aload_0
     216: checkcast     #8                  // class "[Ljava/lang/Object;"
     219: arraylength
     220: bipush        100
     222: idiv
     223: i2d
     224: ddiv
     225: dreturn

  private static final boolean play(com.nickperov.stud.algorithms.montyhall.Prize[], com.nickperov.stud.algorithms.montyhall.Strategy);
    Code:
       0: getstatic     #86                 // Field kotlin/random/Random.Default:Lkotlin/random/Random$Default;
       3: iconst_3
       4: invokevirtual #92                 // Method kotlin/random/Random$Default.nextInt:(I)I
       7: istore_2
       8: aload_0
       9: iload_2
      10: invokestatic  #96                 // Method openDoor:([Lcom/nickperov/stud/algorithms/montyhall/Prize;I)I
      13: istore_3
      14: iload_2
      15: iload_3
      16: aload_1
      17: invokestatic  #100                // Method makeSecondTry:(IILcom/nickperov/stud/algorithms/montyhall/Strategy;)I
      20: istore        4
      22: aload_0
      23: iload         4
      25: aaload
      26: getstatic     #106                // Field com/nickperov/stud/algorithms/montyhall/Prize.CAR:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      29: if_acmpne     36
      32: iconst_1
      33: goto          37
      36: iconst_0
      37: ireturn

  private static final int makeSecondTry(int, int, com.nickperov.stud.algorithms.montyhall.Strategy);
    Code:
       0: aload_2
       1: getstatic     #116                // Field com/nickperov/stud/algorithms/montyhall/MontyHallSimulatorKt$WhenMappings.$EnumSwitchMapping$0:[I
       4: swap
       5: invokevirtual #119                // Method com/nickperov/stud/algorithms/montyhall/Strategy.ordinal:()I
       8: iaload
       9: tableswitch   { // 1 to 3
                     1: 36
                     2: 40
                     3: 48
               default: 69
          }
      36: iload_0
      37: goto          77
      40: iload_0
      41: iload_1
      42: invokestatic  #123                // Method nextDoor:(II)I
      45: goto          77
      48: getstatic     #86                 // Field kotlin/random/Random.Default:Lkotlin/random/Random$Default;
      51: invokevirtual #126                // Method kotlin/random/Random$Default.nextBoolean:()Z
      54: ifeq          65
      57: iload_0
      58: iload_1
      59: invokestatic  #123                // Method nextDoor:(II)I
      62: goto          77
      65: iload_0
      66: goto          77
      69: new           #128                // class kotlin/NoWhenBranchMatchedException
      72: dup
      73: invokespecial #129                // Method kotlin/NoWhenBranchMatchedException."<init>":()V
      76: athrow
      77: ireturn

  private static final int nextDoor(int, int);
    Code:
       0: iconst_0
       1: istore_2
       2: iload_2
       3: iconst_3
       4: if_icmpge     25
       7: iload_2
       8: iload_0
       9: if_icmpeq     19
      12: iload_2
      13: iload_1
      14: if_icmpeq     19
      17: iload_2
      18: ireturn
      19: iinc          2, 1
      22: goto          2
      25: new           #131                // class java/lang/RuntimeException
      28: dup
      29: ldc           #133                // String Fatal error
      31: invokespecial #136                // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
      34: athrow

  private static final int openDoor(com.nickperov.stud.algorithms.montyhall.Prize[], int);
    Code:
       0: aload_0
       1: astore_2
       2: iconst_0
       3: istore_3
       4: iconst_0
       5: istore        4
       7: iconst_0
       8: istore        5
      10: aload_2
      11: arraylength
      12: istore        6
      14: iload         5
      16: iload         6
      18: if_icmpge     66
      21: aload_2
      22: iload         5
      24: aaload
      25: astore        7
      27: iload         4
      29: iinc          4, 1
      32: aload         7
      34: astore        8
      36: istore        9
      38: iconst_0
      39: istore        10
      41: iload         9
      43: iload_1
      44: if_icmpeq     58
      47: aload         8
      49: getstatic     #141                // Field com/nickperov/stud/algorithms/montyhall/Prize.GOAT:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      52: if_acmpne     58
      55: iload         9
      57: ireturn
      58: nop
      59: nop
      60: iinc          5, 1
      63: goto          14
      66: nop
      67: new           #131                // class java/lang/RuntimeException
      70: dup
      71: ldc           #133                // String Fatal error
      73: invokespecial #136                // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
      76: athrow

  private static final com.nickperov.stud.algorithms.montyhall.Prize[][] generateRounds(int);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_0
       3: anewarray     #18                 // class "[Lcom/nickperov/stud/algorithms/montyhall/Prize;"
       6: astore_2
       7: iload_1
       8: iload_0
       9: if_icmpge     26
      12: iload_1
      13: istore_3
      14: aload_2
      15: iload_3
      16: invokestatic  #154                // Method generateRound:()[Lcom/nickperov/stud/algorithms/montyhall/Prize;
      19: aastore
      20: iinc          1, 1
      23: goto          7
      26: aload_2
      27: areturn

  private static final com.nickperov.stud.algorithms.montyhall.Prize[] generateRound();
    Code:
       0: getstatic     #86                 // Field kotlin/random/Random.Default:Lkotlin/random/Random$Default;
       3: iconst_3
       4: invokevirtual #92                 // Method kotlin/random/Random$Default.nextInt:(I)I
       7: tableswitch   { // 0 to 1
                     0: 28
                     1: 55
               default: 82
          }
      28: iconst_3
      29: anewarray     #102                // class com/nickperov/stud/algorithms/montyhall/Prize
      32: astore_0
      33: aload_0
      34: iconst_0
      35: getstatic     #106                // Field com/nickperov/stud/algorithms/montyhall/Prize.CAR:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      38: aastore
      39: aload_0
      40: iconst_1
      41: getstatic     #141                // Field com/nickperov/stud/algorithms/montyhall/Prize.GOAT:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      44: aastore
      45: aload_0
      46: iconst_2
      47: getstatic     #141                // Field com/nickperov/stud/algorithms/montyhall/Prize.GOAT:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      50: aastore
      51: aload_0
      52: goto          106
      55: iconst_3
      56: anewarray     #102                // class com/nickperov/stud/algorithms/montyhall/Prize
      59: astore_0
      60: aload_0
      61: iconst_0
      62: getstatic     #141                // Field com/nickperov/stud/algorithms/montyhall/Prize.GOAT:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      65: aastore
      66: aload_0
      67: iconst_1
      68: getstatic     #106                // Field com/nickperov/stud/algorithms/montyhall/Prize.CAR:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      71: aastore
      72: aload_0
      73: iconst_2
      74: getstatic     #141                // Field com/nickperov/stud/algorithms/montyhall/Prize.GOAT:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      77: aastore
      78: aload_0
      79: goto          106
      82: iconst_3
      83: anewarray     #102                // class com/nickperov/stud/algorithms/montyhall/Prize
      86: astore_0
      87: aload_0
      88: iconst_0
      89: getstatic     #141                // Field com/nickperov/stud/algorithms/montyhall/Prize.GOAT:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      92: aastore
      93: aload_0
      94: iconst_1
      95: getstatic     #141                // Field com/nickperov/stud/algorithms/montyhall/Prize.GOAT:Lcom/nickperov/stud/algorithms/montyhall/Prize;
      98: aastore
      99: aload_0
     100: iconst_2
     101: getstatic     #106                // Field com/nickperov/stud/algorithms/montyhall/Prize.CAR:Lcom/nickperov/stud/algorithms/montyhall/Prize;
     104: aastore
     105: aload_0
     106: areturn

  public static final com.nickperov.stud.algorithms.montyhall.Prize[][] access$generateRounds(int);
    Code:
       0: iload_0
       1: invokestatic  #157                // Method generateRounds:(I)[[Lcom/nickperov/stud/algorithms/montyhall/Prize;
       4: areturn

  public static final double access$play(com.nickperov.stud.algorithms.montyhall.Prize[][], com.nickperov.stud.algorithms.montyhall.Strategy);
    Code:
       0: aload_0
       1: aload_1
       2: invokestatic  #160                // Method play:([[Lcom/nickperov/stud/algorithms/montyhall/Prize;Lcom/nickperov/stud/algorithms/montyhall/Strategy;)D
       5: dreturn
}


package com.nickperov.stud.algorithms.fibonacci

import java.math.BigInteger

fun main() {
    println("Hello, large Fibonacci numbers")

    println(FibonacciLargeTailRecursiveOptimisedGenerator().calculate(1000000))

    /*for (number in 93..150) {
        println("====================>$number<==================")
        println(FibonacciLargeTailRecursiveOptimisedGenerator().calculate(number))
        println(FibonacciLargeIterativeGenerator02().calculate(number))
        println(FibonacciLargeMatrixGenerator().calculate(number))
    }*/
}

/**
 * Generator to calculate fibonacci number greater than 7540113804746346429 (92nd number)
 */
abstract class FibonacciLargeGenerator {
    abstract fun calculate(number: Int): BigInteger
}

class FibonacciLargeTailRecursiveOptimisedGenerator : FibonacciLargeGenerator() {

    override fun calculate(number: Int): BigInteger {
        return if (number == 0)
            BigInteger.ZERO
        else if (number == 1 || number == 2)
            BigInteger.ONE
        else calculate(BigInteger.ONE, BigInteger.ONE, 3, number)
    }

    private tailrec fun calculate(antePenultimate: BigInteger, penultimate: BigInteger, current: Int, target: Int): BigInteger {
        return if (current == target) antePenultimate.add(penultimate)
        else calculate(penultimate, antePenultimate.add(penultimate), current + 1, target)
    }
}

class FibonacciLargeIterativeGenerator02 : FibonacciLargeGenerator() {
    override fun calculate(number: Int): BigInteger {

        val numberPair = arrayOf(BigInteger.ZERO, BigInteger.ZERO)
        for (i in 0..number) {
            calculate(i, numberPair)
        }

        return numberPair[1]
    }

    private fun calculate(number: Int, prev: Array<BigInteger>) {
        when (number) {
            0 -> {
                prev[1] = BigInteger.ZERO
            }
            1 -> {
                prev[1] = BigInteger.ONE
            }
            2 -> {
                prev[0] = BigInteger.ONE
            }
            else -> {
                val next = prev[0].add(prev[1])
                prev[0] = prev[1]
                prev[1] = next
            }

        }
    }
}

class FibonacciLargeMatrixGenerator : FibonacciLargeGenerator() {
    /**
     *  Matrix:
    | 0 1 |
    | 1 1 |
     */
    private val matrix = arrayOf(arrayOf(BigInteger.ZERO, BigInteger.ONE), arrayOf(BigInteger.ONE, BigInteger.ONE))

    override fun calculate(number: Int): BigInteger {
        if (number == 0 || number == 1) {
            return BigInteger.valueOf(number.toLong())
        } else if (number == 2) {
            return BigInteger.ONE
        } else {
            var currMatrix = matrix
            val power = number - 1

            currMatrix = powerOf(currMatrix, power)

            return currMatrix[1][1]
        }
    }

    private fun powerOf(m: Array<Array<BigInteger>>, n: Int): Array<Array<BigInteger>> {
        return when {
            n == 1 -> {
                m
            }
            n % 2 == 0 -> {
                val mP = powerOf(m, n / 2)
                multiply(mP, mP)
            }
            else -> {
                val mP = powerOf(m, n - 1)
                multiply(mP, m)
            }
        }
    }

    private fun multiply(m1: Array<Array<BigInteger>>, m2: Array<Array<BigInteger>>): Array<Array<BigInteger>> {
        val l = m1.size
        val n = m2.size
        val result = Array(l) { Array(n) { BigInteger.ZERO } }

        for (i in 0 until l) {
            for (k in 0 until n) {
                var sum = BigInteger.ZERO
                for (j in 0 until m1[i].size) {
                    sum = sum.add(m1[i][j].multiply(m2[k][j]))
                }
                result[i][k] = sum
            }
        }

        return result
    }
}

Compiled from "FibonacciLargeGenerator.kt"
public final class com.nickperov.stud.algorithms.fibonacci.FibonacciLargeGeneratorKt {
  public static final void main();
    Code:
       0: ldc           #8                  // String Hello, large Fibonacci numbers
       2: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
       5: swap
       6: invokevirtual #20                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       9: new           #22                 // class com/nickperov/stud/algorithms/fibonacci/FibonacciLargeTailRecursiveOptimisedGenerator
      12: dup
      13: invokespecial #25                 // Method com/nickperov/stud/algorithms/fibonacci/FibonacciLargeTailRecursiveOptimisedGenerator."<init>":()V
      16: ldc           #26                 // int 1000000
      18: invokevirtual #30                 // Method com/nickperov/stud/algorithms/fibonacci/FibonacciLargeTailRecursiveOptimisedGenerator.calculate:(I)Ljava/math/BigInteger;
      21: getstatic     #14                 // Field java/lang/System.out:Ljava/io/PrintStream;
      24: swap
      25: invokevirtual #20                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      28: return

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

Compiled from "FibonacciLargeGenerator.kt"
public abstract class com.nickperov.stud.algorithms.fibonacci.FibonacciLargeGenerator {
  public com.nickperov.stud.algorithms.fibonacci.FibonacciLargeGenerator();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public abstract java.math.BigInteger calculate(int);
}