package dev.achammer.tuwea.core

import kotlin.random.Random

data class StudentCheckmarksEntry(
    val firstName: String,
    val lastName: String,
    val idNumber: String,
    val checkmarks: Set<String>
)

data class ParseConfiguration(
    val csvDelimiter: Char,
    val csvLineOffset: Int,
    val preCheckmarksFieldOffset: Int,
    val firstNameKey: String,
    val lastNameKey: String,
    val idNumberKey: String,
    val exerciseEndSignifierKey: String,
    val checkmarkSignifiers: Set<String>
)

val tuwelParseConfiguration = ParseConfiguration(
    csvDelimiter = ';',
    csvLineOffset = 6,
    preCheckmarksFieldOffset = 3,
    firstNameKey = "Vorname",
    lastNameKey = "Nachname",
    idNumberKey = "ID-Nummer",
    exerciseEndSignifierKey = "Kreuzerl",
    checkmarkSignifiers = setOf("X", "(X)")
)

data class ParseResult(val exercises: List<String>, val studentCheckmarksEntries: List<StudentCheckmarksEntry>)
typealias ExerciseStudentAssignment = List<Pair<String, StudentCheckmarksEntry>>

fun findExerciseAssignment(
    parseResult: ParseResult,
    isStudentPresent: (StudentCheckmarksEntry) -> Boolean
): ExerciseStudentAssignment {
    val exercises = parseResult.exercises
    val entries = parseResult.studentCheckmarksEntries
    return exercises
        .sortedBy { exercise -> entries.count { it.checkmarks.contains(exercise) } }
        .fold(emptyList()) { chosenAssignments, exercise ->
            val potentialEntries = entries
                .filter { it.checkmarks.contains(exercise) }
                .filter { isStudentPresent(it) }
                .filterNot { entry -> chosenAssignments.firstOrNull { it.second == entry } != null }
            if (potentialEntries.isEmpty()) {
                chosenAssignments
            } else {
                chosenAssignments + Pair(exercise, potentialEntries[Random.nextInt(potentialEntries.size)])
            }
        }
}

fun parseCsvContent(parseConfiguration: ParseConfiguration, csvContent: String): ParseResult {
    parseConfiguration.apply {
        val csvLines = csvContent.split("\n")
        val sanitizedCsvLines = csvLines.drop(csvLineOffset)
        val headerRow = sanitizedCsvLines.first()
        val fields = headerRow.split(csvDelimiter)
        val exercises = fields
            .drop(preCheckmarksFieldOffset)
            .takeWhile { s -> s != exerciseEndSignifierKey }
            .map { sanitizeExerciseName(it) }

        val entries = sanitizedCsvLines
            .drop(1)
            .map { line -> fields.zip(line.split(csvDelimiter)).toMap() }
            .map { entry -> parseCsvLine(entry) }
        return ParseResult(exercises, entries)
    }
}

private fun ParseConfiguration.parseCsvLine(entry: Map<String, String>): StudentCheckmarksEntry {
    val checkmarks = entry.keys
        .filterNot { it in setOf(firstNameKey, lastNameKey, idNumberKey) }
        .filter { entry[it] in checkmarkSignifiers }
        .map { sanitizeExerciseName(it) }
        .toSet()
    return StudentCheckmarksEntry(
        firstName = sanitizeFirstName(entry[firstNameKey]!!),
        lastName = entry[lastNameKey]!!,
        idNumber = entry[idNumberKey]!!,
        checkmarks = checkmarks
    )
}

private fun sanitizeExerciseName(exerciseName: String): String = firstWordOf(exerciseName)
private fun sanitizeFirstName(firstName: String): String = firstWordOf(firstName)
private fun firstWordOf(string: String) = string.trim().split(" ").first()

Compiled from "Core.kt"
public final class dev.achammer.tuwea.core.CoreKt {
  private static final dev.achammer.tuwea.core.ParseConfiguration tuwelParseConfiguration;

  public static final dev.achammer.tuwea.core.ParseConfiguration getTuwelParseConfiguration();
    Code:
       0: getstatic     #11                 // Field tuwelParseConfiguration:Ldev/achammer/tuwea/core/ParseConfiguration;
       3: areturn

