#!/usr/bin/perl use v5.35.0; use List::Util 'sum'; # Parse input map my $width = 100; my (@wall, @box_l, @box_r, $start); my $size = 0; while (defined($_ = <>) && /./) { my $pos = $size; chomp; for (split //) { $wall[$pos] = 0 + /#/; $wall[$pos+1] = $wall[$pos]; $box_l[$pos] = 0 + /O/; $box_r[$pos+1] = $box_l[$pos]; $start = $pos if /@/; $pos += 2; } $size += $width; } # Walk around as directed my $robot = $start; #show('Start'); while (<>) { for (split //) { my $dir = index '^>v<', $_; if ($dir >= 0) { my $step = (-$width, 1, $width, -1)[$dir]; $robot += $step if pusher($robot, $step); #show($_); } } } # Deliver the box say sum map {defined($box_l[$_]) && $box_l[$_] && $_} (0 .. $#box_l); sub pusher($pos, $step) { my (@must_be_shovable, @tested, @to_be_shoved); push @must_be_shovable, $pos + $step; while (@must_be_shovable) { my $pos = shift @must_be_shovable; return 0 if $wall[$pos]; next if $tested[$pos]; $tested[$pos] = 1; if ($box_l[$pos]) { push @to_be_shoved, $pos; push @must_be_shovable, $pos + 1; push @must_be_shovable, $pos + $step; } if ($box_r[$pos]) { push @to_be_shoved, $pos; push @must_be_shovable, $pos - 1; push @must_be_shovable, $pos + $step; } } # Shove is all you need #show("shoving " . join ' ', @to_be_shoved); while (@to_be_shoved) { my $pos = pop @to_be_shoved; $box_l[$pos + $step] = $box_l[$pos]; $box_r[$pos + $step] = $box_r[$pos]; $box_l[$pos] = $box_r[$pos] = 0; #show('shoved'); } return 1; } sub show { #return; say shift if @_; my $row = 0; while ($row < $size) { my $pos = $row; $row += $width; my $line = ''; while ($pos < $row && defined($wall[$pos])) { $line .= $robot == $pos? '@': $wall[$pos]? '#': $box_l[$pos]? '[': $box_r[$pos]? ']': '.'; ++$pos; } say $line; } say ''; }