This is a solution to Advent of Code 2020 day 14, written in Raku.
https://adventofcode.com/2020/day/14
Part One
Execute the initialization program. What is the sum of all values left in memory after it completes?
Raku
Raku's given / when
construct is ideal for alternating input lines that require different
parsing. I quickly realised that the mask could be applied to the values as a pair of and
and
or
operations.
my @lines = '14-input.txt'.IO.lines;
my $and;
my $or;
my %mem;
for @lines {
when /'mask = ' (\w+)/ {
my $mask = ~$0;
$and = $mask.trans('X' => '1').parse-base(2);
$or = $mask.trans('X' => '0').parse-base(2);
}
when /'mem[' (\d+) '] = ' (\d+)/ {
%mem{~$0} = (+$1) +& $and +| $or;
}
}
say [+] %mem.values;
15403588588538
Execute the initialization program using an emulator for a version 2 decoder chip. What is the sum of all values left in memory after it completes?
Raku
Part two is very similar, with the added step of generating all binary combinations for the
sequence of X
mask element then generating all the addresses to write into.
my @lines = '14-input.txt'.IO.lines;
my $or;
my @bits;
my %mem;
sub base2-word($n, $width) {
my $base2 = $n.base(2);
'0' x ($width - $base2.chars) ~ $base2
}
for @lines {
when /'mask = ' (\w+)/ {
my $mask = ~$0;
$or = $mask.trans('X' => '0').parse-base(2);
my @mask = $mask.comb;
@bits = (^@mask.elems).grep( -> $i { @mask[$i] eq 'X' });
}
when /'mem[' (\d+) '] = ' (\d+)/ {
my $addr = base2-word((+$0) +| $or, 36);
my $value = +$1;
for ^(2 ** @bits.elems) -> $n {
my $bit-values = base2-word($n, @bits.elems);
my @addr = $addr.comb;
@addr[@bits] = $bit-values.comb;
%mem{@addr.join} = $value;
}
}
}
say "{+%mem} memory locations";
say [+] %mem.values;
78824 memory locations 3260587250457