  public static final java.util.List<kotlin.Pair<java.lang.String, dev.achammer.tuwea.core.StudentCheckmarksEntry>> findExerciseAssignment(dev.achammer.tuwea.core.ParseResult, kotlin.jvm.functions.Function1<? super dev.achammer.tuwea.core.StudentCheckmarksEntry, java.lang.Boolean>);
    Code:
       0: aload_0
       1: ldc           #16                 // String parseResult
       3: invokestatic  #22                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #24                 // String isStudentPresent
       9: invokestatic  #22                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: invokevirtual #30                 // Method dev/achammer/tuwea/core/ParseResult.getExercises:()Ljava/util/List;
      16: astore_2
      17: aload_0
      18: invokevirtual #33                 // Method dev/achammer/tuwea/core/ParseResult.getStudentCheckmarksEntries:()Ljava/util/List;
      21: astore_3
      22: aload_2
      23: checkcast     #35                 // class java/lang/Iterable
      26: astore        4
      28: nop
      29: iconst_0
      30: istore        5
      32: aload         4
      34: new           #37                 // class dev/achammer/tuwea/core/CoreKt$findExerciseAssignment$$inlined$sortedBy$1
      37: dup
      38: aload_3
      39: invokespecial #41                 // Method dev/achammer/tuwea/core/CoreKt$findExerciseAssignment$$inlined$sortedBy$1."<init>":(Ljava/util/List;)V
      42: checkcast     #43                 // class java/util/Comparator
      45: invokestatic  #49                 // Method kotlin/collections/CollectionsKt.sortedWith:(Ljava/lang/Iterable;Ljava/util/Comparator;)Ljava/util/List;
      48: checkcast     #35                 // class java/lang/Iterable
      51: astore        4
      53: invokestatic  #52                 // Method kotlin/collections/CollectionsKt.emptyList:()Ljava/util/List;
      56: astore        5
      58: iconst_0
      59: istore        6
      61: aload         5
      63: astore        7
      65: aload         4
      67: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      72: astore        8
      74: aload         8
      76: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      81: ifeq          533
      84: aload         8
      86: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      91: astore        9
      93: aload         7
      95: aload         9
      97: checkcast     #68                 // class java/lang/String
     100: astore        10
     102: astore        11
     104: iconst_0
     105: istore        12
     107: aload_3
     108: checkcast     #35                 // class java/lang/Iterable
     111: astore        13
     113: nop
     114: iconst_0
     115: istore        14
     117: aload         13
     119: astore        15
     121: new           #70                 // class java/util/ArrayList
     124: dup
     125: invokespecial #73                 // Method java/util/ArrayList."<init>":()V
     128: checkcast     #75                 // class java/util/Collection
     131: astore        16
     133: iconst_0
     134: istore        17
     136: aload         15
     138: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     143: astore        18
     145: aload         18
     147: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     152: ifeq          202
     155: aload         18
     157: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     162: astore        19
     164: aload         19
     166: checkcast     #77                 // class dev/achammer/tuwea/core/StudentCheckmarksEntry
     169: astore        20
     171: iconst_0
     172: istore        21
     174: aload         20
     176: invokevirtual #81                 // Method dev/achammer/tuwea/core/StudentCheckmarksEntry.getCheckmarks:()Ljava/util/Set;
     179: aload         10
     181: invokeinterface #87,  2           // InterfaceMethod java/util/Set.contains:(Ljava/lang/Object;)Z
     186: ifeq          145
     189: aload         16
     191: aload         19
     193: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     198: pop
     199: goto          145
     202: aload         16
     204: checkcast     #92                 // class java/util/List
     207: nop
     208: checkcast     #35                 // class java/lang/Iterable
     211: astore        13
     213: nop
     214: iconst_0
     215: istore        14
     217: aload         13
     219: astore        15
     221: new           #70                 // class java/util/ArrayList
     224: dup
     225: invokespecial #73                 // Method java/util/ArrayList."<init>":()V
     228: checkcast     #75                 // class java/util/Collection
     231: astore        16
     233: iconst_0
     234: istore        17
     236: aload         15
     238: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     243: astore        18
     245: aload         18
     247: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     252: ifeq          304
     255: aload         18
     257: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     262: astore        19
     264: aload         19
     266: checkcast     #77                 // class dev/achammer/tuwea/core/StudentCheckmarksEntry
     269: astore        20
     271: iconst_0
     272: istore        21
     274: aload_1
     275: aload         20
     277: invokeinterface #98,  2           // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
     282: checkcast     #100                // class java/lang/Boolean
     285: invokevirtual #103                // Method java/lang/Boolean.booleanValue:()Z
     288: ifeq          245
     291: aload         16
     293: aload         19
     295: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     300: pop
     301: goto          245
     304: aload         16
     306: checkcast     #92                 // class java/util/List
     309: nop
     310: checkcast     #35                 // class java/lang/Iterable
     313: astore        13
     315: nop
     316: iconst_0
     317: istore        14
     319: aload         13
     321: astore        15
     323: new           #70                 // class java/util/ArrayList
     326: dup
     327: invokespecial #73                 // Method java/util/ArrayList."<init>":()V
     330: checkcast     #75                 // class java/util/Collection
     333: astore        16
     335: iconst_0
     336: istore        17
     338: aload         15
     340: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     345: astore        18
     347: aload         18
     349: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     354: ifeq          467
     357: aload         18
     359: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     364: astore        19
     366: aload         19
     368: checkcast     #77                 // class dev/achammer/tuwea/core/StudentCheckmarksEntry
     371: astore        20
     373: iconst_0
     374: istore        21
     376: aload         11
     378: checkcast     #35                 // class java/lang/Iterable
     381: astore        22
     383: iconst_0
     384: istore        23
     386: aload         22
     388: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     393: astore        24
     395: aload         24
     397: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     402: ifeq          442
     405: aload         24
     407: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     412: astore        25
     414: aload         25
     416: checkcast     #105                // class kotlin/Pair
     419: astore        26
     421: iconst_0
     422: istore        27
     424: aload         26
     426: invokevirtual #108                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     429: aload         20
     431: invokestatic  #112                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     434: ifeq          395
     437: aload         25
     439: goto          443
     442: aconst_null
     443: ifnull        450
     446: iconst_1
     447: goto          451
     450: iconst_0
     451: ifne          347
     454: aload         16
     456: aload         19
     458: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     463: pop
     464: goto          347
     467: aload         16
     469: checkcast     #92                 // class java/util/List
     472: nop
     473: astore        28
     475: aload         28
     477: invokeinterface #115,  1          // InterfaceMethod java/util/List.isEmpty:()Z
     482: ifeq          490
     485: aload         11
     487: goto          527
     490: aload         11
     492: checkcast     #75                 // class java/util/Collection
     495: new           #105                // class kotlin/Pair
     498: dup
     499: aload         10
     501: aload         28
     503: getstatic     #121                // Field kotlin/random/Random.Default:Lkotlin/random/Random$Default;
     506: aload         28
     508: invokeinterface #125,  1          // InterfaceMethod java/util/List.size:()I
     513: invokevirtual #131                // Method kotlin/random/Random$Default.nextInt:(I)I
     516: invokeinterface #135,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     521: invokespecial #138                // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
     524: invokestatic  #142                // Method kotlin/collections/CollectionsKt.plus:(Ljava/util/Collection;Ljava/lang/Object;)Ljava/util/List;
     527: nop
     528: astore        7
     530: goto          74
     533: aload         7
     535: areturn

