unit U_MagicSquare1;
{Finds magic squares of odd size using an algorithm
developed by Cornelius Agrippa around 1500 or De La Loubere - date unknown (by me)
as follows:
"Start with 1 in the middle of the top row; then go up
and left assigning numbers in increasing order to
empty cells; if you fall off of the square imagine
the same square as tiling the plane and continue; if a
cell is occupied, move down instead and
continue."}

.
.  {generated code snipped here}
.
Function isodd(n:integer):boolean;
{tests for odd number}
Begin
  if n mod 2 =0 then result:=false
  else result:=true;
end;

procedure TForm1.CalcBtnClick(Sender: TObject);
{calculate an odd order magic square}
var
  i,j,count,order,size:integer;
  oldi,oldj:integer;
begin
  order:=strtoint(intedit1.text);
  if (isodd(order)) and (order<=51) then
  begin
    with stringgrid1 do
    begin
      {initialize things}
      rowcount:=order+1;
      colcount:=order+1;
      for i:=0 to colcount-1 do
      for j:=0 to rowcount-1 do cells[i,j]:='';
      size:=order*order;
      {make font size bigger for small squares, smaller for big squares}
      if size<100 then font.size:=12 else font.size:=8;
      {now we have to adjust cell size appropriately for the font}
      canvas.font:=font;
      defaultcolwidth:=canvas.textwidth(inttostr(size))+4;
      defaultrowheight:=defaultcolwidth;
      {make the grid size match the sum of the cells + grid lines sizes}
      width:=(defaultcolwidth+1)*order+2;
      height:=((defaultrowheight+1)*order+2);
      {here's the algorithm}  
      i:=order div 2; {center of top row}
      j:=0;
      count:=0;
      repeat
        inc(count);
        cells[i,j]:=inttostr(count); {get next number}
        if count<size then
        Begin
          oldi:=i;
          dec(i);   {move up}
          if i<0 then i:=order-1; {loop around if necessary}
          oldj:=j;
          dec(j); {and left}
          if j<0 then j:=order-1; {loop around if necessary}
          if cells[i,j]<>'' then {occupied?}
          Begin
            i:=oldi;
            j:=oldj+1; {move down instead}
            if j>order then j:=0;
          end;
          if cells[i,j]<>'' then showmessage('Algorithm error');
        end;
      until count=size;
    end;
    {Sum is always (order^3+order) div 2}
    SumLbl.caption:='Sum of each row, column and diagonal is '
                    +inttostr((size*order+order) div 2);
    Sumlbl.visible:=true;
  end
  else beep;
end;



procedure TForm1.IntEdit1KeyPress(Sender: TObject; var Key: Char);
{make sure only digits or backspace keys are pressed}
begin
  If not (key in ['0'..'9',#8 {backsapace}]) then
  begin
    key:=#0;
    beep;
  end;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
   windowstate := wsMaximized; {make form full size}
end;

end.