#!/usr/bin/perl use v5.35.0; # Parse input map my ($width, @edge, @obstacle, @obstacles, $start, $facing); my $pos = 0; while (<>) { $width ||= length; for (split //) { $edge[$pos] = /\s/; if (/#/) { $obstacle[$pos] = 1; push @obstacles, $pos; } if ((my $i = index('^>v<', $_)) >= 0) { $start = $pos; $facing = $i; } $pos++; } } my @step = (-$width, 1, $width, -1); # Try placing a single obstacle in each spot that doesn't # already have one and isn't where the guard starts from, # and count how many times that makes the guard get stuck my $loops = 0; my @hit = (0) x @edge; for my $proposed (0 .. $#edge) { next if $obstacle[$proposed]; next if $proposed == $start; $obstacle[$proposed] = 1; my $pos = $start; my $dir = $facing; my $mark = 1 << $dir; for (;;) { $pos += $step[$dir]; # Advance last unless 0 <= $pos < @edge; # Escape last if $edge[$pos]; if ($obstacle[$pos]) { # If this obstacle has already been hit # from this direction, that's a loop if ($hit[$pos] & $mark) { ++$loops; last; } $hit[$pos] |= $mark; # Record hit $pos -= $step[$dir]; # Retreat $dir++, $dir &= 3; # Turn right $mark = 1 << $dir; } } # Clean up for next proposed obstacle $obstacle[$proposed] = 0; $hit[$_] = 0 for ($proposed, @obstacles); } say $loops;