From c8fa4449b27bd900b9818473f53d8165782dc99e Mon Sep 17 00:00:00 2001 From: Jeremy Kaplan Date: Sun, 13 Dec 2020 23:32:42 -0800 Subject: [PATCH] Day 14 Part 2 --- 2020/day14/day14.ex | 113 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/2020/day14/day14.ex b/2020/day14/day14.ex index c388f74..3b7a5b1 100644 --- a/2020/day14/day14.ex +++ b/2020/day14/day14.ex @@ -6,10 +6,10 @@ defmodule Day14 do defp test_input do """ - mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X - mem[8] = 11 - mem[7] = 101 - mem[8] = 0 + mask = 000000000000000000000000000000X1001X + mem[42] = 100 + mask = 00000000000000000000000000000000X0XX + mem[26] = 1 """ end @@ -31,28 +31,15 @@ defmodule Day14 do end) end - defp pow(_base, 0) do - 1 - end - - defp pow(_base, exp) when exp < 0 do - raise ArithmeticError, "negative exponents not supported" - end - - defp pow(base, exp) when exp > 0 do - List.duplicate(base, exp) - |> Enum.reduce(1, &(&1 * &2)) - end - defp parse_mask(mask) do String.codepoints(mask) |> Enum.reverse() |> Enum.with_index() |> Enum.reduce([], fn {char, idx}, ops -> case char do - "X" -> ops - "0" -> [{:and, Bitwise.bnot(pow(2, idx))} | ops] - "1" -> [{:or, pow(2, idx)} | ops] + "X" -> [{:float, idx} | ops] + "0" -> [{:unset, idx} | ops] + "1" -> [{:set, idx} | ops] end end) end @@ -61,12 +48,16 @@ defmodule Day14 do num end - defp apply_mask([{:and, val} | rest], num) do - apply_mask(rest, Bitwise.band(val, num)) + defp apply_mask([{:float, _} | rest], num) do + apply_mask(rest, num) end - defp apply_mask([{:or, val} | rest], num) do - apply_mask(rest, Bitwise.bor(val, num)) + defp apply_mask([{:unset, idx} | rest], num) do + apply_mask(rest, Bitwise.band(num, Bitwise.bnot(Bitwise.bsl(1, idx)))) + end + + defp apply_mask([{:set, idx} | rest], num) do + apply_mask(rest, Bitwise.bor(num, Bitwise.bsl(1, idx))) end defp run([], {_, memory}) do @@ -93,10 +84,80 @@ defmodule Day14 do |> Enum.sum() end + def part2 do + read_input() + |> parse_program() + |> run_v2({nil, %{}}) + |> Enum.map(fn {_, val} -> val end) + |> Enum.sum() + end + + defp run_v2([], {_, memory}) do + memory + end + + defp run_v2([{:mask, mask} | rest], {_, memory}) do + run_v2(rest, {mask, memory}) + end + + defp run_v2([{:mem, addr, value} | rest], {mask, memory}) do + addrs = expand_float(mask, [apply_mask_v2(mask, addr)]) + + memory = + Enum.reduce(addrs, memory, fn addr, mem -> + Map.put(mem, addr, value) + end) + + run_v2(rest, {mask, memory}) + end + + defp expand_float([], addrs) do + addrs + end + + defp expand_float([{:float, idx} | rest], addrs) do + addrs = + Enum.reduce(addrs, [], fn addr, expanded -> + [ + apply_mask([{:unset, idx}], addr), + apply_mask([{:set, idx}], addr) + ] ++ expanded + end) + + expand_float(rest, addrs) + end + + defp expand_float([{:set, _} | rest], addrs) do + expand_float(rest, addrs) + end + + defp expand_float([{:unset, _} | rest], addrs) do + expand_float(rest, addrs) + end + + defp apply_mask_v2([], num) do + num + end + + defp apply_mask_v2([{:float, _} | rest], num) do + apply_mask_v2(rest, num) + end + + defp apply_mask_v2([{:unset, _} | rest], num) do + apply_mask_v2(rest, num) + end + + defp apply_mask_v2([{:set, idx} | rest], num) do + apply_mask_v2(rest, Bitwise.bor(num, Bitwise.bsl(1, idx))) + end + def debug do - nil + mask = parse_mask("000000000000000000000000000000X1001X") + addr = 42 + expand_float(mask, [apply_mask_v2(mask, addr)]) end end Day14.part1() |> IO.inspect() -Day14.debug() |> IO.inspect() +Day14.part2() |> IO.inspect() +# Day14.debug() |> IO.inspect()