# # 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!\n!; for ($j=0;$j<$len;$j++) { print "\n"; for ($i=0;$i<$len;$i++) { print "\n"; } print "\n"; } print "
$self->[$j][$i]
\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__ =pod =head1 NAME Math::MagicSquare - Magic Square Checker and Designer =head1 SYNOPSIS use Math::MagicSquare; $a= Math::MagicSquare -> new ([num,...,num], ..., [num,...,num]); $a->print("string"); $a->printhtml(); $a->printimage(); $a->check(); $a->rotation(); $a->reflection(); =head1 DESCRIPTION The following methods are available: =head2 new Constructor arguments are a list of references to arrays of the same length. $a = Math::MagicSquare -> new ([num,...,num], ..., [num,...,num]); =head2 check This function can return 4 value =over =item * B<0:> the Square is not Magic =item * B<1:> the Square is a B (the sum of the rows and the columns is equal) =item * B<2:> the Square is a B (the sum of the rows, the columns and the diagonals is equal) =item * B<3:> the Square ia B (the sum of the rows, the columns, the diagonals and the broken diagonals is equal) =back =head2 print Prints the Square on STDOUT. If the method has additional parameters, these are printed before the Magic Square is printed. =head2 printhtml Prints the Square on STDOUT in an HTML format (exactly a inside a TABLE) =head2 printimage Prints the Square on STDOUT in png format. =head2 rotation Rotates the Magic Square of 90 degree clockwise =head2 reflection Reflect the Magic Square =head1 REQUIRED GD perl module. =head1 EXAMPLE 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
8 1 6
3 5 7
4 9 2
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 =head1 AUTHOR Fabrizio Pivari fabrizio@pivari.com http://www.pivari.com/ =head1 Copyright Copyright 2003, Fabrizio Pivari fabrizio@pivari.com This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Are you interested in a Windows cgi distribution? Test http://www.pivari.com/squaremaker.html and contact me. =head1 Availability The latest version of this library is likely to be available from: http://www.pivari.com/magicsquare.html and at any CPAN mirror =head1 Information about Magic Square Do you like Magic Square? Do you want to know more information about Magic Square? Try to visit =over =item A very good introduction on Magic Square http://mathworld.wolfram.com/MagicSquare.html =item Whole collections of links and documents in Internet http://mathforum.org/alejandre/magic.square.html http://mathforum.org/te/exchange/hosted/suzuki/MagicSquare.html =item A good collection of strange Magic Square http://www.geocities.com/pivari/examples.html =back =cut