sub mirror-pos-p1(@lines) {
do for (^(+@lines-1)).grep({ @lines[$_+1] eq @lines[$_] }) -> $row {
my $size = min($row+1, +@lines-$row-1);
$row+1 if all(($row-$size+1 .. $row-1).map({ @lines[$_] eq @lines[2*$row-$_+1] }));
}
}
sub one-diff(@L1, @L2) {
my %diff = @L1.pairs.map({.key~.value}) (-) @L2.pairs.map({.key~.value});
+%diff == 1 ?? %diff.keys[0].match(/\d+/).Int !! -1
}
sub one-diff-lines(@M) {
(^+@M X ^+@M).grep({ .[0] < .[1] }).map({
my $pos = one-diff(@M[.[0]], @M[.[1]]);
[.[0], .[1], $pos] if $pos != -1
})
}
sub find-mirrors(@M, @matched) {
my @mirrors;
for one-diff-lines(@M) -> (\row1, \row2, \pos) {
my @M_ = @M.deepmap(*.clone);
@M_[row2].splice(pos, 1, @M_[row1;pos]);
@mirrors.push(|(mirror-pos-p1(@M_».join) (-) @matched).keys);
}
@mirrors.unique
}
sub mirror-pos-p2(@M, @matched-rows, @matched-cols) {
find-mirrors(@M, @matched-rows),
find-mirrors((^+@M[0]).map({ @M[*;$_].Array }), @matched-cols)
}
my ($sum1, $sum2);
for $*IN.slurp.split("\n\n") -> $pat {
my @M = $pat.lines.map(*.comb.Array);
my @rows = mirror-pos-p1(@M».join);
my @cols = mirror-pos-p1((^+@M[0]).map({ @M[*;$_].join }));
$sum1 += @rows.sum * 100 + @cols.sum;
with mirror-pos-p2(@M, @rows, @cols) {
$sum2 += .[0].sum * 100 + .[1].sum;
}
}
put 'part 1: ', $sum1;
put 'part 2: ', $sum2;