  public static final dev.achammer.tuwea.core.ParseResult parseCsvContent(dev.achammer.tuwea.core.ParseConfiguration, java.lang.String);
    Code:
       0: aload_0
       1: ldc           #187                // String parseConfiguration
       3: invokestatic  #22                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #189                // String csvContent
       9: invokestatic  #22                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: astore_2
      14: iconst_0
      15: istore_3
      16: aload_1
      17: checkcast     #191                // class java/lang/CharSequence
      20: iconst_1
      21: anewarray     #68                 // class java/lang/String
      24: astore        4
      26: aload         4
      28: iconst_0
      29: ldc           #193                // String \n
      31: aastore
      32: aload         4
      34: iconst_0
      35: iconst_0
      36: bipush        6
      38: aconst_null
      39: invokestatic  #199                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      42: astore        5
      44: aload         5
      46: checkcast     #35                 // class java/lang/Iterable
      49: aload_2
      50: invokevirtual #204                // Method dev/achammer/tuwea/core/ParseConfiguration.getCsvLineOffset:()I
      53: invokestatic  #208                // Method kotlin/collections/CollectionsKt.drop:(Ljava/lang/Iterable;I)Ljava/util/List;
      56: astore        4
      58: aload         4
      60: invokestatic  #212                // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
      63: checkcast     #68                 // class java/lang/String
      66: astore        6
      68: aload         6
      70: checkcast     #191                // class java/lang/CharSequence
      73: iconst_1
      74: newarray       char
      76: astore        7
      78: aload         7
      80: iconst_0
      81: aload_2
      82: invokevirtual #216                // Method dev/achammer/tuwea/core/ParseConfiguration.getCsvDelimiter:()C
      85: castore
      86: aload         7
      88: iconst_0
      89: iconst_0
      90: bipush        6
      92: aconst_null
      93: invokestatic  #219                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[CZIILjava/lang/Object;)Ljava/util/List;
      96: astore        8
      98: aload         8
     100: checkcast     #35                 // class java/lang/Iterable
     103: aload_2
     104: invokevirtual #222                // Method dev/achammer/tuwea/core/ParseConfiguration.getPreCheckmarksFieldOffset:()I
     107: invokestatic  #208                // Method kotlin/collections/CollectionsKt.drop:(Ljava/lang/Iterable;I)Ljava/util/List;
     110: checkcast     #35                 // class java/lang/Iterable
     113: astore        9
     115: nop
     116: iconst_0
     117: istore        10
     119: new           #70                 // class java/util/ArrayList
     122: dup
     123: invokespecial #73                 // Method java/util/ArrayList."<init>":()V
     126: astore        11
     128: aload         9
     130: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     135: astore        12
     137: aload         12
     139: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     144: ifeq          200
     147: aload         12
     149: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     154: astore        13
     156: aload         13
     158: checkcast     #68                 // class java/lang/String
     161: astore        14
     163: iconst_0
     164: istore        15
     166: aload         14
     168: aload_2
     169: invokevirtual #226                // Method dev/achammer/tuwea/core/ParseConfiguration.getExerciseEndSignifierKey:()Ljava/lang/String;
     172: invokestatic  #112                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     175: ifne          182
     178: iconst_1
     179: goto          183
     182: iconst_0
     183: ifne          189
     186: goto          200
     189: aload         11
     191: aload         13
     193: invokevirtual #227                // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
     196: pop
     197: goto          137
     200: aload         11
     202: checkcast     #92                 // class java/util/List
     205: checkcast     #35                 // class java/lang/Iterable
     208: astore        9
     210: nop
     211: iconst_0
     212: istore        10
     214: aload         9
     216: astore        11
     218: new           #70                 // class java/util/ArrayList
     221: dup
     222: aload         9
     224: bipush        10
     226: invokestatic  #231                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     229: invokespecial #234                // Method java/util/ArrayList."<init>":(I)V
     232: checkcast     #75                 // class java/util/Collection
     235: astore        12
     237: iconst_0
     238: istore        13
     240: aload         11
     242: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     247: astore        14
     249: aload         14
     251: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     256: ifeq          299
     259: aload         14
     261: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     266: astore        15
     268: aload         12
     270: aload         15
     272: checkcast     #68                 // class java/lang/String
     275: astore        16
     277: astore        17
     279: iconst_0
     280: istore        18
     282: aload         16
     284: invokestatic  #238                // Method sanitizeExerciseName:(Ljava/lang/String;)Ljava/lang/String;
     287: aload         17
     289: swap
     290: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     295: pop
     296: goto          249
     299: aload         12
     301: checkcast     #92                 // class java/util/List
     304: nop
     305: astore        7
     307: aload         4
     309: checkcast     #35                 // class java/lang/Iterable
     312: iconst_1
     313: invokestatic  #208                // Method kotlin/collections/CollectionsKt.drop:(Ljava/lang/Iterable;I)Ljava/util/List;
     316: checkcast     #35                 // class java/lang/Iterable
     319: astore        10
     321: nop
     322: iconst_0
     323: istore        11
     325: aload         10
     327: astore        12
     329: new           #70                 // class java/util/ArrayList
     332: dup
     333: aload         10
     335: bipush        10
     337: invokestatic  #231                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     340: invokespecial #234                // Method java/util/ArrayList."<init>":(I)V
     343: checkcast     #75                 // class java/util/Collection
     346: astore        13
     348: iconst_0
     349: istore        14
     351: aload         12
     353: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     358: astore        15
     360: aload         15
     362: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     367: ifeq          450
     370: aload         15
     372: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     377: astore        16
     379: aload         13
     381: aload         16
     383: checkcast     #68                 // class java/lang/String
     386: astore        18
     388: astore        17
     390: iconst_0
     391: istore        19
     393: aload         8
     395: checkcast     #35                 // class java/lang/Iterable
     398: aload         18
     400: checkcast     #191                // class java/lang/CharSequence
     403: iconst_1
     404: newarray       char
     406: astore        20
     408: aload         20
     410: iconst_0
     411: aload_2
     412: invokevirtual #216                // Method dev/achammer/tuwea/core/ParseConfiguration.getCsvDelimiter:()C
     415: castore
     416: aload         20
     418: iconst_0
     419: iconst_0
     420: bipush        6
     422: aconst_null
     423: invokestatic  #219                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[CZIILjava/lang/Object;)Ljava/util/List;
     426: checkcast     #35                 // class java/lang/Iterable
     429: invokestatic  #242                // Method kotlin/collections/CollectionsKt.zip:(Ljava/lang/Iterable;Ljava/lang/Iterable;)Ljava/util/List;
     432: checkcast     #35                 // class java/lang/Iterable
     435: invokestatic  #248                // Method kotlin/collections/MapsKt.toMap:(Ljava/lang/Iterable;)Ljava/util/Map;
     438: aload         17
     440: swap
     441: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     446: pop
     447: goto          360
     450: aload         13
     452: checkcast     #92                 // class java/util/List
     455: nop
     456: checkcast     #35                 // class java/lang/Iterable
     459: astore        10
     461: nop
     462: iconst_0
     463: istore        11
     465: aload         10
     467: astore        12
     469: new           #70                 // class java/util/ArrayList
     472: dup
     473: aload         10
     475: bipush        10
     477: invokestatic  #231                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     480: invokespecial #234                // Method java/util/ArrayList."<init>":(I)V
     483: checkcast     #75                 // class java/util/Collection
     486: astore        13
     488: iconst_0
     489: istore        14
     491: aload         12
     493: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     498: astore        15
     500: aload         15
     502: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     507: ifeq          551
     510: aload         15
     512: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     517: astore        16
     519: aload         13
     521: aload         16
     523: checkcast     #250                // class java/util/Map
     526: astore        18
     528: astore        17
     530: iconst_0
     531: istore        19
     533: aload_2
     534: aload         18
     536: invokestatic  #254                // Method parseCsvLine:(Ldev/achammer/tuwea/core/ParseConfiguration;Ljava/util/Map;)Ldev/achammer/tuwea/core/StudentCheckmarksEntry;
     539: aload         17
     541: swap
     542: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     547: pop
     548: goto          500
     551: aload         13
     553: checkcast     #92                 // class java/util/List
     556: nop
     557: astore        9
     559: new           #26                 // class dev/achammer/tuwea/core/ParseResult
     562: dup
     563: aload         7
     565: aload         9
     567: invokespecial #257                // Method dev/achammer/tuwea/core/ParseResult."<init>":(Ljava/util/List;Ljava/util/List;)V
     570: areturn

