AoC Day 20 – Jurassic Jigsaw

This is a solution to Advent of Code 2020 day 20, written in Raku.

https://adventofcode.com/2020/day/20

Part One

Assemble the tiles into an image. What do you get if you multiply together the IDs of the four corner tiles?

I have chosen to use a bag of tuples to store each tile. This will allow for tile transformations and for taking slices of the edge coordinates to generate a numeric representation for each edge.

In part one we need to identify the corner tiles. To do this, we can "cheat" and look for the tiles that have two edge values that don't match any other edge value (in normal or flipped orientation). This can be done by creating a bag of all edge values and then finding tiles that can only be adjacent to two other tiles.

  use Tuple;

  my @tiles = '20-input.txt'.IO.slurp.trim.split("\n\n");
  say +@tiles;

  class Tile {
      has $.id;
      has $.active;

      my @edge-coords = ((0 X 0..9), (9 X 0..9), (0..9 X 0), (0..9 X 9))>>.Array;

      method edge-bits {
          @edge-coords.map(
              -> $e {
                  $!active{ $e.map(-> $p { tuple($p) } ) }
              }
          )
      }

      method edges {
          self.edge-bits.map(*.join.parse-base(2))
      }

      method edge-variants {
          self.edge-bits.map(*.join).map(
              -> $e {
                    ($e.parse-base(2), $e.flip.parse-base(2))
              })
      }
  }

  @tiles .= map(
      -> $t {
          my $id = $t.match(/\d+/).Str;
          my @grid = $t.lines.skip>>.comb;
          my $active = Bag.new: @grid.kv.map: -> $y, @row {
              |@row.kv.map: -> $x, $state {
                  tuple($x, $y) if $state eq '#'
              }
          }

          Tile.new(:$id, :$active)
      });

  my $all-possible = @tiles.map(*.edge-variants).flat.Bag;

  say [*] @tiles.grep(-> $t { $all-possible{$t.edges}.Bag{1} == 2 }).map(*.id);
144
29584525501199

Part Two

Determine how rough the waters are in the sea monsters' habitat by counting the number of # that are not part of a sea monster.

How many # are not part of a sea monster?

For part two we actually need to do the work of assemblig the image. The information we calculated in part one should be sufficient to do this.

Then we should be able to search for a set of coordinates translated to each potential position in the bag of active coordinates.

  use Tuple;

  my @tiles = '20-input.txt'.IO.slurp.trim.split("\n\n");
  say +@tiles;

  class Tile {
      has $.id;
      has @.edges;
      has @.edges-flipped;
      has $.active;

      submethod TWEAK {
          my @edge-coords = ((0 X 0..9), (0..9 X 9), (9 X 0..9), (0..9 X 0))>>.Array;

          my @edge-words = @edge-coords.map(
              -> $e {
                  $!active{ $e.map(-> $p { tuple($p) } ) }
              }).map(*.join);

          @!edges = @edge-words.map(*.parse-base(2));
          @!edges-flipped = @edge-words.map(*.flip.parse-base(2));
      }

      method edge-variants {
          flat(@!edges, @!edges-flipped)
      }

      method flip-v {
          $!active = Bag.new: $!active.keys.map(-> $p { tuple($p[0], 9 - $p[1]) } )
      }

      method flip-h {
          $!active = Bag.new: $!active.keys.map(-> $p { tuple(9 - $p[0], $p[1]) } )
      }

      method rotate-a {
          $!active = Bag.new: $!active.keys.map(-> $p { tuple($p[1], 9 - $p[0]) } )
      }

      method rotate-c {
          $!active = Bag.new: $!active.keys.map(-> $p { tuple(9 - $p[1], $p[0]) } )
      }

      method draw {
          for ^10 -> $y {
              my @chars = do for ^10 -> $x {
                  $!active{tuple($x,$y)}:exists ?? '#' !! '.'
              }
              say @chars.join
          }
          say '';
      }
  }

  @tiles .= map(
      -> $t {
          my $id = $t.match(/\d+/).Int;
          my @grid = $t.lines.skip>>.comb;
          my $active = Bag.new: @grid.kv.map: -> $y, @row {
              |@row.kv.map: -> $x, $state {
                  tuple($x, $y) if $state eq '#'
              }
          }

          Tile.new(:$id, :$active)
      });

  my $all-possible = @tiles.map(*.edge-variants).flat.Bag;

  my $a-corner = @tiles.grep(-> $t { $all-possible{$t.edges}.Bag{1} == 2 }).first;
  say $a-corner;

  say @tiles.grep(-> $t { $t.edge-variants.Set (&) $a-corner.edges.Set and $t.id != $a-corner.id } ).map(*.gist).join("\n");
  say "";
  my $t = @tiles.grep(-> $t { $t.edge-variants.Set (cont) 211 and $t.id != 2111} ).first;
  say "Tile:";
  $t.draw;
