Last active
December 5, 2019 16:30
-
-
Save emiflake/0b46e22df4b3c71b4200fa8b1b179e40 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.File | |
import java.util.stream.Stream | |
import kotlin.streams.toList | |
import kotlin.system.measureNanoTime | |
import kotlin.system.measureTimeMillis | |
sealed class IntCode { | |
abstract val steps: Int | |
object Halt : IntCode() { | |
override val steps = 1 | |
override fun toString() = "Halt" | |
} | |
data class Add(val a: Loc, val b: Loc, val out: Loc.Ref) : IntCode() { | |
override val steps = 4 | |
override fun toString() = "Add($a, $b, $out)" | |
} | |
data class Mul(val a: Loc, val b: Loc, val out: Loc.Ref) : IntCode() { | |
override val steps = 4 | |
override fun toString() = "Mul($a, $b, $out)" | |
} | |
data class Input(val out: Loc.Ref) : IntCode() { | |
override val steps = 2 | |
override fun toString() = "Input($out)" | |
} | |
data class Output(val out: Loc) : IntCode() { | |
override val steps = 2 | |
override fun toString() = "Output($out)" | |
} | |
data class JumpIfTrue(val bool: Loc, val jmpLoc: Loc) : IntCode() { | |
override val steps = 3 | |
override fun toString() = "JumpIfTrue($bool, $jmpLoc)" | |
} | |
data class JumpIfFalse(val bool: Loc, val jmpLoc: Loc) : IntCode() { | |
override val steps = 3 | |
override fun toString() = "JumpIfFalse($bool, $jmpLoc)" | |
} | |
data class Less(val a: Loc, val b: Loc, val out: Loc.Ref) : IntCode() { | |
override val steps = 4 | |
override fun toString() = "Less($a, $b, $out)" | |
} | |
data class Equals(val a: Loc, val b: Loc, val out: Loc.Ref) : IntCode() { | |
override val steps = 4 | |
override fun toString() = "Equals($a, $b, $out)" | |
} | |
} | |
sealed class Loc { | |
data class Im(val value: Int) : Loc() | |
data class Ref(val ref: Int) : Loc() | |
fun get(memory: IntArray) = when (this) { | |
is Im -> this.value | |
is Ref -> memory[this.ref] | |
} | |
} | |
fun Int.digits(take: Long) = | |
Stream.iterate(this) { it.div(10) } | |
.limit(take) | |
.toList() | |
.reversed() | |
.map { it.rem(10) } | |
fun getCode(ip: Int, memory: IntArray): IntCode { | |
val raw = memory[ip] | |
val (c,b,a,d,e) = raw.digits(5) | |
fun lda(im: Int, offset: Int) = when (im) { | |
0 -> Loc.Ref(memory[ip + offset]) | |
1 -> Loc.Im(memory[ip + offset]) | |
else -> error("???") | |
} | |
val inst = d * 10 + e | |
return when (inst) { | |
1 -> IntCode.Add(lda(a, 1), lda(b, 2), Loc.Ref(memory[ip + 3])) | |
2 -> IntCode.Mul(lda(a, 1), lda(b, 2), Loc.Ref(memory[ip + 3])) | |
3 -> IntCode.Input(Loc.Ref(memory[ip + 1])) | |
4 -> IntCode.Output(lda(a, 1)) | |
5 -> IntCode.JumpIfTrue(lda(a, 1), lda(b, 2)) | |
6 -> IntCode.JumpIfFalse(lda(a, 1), lda(b, 2)) | |
7 -> IntCode.Less(lda(a, 1), lda(b, 2), Loc.Ref(memory[ip + 3])) | |
8 -> IntCode.Equals(lda(a, 1), lda(b, 2), Loc.Ref(memory[ip + 3])) | |
99 -> IntCode.Halt | |
else -> error("Unknown opcode $inst") | |
} | |
} | |
fun runMachine(input: Int, memory: IntArray) { | |
var ip = 0 | |
loop@ while (true) { | |
val opcode = getCode(ip, memory) | |
when (opcode) { | |
is IntCode.Add -> memory[opcode.out.ref] = opcode.a.get(memory) + opcode.b.get(memory) | |
is IntCode.Mul -> memory[opcode.out.ref] = opcode.a.get(memory) * opcode.b.get(memory) | |
is IntCode.Input -> memory[opcode.out.ref] = input | |
is IntCode.Output -> println(opcode.out.get(memory)) | |
is IntCode.JumpIfTrue -> if (opcode.bool.get(memory) != 0) ip = opcode.jmpLoc.get(memory) - opcode.steps else Unit | |
is IntCode.JumpIfFalse -> if (opcode.bool.get(memory) == 0) ip = opcode.jmpLoc.get(memory) - opcode.steps else Unit | |
is IntCode.Less -> memory[opcode.out.ref] = if (opcode.a.get(memory) < opcode.b.get(memory)) 1 else 0 | |
is IntCode.Equals -> memory[opcode.out.ref] = if (opcode.a.get(memory) == opcode.b.get(memory)) 1 else 0 | |
IntCode.Halt -> break@loop | |
} | |
ip += opcode.steps | |
} | |
} | |
fun main() { | |
val memory = File("input.txt").readLines().first().split(",").map { it.toInt() }.toIntArray() | |
var avgPart1: Long = 0 | |
var avgPart2: Long = 0 | |
for (i in 1..100) { | |
avgPart1 += measureTimeMillis { runMachine(1, memory.clone()) } | |
avgPart2 += measureTimeMillis { runMachine(5, memory.clone()) } | |
} | |
println("Time of Part 01: ${avgPart1.toDouble() / 100} ms") | |
println("Time of Part 02: ${avgPart2.toDouble() / 100} ms") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment