]> www.fi.muni.cz Git - aoc2020.git/commitdiff
40.pl cleaner solution
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Sun, 20 Dec 2020 15:56:00 +0000 (16:56 +0100)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Sun, 20 Dec 2020 16:18:30 +0000 (17:18 +0100)
40.pl

diff --git a/40.pl b/40.pl
index df479d91baa74f58b8d4e6935eee2b2eb1de1fe5..074e56152106287dd84e4420d59c428cfeac882d 100755 (executable)
--- a/40.pl
+++ b/40.pl
 
 use strict;
 
-local $/ = "\n\n";
+sub rows2str {
+       my (@rows) = @_;
+       return join("\n", @rows) . "\n";
+}
 
-sub rev {
-       my ($in) = @_;
-       return join('', reverse split //, $in);
+sub rotate {
+       my ($str) = (@_);
+       my $dim =()= $str =~ /(\n)/g;
+       my $newstr = '';
+       for my $y (0 .. $dim-1) {
+               for my $x (0 .. $dim-1) {
+                       $newstr .= substr($str, $y + ($dim+1)*($dim - $x - 1), 1);
+               }
+               $newstr .= "\n";
+       }
+       return $newstr;
 }
 
+sub flip {
+       my ($str) = @_;
+       return rows2str(map { join('', reverse split //) } split /\n/, $str);
+}
+
+sub rotate_or_flip {
+       my ($str, $count) = @_;
+       return $count == 4 ? flip($str) : rotate($str);
+}
+
+sub trim {
+       my ($str) = @_;
+       my @rows = split /\n/, $str;
+       shift @rows;
+       pop @rows;
+       return map { s/\A.//; s/.\z//; $_ } @rows;
+}
+
+sub top_side {
+       $_[0] =~ /\A(.*?)\n/xms;
+       return $1;
+}
+
+sub bottom_side {
+       $_[0] =~ /\A.*\n(.*?)\n\z/xms;
+       return $1;
+}
+
+sub left_side {
+       return join('', map { substr($_, 0, 1) } split /\n/, $_[0]);
+}
+
+sub right_side {
+       return join('', map { substr($_, -1, 1) } split /\n/, $_[0]);
+}
+
+my (%top2tile, %left2tile);
+
+local $/ = "\n\n";
 
-my %tiles;
-my %sides;
-my %side2tiles;
 while (<>) {
-       my ($id, @rows) = split /\n/;
-       $id =~ s/Tile //;
-       $id =~ s/://;
-       $tiles{$id} = \@rows;
-       $sides{$id} = [
-               $rows[0],
-               join('', map { substr($_, -1, 1) } @rows),
-               rev($rows[-1]),
-               rev(join('', map { substr($_, 0, 1) } @rows)),
-       ];
-       print "Tile <$id> sides ", join(' ', @{ $sides{$id} }), "\n";
-       my $i = 0;
-       for my $side (@{ $sides{$id} }) {
-               $side2tiles{$side}->{$id} = $i;
-               $side2tiles{rev($side)}->{$id} = $i+4;
-               $i++;
+       my ($id, $data) = /\ATile\s+(\d+):\n(.*?\n)\n?\z/xms;
+       for (1 .. 8) {
+               push @{ $top2tile{top_side($data)} }, [ $id, $data ];
+               push @{ $left2tile{left_side($data)} }, [ $id, $data ];
+               $data = rotate_or_flip($data, $_);
        }
 }
 
+# computed in 39.pl
 my $dim = 12;
-my $next = '###.#.#...';
+my $top_row = '###.#.#...';
 
 # my $dim = 3;
-# my $next = '#...##.#..';
-my $next_id = -1;
-my $map;
-my %seen;
+# my $top_row = '#...##.#..';
+
+my $top_id = -1;
+my @map_rows;
+my $data;
 
 for my $y (0 .. $dim-1) {
-       my ($id) = grep { $_ != $next_id } keys %{ $side2tiles{$next} };
-       my $side = $side2tiles{$next}->{$id};
-       $map->[$y][0] = [ $id, $side ];
-       die "$id seen again\n"
-               if $seen{$id};
-       $seen{$id} = 1;
-       my $next_side = $side > 3
-               ? (($side - 1) & 3)
-               : ($side + 1) & 3;
-       $next = $sides{$id}->[$next_side];
-       $next = rev($next) if $side > 3;
-       my $top_side = $side;
-       print "id=$id, side=$side, next_side=$next_side, top_side=$top_side, next=|$next|\n";
-       $next_id = $id;
-       
-       for my $x (1 .. $dim-1) {
-               ($id) = grep { $_ != $next_id } keys %{ $side2tiles{$next} };
-               $side = $side2tiles{$next}->{$id};
-               die "$id seen again\n"
-                       if $seen{$id};
-               $seen{$id} = 1;
-               my $top_side = ((($side & 3) + (($side >> 2) ? 1 : -1)) & 3) | (($side & 4) ^ 4);
-               $map->[$y][$x] = [ $id, $top_side ];
-               $next_side = (($side + 2) & 3);
-               $next = $sides{$id}->[$next_side];
-               $next = rev($next) if $side < 4;
-               $next_id = $id;
-               print "id=$id, side=$side, next_side=$next_side, top_side=$top_side, next=|$next|\n";
-       }
+       my ($id)  = grep { $_->[0] != $top_id } @{ $top2tile{$top_row} };
+       ($top_id, $data) = @$id;
+       $top_row = bottom_side($data);
 
-       print "\n";
+       push @map_rows, trim($data);
 
-       ($next_id, $next_side) = @{ $map->[$y][0] };
-       $next = $sides{$next_id}->[($next_side + 2) & 3];
-       $next = rev($next) if $next_side < 4;
-       print "bottom side of $next_id = |$next|\n";
-}
+       my $right_id = $top_id;
+       my $right_row = right_side($data);
+
+       for my $x (1 .. $dim-1) {
+               my ($id) = grep { $_->[0] != $right_id } @{ $left2tile{$right_row} };
+               ($right_id, $data) = @$id;
+               $right_row = right_side($data);
 
-my $shortmap = '';
-for my $y (0 .. 8*$dim-1) {
-       my $y1 = 1 + ($y % 8);
-       for my $x (0 .. 8*$dim-1) {
-               my $x1 = 1 + ($x % 8);
-               my ($id, $or) = @{ $map->[int($y/8)][int($x/8)] };
-               my ($x2, $y2) = ($x1, $y1);
-               if ($or == 1) {
-                       ($x2, $y2) = (9-$y1, $x1);
-               } elsif ($or == 2) {
-                       ($x2, $y2) = (9-$x1, 9-$y1);
-               } elsif ($or == 3) {
-                       ($x2, $y2) = ($y1, 9-$x1);
-               } elsif ($or == 4) {
-                       ($x2, $y2) = (9-$x1, $y1);
-               } elsif ($or == 5) {
-                       ($x2, $y2) = (9-$y1, 9-$x1);
-               } elsif ($or == 6) {
-                       ($x2, $y2) = ($x1, 9-$y1);
-               } elsif ($or == 7) {
-                       ($x2, $y2) = ($y1, $x1);
+               my $i = @map_rows - 8;
+               for (trim($data)) {
+                       $map_rows[$i++] .= $_;
                }
-               $shortmap .= substr($tiles{$id}->[$y2], $x2, 1);
        }
-       $shortmap .= "\n";
 }
 
-print join("\n", $shortmap), "\n";
-
-my $monster = join('[\.#\n]' x ($dim * 8 - 20 + 1), map { $a=$_; $a=~ s/\./[\.#]/g; $a } 
-        '..................#.',
-       '#....##....##....###',
-       '.#..#..#..#..#..#...'
-);
-
-$monster = ".(?=$monster)";
-print "monster=$monster\n";
-
-for (1 .. 2) {
-       for (1 .. 4) {
-               my $count;
-               if (my $count =()= $shortmap =~ /($monster)/g) {
-                       print "$count matches\n";
-                       my $hashes =()= $shortmap =~ /#/g;
-                       print "$hashes-$count*15=", $hashes-$count*15, "\n";
-                       exit 0;
-               }
-               my $newmap = '';
-               for my $y (0 .. 8*$dim-1) {
-                       for my $x (0 .. 8*$dim-1) {
-                               print "$x,$y\n";
-                               $newmap .= substr($shortmap,
-                                       $y + (8*$dim+1)*(8*$dim-$x-1), 1);
-                       }
-                       $newmap .= "\n";
-               }
-               print "\nRotate:\n$newmap\n";
-               $shortmap = $newmap;
-       }
-       my $newmap;
-       for my $y (0 .. 8*$dim-1) {
-               for my $x (0 .. 8*$dim-1) {
-                       $newmap .= substr($shortmap,
-                               $x + (8*$dim+1)*(8*$dim-$y-1), 1);
-               }
-               $newmap .= "\n";
+my $map = rows2str(@map_rows);
+my $hashes =()= $map =~ /#/g;
+
+my $monster = '.(?='
+       . join('[\.#\n]' x ($dim * 8 - 20 + 1),
+               map { my $a=$_; $a=~ s/\./[\.#]/g; $a }
+                '..................#.',
+               '#....##....##....###',
+               '.#..#..#..#..#..#...'
+       ) . ')';
+
+for (1 .. 8) {
+       if (my $count =()= $map =~ /($monster)/g) {
+               print "$count matches\n";
+               print "$hashes-$count*15=", $hashes-$count*15, "\n";
+               exit 0;
        }
-       $shortmap = $newmap;
-       print "\nFlip:\n$newmap\n";
-
+       $map = rotate_or_flip($map, $_);
 }
 
-               
-
-