Skip to content

Instantly share code, notes, and snippets.

@mscha
Created December 6, 2024 13:11
Show Gist options
  • Select an option

  • Save mscha/e316bc084ddb1839e2fb74206d139e2a to your computer and use it in GitHub Desktop.

Select an option

Save mscha/e316bc084ddb1839e2fb74206d139e2a to your computer and use it in GitHub Desktop.
Advent of Code 2024 day 6
#!/usr/bin/env raku
use v6.d;
$*OUT.out-buffer = False; # Autoflush
# Advent of Code 2024 day 6 -- https://adventofcode.com/2024/day/6
enum Direction <north east south west>;
sub left(Direction $d --> Direction) { Direction(($d - 1) % 4) }
sub right(Direction $d --> Direction) { Direction(($d + 1) % 4) }
class Position
{
has Int $.x;
has Int $.y;
my Int %dx{Direction} = north, 0, east,1, south,0, west,-1;
my Int %dy{Direction} = north,-1, east,0, south,1, west, 0;
method step(Direction $d) { pos($!x+%dx{$d}, $!y+%dy{$d}) }
method Str { "($!x,$!y)" }
method gist { self.Str }
method WHICH { ValueObjAt.new("Position|$!x|$!y") }
}
multi sub pos(Int() $x, Int() $y) { Position.new(:$x, :$y) }
multi sub pos(@xy) { pos(@xy[0], @xy[1]) }
class Lab
{
has $.input;
has $.verbose;
has @!grid = $!input.lines».comb».Array;
has $!height = @!grid.elems;
has $!width = @!grid[0].elems;
has $.start-pos = pos((^$!width X ^$!height).first(
-> ($x,$y) { @!grid[$y;$x] eq '^' }));
has $!guard-pos = $!start-pos;
has $!guard-dir = north;
has @!visited;
has $.visited-count = 0;
has @.visited-pos;
has $.loop-detected = False;
method reset
{
$!guard-pos = $!start-pos;
$!guard-dir = north;
@!visited = Empty;
$!visited-count = 0;
@!visited-pos = Empty;
$!loop-detected = False;
}
method add-obstacle($obstacle)
{
@!grid[$obstacle.y;$obstacle.x] = '#';
say "Obstacle added at $obstacle" if $!verbose;
}
method remove-obstacle($obstacle)
{
@!grid[$obstacle.y;$obstacle.x] = '.';
say "Obstacle removed from $obstacle" if $!verbose;
}
method off-grid($p) { $p.x !~~ ^$!width || $p.y !~~ ^$!height }
method blocked($p) { !self.off-grid($p) && @!grid[$p.y;$p.x] eq '#' }
method visit($p, $d)
{
unless @!visited[$p.y;$p.x] {
$!visited-count++;
@!visited-pos.append($p);
}
@!visited[$p.y;$p.x;$d]++;
}
method patrol
{
say "Guard starts at $!guard-pos, going $!guard-dir" if $!verbose;
self.visit($!guard-pos, $!guard-dir);
STEP:
loop {
my $new-pos = $!guard-pos.step($!guard-dir);
while self.blocked($new-pos) {
$!guard-dir = right($!guard-dir);
$new-pos = $!guard-pos.step($!guard-dir);
}
$!guard-pos = $new-pos;
say "Guard at $!guard-pos, going $!guard-dir" if $!verbose;
if @!visited[$!guard-pos.y;$!guard-pos.x;$!guard-dir] {
say "Guard loop detected!" if $!verbose;
$!loop-detected = True;
last STEP;
}
if self.off-grid($!guard-pos) {
say "Guard left the grid!" if $!verbose;
last STEP;
}
self.visit($!guard-pos, $!guard-dir);
}
}
}
sub MAIN(IO() $inputfile where *.f = 'aoc06.input', Bool :v(:$verbose) = False)
{
my $lab = Lab.new(:input($inputfile.slurp), :$verbose);
$lab.patrol;
say "Part 1: the guard visited $lab.visited-count() positions.";
my @candidates = $lab.visited-pos.grep(none $lab.start-pos);
my $loop-count = 0;
for @candidates -> $obstacle {
$lab.reset;
$lab.add-obstacle($obstacle);
$lab.patrol;
$loop-count++ if $lab.loop-detected;
$lab.remove-obstacle($obstacle);
}
say "Part 2: $loop-count positions result in a loop.";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment