Created
December 6, 2024 13:11
-
-
Save mscha/e316bc084ddb1839e2fb74206d139e2a to your computer and use it in GitHub Desktop.
Advent of Code 2024 day 6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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