#!/usr/local/bin/perl

# $Header: squaremaker,v 4.1 1997/06/19 $
# 1997 Fabrizio Pivari (Pivari@geocities.com)
# "Simple Magic Square checker and gif maker" script

use Getopt::Long;
use GD;

MAIN:
{
$square="";
$opt_conf="./Square.cnf";

@elem=("data","html","SQUAREfile","LINEfile","separator","skipblank",
       "table","gif","check","transparent","rbg","gbg","bng","rfg","bfg","gfg");

%option=(
      data => './Square.dat',
      html => './Square.html',
      SQUAREfile => './Square.gif',
      LINEfile => './Line.gif',
      separator => ' ',
      skipblank => 'yes',
      table => 'yes',
      gif => 'yes',
      check => 'yes',
      transparent => 'yes',
      rbg => '255',
      gbg => '255',
      bbg => '255',
      rfg => '0',
      bfg => '0',
      gfg => '0');

&GetOptions("conf=s","help") || &printusage ;

if ($opt_help) {&printusage};
open (CNF, "$opt_conf") || die "Error: $opt_conf - $!\n";
while (<CNF>)
   {
   s/\t/ /g;  #replace tabs by space
   next if /^\s*\#/; #ignore comment lines
   next if /^\s*$/;  #ignore empty lines
   foreach $elem (@elem) {if (/\s*$elem\s*:\s*(.*)/) {$option{$elem}=$1;}}
   }
close(CNF);

open (DATA,"$option{'data'}") || die "Error: $option{'data'} - $!\n";
while (<DATA>) {$square .= $_;}
close (DATA);

$separ=$option{'separator'};
if ($separ eq ""){$separ=" ";}
if ($separ eq " ")
   {
   if ($option{'skipblank'} eq "yes")
      {$square =~ s/\n/ /g; $square =~ s/^\s*//; $square =~ s/\s+/ /g;}
   else {$square =~ s/\n/ /g;}
   }
else
   {
   if ($option{'skipblank'} eq "yes")
      {$square =~ s/\n/$separ/g;$square =~ s/^\s*//; $square =~ s/\s+//g;}
   else {$square =~ s/\n/$separ/g;}
   }

@all = split(/$separ/,$square);
$ORD = sqrt($#all+1);
if ($ORD =~ /\d+\.\d+/)
   {
   print "The number of elements in every line or column is not the same\n";
   exit(1);
   }

$HTML="<html>\n<head>\n<title>$ORD x $ORD Magic Square</title>\n</head>\n";
$HTML.="<body>\n<h1>$ORD x $ORD Magic Square</h1>\n";

$i=0; $j=0;
foreach $all (@all)
   {
   $elem[$j][$i] = $all;
   $i++;
   if (($i)%$ORD == 0) {$j++; $i=0;}
   }

$CELLGRIDSIZE = 31;
$GRIDSIZE = 8+($ORD -1)*2+$ORD*$CELLGRIDSIZE;
if ($option{'check'} eq "yes")
   {
# Magic constant for a Magic Square 1,2,...,n
   $sum=$ORD*($ORD*$ORD+1)/2;
   $i=0;
# Generic magic constant
   for(0..$ORD-1) { $SUM+=$elem[0][$i]; $i++;}
# Check lines and columns
   $j=0;
   for($j=0;$j<$ORD;$j++)
      {
      $i=0; $line1=0; $line2=0;
      for($i=0;$i<$ORD;$i++) {$line1+=$elem[$j][$i]; $line2+=$elem[$i][$j];}
      if ($line1 != $SUM || $line2 != $SUM)
         {
         $HTML.="This isn't a magic square<p>\n";
         goto NEXT;
         }
      }

# Check diagonals and broken diagonals
   $j=0;
   for($j=0;$j<$ORD;$j++)
      {
      $i=0; $diag1=0; $diag2=0;
      for($i=0;$i<$ORD;$i++)
         {
         $diag1+=$elem[$i][($i+$j)%$ORD];
         $diag2+=$elem[$ORD-1][($i+$j)%$ORD];
         }
      if ($j == 0)
         {
         if ($diag1 != $SUM || $diag2 != $SUM)
            {
            if ($SUM == $sum)
               {
               $HTML.="This is a Semimagic Square with magic constant
                      n(n<sup>2</sup>+1)/2 = $sum<p>\n";
               goto NEXT;
               }
            else
               {
               $HTML.="This is a Semimagic Square with magic constant
                      = $SUM<p>\n";
               goto NEXT;
               }
            }
         }
      else
         {
         if ($diag1 != $SUM || $diag2 != $SUM)
            {
            if ($SUM == $sum)
               {
               $HTML.="This is a Magic Square with magic constant
                      n(n<sup>2</sup>+1)/2 = $sum<p>\n";
               $k=1;
               $MIDDLE = ($CELLGRIDSIZE+1)/2;
               $im=new GD::Image($GRIDSIZE,$GRIDSIZE);
               $bg=$im->colorAllocate($option{'rbg'},$option{'gbg'},$option{'bbg'});
               $fg=$im->colorAllocate($option{'rfg'},$option{'gfg'},$option{'bfg'});

               # GRID
               if ($option{'transparent'} eq "yes")
                  {
                  $im->transparent($bg);
                  }
               $im->filledRectangle(0,0,255,255,$bg);
               $im->filledRectangle(0,0,4,$GRIDSIZE,$fg);
               $im->filledRectangle(0,0,$GRIDSIZE,4,$fg);
               $tmp = $GRIDSIZE -5;
               $im->filledRectangle($tmp,0,$GRIDSIZE,$GRIDSIZE,$fg);
               $im->filledRectangle(0,$tmp,$GRIDSIZE,$GRIDSIZE,$fg);
               $xy = 4 + $CELLGRIDSIZE;
               $xy2 = $xy +2;
               for (1..$ORD-1)
                  {
                  $im->filledRectangle($xy,0,$xy2,$GRIDSIZE,$fg);
                  $im->filledRectangle(0,$xy,$GRIDSIZE,$xy2,$fg);
                  $xy = $xy2 + $CELLGRIDSIZE;
                  $xy2 = $xy + 2;
                  }

               ANOTHER:    $j=0;
               for($j=0;$j<$ORD;$j++)
                  {
                  $i=0;
                  for($i=0;$i<$ORD;$i++)
                     {
                     if ($elem[$j][$i] == $k)
                        {
                        if ($elem[$j][$i] == 1)
                           {
                           $x1=$i*$CELLGRIDSIZE+$MIDDLE+4+$i*2;
                           $y1=$j*$CELLGRIDSIZE+$MIDDLE+4+$j*2;
                           $im->arc($x1,$y1,2,2,0,360,$fg);
                           $k++;
                           goto ANOTHER;
                           }
                        $x2=$i*$CELLGRIDSIZE+$MIDDLE+4+$i*2;
                        $y2=$j*$CELLGRIDSIZE+$MIDDLE+4+$j*2;
                        $im->line($x1,$y1,$x2,$y2,$fg);
                        $im->arc($x2,$y2,2,2,0,360,$fg);

                        $x1=$x2;
                        $y1=$y2;
                        $k++;
                        goto ANOTHER;
                        }
                     }
                  }
               print "Generation of $option{'LINEfile'}\n";

               open (LINE,">$option{'LINEfile'}") || die "Error: $option{'LINEfile'} - $!\n";
               print LINE $im -> gif;
               close (LINE);

               $HTML.=qq!<img src="$option{'LINEfile'}"><p>\n!;

               goto NEXT;
               }
            else
               {
               $HTML.="This is a Magic Square with magic constant = $SUM<p>\n";
               goto NEXT;
               }
            }
         }
      }
      if ($SUM == $sum) { $HTML.="This is a Panmagic Square with magic
                                 constant n(n<sup>2</sup>+1)/2 = $sum<p>\n";}
      else { $HTML.="This is a Panmagic Square with magic constant = $SUM<p>\n";}
   }

NEXT: if ($option{'gif'} eq "yes")
   {
   $im=new GD::Image($GRIDSIZE,$GRIDSIZE);
   $bg=$im->colorAllocate($option{'rbg'},$option{'gbg'},$option{'bbg'});
   $fg=$im->colorAllocate($option{'rfg'},$option{'gfg'},$option{'bfg'});

   # GRID
   if ($option{'transparent'} eq "yes") {$im->transparent($bg);}
   $im->filledRectangle(0,0,255,255,$bg);
   $im->filledRectangle(0,0,4,$GRIDSIZE,$fg);
   $im->filledRectangle(0,0,$GRIDSIZE,4,$fg);
   $tmp = $GRIDSIZE -5;
   $im->filledRectangle($tmp,0,$GRIDSIZE,$GRIDSIZE,$fg);
   $im->filledRectangle(0,$tmp,$GRIDSIZE,$GRIDSIZE,$fg);
   $xy = 4 + $CELLGRIDSIZE;
   $xy2 = $xy +2;
   for (1..$ORD-1)
      {
      $im->filledRectangle($xy,0,$xy2,$GRIDSIZE,$fg);
      $im->filledRectangle(0,$xy,$GRIDSIZE,$xy2,$fg);
      $xy = $xy2 + $CELLGRIDSIZE;
      $xy2 = $xy + 2;
      }

   # NUMBERS
   $x1 = 4 + 8;
   $y1 = 4 + 9;
   $j=0;
   for ($j=0;$j<$ORD;$j++)
      {
      $i=0;
      for ($i=0;$i<$ORD;$i++)
         {
         # to hit the centre with numbers < -9
         if ($elem[$j][$i] < -9) { $x1 = $x1 - 3; }
         # to hit the centre with numbers between -9 and -1
         if ($elem[$j][$i] < 0 && $elem[$j][$i] > -10) { $x1 = $x1 - 2; }
         # to hit the centre with numbers between 0 and 9
         if ($elem[$j][$i] < 10 && $elem[$j][$i] >= 0) { $x1 = $x1 + 4; }
         # to hit the centre with numbers > 99
         if ($elem[$j][$i] > 99) { $x1 = $x1 - 4; }
         $im->string(gdLargeFont,$x1,$y1,"$elem[$j][$i]",$fg);
         $x1 = $x1 + $CELLGRIDSIZE + 2;
         if ($elem[$j][$i] < -9) { $x1 = $x1 + 3; }
         if ($elem[$j][$i] < 0 && $elem[$j][$i] > -10) { $x1 = $x1 + 2; }
         if ($elem[$j][$i] < 10 && $elem[$j][$i] >= 0) { $x1 = $x1 - 4; }
         if ($elem[$j][$i] > 99) { $x1 = $x1 + 4; }
         }
      $x1 = 4 + 8;
      $y1 = $y1 + $CELLGRIDSIZE + 2;
      } 

   print "Generation of $option{'SQUAREfile'}\n";
   open (SQUARE,">$option{'SQUAREfile'}") || die "Error: $option{'SQUAREfile'} - $!\n";
   print SQUARE $im -> gif;
   close (SQUARE);

   $HTML.=qq!<img src="$option{'SQUAREfile'}"><p>\n!;
   }

if ($option{'table'} eq "yes")
   {
   $HTML.=qq!<table border=3 width="2" height="2" cellpadding=1 cellspacing=1>\n!;
   $j=0;
   for $j (0..$ORD-1)
      {
      $i=0;
      $HTML.="<tr>\n";
      for $i (0..$ORD-1)
         {
         $HTML.="<td align=right><font size=+2><b>$elem[$j][$i]</b></font></td>\n";
         }
      $HTML.="</tr>\n";
      }
   $HTML.="</table><p>\n";
   }

$HTML.=qq!Generated with SquareMaker-4.0 by <a href="mailto:Pivari\@geocities.com">Fabrizio Pivari</a>\n!;

# Close the document cleanly
   $HTML.="</body>\n</html>\n";
print "Generation of $option{'html'}\n";
open (HTMLFILE,">$option{'html'}") || die "Error: $option{'html'} - $!\n";
print HTMLFILE "$HTML";
close(HTMLFILE);
exit(0);
}


sub printusage {
    print <<USAGEDESC;

usage:
        squaremaker [-options ...]

where options include:
    -help                        print out this message
    -conf  file                  the configuration file (default Square.cnf)

If you want to know more about this tool, you might want
to read the docs. They came together with squaremaker!

Home: http://www.geocities.com/CapeCanaveral/Lab/3469/squaremaker.html

USAGEDESC
    exit(1);
}
