The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

# Copyright 2011, 2012 Kevin Ryde

# This file is part of Math-PlanePath.
#
# Math-PlanePath is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3, or (at your option) any later
# version.
#
# Math-PlanePath is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with Math-PlanePath.  If not, see <http://www.gnu.org/licenses/>.

use 5.010;
use strict;

# uncomment this to run the ### lines
#use Smart::Comments;


sub make_state {
  my ($rev, $rot) = @_;
  $rev %= 2;
  $rot %= 4;
  return 10*($rot + 4*$rev);
}
sub state_string {
  my ($state) = @_;
  my $digit = $state % 10; $state = int($state/10);
  my $rot = $state % 4; $state = int($state/4);
  my $rev = $state % 2; $state = int($state/2);
  return "rot=$rot rev=$rev" . ($digit ? " digit=$digit" : "");
}

my @min_digit;
my @max_digit;

my @next_state;
my @digit_to_x;
my @digit_to_y;
my @xy_to_digit;

my @unrot_digit_to_x = (0,1,1, 0,-1,-2, -2,-2,-3, -3);
my @unrot_digit_to_y = (0,0,1, 1, 1, 1,  0,-1,-1,  0);
my @segment_to_rev = (0,0,0, 1,0,0, 1,1,1, 0);
my @segment_to_dir = (0,1,2, 2,2,3, 3,2,1, 0);

foreach my $rot (0, 1, 2, 3) {
  foreach my $rev (0, 1) {
    my $state = make_state ($rev, $rot);

    foreach my $digit (0 .. 9) {
      my $xo = $unrot_digit_to_x[$rev ? 9-$digit : $digit];
      my $yo = $unrot_digit_to_y[$rev ? 9-$digit : $digit];
      if ($rev) { $xo += 3 }

      my $new_rev = $rev ^ $segment_to_rev[$rev ? 8-$digit : $digit];
      my $new_rot = $rot + $segment_to_dir[$rev ? 8-$digit : $digit];
      if ($new_rev) {
        $new_rot += 0;
      } else {
        $new_rot += 2;
      }
      if ($rev) {
        $new_rot += 2;
      } else {
        $new_rot += 0;
      }

      if ($rot & 2) {
        $xo = - $xo;
        $yo = - $yo;
      }
      if ($rot & 1) {
        ($xo,$yo) = (-$yo,$xo);
      }
      ### rot to: "$xo, $yo"

      $digit_to_x[$state+$digit] = $xo;
      $digit_to_y[$state+$digit] = $yo;

      # $xy_to_digit[$state + 3*$xo + $yo] = $orig_digit;

      my $next_state = make_state ($new_rev, $new_rot);
      if ($digit == 9) { $next_state = undef; }
      $next_state[$state+$digit] = $next_state;
    }
  }
}


use List::Util 'min','max';

sub print_table {
  my ($name, $aref) = @_;
  print "my \@$name = (";
  my $entry_width = max (map {defined && length} @$aref);

  foreach my $i (0 .. $#$aref) {
    printf "%*s", $entry_width, $aref->[$i]//'undef';
    if ($i == $#$aref) {
      print ");   # ",$i-9,"\n";
    } else {
      print ",";
      if (($i % 10) == 9) {
        print "    # ".($i-9);
      }
      if (($i % 10) == 9) {
        print "\n        ".(" " x length($name));
      } elsif (($i % 3) == 2) {
        print " ";
      }
    }
  }
}

    print_table ("next_state", \@next_state);
  print_table ("digit_to_x", \@digit_to_x);
  print_table ("digit_to_y", \@digit_to_y);
  # print_table ("xy_to_digit", \@xy_to_digit);
  # print_table36 ("min_digit", \@min_digit);
  # print_table36 ("max_digit", \@max_digit);
  print "# state length ",scalar(@next_state)," in each of 4 tables\n";
  print "# rot2 state ",make_state(0,2),"\n";
  exit 0;