data class Crate(val crateMarking: Char)
data class CrateStack(val stack: ArrayDeque<Crate>)
data class MoveInstruction(val numberToMove: Int, val target: Int, val destination: Int)
fun run() {
val input = File("src/input/day5.txt").readText()
val inputParts = input.split("\r\n\r\n")
val crates = inputParts[0]
val instructions = inputParts[1]
val rowsFromBottom = crates.split("\n").reversed()
val numberOfStacks = rowsFromBottom.first().trim().last().digitToInt()
val part1Lambda = {moves: Int, targetStack: CrateStack, destinationStack: CrateStack ->
for (i in 1..moves) {
destinationStack.stack.addFirst(targetStack.stack.removeFirst())
}
}
val part2Lambda = {moves: Int, targetStack: CrateStack, destinationStack: CrateStack ->
val tempCrateStack = ArrayDeque<Crate>()
for (i in 1..moves) {
val topCrate = targetStack.stack.removeFirst()
tempCrateStack.add(topCrate)
}
repeat(tempCrateStack.size) { destinationStack.stack.addFirst(tempCrateStack.removeLast()) }
}
println(solver(part1Lambda, instructions, getCrates(rowsFromBottom, numberOfStacks)))
println(solver(part2Lambda, instructions, getCrates(rowsFromBottom, numberOfStacks)))
}
private fun getCrates(rowsFromBottom: List<String>, numberOfStacks: Int): List<CrateStack> {
val stacks = IntRange(1, numberOfStacks).map { CrateStack(ArrayDeque()) }
rowsFromBottom.drop(1).forEach { row ->
for ((currentStack, i) in (1..row.length step 4).withIndex()) {
val crateMarking = row[i]
if (crateMarking.isLetter()) {
val crate = Crate(crateMarking)
stacks[currentStack].stack.addFirst(crate)
}
}
}
return stacks
}
private fun solver(lambda: (Int,CrateStack, CrateStack) -> Unit, moveInstructions: String, stacks:List<CrateStack>): String {
buildMoveCrateInstruction(moveInstructions).forEach { instruction ->
val targetStack = stacks[instruction.target - 1]
val destinationStack = stacks[instruction.destination - 1]
lambda(instruction.numberToMove, targetStack, destinationStack)
}
return stacks.map { it.stack.first().crateMarking }.toString()
}
private fun buildMoveCrateInstruction(moveInstructions: String): List<MoveInstruction> {
val instructionParts = moveInstructions.split("\r\n").map { it.split(" ") }
return instructionParts.map { MoveInstruction(it[1].toInt(), it[3].toInt(), it.last().toInt()) }
}