144
Tile.new(id => 2111, edges => [602, 211, 789, 727], edges-flipped => [361, 812, 675, 941], active => ((3, 0).IterationBuffer=>1,(9, 5).IterationBuffer=>1,(6, 2).IterationBuffer=>1,(0, 5).IterationBuffer=>1,(2, 0).IterationBuffer=>1,(1, 8).IterationBuffer=>1,(7, 0).IterationBuffer=>1,(9, 0).IterationBuffer=>1,(3, 9).IterationBuffer=>1,(2, 9).IterationBuffer=>1,(8, 3).IterationBuffer=>1,(0, 3).IterationBuffer=>1,(8, 0).IterationBuffer=>1,(1, 1).IterationBuffer=>1,(0, 6).IterationBuffer=>1,(9, 1).IterationBuffer=>1,(1, 2).IterationBuffer=>1,(5, 9).IterationBuffer=>1,(5, 0).IterationBuffer=>1,(7, 8).IterationBuffer=>1,(8, 9).IterationBuffer=>1,(5, 7).IterationBuffer=>1,(0, 0).IterationBuffer=>1,(9, 9).IterationBuffer=>1,(4, 1).IterationBuffer=>1,(3, 2).IterationBuffer=>1,(9, 7).IterationBuffer=>1,(7, 4).IterationBuffer=>1,(0, 8).IterationBuffer=>1,(7, 5).IterationBuffer=>1).Bag)
Tile.new(id => 1789, edges => [970, 211, 405, 914], edges-flipped => [335, 812, 678, 295], active => ((6, 7).IterationBuffer=>1,(1, 0).IterationBuffer=>1,(7, 6).IterationBuffer=>1,(2, 5).IterationBuffer=>1,(6, 6).IterationBuffer=>1,(9, 7).IterationBuffer=>1,(0, 6).IterationBuffer=>1,(7, 8).IterationBuffer=>1,(0, 1).IterationBuffer=>1,(5, 0).IterationBuffer=>1,(9, 1).IterationBuffer=>1,(9, 5).IterationBuffer=>1,(2, 6).IterationBuffer=>1,(0, 8).IterationBuffer=>1,(5, 8).IterationBuffer=>1,(8, 0).IterationBuffer=>1,(5, 2).IterationBuffer=>1,(2, 0).IterationBuffer=>1,(3, 9).IterationBuffer=>1,(2, 9).IterationBuffer=>1,(6, 1).IterationBuffer=>1,(8, 5).IterationBuffer=>1,(9, 2).IterationBuffer=>1,(4, 4).IterationBuffer=>1,(8, 9).IterationBuffer=>1,(8, 8).IterationBuffer=>1,(2, 1).IterationBuffer=>1,(5, 1).IterationBuffer=>1,(8, 7).IterationBuffer=>1,(9, 9).IterationBuffer=>1,(8, 1).IterationBuffer=>1,(0, 3).IterationBuffer=>1,(0, 2).IterationBuffer=>1,(4, 5).IterationBuffer=>1,(0, 0).IterationBuffer=>1,(2, 4).IterationBuffer=>1,(5, 6).IterationBuffer=>1,(5, 5).IterationBuffer=>1,(6, 8).IterationBuffer=>1,(5, 9).IterationBuffer=>1,(4, 2).IterationBuffer=>1,(7, 7).IterationBuffer=>1,(3, 5).IterationBuffer=>1).Bag)
Tile.new(id => 3049, edges => [675, 722, 418, 546], edges-flipped => [789, 301, 278, 273], active => ((9, 1).IterationBuffer=>1,(0, 8).IterationBuffer=>1,(2, 6).IterationBuffer=>1,(7, 8).IterationBuffer=>1,(5, 8).IterationBuffer=>1,(3, 4).IterationBuffer=>1,(5, 9).IterationBuffer=>1,(8, 3).IterationBuffer=>1,(3, 3).IterationBuffer=>1,(7, 3).IterationBuffer=>1,(1, 2).IterationBuffer=>1,(3, 9).IterationBuffer=>1,(4, 0).IterationBuffer=>1,(7, 5).IterationBuffer=>1,(0, 4).IterationBuffer=>1,(9, 4).IterationBuffer=>1,(6, 6).IterationBuffer=>1,(5, 5).IterationBuffer=>1,(0, 2).IterationBuffer=>1,(3, 2).IterationBuffer=>1,(9, 8).IterationBuffer=>1,(9, 2).IterationBuffer=>1,(8, 0).IterationBuffer=>1,(2, 9).IterationBuffer=>1,(1, 1).IterationBuffer=>1,(0, 9).IterationBuffer=>1,(3, 6).IterationBuffer=>1,(0, 0).IterationBuffer=>1,(7, 6).IterationBuffer=>1,(8, 9).IterationBuffer=>1,(2, 4).IterationBuffer=>1,(4, 1).IterationBuffer=>1).Bag)

Tile:
###..#..#.
#.#..##.##
#...##...#
#.........
..#.#.....
..####..##
#.#..###..
......####
#....####.
..##.#..##
Notes

Left 602 (T to B) – 361 (B to T)

Bottom 211 (L to R) - 812 (R to L)

Right 789 (T to B) - 675 (B to T)

Top 727 (L to R) - 941 (R to L)

Tile 2111: #.##.#.### .#..#….# .#.#..#… #…….#. …….#.. #……#.# #……… …..#…# ##…..#.. ..##.#..##

Tile.new(id => 2111, edges => [602, 211, 789, 727], edges-flipped => [361, 812, 675, 941], active => ((7, 0), (2, 0), (1, 1), (7, 5), (9, 0), (5, 0), (5, 9), (8, 3), (2, 9), (6, 2), (9, 1), (9, 9), (9, 5), (3, 0), (7, 8), (9, 7), (3, 2), (5, 7), (0, 8), (7, 4), (1, 8), (4, 1), (3, 9), (0, 6), (0, 5), (8, 9), (8, 0), (1, 2), (0, 3), (0, 0)).Bag)

raku 
comments powered by Disqus