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, $_);
}
-
-
-