  private static final dev.achammer.tuwea.core.StudentCheckmarksEntry parseCsvLine(dev.achammer.tuwea.core.ParseConfiguration, java.util.Map<java.lang.String, java.lang.String>);
    Code:
       0: aload_1
       1: invokeinterface #286,  1          // InterfaceMethod java/util/Map.keySet:()Ljava/util/Set;
       6: checkcast     #35                 // class java/lang/Iterable
       9: astore_3
      10: nop
      11: iconst_0
      12: istore        4
      14: aload_3
      15: astore        5
      17: new           #70                 // class java/util/ArrayList
      20: dup
      21: invokespecial #73                 // Method java/util/ArrayList."<init>":()V
      24: checkcast     #75                 // class java/util/Collection
      27: astore        6
      29: iconst_0
      30: istore        7
      32: aload         5
      34: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      39: astore        8
      41: aload         8
      43: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      48: ifeq          128
      51: aload         8
      53: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      58: astore        9
      60: aload         9
      62: checkcast     #68                 // class java/lang/String
      65: astore        10
      67: iconst_0
      68: istore        11
      70: iconst_3
      71: anewarray     #68                 // class java/lang/String
      74: astore        12
      76: aload         12
      78: iconst_0
      79: aload_0
      80: invokevirtual #289                // Method dev/achammer/tuwea/core/ParseConfiguration.getFirstNameKey:()Ljava/lang/String;
      83: aastore
      84: aload         12
      86: iconst_1
      87: aload_0
      88: invokevirtual #292                // Method dev/achammer/tuwea/core/ParseConfiguration.getLastNameKey:()Ljava/lang/String;
      91: aastore
      92: aload         12
      94: iconst_2
      95: aload_0
      96: invokevirtual #295                // Method dev/achammer/tuwea/core/ParseConfiguration.getIdNumberKey:()Ljava/lang/String;
      99: aastore
     100: aload         12
     102: invokestatic  #301                // Method kotlin/collections/SetsKt.setOf:([Ljava/lang/Object;)Ljava/util/Set;
     105: aload         10
     107: invokeinterface #87,  2           // InterfaceMethod java/util/Set.contains:(Ljava/lang/Object;)Z
     112: ifne          41
     115: aload         6
     117: aload         9
     119: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     124: pop
     125: goto          41
     128: aload         6
     130: checkcast     #92                 // class java/util/List
     133: nop
     134: checkcast     #35                 // class java/lang/Iterable
     137: astore_3
     138: nop
     139: iconst_0
     140: istore        4
     142: aload_3
     143: astore        5
     145: new           #70                 // class java/util/ArrayList
     148: dup
     149: invokespecial #73                 // Method java/util/ArrayList."<init>":()V
     152: checkcast     #75                 // class java/util/Collection
     155: astore        6
     157: iconst_0
     158: istore        7
     160: aload         5
     162: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     167: astore        8
     169: aload         8
     171: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     176: ifeq          232
     179: aload         8
     181: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     186: astore        9
     188: aload         9
     190: checkcast     #68                 // class java/lang/String
     193: astore        10
     195: iconst_0
     196: istore        11
     198: aload_0
     199: invokevirtual #304                // Method dev/achammer/tuwea/core/ParseConfiguration.getCheckmarkSignifiers:()Ljava/util/Set;
     202: checkcast     #35                 // class java/lang/Iterable
     205: aload_1
     206: aload         10
     208: invokeinterface #306,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     213: invokestatic  #309                // Method kotlin/collections/CollectionsKt.contains:(Ljava/lang/Iterable;Ljava/lang/Object;)Z
     216: ifeq          169
     219: aload         6
     221: aload         9
     223: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     228: pop
     229: goto          169
     232: aload         6
     234: checkcast     #92                 // class java/util/List
     237: nop
     238: checkcast     #35                 // class java/lang/Iterable
     241: astore_3
     242: nop
     243: iconst_0
     244: istore        4
     246: aload_3
     247: astore        5
     249: new           #70                 // class java/util/ArrayList
     252: dup
     253: aload_3
     254: bipush        10
     256: invokestatic  #231                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     259: invokespecial #234                // Method java/util/ArrayList."<init>":(I)V
     262: checkcast     #75                 // class java/util/Collection
     265: astore        6
     267: iconst_0
     268: istore        7
     270: aload         5
     272: invokeinterface #56,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     277: astore        8
     279: aload         8
     281: invokeinterface #62,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     286: ifeq          329
     289: aload         8
     291: invokeinterface #66,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     296: astore        9
     298: aload         6
     300: aload         9
     302: checkcast     #68                 // class java/lang/String
     305: astore        10
     307: astore        13
     309: iconst_0
     310: istore        11
     312: aload         10
     314: invokestatic  #238                // Method sanitizeExerciseName:(Ljava/lang/String;)Ljava/lang/String;
     317: aload         13
     319: swap
     320: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     325: pop
     326: goto          279
     329: aload         6
     331: checkcast     #92                 // class java/util/List
     334: nop
     335: checkcast     #35                 // class java/lang/Iterable
     338: invokestatic  #313                // Method kotlin/collections/CollectionsKt.toSet:(Ljava/lang/Iterable;)Ljava/util/Set;
     341: astore_2
     342: new           #77                 // class dev/achammer/tuwea/core/StudentCheckmarksEntry
     345: dup
     346: aload_1
     347: aload_0
     348: invokevirtual #289                // Method dev/achammer/tuwea/core/ParseConfiguration.getFirstNameKey:()Ljava/lang/String;
     351: invokeinterface #306,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     356: dup
     357: invokestatic  #317                // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
     360: checkcast     #68                 // class java/lang/String
     363: invokestatic  #320                // Method sanitizeFirstName:(Ljava/lang/String;)Ljava/lang/String;
     366: aload_1
     367: aload_0
     368: invokevirtual #292                // Method dev/achammer/tuwea/core/ParseConfiguration.getLastNameKey:()Ljava/lang/String;
     371: invokeinterface #306,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     376: dup
     377: invokestatic  #317                // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
     380: checkcast     #68                 // class java/lang/String
     383: aload_1
     384: aload_0
     385: invokevirtual #295                // Method dev/achammer/tuwea/core/ParseConfiguration.getIdNumberKey:()Ljava/lang/String;
     388: invokeinterface #306,  2          // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
     393: dup
     394: invokestatic  #317                // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
     397: checkcast     #68                 // class java/lang/String
     400: aload_2
     401: invokespecial #323                // Method dev/achammer/tuwea/core/StudentCheckmarksEntry."<init>":(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;)V
     404: areturn

  private static final java.lang.String sanitizeExerciseName(java.lang.String);
    Code:
       0: aload_0
       1: invokestatic  #332                // Method firstWordOf:(Ljava/lang/String;)Ljava/lang/String;
       4: areturn

  private static final java.lang.String sanitizeFirstName(java.lang.String);
    Code:
       0: aload_0
       1: invokestatic  #332                // Method firstWordOf:(Ljava/lang/String;)Ljava/lang/String;
       4: areturn

  private static final java.lang.String firstWordOf(java.lang.String);
    Code:
       0: aload_0
       1: checkcast     #191                // class java/lang/CharSequence
       4: invokestatic  #338                // Method kotlin/text/StringsKt.trim:(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
       7: invokevirtual #341                // Method java/lang/Object.toString:()Ljava/lang/String;
      10: checkcast     #191                // class java/lang/CharSequence
      13: iconst_1
      14: anewarray     #68                 // class java/lang/String
      17: astore_1
      18: aload_1
      19: iconst_0
      20: ldc_w         #343                // String
      23: aastore
      24: aload_1
      25: iconst_0
      26: iconst_0
      27: bipush        6
      29: aconst_null
      30: invokestatic  #199                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      33: invokestatic  #212                // Method kotlin/collections/CollectionsKt.first:(Ljava/util/List;)Ljava/lang/Object;
      36: checkcast     #68                 // class java/lang/String
      39: areturn

  static {};
    Code:
       0: new           #201                // class dev/achammer/tuwea/core/ParseConfiguration
       3: dup
       4: bipush        59
       6: bipush        6
       8: iconst_3
       9: ldc_w         #347                // String Vorname
      12: ldc_w         #349                // String Nachname
      15: ldc_w         #351                // String ID-Nummer
      18: ldc_w         #353                // String Kreuzerl
      21: iconst_2
      22: anewarray     #68                 // class java/lang/String
      25: astore_0
      26: aload_0
      27: iconst_0
      28: ldc_w         #355                // String X
      31: aastore
      32: aload_0
      33: iconst_1
      34: ldc_w         #357                // String (X)
      37: aastore
      38: aload_0
      39: invokestatic  #301                // Method kotlin/collections/SetsKt.setOf:([Ljava/lang/Object;)Ljava/util/Set;
      42: invokespecial #360                // Method dev/achammer/tuwea/core/ParseConfiguration."<init>":(CIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;)V
      45: putstatic     #11                 // Field tuwelParseConfiguration:Ldev/achammer/tuwea/core/ParseConfiguration;
      48: return
}

