Last active
March 12, 2021 13:40
-
-
Save sungkmi/d48af906a7c18a4477b51b8a7c69a58e 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
package sungkmi.aoc2020.day14 | |
case class State(mask: Mask, memory: Memory) | |
object State: | |
val initial: State = State( | |
mask = Mask(Set.empty, Set.empty), | |
memory = Map.empty | |
) | |
case class Mask(zero: Set[Int], one: Set[Int]) | |
object Mask: | |
def fromString(s: String): Mask = | |
val grouped: Map[Char, Seq[(Char, Int)]] = s.reverse.zipWithIndex.groupBy(_._1) | |
def mkSet(key: Char): Set[Int] = grouped(key).map(_._2).toSet | |
Mask(zero = mkSet('0'), one = mkSet('1')) | |
extension (m: Mask) | |
def apply(n: BigInt): BigInt = | |
val cleared = m.zero.foldLeft(n)(_ `clearBit` _) | |
m.one.foldLeft(cleared)(_ `setBit` _) | |
type Memory = Map[Int, BigInt] | |
extension (m: Memory) | |
def apply(mask: Mask): Memory = m.view.mapValues(mask(_)).toMap | |
def sumValues: BigInt = m.values.sum | |
enum Instruction: | |
case SetMask(maskString: String) | |
case SetMemory(index: Int, value: BigInt) | |
extension (i: Instruction) | |
def apply(s: State): State = i match | |
case Instruction.SetMask(maskString) => | |
s.copy(mask = Mask.fromString(maskString)) | |
case Instruction.SetMemory(index, value) => | |
s.copy(memory = s.memory + (index -> s.mask(value))) | |
object Instruction: | |
def parse(s: String): Seq[Instruction] = s.split("\n").toSeq.map: | |
case line if line.startsWith("mask = ") => | |
SetMask(line.drop(7)) | |
case line => | |
val Array(k, v) = line `split` " = " | |
SetMemory(k.drop(4).dropRight(1).toInt, BigInt(v)) | |
case class State2(mask: Mask2, memory: Memory2) | |
object State2: | |
val initial: State2 = State2( | |
mask = Mask2(Set.empty, Set.empty), | |
memory = Map.empty | |
) | |
case class Mask2(sets: Set[Int], floats: Set[Int]) | |
object Mask2: | |
def fromString(s: String): Mask2 = | |
val grouped: Map[Char, Seq[(Char, Int)]] = | |
s.reverse.zipWithIndex.groupBy(_._1).withDefaultValue(Seq.empty) | |
def mkSet(key: Char): Set[Int] = grouped(key).map(_._2).toSet | |
Mask2(sets = mkSet('1'), floats = mkSet('X')) | |
extension (m: Mask2) | |
def apply(n: BigInt): Seq[BigInt] = | |
val afterSet = m.sets.foldLeft(n)((n1, index) => n1.setBit(index)) | |
m.floats.foldLeft(Seq(afterSet)): | |
case (ints, float) => ints.map(_.setBit(float)) ++ ints.map(_.clearBit(float)) | |
type Memory2 = Map[BigInt, BigInt] | |
enum Instruction2: | |
case SetMask(maskString: String) | |
case SetMemory(index: BigInt, value: BigInt) | |
object Instruction2: | |
def parse(s: String): Seq[Instruction2] = s.split("\n").toSeq.map: | |
case line if line.startsWith("mask = ") => | |
SetMask(line.drop(7)) | |
case line => | |
val Array(k, v) = line `split` " = " | |
SetMemory(BigInt(k.drop(4).dropRight(1)), BigInt(v)) | |
extension (i: Instruction2) | |
def apply(s: State2): State2 = i match | |
case Instruction2.SetMask(maskString) => | |
s.copy(mask = Mask2.fromString(maskString)) | |
case Instruction2.SetMemory(index, value) => | |
val newMemory = s.mask(index).foldLeft(s.memory): | |
(memory, i) => memory + (i -> value) | |
s.copy(memory = newMemory) | |
def solve1(input: String): BigInt = | |
val instructions = Instruction.parse(input) | |
instructions.foldLeft(State.initial): | |
case (state, instruction) => instruction(state) | |
._2.sumValues | |
def solve2(input: String): BigInt = | |
val instructions = Instruction2.parse(input) | |
instructions.foldLeft(State2.initial): | |
case (state, instruction) => instruction(state) | |
.memory.values.sum | |
@main def part1: Unit = | |
val ans = solve1(input) | |
println(ans) | |
@main def part2: Unit = | |
val ans = solve2(input) | |
println(ans) | |
//lazy val input: String = """mask = 0XX1XXX1101X101100101001010X1X110000 |
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
package sungkmi.aoc2020.day14 | |
class Day14Test extends munit.FunSuite { | |
val s = """mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X | |
mem[8] = 11 | |
mem[7] = 101 | |
mem[8] = 0""" | |
test("Mask#fromString") { | |
val mask = Mask.fromString("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X") | |
val expected = Mask(zero = Set(1), one = Set(6)) | |
assertEquals(mask, expected) | |
} | |
test("Mask#apply") { | |
val mask = Mask(zero = Set(1), one = Set(6)) | |
assertEquals(mask(BigInt(11)), BigInt(73)) | |
assertEquals(mask(BigInt(101)), BigInt(101)) | |
assertEquals(mask(BigInt(0)), BigInt(64)) | |
} | |
test("parse") { | |
import Instruction._ | |
val expected = Seq( | |
SetMask("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X"), | |
SetMemory(8, BigInt(11)), | |
SetMemory(7, BigInt(101)), | |
SetMemory(8, BigInt(0)), | |
) | |
assertEquals(Instruction.parse(s), expected) | |
} | |
test("solve1") { | |
assertEquals(solve1(s), BigInt(165)) | |
} | |
val s2 = """mask = 000000000000000000000000000000X1001X | |
mem[42] = 100 | |
mask = 00000000000000000000000000000000X0XX | |
mem[26] = 1""" | |
test("solve2") { | |
assertEquals(solve2(s2), BigInt(208)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment