Math::MagicSquare - Magic Square Checker and Designer


Math-MagicSquare documentation Contained in the Math-MagicSquare distribution.

Index


Code Index:

NAME

Top

Math::MagicSquare - Magic Square Checker and Designer

SYNOPSIS

Top

  use Math::MagicSquare;

  $a= Math::MagicSquare -> new ([num,...,num],
                                 ...,
                                [num,...,num]);
  $a->print("string");
  $a->printhtml();
  $a->printimage();
  $a->check();
  $a->rotation();
  $a->reflection();

DESCRIPTION

Top

The following methods are available:

new

Constructor arguments are a list of references to arrays of the same length.

    $a = Math::MagicSquare -> new ([num,...,num],
                                    ...,
                                   [num,...,num]);

check

This function can return 4 value

print

printhtml

Prints the Square on STDOUT in an HTML format (exactly a inside a TABLE)

printimage

Prints the Square on STDOUT in png format.

rotation

Rotates the Magic Square of 90 degree clockwise

reflection

Reflect the Magic Square

REQUIRED

Top

GD perl module.

EXAMPLE

Top

    use Math::MagicSquare;

    $A = Math::MagicSquare -> new ([8,1,6],
                                   [3,5,7],
                                   [4,9,2]);
    $A->print("Magic Square A:\n");
    $A->printhtml();
    $i=$A->check();
    if($i == 2) {print "This is a Magic Square.\n";}
    $A->rotation();
    $A->print("Rotation:\n");
    $A->reflection();
    $A->print("Reflection:\n");
    $A->printimage();

 This is the output:
    Magic Square A:
        8     1     6 
        3     5     7 
        4     9     2 
    <TABLE border=3 width="2" height="2" cellpadding=1 cellspacing=1>
    <TR>
    <TD align=right><FONT size=+2><B>8</B></font></TD>
    <TD align=right><FONT size=+2><B>1</B></font></TD>
    <TD align=right><FONT size=+2><B>6</B></font></TD>
    </TR>
    <TR>
    <TD align=right><FONT size=+2><B>3</B></font></TD>
    <TD align=right><FONT size=+2><B>5</B></font></TD>
    <TD align=right><FONT size=+2><B>7</B></font></TD>
    </TR>
    <TR>
    <TD align=right><FONT size=+2><B>4</B></font></TD>
    <TD align=right><FONT size=+2><B>9</B></font></TD>
    <TD align=right><FONT size=+2><B>2</B></font></TD>
    </TR>
    </TABLE>
    This is a Magic Square.
    Rotation:
        4     3     8 
        9     5     1 
        2     7     6
    Reflection:
        8     3     4
        1     5     9
        6     7     2

AUTHOR

Top

 Fabrizio Pivari fabrizio@pivari.com
 http://www.pivari.com/

Copyright

Top

Availability

Top

 The latest version of this library is likely to be available from:
 http://www.pivari.com/magicsquare.html
 and at any CPAN mirror

Information about Magic Square

Top

 Do you like Magic Square?
 Do you want to know more information about Magic Square?
 Try to visit

A very good introduction on Magic Square

http://mathworld.wolfram.com/MagicSquare.html

http://mathforum.org/alejandre/magic.square.html http://mathforum.org/te/exchange/hosted/suzuki/MagicSquare.html

A good collection of strange Magic Square

http://www.geocities.com/pivari/examples.html


Math-MagicSquare documentation Contained in the Math-MagicSquare distribution.

#
# MagicSquare.pm, version 2.04 13 Dec 2003
#
# Copyright (c) 2003 Fabrizio Pivari Italy
# fabrizio@pivari.com
#
# Free usage under the same Perl Licence condition.
#

package Math::MagicSquare;

use Carp;
use GD;
use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);

use Exporter();
@ISA= qw(Exporter);
@EXPORT=qw();
@EXPORT_OK=qw(new check print printhtml rotation reflection);
$VERSION='2.04';

sub new {
  my $type = shift;
  my $self = [];
  my $len = scalar(@{$_[0]});
  my $numelem = 0;
  for (@_) {
    push(@{$self}, [@{$_}]);
    $numelem += scalar(@{$_});
    }
  croak "Math::MagicSquare::new(): number of rows and columns must be equal"
    if ($numelem != $len*$len);
  bless $self, $type;
  }

sub check {
  my $self = shift;
  my $i=0; my $j=0;
  my $line1=0; my $line2=0; my $diag1=0; my $diag2=0; my $SUM=0;
  my $sms=1;
  my $len = scalar(@{$self});

# Magic Constant for a Magic Square 1,2,...,n
  my $sum=$len*($len*$len+1)/2;
# Generic Magic Constant
  for ($i=0;$i<$len;$i++) {
    $SUM+=$self->[$i][0];
    }
  if ($SUM != $sum) {$sum=$SUM;}
# Check lines and columns
  for ($i=0;$i<$len;$i++) {
    $j=0; $line1=0; $line2=0;
    for ($j=0;$j<$len;$j++) {
      $line1+=$self->[$i][$j];
      $line2+=$self->[$j][$i];
      }
    if ($line1 != $sum || $line2 != $sum) {
# This isn't a Magic
      return(0);
      }
    }
# Check diagonals and broken diagonals
  for ($j=0;$j<$len;$j++) {
    $i=0; $diag1=0; $diag2=0;
    for ($i=0;$i<$len;$i++) {
      $diag1+=$self->[$i][($i+$j)%$len];
      $diag2+=$self->[$len-1-$i][($i+$j)%$len];
      }
    if ($j == 0) {
      if ($diag1 != $sum || $diag2 != $sum) {
# This is a Semimagic Square
        return(1);
        }
      } else {
      if ($diag1 != $sum || $diag2 != $sum) {
# This is a Magic Square
        return(2);
        }
      }
    }
# This is a Panmagic Square
  return(3);
  }

sub print {
  my $self = shift;
  my $initialtext = shift;
  my $i=0; my $j=0;
  my $len = scalar(@{$self});
    
  print "$initialtext\n" if $initialtext;
  print @_ if scalar(@_);
  for ($j=0;$j<$len;$j++) {
    for ($i=0;$i<$len;$i++) {
      printf "%5d ", $self->[$j][$i];
      }
    print "\n";
    }
  }

sub printhtml {
  my $self = shift;
  my $i=0; my $j=0;
  my $len = scalar(@{$self});

  print qq!<TABLE border=3 width="2" height="2" cellpadding=1 cellspacing=1>\n!;
  for ($j=0;$j<$len;$j++) {
    print "<TR>\n";
    for ($i=0;$i<$len;$i++) {
      print "<TD align=right><FONT size=+2><B>$self->[$j][$i]</B></font></TD>\n";
      }
    print "</TR>\n";
    }
  print "</TABLE>\n";
  }

sub printimage {
  my $self = shift;
  my $i=0; my $j=0;
  my $len = scalar(@{$self});

  my $CELLGRIDSIZE = 31;
  my $GRIDSIZE = 8+($len -1)*2+$len*$CELLGRIDSIZE;
  my $im=new GD::Image($GRIDSIZE,$GRIDSIZE);
  my $bg=$im->colorAllocate(255,255,255);
  my $fg=$im->colorAllocate(0,0,0);

   # GRID
#   $im->transparent($bg);
   $im->filledRectangle(0,0,255,255,$bg);
   $im->filledRectangle(0,0,4,$GRIDSIZE,$fg);
   $im->filledRectangle(0,0,$GRIDSIZE,4,$fg);
   my $tmp = $GRIDSIZE -5;
   $im->filledRectangle($tmp,0,$GRIDSIZE,$GRIDSIZE,$fg);
   $im->filledRectangle(0,$tmp,$GRIDSIZE,$GRIDSIZE,$fg);
   my $xy = 4 + $CELLGRIDSIZE;
   my $xy2 = $xy +2;
   for (1..$len-1)
      {
      $im->filledRectangle($xy,0,$xy2,$GRIDSIZE,$fg);
      $im->filledRectangle(0,$xy,$GRIDSIZE,$xy2,$fg);
      $xy = $xy2 + $CELLGRIDSIZE;
      $xy2 = $xy + 2;
      }

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

   binmode STDOUT;
   print $im -> png;
   }

sub rotation {
  my $self = shift;
  my $i=0; my $j=0;
  my @TMP;
  my $len = scalar(@{$self});

  for ($j=0;$j<$len;$j++) {
    for ($i=0;$i<$len;$i++) {
      $TMP[$j][$i]=$self->[$j][$i];
      }
    }
  for ($j=0;$j<$len;$j++) {
    for ($i=0;$i<$len;$i++) {
      $self->[$j][$i]=$TMP[$len-1-$i][$j];
      }
    }
  }

sub reflection {
  my $self = shift;
  my $i=0; my $j=0;
  my @TMP;
  my $len = scalar(@{$self});

  for ($j=0;$j<$len;$j++) {
    for ($i=0;$i<$len;$i++) {
      $TMP[$j][$i]=$self->[$j][$i];
      }
    }
  for ($j=0;$j<$len;$j++) {
    for ($i=0;$i<$len;$i++) {
      $self->[$i][$j]=$TMP[$i][$len-1-$j];
      }
    }
  }

1;

__END__