Compiled from "Comparisons.kt"
public final class dev.achammer.tuwea.core.CoreKt$findExerciseAssignment$$inlined$sortedBy$1<T> implements java.util.Comparator {
  final java.util.List $entries$inlined;

  public dev.achammer.tuwea.core.CoreKt$findExerciseAssignment$$inlined$sortedBy$1(java.util.List);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #18                 // Field $entries$inlined:Ljava/util/List;
       5: aload_0
       6: invokespecial #21                 // Method java/lang/Object."<init>":()V
       9: return

  public final int compare(T, T);
    Code:
       0: aload_1
       1: checkcast     #28                 // class java/lang/String
       4: astore_3
       5: iconst_0
       6: istore        4
       8: aload_0
       9: getfield      #18                 // Field $entries$inlined:Ljava/util/List;
      12: checkcast     #30                 // class java/lang/Iterable
      15: astore        5
      17: iconst_0
      18: istore        6
      20: aload         5
      22: instanceof    #32                 // class java/util/Collection
      25: ifeq          45
      28: aload         5
      30: checkcast     #32                 // class java/util/Collection
      33: invokeinterface #36,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
      38: ifeq          45
      41: iconst_0
      42: goto          116
      45: iconst_0
      46: istore        7
      48: aload         5
      50: invokeinterface #40,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      55: astore        8
      57: aload         8
      59: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      64: ifeq          114
      67: aload         8
      69: invokeinterface #49,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      74: astore        9
      76: aload         9
      78: checkcast     #51                 // class dev/achammer/tuwea/core/StudentCheckmarksEntry
      81: astore        10
      83: iconst_0
      84: istore        11
      86: aload         10
      88: invokevirtual #55                 // Method dev/achammer/tuwea/core/StudentCheckmarksEntry.getCheckmarks:()Ljava/util/Set;
      91: aload_3
      92: invokeinterface #61,  2           // InterfaceMethod java/util/Set.contains:(Ljava/lang/Object;)Z
      97: ifeq          57
     100: iinc          7, 1
     103: iload         7
     105: ifge          57
     108: invokestatic  #66                 // Method kotlin/collections/CollectionsKt.throwCountOverflow:()V
     111: goto          57
     114: iload         7
     116: invokestatic  #72                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     119: nop
     120: checkcast     #74                 // class java/lang/Comparable
     123: aload_2
     124: checkcast     #28                 // class java/lang/String
     127: astore_3
     128: astore        12
     130: iconst_0
     131: istore        4
     133: aload_0
     134: getfield      #18                 // Field $entries$inlined:Ljava/util/List;
     137: checkcast     #30                 // class java/lang/Iterable
     140: astore        5
     142: iconst_0
     143: istore        6
     145: aload         5
     147: instanceof    #32                 // class java/util/Collection
     150: ifeq          170
     153: aload         5
     155: checkcast     #32                 // class java/util/Collection
     158: invokeinterface #36,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
     163: ifeq          170
     166: iconst_0
     167: goto          241
     170: iconst_0
     171: istore        7
     173: aload         5
     175: invokeinterface #40,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     180: astore        8
     182: aload         8
     184: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     189: ifeq          239
     192: aload         8
     194: invokeinterface #49,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     199: astore        9
     201: aload         9
     203: checkcast     #51                 // class dev/achammer/tuwea/core/StudentCheckmarksEntry
     206: astore        10
     208: iconst_0
     209: istore        11
     211: aload         10
     213: invokevirtual #55                 // Method dev/achammer/tuwea/core/StudentCheckmarksEntry.getCheckmarks:()Ljava/util/Set;
     216: aload_3
     217: invokeinterface #61,  2           // InterfaceMethod java/util/Set.contains:(Ljava/lang/Object;)Z
     222: ifeq          182
     225: iinc          7, 1
     228: iload         7
     230: ifge          182
     233: invokestatic  #66                 // Method kotlin/collections/CollectionsKt.throwCountOverflow:()V
     236: goto          182
     239: iload         7
     241: invokestatic  #72                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     244: nop
     245: aload         12
     247: swap
     248: checkcast     #74                 // class java/lang/Comparable
     251: invokestatic  #80                 // Method kotlin/comparisons/ComparisonsKt.compareValues:(Ljava/lang/Comparable;Ljava/lang/Comparable;)I
     254: ireturn
}


package dev.kosmx.aoc23.differential

import kotlin.math.*

// It's beautiful how mathematical functions can be written down in functional programming :D

fun distance(totalTime: Int, buttonPress: Int): Int = (totalTime - buttonPress) * buttonPress // travel time times speed
// -(buttonPress^2) + totalTime*buttonPress

// dl/dp  -- differentiated by buttonPress
fun dDistance(totalTime: Int, buttonPress: Int) = 2*buttonPress - totalTime
// this one is quite useless

// quadratic solution
// val x = buttonPress
// x^2 - totalTime*x + equals
fun zeroOfDistanceMinusTravel(totalTime: Double, equals: Double): Pair<Double, Double> {
    val discriminant = sqrt(totalTime * totalTime - 4 * equals) // -4ac => -4*1*-equals
    return (totalTime + discriminant)/2 to (totalTime - discriminant)/2
}

fun main() {
    // This input is simple, I don't see its necessary to use files
    val input = """
        Time:      7  15   30
        Distance:  9  40  200
    """.trimIndent().lines()

    val races = run {
        val times = input[0].split(" ").asSequence().mapNotNull { it.toLongOrNull() }.toList()
        val distances = input[1].split(" ").asSequence().mapNotNull { it.toLongOrNull() }.toList()

        times.indices.map { times[it] to distances[it] }
    }

    races.fold(1L) { acc, (time, distance) ->
        val solutions = zeroOfDistanceMinusTravel(time.toDouble(), distance.toDouble())
        val margin = (solutions.first.nextDown().toLong() - (solutions.second.toLong()))
        println("solutions: $solutions margin: $margin")
        acc * margin
    }.let {
        println("part1: $it")
    }

    // for part2, just remove spaces
}

Compiled from "OhMoarMath.kt"
public final class dev.kosmx.aoc23.differential.OhMoarMathKt {
  public static final int distance(int, int);
    Code:
       0: iload_0
       1: iload_1
       2: isub
       3: iload_1
       4: imul
       5: ireturn

  public static final int dDistance(int, int);
    Code:
       0: iconst_2
       1: iload_1
       2: imul
       3: iload_0
       4: isub
       5: ireturn

  public static final kotlin.Pair<java.lang.Double, java.lang.Double> zeroOfDistanceMinusTravel(double, double);
    Code:
       0: dload_0
       1: dload_0
       2: dmul
       3: iconst_4
       4: i2d
       5: dload_2
       6: dmul
       7: dsub
       8: invokestatic  #20                 // Method java/lang/Math.sqrt:(D)D
      11: dstore        4
      13: dload_0
      14: dload         4
      16: dadd
      17: iconst_2
      18: i2d
      19: ddiv
      20: invokestatic  #26                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      23: dload_0
      24: dload         4
      26: dsub
      27: iconst_2
      28: i2d
      29: ddiv
      30: invokestatic  #26                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      33: invokestatic  #32                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
      36: areturn

