sub solve-p1(@dish, \rows, \cols) {
for ^cols -> $col {
my ($start-row, $row) = 0, 0;
while $row < rows {
given @dish[$row;$col] {
when 'O' {
@dish[$start-row,$row;$col] = 'O', '.' if $start-row != $row;
++$start-row;
}
when '#' { $start-row = $row + 1; }
}
++$row;
}
}
}
sub tilt-line-front(@line, @ranges) {
for @ranges -> (\begin, \end) {
my $circles = +@line[begin..end].grep('O');
@line[begin..(begin+$circles-1)] X= 'O' if $circles;
@line[(begin+$circles)..end] X= '.';
@line.eager;
}
}
sub tilt-line-back(@line, @ranges) {
for @ranges -> (\begin, \end) {
my $circles = +@line[begin..end].grep('O');
@line[(end-$circles+1)..end] X= 'O' if $circles;
@line[begin..(end-$circles)] X= '.';
@line.eager;
}
}
my @recs;
sub solve-p2(@dish, \rows, \cols, \rounds) {
my %rocks is Set = @dish[*;*].grep('#', :k).map({ [$_ div cols, $_ mod cols] });
my (@row-ranges, @col-ranges);
for ^rows -> \row {
my $start = 0;
@row-ranges[row] = (gather {
for %rocks.keys.grep(*[0] == row).sort -> ($, \col) {
take [$start,col-1] if col - $start > 1;
$start = col + 1;
}
take [$start,cols-1] if cols - $start > 1;
}).Array;
}
for ^cols -> \col {
my $start = 0;
@col-ranges[col] = (gather {
for %rocks.keys.grep(*[1] == col).sort -> (\row, $) {
take [$start,row-1] if row - $start > 1;
$start = row + 1;
}
take [$start,rows-1] if rows - $start > 1;
}).Array;
}
for ^rounds -> \round {
tilt-line-front(@dish[*;$_], @col-ranges[$_]) for ^cols; # north
tilt-line-front(@dish[$_], @row-ranges[$_]) for ^rows; # west
tilt-line-back(@dish[*;$_], @col-ranges[$_]) for ^cols; # south
tilt-line-back(@dish[$_], @row-ranges[$_]) for ^rows; # east
my $rec = @dish[*;*].grep('O', :k).sort.Array;
return [$_, round] with @recs.first($rec, :k);
@recs.push($rec);
}
}
my @dish = $*IN.lines.map(*.comb.Array);
my (\rows, \cols) = +@dish, +@dish[0];
solve-p1(@dish, rows, cols);
put 'part 1: ', @dish[*;*].grep('O', :k).map({ rows - $_ div cols }).sum;
with solve-p2(@dish, rows, cols, 1_000_000_000) {
put 'part 2: ', @recs[.[0] + (1_000_000_000 - .[0] - 1) % (.[1] - .[0])].map({ rows - $_ div cols }).sum;
}