#!/usr/local/bin/perl -*- perl -*- # # There are four kinds of patches: NW, NE, SW, and SE. They are named # depending on the direction that the black triangle is pointing. @patchdirs = ('nw', 'ne', 'se', 'sw'); # Each 2-block has four patches and is represented as a list of four patches. # The nw patch first, then ne, se, and sw. sub reflect_block { local($nw, $ne, $se, $sw) = @_; return (&reflect_patch($ne), &reflect_patch($nw), &reflect_patch($sw), &reflect_patch($se)); } sub reflect_patch { local($patch) = @_; $patch =~ tr/we/ew/; return $patch; } sub reverse_block_ground { local(@patches) = @_; local(@reversed) = (); for $p (@patches) { @reversed = (@reversed, &reverse_patch_ground($p)); } return @reversed; } sub rotate_block { local($nw, $ne, $sw, $se, $n) = @_; local(@patch) = ($nw, $ne, $sw, $se); $n = $n % 4; for $i (0 .. 3) { $patch[$i] = &rotate_patch($patch[$i], $n); } for $i (1 .. $n) { local($nw) = shift(@patch); @patch = (@patch, $nw); } return @patch; } sub rotate_patch_cw { return &rotate_patch(@_, 1); } sub rotate_patch_ccw { return &rotate_patch(@_, 3); } sub reverse_patch_ground { return &rotate_patch(@_, 2); } # Rotate patch n*90 degrees. sub rotate_patch { local($patch, $n) = @_; for $i (0 .. 3) { if ($patchdirs[$i] eq $patch) { return $patchdirs[($i + $n)%4]; } } print STDERR "Failed: Couldn't recognize patch $patch.\n"; return $patch; } sub compare_blocks_without_transformation { local($nw1, $ne1, $se1, $sw1, $nw2, $ne2, $se2, $sw2) = @_; return ($nw1 eq $nw2 && $ne1 eq $ne2 && $se1 eq $se2 && $sw1 eq $sw2); } sub compare_blocks_with_transformation { local($nw1, $ne1, $se1, $sw1, $nw2, $ne2, $se2, $sw2) = @_; local(@b1) = ($nw1, $ne1, $se1, $sw1); local(@b2) = ($nw2, $ne2, $se2, $sw2); local(@tb); for $rot (0 .. 3) { for $inv (0 .. 1) { for $ref (0 .. 1) { @tb = &rotate_block(@b1, $rot); @tb = &reverse_block_ground(@tb) if ($inv == 1); @tb = &reflect_block(@tb) if ($ref == 1); return 1 if &compare_blocks_without_transformation(@tb, @b2); } } } return 0; } sub enumerate_all_blocks { local(@the_block) = ('nw', 'nw', 'nw', 'nw'); local($pos) = 0; local(@all_blocks) = @the_block; while (1) { while ($the_block[$pos] eq 'sw') { $the_block[$pos++] = 'nw'; } if ($pos gt 3) { return @all_blocks; } $the_block[$pos] = &rotate_patch_cw($the_block[$pos]); $pos = 0; @all_blocks = (@all_blocks, @the_block); } } @all_blocks = &enumerate_all_blocks(); $nb = ($#all_blocks + 1) / 4; print "Constructed list of $nb potential blocks.\n"; @unique_blocks = (); BLOCK: while (@all_blocks) { $count++; $nw = shift(@all_blocks); $ne = shift(@all_blocks); $se = shift(@all_blocks); $sw = shift(@all_blocks); @b = ($nw, $ne, $se, $sw); print "Now examining block #$count (@b).\n"; @ubls = @unique_blocks; $is_new_block = 1; UNIQUE_BLOCK: while (@ubls) { $nw = shift(@ubls); $ne = shift(@ubls); $se = shift(@ubls); $sw = shift(@ubls); @ub = ($nw, $ne, $se, $sw); if (&compare_blocks_with_transformation(@b, @ub)) { print "Blocks (@b) and (@ub) are the same.\n"; next BLOCK; } } # If we got here, this block is new. @unique_blocks = (@unique_blocks, @b); $num_unique_blocks++; print "$num_unique_blocks unique out of $count examined so far.\n"; } $count = 1; while (@unique_blocks) { $nw = shift(@unique_blocks); $ne = shift(@unique_blocks); $se = shift(@unique_blocks); $sw = shift(@unique_blocks); @b = ($nw, $ne, $se, $sw); print "$count: @b\n"; $count++; }