  public static final void main();
    Code:
       0: ldc           #39                 // String Time:      7  15   30\nDistance:  9  40  200
       2: checkcast     #41                 // class java/lang/CharSequence
       5: invokestatic  #47                 // Method kotlin/text/StringsKt.lines:(Ljava/lang/CharSequence;)Ljava/util/List;
       8: astore_0
       9: iconst_0
      10: istore_2
      11: aload_0
      12: iconst_0
      13: invokeinterface #53,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      18: checkcast     #41                 // class java/lang/CharSequence
      21: iconst_1
      22: anewarray     #55                 // class java/lang/String
      25: astore_3
      26: aload_3
      27: iconst_0
      28: ldc           #57                 // String
      30: aastore
      31: aload_3
      32: iconst_0
      33: iconst_0
      34: bipush        6
      36: aconst_null
      37: invokestatic  #61                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      40: checkcast     #63                 // class java/lang/Iterable
      43: invokestatic  #69                 // Method kotlin/collections/CollectionsKt.asSequence:(Ljava/lang/Iterable;)Lkotlin/sequences/Sequence;
      46: invokedynamic #88,  0             // InvokeDynamic #0:invoke:()Lkotlin/jvm/functions/Function1;
      51: invokestatic  #94                 // Method kotlin/sequences/SequencesKt.mapNotNull:(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
      54: invokestatic  #98                 // Method kotlin/sequences/SequencesKt.toList:(Lkotlin/sequences/Sequence;)Ljava/util/List;
      57: astore        5
      59: aload_0
      60: iconst_1
      61: invokeinterface #53,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      66: checkcast     #41                 // class java/lang/CharSequence
      69: iconst_1
      70: anewarray     #55                 // class java/lang/String
      73: astore        6
      75: aload         6
      77: iconst_0
      78: ldc           #57                 // String
      80: aastore
      81: aload         6
      83: iconst_0
      84: iconst_0
      85: bipush        6
      87: aconst_null
      88: invokestatic  #61                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
      91: checkcast     #63                 // class java/lang/Iterable
      94: invokestatic  #69                 // Method kotlin/collections/CollectionsKt.asSequence:(Ljava/lang/Iterable;)Lkotlin/sequences/Sequence;
      97: invokedynamic #103,  0            // InvokeDynamic #1:invoke:()Lkotlin/jvm/functions/Function1;
     102: invokestatic  #94                 // Method kotlin/sequences/SequencesKt.mapNotNull:(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
     105: invokestatic  #98                 // Method kotlin/sequences/SequencesKt.toList:(Lkotlin/sequences/Sequence;)Ljava/util/List;
     108: astore_3
     109: aload         5
     111: checkcast     #105                // class java/util/Collection
     114: invokestatic  #109                // Method kotlin/collections/CollectionsKt.getIndices:(Ljava/util/Collection;)Lkotlin/ranges/IntRange;
     117: checkcast     #63                 // class java/lang/Iterable
     120: astore        6
     122: iconst_0
     123: istore        8
     125: aload         6
     127: astore        9
     129: new           #111                // class java/util/ArrayList
     132: dup
     133: aload         6
     135: bipush        10
     137: invokestatic  #115                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     140: invokespecial #119                // Method java/util/ArrayList."<init>":(I)V
     143: checkcast     #105                // class java/util/Collection
     146: astore        10
     148: iconst_0
     149: istore        11
     151: aload         9
     153: invokeinterface #123,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     158: astore        12
     160: aload         12
     162: invokeinterface #129,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     167: ifeq          223
     170: aload         12
     172: checkcast     #131                // class kotlin/collections/IntIterator
     175: invokevirtual #135                // Method kotlin/collections/IntIterator.nextInt:()I
     178: istore        13
     180: aload         10
     182: iload         13
     184: istore        14
     186: astore        15
     188: iconst_0
     189: istore        16
     191: aload         5
     193: iload         14
     195: invokeinterface #53,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     200: aload_3
     201: iload         14
     203: invokeinterface #53,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     208: invokestatic  #32                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     211: aload         15
     213: swap
     214: invokeinterface #139,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     219: pop
     220: goto          160
     223: aload         10
     225: checkcast     #49                 // class java/util/List
     228: nop
     229: nop
     230: nop
     231: astore_1
     232: aload_1
     233: checkcast     #63                 // class java/lang/Iterable
     236: astore_2
     237: lconst_1
     238: lstore_3
     239: iconst_0
     240: istore        5
     242: lload_3
     243: lstore        6
     245: aload_2
     246: invokeinterface #123,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     251: astore        8
     253: aload         8
     255: invokeinterface #129,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     260: ifeq          403
     263: aload         8
     265: invokeinterface #143,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     270: astore        9
     272: lload         6
     274: aload         9
     276: checkcast     #145                // class kotlin/Pair
     279: astore        10
     281: lstore        11
     283: iconst_0
     284: istore        13
     286: aload         10
     288: invokevirtual #148                // Method kotlin/Pair.component1:()Ljava/lang/Object;
     291: checkcast     #150                // class java/lang/Number
     294: invokevirtual #154                // Method java/lang/Number.longValue:()J
     297: lstore        14
     299: aload         10
     301: invokevirtual #157                // Method kotlin/Pair.component2:()Ljava/lang/Object;
     304: checkcast     #150                // class java/lang/Number
     307: invokevirtual #154                // Method java/lang/Number.longValue:()J
     310: lstore        16
     312: lload         14
     314: l2d
     315: lload         16
     317: l2d
     318: invokestatic  #159                // Method zeroOfDistanceMinusTravel:(DD)Lkotlin/Pair;
     321: astore        18
     323: aload         18
     325: invokevirtual #162                // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     328: checkcast     #150                // class java/lang/Number
     331: invokevirtual #166                // Method java/lang/Number.doubleValue:()D
     334: ldc2_w        #167                // double -Infinityd
     337: invokestatic  #172                // Method java/lang/Math.nextAfter:(DD)D
     340: d2l
     341: aload         18
     343: invokevirtual #175                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     346: checkcast     #150                // class java/lang/Number
     349: invokevirtual #166                // Method java/lang/Number.doubleValue:()D
     352: d2l
     353: lsub
     354: lstore        19
     356: new           #177                // class java/lang/StringBuilder
     359: dup
     360: invokespecial #179                // Method java/lang/StringBuilder."<init>":()V
     363: ldc           #181                // String solutions:
     365: invokevirtual #185                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     368: aload         18
     370: invokevirtual #188                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
     373: ldc           #190                // String  margin:
     375: invokevirtual #185                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     378: lload         19
     380: invokevirtual #193                // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
     383: invokevirtual #197                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     386: getstatic     #203                // Field java/lang/System.out:Ljava/io/PrintStream;
     389: swap
     390: invokevirtual #209                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     393: lload         11
     395: lload         19
     397: lmul
     398: lstore        6
     400: goto          253
     403: lload         6
     405: lstore_3
     406: iconst_0
     407: istore        6
     409: new           #177                // class java/lang/StringBuilder
     412: dup
     413: invokespecial #179                // Method java/lang/StringBuilder."<init>":()V
     416: ldc           #211                // String part1:
     418: invokevirtual #185                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     421: lload_3
     422: invokevirtual #193                // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
     425: invokevirtual #197                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     428: getstatic     #203                // Field java/lang/System.out:Ljava/io/PrintStream;
     431: swap
     432: invokevirtual #209                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     435: nop
     436: nop
     437: return

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

