Advent of Code 2021 day 5
12/05/2022, 5:00 AMDavid Whittaker
12/05/2022, 5:36 AMMichael de Kaste
12/05/2022, 5:36 AMMichael Böiers
12/05/2022, 5:40 AMpackage aoc2022
fun main() = day05(String(System.`in`.readAllBytes())).forEach(::println)
fun day05(input: String): List<Any?> {
val (stacksInput, commandsInput) = input.split("\n\n").map { it.split("\n") }
fun loadStacks(stacksInput: List<String>): MutableList<MutableList<Char>> {
val stacks = MutableList((stacksInput.last().length + 2) / 4) { mutableListOf<Char>() }
stacksInput.take(stacksInput.size - 1).reversed().forEach { line ->
val chunked = line.chunked(4).map(String::trim)
chunked.forEachIndexed { i, token ->
if (token.isNotBlank()) stacks[i] += token[1]
}
}
return stacks
}
fun compute(part1: Boolean = false) = loadStacks(stacksInput).also { stacks ->
for (line in commandsInput) {
val (n, from, to) = line.split(" ").mapNotNull(String::toIntOrNull)
if (part1) {
repeat(n) { stacks[to - 1] += stacks[from - 1].removeLast() }
} else {
val newCrates = mutableListOf<Char>()
repeat(n) { newCrates += stacks[from - 1].removeLast() }
stacks[to - 1] += newCrates.reversed()
}
}
}
return listOf(compute(part1 = true), compute(part1 = false))
.map { it.joinToString("") { it.last().toString() } }
}
Christian Ricardo
12/05/2022, 5:40 AMMichael de Kaste
12/05/2022, 5:42 AMJakub Gwóźdź
12/05/2022, 5:51 AMDavid Whittaker
12/05/2022, 5:52 AMprintln(crates.values.map { it.last() }.joinToString(""))
David Whittaker
12/05/2022, 5:52 AMjonas.app
12/05/2022, 5:54 AMJakub Gwóźdź
12/05/2022, 5:54 AM.reversed()
when doing part 1 🙂Michael de Kaste
12/05/2022, 5:56 AMobject Day5 : Challenge() {
val stacks: List<List<Char>>
val moves: List<List<Int>>
init {
val regex = """move (\d+) from (\d+) to (\d+)""".toRegex()
input.split(System.lineSeparator() + System.lineSeparator()).let { (a,b) ->
stacks = List(9){ mutableListOf<Char>() }.apply {
a.lines().forEach { line ->
for((index, value) in line.withIndex()){
if(value.isUpperCase()){
this[(index - 1) / 4].add(0, value)
}
}
}
}
moves = b.lines().mapNotNull { line ->
regex.matchEntire(line)?.destructured?.toList()?.map(String::toInt)
}
}
}
override fun part1() = craneGame(reverse = false)
override fun part2() = craneGame(reverse = true)
private fun craneGame(reverse: Boolean) = stacks.map(List<Char>::toMutableList).apply {
for ((amount, from, to) in moves) {
this[to - 1] += MutableList(amount) { this[from - 1].removeLast() }.apply { if (reverse) reverse() }
}
}.joinToString(separator = ""){ it.last().toString() }
}
Marcin Wisniowski
12/05/2022, 6:03 AMChristian Ricardo
12/05/2022, 6:03 AMMarcin Wisniowski
12/05/2022, 6:03 AMMarcin Wisniowski
12/05/2022, 6:03 AMVlad Petrushkevich
12/05/2022, 6:12 AMMichael de Kaste
12/05/2022, 6:24 AMval newCrates = mutableListOf<Char>()
repeat(n) { newCrates += stacks[from - 1].removeLast() }
stacks[to - 1] += newCrates.reversed()
to
stacks[to - 1] += List(n){ stacks[from - 1].removeLast() }.reversed()
👀Sergei Petunin
12/05/2022, 6:36 AMclass Crane(input: List<String>) {
data class CrateMove(val num: Int, val from: Int, val to: Int)
private val emptyLine = input.indexOfFirst { it.isEmpty() }
private val stacks = input.parseStacks()
private val regex = Regex("\\d+")
private val moves: List<CrateMove> = input.drop(emptyLine + 1).map(::parseCrateMove)
private fun List<String>.parseStacks() = MutableList<Stack<Char>>((first().length + 1) / 4) { Stack() }
.also { stacks ->
take(emptyLine - 1).reversed()
.flatMap { it.chunked(4) }
.map { it[1] }
.forEachIndexed { idx, char ->
if (char != ' ') {
stacks[idx % stacks.size].push(char)
}
}
}
private fun parseCrateMove(command: String): CrateMove {
val (num, from, to) = regex.findAll(command).map { it.value.toInt() }.toList()
return CrateMove(num, from - 1, to - 1)
}
private fun moveAll(mover: (move: CrateMove) -> Unit): String {
moves.forEach(mover)
return String(stacks.map { it.pop() }.toCharArray())
}
fun part1() = moveAll { move -> move.moveOneByOne() }
fun part2() = moveAll { move -> move.moveAtOnce() }
private fun CrateMove.moveOneByOne() = repeat(num) {
stacks[to].push(stacks[from].pop())
}
private fun CrateMove.moveAtOnce() = Stack<Char>().apply {
repeat(num) {
push(stacks[from].pop())
}
repeat(num) {
stacks[to].push(pop())
}
}
}
Brian Hartvigsen
12/05/2022, 6:44 AMList<List<String>>
meant having to go from a map to a string, I couldn't figure out how to do it otherwise...Dan Fingal-Surma
12/05/2022, 6:58 AMnkiesel
12/05/2022, 6:58 AMval cr = Regex("""\[(.)\]""")
val mr = Regex("""move (\d+) from (\d+) to (\d+)""")
val stacks = mutableMapOf<Int, ArrayDeque<Char>>()
val moves = mutableListOf<Move>()
for (line in input) {
cr.findAll(line).forEach { r -> stacks.getOrPut(r.range.first / 4 + 1) { ArrayDeque() }.addFirst(r.groupValues[1][0]) }
mr.find(line)?.let { r -> moves += Move(r.groupValues[1].toInt(), r.groupValues[2].toInt(), r.groupValues[3].toInt()) }
}
Cognitive Gear
12/05/2022, 6:59 AMprivate fun processInput(){
val divide = input.indexOfFirst { it == "\n\n" }
// Deal with the crane state
input.subList(0, divide).reversed().drop(1).forEach {
for (i in 1..it.length step 4) {
if (it[i] != ' ') {
val index = (i - 1) / 4
craneState1[index].push(it[i])
craneState2[index].add(it[i])
}
}
}
// Deal with the instructions
input.subList(divide + 1, input.size)
.map { it.toInstruction() }
.forEach {
craneState1.doInstruction1(it)
craneState2.doInstruction2(it)
}
}
Cognitive Gear
12/05/2022, 7:01 AMDan Fingal-Surma
12/05/2022, 7:02 AMnkiesel
12/05/2022, 7:04 AMrange.first
to compute the stack id.xxfast
12/05/2022, 7:04 AMmutableList.removeAll
strikes again! This made me question my existence 😅 😢xxfast
12/05/2022, 7:06 AMDan Fingal-Surma
12/05/2022, 7:14 AMCognitive Gear
12/05/2022, 7:43 AMDan Fingal-Surma
12/05/2022, 7:44 AMjava.util.ArrayDeque
, the Kotlin version doesn’t have methods named push
or pop
Dan Fingal-Surma
12/05/2022, 7:44 AMDeque
is recommended when you need a stack (or a queue). java.util.Stack
is based on java.util.Vector
which was obsoleted by the collections framework in 1.2 (https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html)babel
12/05/2022, 7:53 AMxxfast
12/05/2022, 8:08 AMritesh
12/05/2022, 8:14 AMstack + hashmap
Michael Böiers
12/05/2022, 8:20 AMpackage aoc2022
fun main() = day05(String(System.`in`.readAllBytes())).forEach(::println)
fun day05(input: String): List<Any?> {
val (stacksInput, commandsInput) = input.split("\n\n").map { it.split("\n") }
val size = stacksInput.last().split(" ").mapNotNull(String::toIntOrNull).last()
val stacksContents = with(stacksInput) { take(size - 1).reversed() }
val initialStacks = List(size) { stack ->
buildList {
for (line in stacksContents) line.getOrNull(1 + (stack * 4))?.takeIf { it != ' ' }?.let { add(it) }
}
}
val commands = commandsInput.map {
it.split(" ").mapNotNull(String::toIntOrNull).mapIndexed { i, x -> if (i == 0) x else x - 1 }
}
fun compute(mod: ArrayDeque<Char>.(Char) -> Unit): String {
val stacks = List(initialStacks.size) { initialStacks[it].toMutableList() }
for ((n, from, to) in commands)
stacks[to] += ArrayDeque<Char>().apply { repeat(n) { mod(stacks[from].removeLast()) } }
return stacks.joinToString("") { it.last().toString() }
}
return listOf(compute { addLast(it) }, compute { addFirst(it) })
}
Jan Durovec
12/05/2022, 8:23 AMDeque<Char>
which worked fine but then decided to rewrite it to simple (...) string manipulations. The combination of with/when
turned out to be quite readable for parsingxxfast
12/05/2022, 8:35 AMMichael Böiers
12/05/2022, 8:40 AMMutableList.remove(IntRange)
and an IntRange.last(n)
and IntRange.first(n)
. Then we could do something like list.remove(list.indices.last(n))
or other cool stuff 🙂Paul Woitaschek
12/05/2022, 8:43 AMPoisonedYouth
12/05/2022, 9:11 AMMonster Brain
12/05/2022, 9:21 AMMichael Böiers
12/05/2022, 9:24 AMritesh
12/05/2022, 9:24 AMDequeue
would be more beneficial here (stack reverse can be avoided in part 2)Kristian Nedrevold
12/05/2022, 9:30 AMfun main() {
fun part1(input: List<String>): String =
loadInput(input, 8, 9).moveOne().second.topToString()
fun part2(input: List<String>): String =
loadInput(input, 8, 9).moveAll().second.topToString()
val input = readInput("day05")
println(part1(input))
println(part2(input))
}
fun loadQueues(input: List<String>, stacks: Int): List<Stack<Char>> {
val queues = mutableListOf<Stack<Char>>()
(0 until stacks).forEach { _ -> queues.add(Stack()) }
input.reversed().forEach {
it.forEachIndexed { index, char ->
if (char != ' ' && char != '[' && char != ']') queues[index / 4].add(char)
}
}
return queues
}
fun loadInput(input: List<String>, stackHeight: Int, stacks: Int): Pair<List<String>, List<Stack<Char>>> =
Pair(input.subList(stackHeight + 2, input.size), loadQueues(input.subList(0, stackHeight), stacks))
fun Pair<List<String>, List<Stack<Char>>>.moveOne(): Pair<List<String>, List<Stack<Char>>> {
this.first.forEach {
val moves = it.parseMoves()
this.second.moveOne(moves.amount, moves.from, <http://moves.to|moves.to>)
}
return this
}
fun Pair<List<String>, List<Stack<Char>>>.moveAll(): Pair<List<String>, List<Stack<Char>>> {
this.first.forEach {
val moves = it.parseMoves()
this.second.moveAll(moves.amount, moves.from, <http://moves.to|moves.to>)
}
return this
}
fun List<Stack<Char>>.topToString(): String =
this.map { it.last() }.joinToString("")
fun List<Stack<Char>>.moveAll(amount: Int, from: Int, to: Int) {
val toMove = (0 until (amount)).map { _ ->
this[from - 1].pop()
}
toMove.reversed().forEach { this[to- 1].add(it)}
}
fun List<Stack<Char>>.moveOne(amount: Int, from: Int, to: Int) {
(0 until (amount)).forEach { _ ->
this[to - 1].add(this[from - 1].pop())
}
}
fun String.parseMoves(): Moves {
val nums = this.split(" ").filter { it.all(Char::isDigit) }.map { it.toInt() }
return Moves(nums[0], nums[1], nums[2])
}
data class Moves(
val amount: Int,
val from: Int,
val to: Int
)
Could probably be improved a lot. Solved using a stack. Ended up just reversing it for part 2, not really optimal...zsmb
12/05/2022, 9:51 AMfun <T> MutableList<T>.removeLast(count: Int): List<T> {
val removeIndex = this.size - count
return List(size = count) { this.removeAt(removeIndex) }
}
Michael de Kaste
12/05/2022, 9:55 AMMichael Böiers
12/05/2022, 9:57 AMfun <T> MutableList<T>.removeLastReversed(count: Int) = buildList { add(removeLast()) }
fun <T> MutableList<T>.removeLast(count: Int) = ArrayDeque<T>().apply { addFirst(removeLast()) } as List
Michael de Kaste
12/05/2022, 10:12 AMfun <T> MutableList<T>.removeLast(count: Int) = List(count) { removeLast() }.asReversed()
Michael Böiers
12/05/2022, 10:15 AMMichael de Kaste
12/05/2022, 10:15 AMMichael de Kaste
12/05/2022, 10:15 AMDavio
12/05/2022, 10:32 AMreturn stacks.joinToString(separator = "") { it.firstOrNull() ?: "" }
I just have a List of Lists with (single letter) Strings in them to represent the crates, in my case every first element is the top crate, I'm accommodating for stacks to be empty, could have done this with a filter as wellDavio
12/05/2022, 10:33 AMFredrik Rødland
12/05/2022, 10:44 AMreversed()
to generate new from
and to
lists for the given indices - avoiding repeat
.
part 2 was then just a matter of not calling reversed
val oldFrom = inventory[cmd.from]!!
val takeFrom = oldFrom.takeLast(cmd.num)
val newFrom = oldFrom.take(oldFrom.size - cmd.num)
val newTo = inventory[<http://cmd.to|cmd.to>]!! + (if (reversed) takeFrom.reversed() else takeFrom)
inventory[cmd.from] = newFrom
inventory[<http://cmd.to|cmd.to>] = newTo
For parsing I just split the input in 2 lists to simplify a bit.
not happy with the over all structure though - I think it can be made more readable/simpler - not the least the parsing of input.
<https://github.com/fmmr/advent/blob/master/src/main/kotlin/no/rodland/advent_2022/Day05.kt>
frascu
12/05/2022, 10:57 AMmcbeelen
12/05/2022, 10:57 AMKarloti
12/05/2022, 11:02 AMfun main() {
fun solution(lines: List<String>, part: Int): String {
val initLines = lines
.takeWhile { it.isNotEmpty() }
.dropLast(1)
.map { it.chunked(4).mapIndexedNotNull { i, s -> s.trim(' ', '[', ']').takeIf(String::isNotEmpty)?.let { i + 1 to it[0] } } }
val repo: MutableMap<Int, List<Char>> = initLines
.flatten()
.groupingBy { it.first }
.fold(emptyList<Char>()) { acc, (i, c) -> listOf(c) + acc }
.toMutableMap()
lines
.drop(initLines.size + 2)
.mapNotNull { Regex("""move\s(\d+)\sfrom\s(\d+)\sto\s(\d+)""").find(it)?.groupValues?.drop(1)?.map(String::toInt) }
.onEach { (count, fromRepo, toRepo) ->
val cargo = repo[fromRepo]!!.takeLast(count)
repo[fromRepo] = repo[fromRepo]!!.dropLast(count)
repo[toRepo] = repo[toRepo]!! + if (part == 1) cargo.reversed() else cargo
}
return repo.toSortedMap().map { it.value.last() }.joinToString("")
}
check(solution(readInput("Day05_test"), part = 1) == "CMZ")
check(solution(readInput("Day05_test"), part = 2) == "MCD")
println(solution(readInput("Day05"), part = 1))
println(solution(readInput("Day05"), part = 2))
}
https://github.com/karloti/advent-of-code-2022-kotlin/blob/main/src/Day05.ktephemient
12/05/2022, 11:24 AMGrzegorz Baczek
12/05/2022, 11:43 AMGrzegorz Baczek
12/05/2022, 11:50 AMWael Ellithy
12/05/2022, 11:51 AMKarloti
12/05/2022, 11:51 AMOzioma Ogbe
12/05/2022, 11:58 AMdata class Instruction(val source: Int, val destination: Int, val amount: Int)
fun parseInput(lines: List<String>): Pair<List<Stack<String>>, List<Instruction>> {
val (stacks, instructionString) = lines.joinToString("\n").split("\n\n")
return List(10) { LinkedList<String>() }.apply {
stacks.split("\n").take(stacks.split("\n").size - 1).forEach { value ->
value.chunked(4).forEachIndexed { index, s ->
if (s.isNotBlank()) {
this[index].add(s)
}
}
}
}.mapIndexed { index, strings ->
val stack = Stack<String>()
strings.reversed().forEach {
stack.push(it)
}
stack
} to instructionString.split("\n").map {
it.split(" ").mapNotNull {
it.toIntOrNull()
}
}.map {
Instruction(it[1], it[2], it[0])
}
}
part1
fun main() = solve { lines ->
parseInput(lines).apply {
second.forEach { instruction ->
(1..instruction.amount).forEach {
first[instruction.destination - 1].push(first[instruction.source - 1].pop())
}
}
first.forEach {
if (it.isNotEmpty()) print(it.peek()[1])
}
}
}
part 2
fun main() = solve { lines ->
parseInput(lines).apply {
second.forEach { instruction ->
val temp = mutableListOf<String>()
(1..instruction.amount).forEach {
temp.add(first[instruction.source - 1].pop())
}
temp.reversed().forEach {
first[instruction.destination - 1].push(it)
}
}
first.forEach {
if (it.isNotEmpty()) print(it.peek()[1])
}
}
}
Michael Böiers
12/05/2022, 12:01 PMDavio
12/05/2022, 12:16 PMritesh
12/05/2022, 12:54 PMAbdul Khaliq
12/05/2022, 1:00 PMKarloti
12/05/2022, 1:05 PMritesh
12/05/2022, 1:27 PMMarc Javier
12/05/2022, 2:00 PMGrzegorz Aniol
12/05/2022, 2:16 PMephemient
12/05/2022, 2:25 PMephemient
12/05/2022, 2:26 PMJacob
12/05/2022, 3:08 PMMarcin Wisniowski
12/05/2022, 3:44 PMKevin Del Castillo
12/05/2022, 5:13 PMNeil Banman
12/05/2022, 5:14 PMchunked(4).map { chunk -> chunk.first { it.isUppercase() } }
. But hey, it worked!
I used ArrayDeques since it seemed so obvious that this was a Stack problem. This burned me a little in Part 2. My ignonimous solution was to transfer to a temporary stack, and then transferring to the destination stack. The ol' double reverse.
https://github.com/nbanman/Play2022/blob/master/src/main/kotlin/org/gristle/adventOfCode/y2022/d5/Y2022D5.ktPoisonedYouth
12/05/2022, 6:03 PMKarloti
12/05/2022, 6:36 PMwakingrufus
12/05/2022, 6:49 PMBen Ooms
12/05/2022, 7:25 PMfun main() {
fun readInitialSupplyStackData(input: List<String>): List<ArrayDeque<String>> {
// Create deque
val supplyStackData = input.subList(0, input.indexOf(""))
val lastStackNumber = supplyStackData.last().last().digitToInt()
val supplyStacks = (1..lastStackNumber).map { ArrayDeque<String>() }
val initialSupplyPositionData = supplyStackData.subList(0,supplyStackData.lastIndex)
initialSupplyPositionData.forEach {
val chuncks = it.chunked(4)
chuncks.forEachIndexed {
index, data ->
if (data.isNotBlank()) {
supplyStacks[index].addLast(data[1].toString())
}
}
}
return supplyStacks
}
fun List<ArrayDeque<String>>.moveSupply(from: Int, to: Int){
val supply = this[from-1].removeFirst()
this[to-1].addFirst(supply)
}
fun List<ArrayDeque<String>>.getTopSupplies(): String {
return this.filter { it.isNotEmpty() }
.map { it.first() }
.reduce { acc, s -> acc+s }
}
fun List<ArrayDeque<String>>.moveMultipleSupply(noOfSupplies: Int, from: Int, to: Int){
val fromList = this[from-1]
val toList = this[to-1]
val supplies = this[from-1].take(noOfSupplies)
val newFromContent = fromList.slice(noOfSupplies..fromList.lastIndex)
fromList.clear()
fromList.addAll(newFromContent)
toList.addAll(0, supplies)
}
fun String.getMove(): Triple<Int, Int, Int> {
val moveRegex = Regex("""^move (\d+) from (\d+) to (\d+)$""")
val match = moveRegex.find(this)
if (this.matches(moveRegex)) {
val move = match?.destructured?.toList()?.map { it.toInt() }
if (move != null) {
return Triple(move[0], move[1], move[2] )
}
}
return Triple(0, 0, 0)
}
fun part1(input: List<String>): String {
val stacks = readInitialSupplyStackData(input)
val moves = input.subList(input.indexOf("")+1, input.lastIndex+1)
moves.forEach {
val (count, from, to) = it.getMove()
if (count == 1) {
stacks.moveSupply(from, to)
} else {
(1..count).forEach { _ ->
stacks.moveSupply(from, to)
}
}
}
return stacks.getTopSupplies()
}
fun part2(input: List<String>): String {
val stacks = readInitialSupplyStackData(input)
val moves = input.subList(input.indexOf("")+1, input.lastIndex+1)
moves.forEach {
val (noOfSupplies, from, to) = it.getMove()
stacks.moveMultipleSupply(noOfSupplies, from, to)
}
return stacks.getTopSupplies()
}
// test if implementation meets criteria from the description, like:
val testInput = readInput("Day05_test")
check(part1(testInput) == "CMZ")
check(part2(testInput) == "MCD")
//
val input = readInput("Day05")
println(part1(input))
println(part2(input))
}
ephemient
12/05/2022, 7:51 PMephemient
12/05/2022, 7:59 PMephemient
12/05/2022, 8:04 PMephemient
12/05/2022, 8:12 PMFilip Wiesner
12/05/2022, 8:17 PMString.columns()
function. Probably overkill but maybe it'll come in handy later:
fun String.columns(): Sequence<String> = sequence {
val rows = lines()
repeat(rows.maxOf(String::length)) { index ->
val column = buildString {
for (row in rows) {
val letter = row.getOrNull(index) ?: continue
if (!letter.isWhitespace()) append(letter)
}
}
yield(column)
}
}
(My full solution)Joakim Tall
12/05/2022, 8:18 PMJoakim Tall
12/05/2022, 8:20 PMephemient
12/05/2022, 8:22 PMJoakim Tall
12/05/2022, 8:25 PMJoakim Tall
12/05/2022, 8:51 PMJacob Moulton
12/05/2022, 10:25 PMKevin Del Castillo
12/05/2022, 10:38 PMMichael Böiers
12/05/2022, 10:57 PMfun day05B(input: String): List<Any?> {
fun solve(part2: Boolean) = with(sortedMapOf<Int, ArrayDeque<Char>>()) {
for (line in input.lines()) when {
line.contains("[") -> line.chunked(4).map { it[1] }.forEachIndexed { i, c ->
if (c != ' ') getOrPut(i + 1) { ArrayDeque() }.addFirst(c)
}
line.startsWith("move") -> line.split(" ").mapNotNull(String::toIntOrNull).let { (n, from, to) ->
getValue(to) += List(n) { getValue(from).removeLast() }.run { if (part2) asReversed() else this }
}
}
values.joinToString("") { it.last().toString() }
}
return listOf(solve(part2 = false), solve(part2 = true))
}
denis090712
12/06/2022, 2:28 AMfun main() {
fun part1(input: List<String>): String {
val crates = Crates.ofDrawing(input.readDrawing())
CrateMover9000().execute(
Instructions.ofList(input.readInstructions()),
crates
)
return <http://crates.top|crates.top>()
}
fun part2(input: List<String>): String {
val crates = Crates.ofDrawing(input.readDrawing())
CrateMover9001().execute(
Instructions.ofList(input.readInstructions()),
crates
)
return <http://crates.top|crates.top>()
}
//val input = readInput("Day05_test")
val input = readInput("Day05")
println(part1(input))
println(part2(input))
}
fun List<String>.readDrawing(): List<String> =
takeWhile { it.isNotBlank() }
fun List<String>.readInstructions(): List<String> =
takeLastWhile { it.startsWith("move") }
@JvmInline
value class Crates(val stacks: List<ArrayDeque<Char>>) {
fun top(): String {
return stacks.joinToString("") { it.last().toString() }
}
companion object {
fun ofDrawing(drawing: List<String>): Crates {
val height = drawing.lastIndex - 1
var stack = 0
val numbers = drawing.last()
val stackCount = numbers.split(" ").count { it.trim().toIntOrNull() != null }
val stacks = MutableList(stackCount) { ArrayDeque<Char>() }
for ((i, stackNumber) in numbers.withIndex()) {
var count = height
if (stackNumber.isDigit()) {
while (count >= 0) {
val letter = drawing[count].getOrNull(i)
if (letter?.isLetter() == true) {
stacks[stack].add(letter)
}
count -= 1
}
stack += 1
}
}
return Crates(stacks)
}
}
}
data class Instruction(
private val count: Int,
private val from: Int,
private val to: Int,
) {
fun execute(crateMover: CrateMover, crates: Crates) {
crateMover.move(from, to, count, crates)
}
companion object {
fun of(line: String): Instruction {
val (count, from, to) = line.split(" ").mapNotNull { it.trim().toIntOrNull() }
return Instruction(count, from, to)
}
}
}
@JvmInline
value class Instructions(private val instructions: List<Instruction>) {
fun execute(crateMover: CrateMover, crates: Crates) {
instructions.forEach { it.execute(crateMover, crates) }
}
companion object {
fun ofList(lines: List<String>): Instructions {
return lines
.map(Instruction::of)
.let(::Instructions)
}
}
}
interface CrateMover {
fun move(from: Int, to: Int, count: Int, crates: Crates)
}
class CrateMover9000 : CrateMover {
fun execute(instructions: Instructions, crates: Crates) {
instructions.execute(this, crates)
}
override fun move(from: Int, to: Int, count: Int, crates: Crates) {
val stacks = crates.stacks
repeat(count) {
val item = stacks[from - 1].removeLast()
stacks[to - 1].add(item)
}
}
}
class CrateMover9001 : CrateMover {
fun execute(instructions: Instructions, crates: Crates) {
instructions.execute(this, crates)
}
override fun move(from: Int, to: Int, count: Int, crates: Crates) {
val stacks = crates.stacks
val fromStack = stacks[from - 1]
val toMove = List(count) { fromStack.removeLast() }.reversed()
stacks[to - 1].addAll(toMove)
}
}
kqr
12/06/2022, 12:21 PMAbdul Khaliq
12/06/2022, 1:10 PMephemient
12/06/2022, 7:15 PMritesh
12/06/2022, 7:31 PMritesh
12/06/2022, 7:33 PMritesh
12/06/2022, 7:35 PM