  private static final java.lang.Long main$lambda$3$lambda$0(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #247                // String it
       3: invokestatic  #253                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokestatic  #256                // Method kotlin/text/StringsKt.toLongOrNull:(Ljava/lang/String;)Ljava/lang/Long;
      10: areturn

  private static final java.lang.Long main$lambda$3$lambda$1(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #247                // String it
       3: invokestatic  #253                // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokestatic  #256                // Method kotlin/text/StringsKt.toLongOrNull:(Ljava/lang/String;)Ljava/lang/Long;
      10: areturn
}


package dev.kosmx.aoc23.poker

import java.io.File
import java.math.BigInteger

fun main() {
    val games = File("poker.txt").readLines().map {
        var (cards, score) = it.split(" ")
        //cards = cards.replace("J", "X") Uncomment it to solve Part1
        Hand(cards) to score.toInt()
    }.sortedByDescending { it.first }

    println(games.filter { game -> game.first.cards.any { it == WILDCARD } }.joinToString("\n"))

    var score = BigInteger.ZERO
    for (i in games.indices) {
        score += BigInteger.valueOf(games[i].second.toLong()) * BigInteger.valueOf(i.toLong()+1)
    }
    println("Part1: Total score is $score")
}

data class Card(val letter: Char) : Comparable<Card> {

    private companion object {
        val ordering = arrayOf('A', 'K', 'Q', 'X', 'T', '9', '8', '7', '6', '5', '4', '3', '2', 'J')
    }
    override fun compareTo(other: Card): Int {
        return ordering.indexOf(this.letter).compareTo(ordering.indexOf(other.letter))
    }
}

val WILDCARD = Card('J')

class Hand(input: String): Comparable<Hand> {
    val cards: Array<Card>

    init {
        cards = input.map { Card(it) }.toTypedArray()
        assert(cards.size == 5)
    }

    override fun compareTo(other: Hand): Int {
        if (type == other.type) {
            for (i in 0..<5) {
                val c = cards[i].compareTo(other.cards[i])
                if (c != 0) return c
            }
        }
        return other.type.compareTo(type) // compare but inverted
    }

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

        other as Hand

        return cards.contentEquals(other.cards)
    }

    override fun hashCode(): Int {
        return cards.contentHashCode()
    }

    override fun toString(): String {
        return "Hand(cards=${cards.joinToString(separator = "") { it.letter.toString() }}, type=$type)"
    }

    val type: Int
        get() {
            val groups = cards.asSequence().groupingBy { it }.eachCount()

            val wildcard = groups[Card('J')] ?: 0

            return when {

                //Only one type or two types including wildcard type. Any number of wildcard can exist in this case
                // edge-case here: all joker
                groups.size == 1 || groups.filter { it.key != WILDCARD }.any { it.value + wildcard == 5 } -> 6

                // Max 3 wildcards here

                //There is at least one group with size of four including wildcards.
                //Max 3 wildcards, if there is more, that would make a five
                // If there are 3 wildcards, this will happen anyway
                groups.filter { it.key != WILDCARD }.any { it.value + wildcard == 4 } -> 5

                // Max 2 wildcards and at least 3 groups

                // 2 groups are easy: If the sizes are 1 and 4, it is a four, it can't be. Only 2 and 3 or 3 and 2 are possible...
                // Wildcard case:
                // 1 single element can't be again
                // only possibility: 2, 2 and 1 wildcard which is matched
                //groups.size == 2 || groups.size == 3 && wildcard != 0 -> 4 // there are only two types or three types with wildcards
                groups.filter { it.key != WILDCARD }.size == 2 -> 4

                // There is any three with wildcards
                groups.any { it.value + wildcard == 3 } -> 3

                // Max 1 wildcard

                // if there would be more wildcards than 1, it would be a three
                // 3 groups are impossible
                // the wildcard will pair with a single card creating 1 extra group
                else -> (groups.count { it.value >= 2 } + wildcard).coerceAtMost(2) // 2 1 or 0 // if we have at least 2 wildcards, it'll be a three in a kind, only one wildcard can exist
                // which will increase the amount of groups but only to two
            }
        }

}

Compiled from "WellItsNot.kt"
public final class dev.kosmx.aoc23.poker.WellItsNotKt {
  private static final dev.kosmx.aoc23.poker.Card WILDCARD;

  public static final void main();
    Code:
       0: new           #8                  // class java/io/File
       3: dup
       4: ldc           #10                 // String poker.txt
       6: invokespecial #14                 // Method java/io/File."<init>":(Ljava/lang/String;)V
       9: aconst_null
      10: iconst_1
      11: aconst_null
      12: invokestatic  #20                 // Method kotlin/io/FilesKt.readLines$default:(Ljava/io/File;Ljava/nio/charset/Charset;ILjava/lang/Object;)Ljava/util/List;
      15: checkcast     #22                 // class java/lang/Iterable
      18: astore_1
      19: iconst_0
      20: istore_2
      21: aload_1
      22: astore_3
      23: new           #24                 // class java/util/ArrayList
      26: dup
      27: aload_1
      28: bipush        10
      30: invokestatic  #30                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      33: invokespecial #33                 // Method java/util/ArrayList."<init>":(I)V
      36: checkcast     #35                 // class java/util/Collection
      39: astore        4
      41: iconst_0
      42: istore        5
      44: aload_3
      45: invokeinterface #39,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      50: astore        6
      52: aload         6
      54: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      59: ifeq          172
      62: aload         6
      64: invokeinterface #49,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      69: astore        7
      71: aload         4
      73: aload         7
      75: checkcast     #51                 // class java/lang/String
      78: astore        8
      80: astore        17
      82: iconst_0
      83: istore        9
      85: aload         8
      87: checkcast     #53                 // class java/lang/CharSequence
      90: iconst_1
      91: anewarray     #51                 // class java/lang/String
      94: astore        10
      96: aload         10
      98: iconst_0
      99: ldc           #55                 // String
     101: aastore
     102: aload         10
     104: iconst_0
     105: iconst_0
     106: bipush        6
     108: aconst_null
     109: invokestatic  #61                 // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
     112: astore        11
     114: aload         11
     116: iconst_0
     117: invokeinterface #67,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     122: checkcast     #51                 // class java/lang/String
     125: astore        10
     127: aload         11
     129: iconst_1
     130: invokeinterface #67,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     135: checkcast     #51                 // class java/lang/String
     138: astore        12
     140: new           #69                 // class dev/kosmx/aoc23/poker/Hand
     143: dup
     144: aload         10
     146: invokespecial #70                 // Method dev/kosmx/aoc23/poker/Hand."<init>":(Ljava/lang/String;)V
     149: aload         12
     151: invokestatic  #76                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     154: invokestatic  #80                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     157: invokestatic  #86                 // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     160: aload         17
     162: swap
     163: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     168: pop
     169: goto          52
     172: aload         4
     174: checkcast     #63                 // class java/util/List
     177: nop
     178: checkcast     #22                 // class java/lang/Iterable
     181: astore_1
     182: nop
     183: iconst_0
     184: istore_2
     185: aload_1
     186: new           #92                 // class dev/kosmx/aoc23/poker/WellItsNotKt$main$$inlined$sortedByDescending$1
     189: dup
     190: invokespecial #94                 // Method dev/kosmx/aoc23/poker/WellItsNotKt$main$$inlined$sortedByDescending$1."<init>":()V
     193: checkcast     #96                 // class java/util/Comparator
     196: invokestatic  #100                // Method kotlin/collections/CollectionsKt.sortedWith:(Ljava/lang/Iterable;Ljava/util/Comparator;)Ljava/util/List;
     199: astore_0
     200: aload_0
     201: checkcast     #22                 // class java/lang/Iterable
     204: astore_1
     205: iconst_0
     206: istore_2
     207: aload_1
     208: astore_3
     209: new           #24                 // class java/util/ArrayList
     212: dup
     213: invokespecial #101                // Method java/util/ArrayList."<init>":()V
     216: checkcast     #35                 // class java/util/Collection
     219: astore        4
     221: iconst_0
     222: istore        5
     224: aload_3
     225: invokeinterface #39,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     230: astore        6
     232: aload         6
     234: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     239: ifeq          345
     242: aload         6
     244: invokeinterface #49,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     249: astore        7
     251: aload         7
     253: checkcast     #103                // class kotlin/Pair
     256: astore        8
     258: iconst_0
     259: istore        9
     261: aload         8
     263: invokevirtual #106                // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
     266: checkcast     #69                 // class dev/kosmx/aoc23/poker/Hand
     269: invokevirtual #110                // Method dev/kosmx/aoc23/poker/Hand.getCards:()[Ldev/kosmx/aoc23/poker/Card;
     272: astore        10
     274: iconst_0
     275: istore        11
     277: iconst_0
     278: istore        12
     280: aload         10
     282: arraylength
     283: istore        13
     285: iload         12
     287: iload         13
     289: if_icmpge     327
     292: aload         10
     294: iload         12
     296: aaload
     297: astore        14
     299: aload         14
     301: astore        15
     303: iconst_0
     304: istore        16
     306: aload         15
     308: getstatic     #114                // Field WILDCARD:Ldev/kosmx/aoc23/poker/Card;
     311: invokestatic  #120                // Method kotlin/jvm/internal/Intrinsics.areEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z
     314: ifeq          321
     317: iconst_1
     318: goto          328
     321: iinc          12, 1
     324: goto          285
     327: iconst_0
     328: nop
     329: ifeq          232
     332: aload         4
     334: aload         7
     336: invokeinterface #90,  2           // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     341: pop
     342: goto          232
     345: aload         4
     347: checkcast     #63                 // class java/util/List
     350: nop
     351: checkcast     #22                 // class java/lang/Iterable
     354: ldc           #122                // String \n
     356: checkcast     #53                 // class java/lang/CharSequence
     359: aconst_null
     360: aconst_null
     361: iconst_0
     362: aconst_null
     363: aconst_null
     364: bipush        62
     366: aconst_null
     367: invokestatic  #126                // 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;
     370: getstatic     #132                // Field java/lang/System.out:Ljava/io/PrintStream;
     373: swap
     374: invokevirtual #138                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     377: getstatic     #144                // Field java/math/BigInteger.ZERO:Ljava/math/BigInteger;
     380: astore_1
     381: iconst_0
     382: istore_2
     383: aload_0
     384: checkcast     #35                 // class java/util/Collection
     387: invokeinterface #148,  1          // InterfaceMethod java/util/Collection.size:()I
     392: istore_3
     393: iload_2
     394: iload_3
     395: if_icmpge     488
     398: aload_1
     399: astore        4
     401: aload         4
     403: invokestatic  #151                // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
     406: aload         4
     408: astore        4
     410: aload_0
     411: iload_2
     412: invokeinterface #67,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     417: checkcast     #103                // class kotlin/Pair
     420: invokevirtual #154                // Method kotlin/Pair.getSecond:()Ljava/lang/Object;
     423: checkcast     #156                // class java/lang/Number
     426: invokevirtual #159                // Method java/lang/Number.intValue:()I
     429: i2l
     430: invokestatic  #162                // Method java/math/BigInteger.valueOf:(J)Ljava/math/BigInteger;
     433: dup
     434: ldc           #164                // String valueOf(...)
     436: invokestatic  #168                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     439: astore        5
     441: iload_2
     442: i2l
     443: lconst_1
     444: ladd
     445: invokestatic  #162                // Method java/math/BigInteger.valueOf:(J)Ljava/math/BigInteger;
     448: dup
     449: ldc           #164                // String valueOf(...)
     451: invokestatic  #168                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     454: aload         5
     456: swap
     457: invokevirtual #172                // Method java/math/BigInteger.multiply:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
     460: dup
     461: ldc           #174                // String multiply(...)
     463: invokestatic  #168                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     466: astore        5
     468: aload         4
     470: aload         5
     472: invokevirtual #176                // Method java/math/BigInteger.add:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
     475: dup
     476: ldc           #178                // String add(...)
     478: invokestatic  #168                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
     481: astore_1
     482: iinc          2, 1
     485: goto          393
     488: new           #180                // class java/lang/StringBuilder
     491: dup
     492: invokespecial #181                // Method java/lang/StringBuilder."<init>":()V
     495: ldc           #183                // String Part1: Total score is
     497: invokevirtual #187                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     500: aload_1
     501: invokevirtual #190                // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
     504: invokevirtual #194                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     507: getstatic     #132                // Field java/lang/System.out:Ljava/io/PrintStream;
     510: swap
     511: invokevirtual #138                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
     514: return

  public static final dev.kosmx.aoc23.poker.Card getWILDCARD();
    Code:
       0: getstatic     #114                // Field WILDCARD:Ldev/kosmx/aoc23/poker/Card;
       3: areturn

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

  static {};
    Code:
       0: new           #231                // class dev/kosmx/aoc23/poker/Card
       3: dup
       4: bipush        74
       6: invokespecial #243                // Method dev/kosmx/aoc23/poker/Card."<init>":(C)V
       9: putstatic     #114                // Field WILDCARD:Ldev/kosmx/aoc23/poker/Card;
      12: return
}

Compiled from "Comparisons.kt"
public final class dev.kosmx.aoc23.poker.WellItsNotKt$main$$inlined$sortedByDescending$1<T> implements java.util.Comparator {
  public dev.kosmx.aoc23.poker.WellItsNotKt$main$$inlined$sortedByDescending$1();
    Code:
       0: aload_0
       1: invokespecial #16                 // Method java/lang/Object."<init>":()V
       4: return

  public final int compare(T, T);
    Code:
       0: aload_2
       1: checkcast     #23                 // class kotlin/Pair
       4: astore_3
       5: iconst_0
       6: istore        4
       8: aload_3
       9: invokevirtual #27                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
      12: checkcast     #29                 // class dev/kosmx/aoc23/poker/Hand
      15: checkcast     #31                 // class java/lang/Comparable
      18: aload_1
      19: checkcast     #23                 // class kotlin/Pair
      22: astore_3
      23: astore        5
      25: iconst_0
      26: istore        4
      28: aload_3
      29: invokevirtual #27                 // Method kotlin/Pair.getFirst:()Ljava/lang/Object;
      32: checkcast     #29                 // class dev/kosmx/aoc23/poker/Hand
      35: aload         5
      37: swap
      38: checkcast     #31                 // class java/lang/Comparable
      41: invokestatic  #37                 // Method kotlin/comparisons/ComparisonsKt.compareValues:(Ljava/lang/Comparable;Ljava/lang/Comparable;)I
      44: ireturn
}