#include <exec/types.h>
#include <lattice/stdio.h>
#include <intuition/intuition.h>

#define VERSION       1

#define MAXBOXES        12
#define MAXLOOK         10
#define WIDE        64 * 2
#define HIGH           512
#define LINEHEIGHT      10
#define XBORDER          6
#define YBORDER          3
#define BOXIT         TRUE
#define NOBOXIT      FALSE
#define IDCMPNORMAL CLOSEWINDOW | MENUPICK | MOUSEBUTTONS

#define DISKDEFNAME      "Othello.def"

#include <othmenu.h>

#define EMPTY            0
#define BLACK            1
#define RED              2
#define OFFSCREEN        3

#define DEFAULTP1        HUMAN
#define DEFAULTP2        HUMAN
#define DEFAULTSIZE      8
#define DEFAULTGURUWAIT  STEPTHROUGH

struct Image logo =
   {
   0, 0,
   POINTERWIDTH * 2, POINTERHEIGHT, 2,
   NULL,
   3, 0,
   NULL
   };

USHORT ourpointerdata[] =
   {
   0x0000, 0x0000,

   0x0000, 0x3000,
   0x0000, 0x4800,
   0x0000, 0x4000,
   0x0080, 0x4000,
   0x0080, 0x4000,
   0x02A0, 0x4800,
   0x01C0, 0x3000,
   0x0080, 0x0000,
   0x1004, 0x1004,
   0x0808, 0x0808,
   0x7C1F, 0x7C9F,
   0x0808, 0x0808,
   0x1004, 0x1004,
   0x0080, 0x0000,
   0x01C0, 0x0006,
   0x02A0, 0x0009,
   0x0080, 0x0008,
   0x0080, 0x0006,
   0x0000, 0x0001,
   0x0000, 0x0009,
   0x0000, 0x0006,

   0x0000, 0x0000
   };

USHORT *ourpointer = 0;
ULONG  *ourlongpointer;
ULONG  expand();

extern struct Menu Titles[];
extern struct MenuItem Items[];
extern struct MenuItem SubItems[];

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase       *GfxBase = NULL;
struct Window *window = NULL;
unsigned char  *circle = NULL;

struct IntuiMessage   *message;
char  gamebuffer[MAXLOOK][MAXBOXES+2][MAXBOXES+2];
char  *game[MAXLOOK][MAXBOXES+2];

short looksp1, looksp2;
short whoseturn;
short guruwait;
BOOL  workbench;
short whostarts = BLACK;

ULONG class;
short xoffset, yoffset, ytextoff;
short xthought, ythought;
short scores[3];
short width, height;
short numboxes, boxheight, boxwidth;
BOOL  stuck, newgame;

char bonus[MAXBOXES+2][MAXBOXES+2];

struct IntuiText Quittext =
   {
      2,1,
      JAM2,
      23,10,
      NULL,
      " Really Quit?",
      NULL
   };

struct IntuiText Postext =
   {
      2,1,
      JAM2,
      6,3,
      NULL,
      "Yes",
      NULL
   };

struct IntuiText Negtext =
   {
      2,1,
      JAM2,
      6,3,
      NULL,
      "No Way!",
      NULL
   };

struct Image textplayer =
{
   0, 0,             /* leftedge, topedge     */
   16, 8, 1,          /* width, height, depth  */
   NULL,             /* image data pointer    */
   1, 0,             /* planepick, planeonoff */
   NULL              /* next image            */
};

struct Image player =
{
   5, 2,             /* leftedge, topedge     */
   0, 0, 1,          /* width, height, depth  */
   NULL,             /* image data pointer    */
   1, 0,             /* planepick, planeonoff */
   NULL              /* next image            */
};

UBYTE *yourmove = "Your move, player   .            ";
UBYTE *cantmove = "Player    can't move.            ";
UBYTE *victory  = "Player    wins.                  ";
UBYTE *tiegame  = "The game is a tie.               ";
UBYTE *finished = "Game over.                       ";
UBYTE *neither  = "Neither player can move.         ";
UBYTE *scoreis  = "                                 ";
UBYTE *notempty = "That square is already taken.    ";
UBYTE *notlegal = "That is not a legal move.        ";
UBYTE *bestmove = "This is your best move.          ";
UBYTE *youcant  = "You can't move.                  ";
UBYTE *possible = "These are all the possible moves.";
UBYTE *blank    = "                                 ";
UBYTE *thinking = "Please wait - I'm thinking.      ";
UBYTE *click    = "Click in window to continue.     ";
UBYTE *openfail = "File could not be opened.        ";
UBYTE *illvalue = "Illegal value in file.           ";
UBYTE *shortfil = "Invalid data file.  Too short.   ";
UBYTE *loaded   = "Game loaded.                     ";
UBYTE *saved    = "Game saved.                      ";
UBYTE *writfail = "Write to file failed.            ";
UBYTE *defsaved = "Defaults saved.                  ";

ULONG powers[32];

struct TextAttr smallfont =
{
   "Topaz80",8,0,0
};

struct IntuiText string =
{
   1, 0,             /* frontpen, backpen */
   JAM2,             /* drawmode          */
   0,0,              /* leftedge, topedge */
   &smallfont,       /* pointer to font   */
   NULL,             /* pointer to text data */
   NULL              /* next text */
};

short squarepoints[10];
short smallsquarepoints[10];

struct Border square =
{
   0, 0,             /* leftedge, topedge */
   2, 0, JAM1,       /* frontpen, backpen, drawmode */
   5,                /* count */
   squarepoints,     /* xy data */
   NULL              /* next border */
};

struct Border smallsquare =
{
   0, 0,             /* leftedge, topedge */
   1, 0, JAM1,       /* frontpen, backpen, drawmode */
   5,                /* count */
   smallsquarepoints, /* xy data */
   NULL              /* next border */
};

struct Border xline =
{
   0, 0,             /* leftedge, topedge */
   3, 0, JAM1,       /* frontpen, backpen, drawmode */
   2,                /* count */
   squarepoints,     /* xy data */
   NULL              /* next border */
};

struct Border yline =
{
   0, 0,             /* leftedge, topedge */
   3, 0, JAM1,       /* frontpen, backpen, drawmode */
   2,                /* count */
   squarepoints + 6, /* xy data */
   NULL              /* next border */
};

struct NewWindow newwindow =
{
   0,0,
   330,185,
   -1,-1,
   IDCMPNORMAL,
   WINDOWDEPTH | WINDOWDRAG | WINDOWCLOSE | SMART_REFRESH | ACTIVATE,
   NULL,
   NULL,
   "CSOthello - © CygnusSoft.",
   NULL,
   NULL,
   330,185,
   330,185,
   WBENCHSCREEN
};






main(argc,argv)
int argc;
char *argv[];
{
short  r, x, y, level;

   powers[0] = 1;
   for (x = 1; x < 32; x++)
      powers[x] = powers[x-1] * 2;

   workbench = (argc == 0);

   if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 29)))
      quit_cleanup("Can't open Intuition Library.");

   if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",29)))
      quit_cleanup("Can't open Graphics library.");

   if (!(window = (struct Window *)OpenWindow(&newwindow)))
      quit_cleanup("Can't open the window.");

   xoffset = window->BorderLeft + XBORDER;
   ytextoff = window->BorderTop + YBORDER;
   yoffset = ytextoff + 3 * LINEHEIGHT + YBORDER;
   width = window->Width - xoffset - window->BorderRight - XBORDER;
   height = window->Height - yoffset - window->BorderBottom - YBORDER;

   string.LeftEdge = xoffset;
   string.TopEdge = ytextoff;

   getdefaults();    /* must be called before set menu strip,
                        but after assigning xoffset, ytextoff */

   SetMenuStrip(window, Titles);

   if (ourpointer = (USHORT *)AllocRaster(POINTERWIDTH*2,POINTERHEIGHT*2))
      {
      ourlongpointer = (ULONG *)ourpointer;
      for (y = 0; y < POINTERHEIGHT; y++)
         {
         ourlongpointer[y] = expand(ourpointerdata[y * 2 + 2]);
/*         ourpointer[y] = ourpointerdata[y * 2 + 2];
         ourpointer[y + POINTERHEIGHT] = ourpointerdata[y * 2 + 3];   */
         ourlongpointer[y + POINTERHEIGHT] = expand(ourpointerdata[y * 2 + 3]);
         }
      logo.ImageData = ourpointer;
      DrawImage(window->RPort, &logo, xoffset + width - 32, ytextoff);
      for (y = 0; y < (POINTERHEIGHT + 2) * 2; y++)
         ourpointer[y] = ourpointerdata[y];
      SetPointer(window,ourpointer,POINTERHEIGHT,POINTERWIDTH,POINTERXOFF,POINTERYOFF);
      }

   if (!(circle = (unsigned char *)AllocRaster(WIDE, HIGH)))
      quit_cleanup("Can't allocate raster data.");

   for (r = 4; r <= 4; r++)
      generatecircle(r, circle + (r-1)*256);
   textplayer.ImageData = (short *)&circle[256 * 3];

   for (level = 0; level < MAXLOOK; level++)
      for (x = 0; x < MAXBOXES + 2; x++)
         game[level][x] = gamebuffer[level][x];

   initialize();

   info(PROJECT, ABOUT, NULL);

   while (TRUE)
   {
      showplayer(whoseturn, 141, 0);
      if (moveable(whoseturn))   /* the player can move */
      {
         stuck = FALSE;
         if (whoseturn == BLACK)
            domoveblack();
         else domovered();
      }
      else if (stuck == TRUE)    /* neither player can move */
         endgame();
      else                       /* one, maybe two, players can move */
      {
         printstring(cantmove, 0, LINEHEIGHT);
         showplayer(whoseturn, 52, LINEHEIGHT);
         stuck = TRUE;
         whoseturn = BLACK + RED - whoseturn;  /*must be done before wait*/
         if (whoseturn == BLACK && looksp1 == HUMAN && looksp2 != HUMAN)
            waitforclick(FALSE,FALSE);
         else if (whoseturn == RED && looksp1 != HUMAN && looksp2 == HUMAN)
            waitforclick(FALSE,FALSE);
         else if (looksp1 != HUMAN && looksp1 != HUMAN && guruwait == STEPTHROUGH)
            waitforclick(TRUE,FALSE);
      }
   }
}



ULONG expand(word)
short word;
{
short bit;
ULONG answer;

   answer = 0;
   for (bit = 0; bit < 16; bit++)
      if (powers[bit] & word)
         answer |= (powers[bit * 2] * 3);
   return(answer);
}



showplayer(current, x, y)
short current, x, y;
{
   textplayer.PlanePick = current;
   DrawImage(window->RPort, &textplayer, xoffset + x, ytextoff + y);
}



generatecircle(r, p)
short r;
unsigned char *p;
{
   short x, y, rsquared, wordwidth;
   short tx, ty;

   for (x = 0; x < 8 * 32; x++)
      p[x] = 0;

   rsquared = r * r * 4 + 2;
   wordwidth = (((r * 4) + 15) / 16) * 2;

   for (x = 0; x < r * 2; x++)
      for (y = 0; y < r; y++)
         if ((x * x + y * y * 4) < rsquared)
         {
            ty = r + y;
            tx = 2 * r + x;
            p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
            ty = r - y - 1;
            p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
            tx = 2 * r - x - 1;
            ty = r + y;
            p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
            ty = r - y - 1;
            p[ty * wordwidth + (tx / 8)] |= powers[7 - (tx & 7)];
         }
}

/*  for debug purposes only

printarray(index)
short index;
{
short x, y;

   for (y = 0; y <= numboxes + 1; y++)
   {
      for (x = 0; x <= numboxes + 1; x++)
         printf("%d ", game[index][x][y]);
      printf("\n");
   }
}                          */



printscores()
{
   sprintf(scoreis, "Score:     %3d      %3d", scores[BLACK], scores[RED]);
   printstring(scoreis, 0, LINEHEIGHT * 2);
   showplayer(BLACK, 68, LINEHEIGHT * 2);
   showplayer(RED, 140, LINEHEIGHT * 2);
}



endgame()
{
   printstring(blank, 0, LINEHEIGHT);
   if (scores[RED] + scores[BLACK] < numboxes * numboxes)
      printstring(neither, 0, 0);
   else
      printstring(finished, 0, 0);
   if (scores[BLACK] > scores[RED])
   {
      printstring(victory, 0, LINEHEIGHT);
      showplayer(BLACK, 52, LINEHEIGHT);
   }
   else if (scores[BLACK] < scores[RED])
   {
      printstring(victory, 0, LINEHEIGHT);
      showplayer(RED, 52, LINEHEIGHT);
   }
   else
      printstring(tiegame, 0, LINEHEIGHT);

   newgame = FALSE;
   while (TRUE)
   {
      WaitPort(window->UserPort);
      message = (struct IntuiMessage *)GetMsg(window->UserPort);
      processmessage();
      if (newgame)
         return(0);
   }
}



think(level, colour, index)
short  level, colour, index;
{
short bestx = 0, besty = 0;
short x, y, count = 0;
int   best = -2000, temp;
BOOL moved = FALSE;

   if (level == 0)
   {
      for ( x = 1; x <= numboxes; x++ )
         for ( y = 1; y <= numboxes; y++ )
           if (game[index][x][y] == EMPTY)
               {
               temp = move_i(x, y, colour, index);
               if (temp > best)
                  {
                  best = temp;
                  bestx = x;
                  besty = y;
                  }
               else if (temp == best && index == MAXLOOK-1 )
                  {
                  count++;
                  if (!(rand() % count))
                     {
                     best = temp;
                     bestx = x;
                     besty = y;
                     }
                  }
               }
      if (index == MAXLOOK - 1)  /* if first level then */
      {
         xthought = bestx;
         ythought = besty;
      }
      return(best);
   }
   for ( x = 1; x <= numboxes; x++ )
      for ( y = 1; y <= numboxes; y++ )
         if (game[index][x][y] == EMPTY)
            {
            temp = move_i(x, y, colour, index);
            if (temp > 0)
               {
               moved = TRUE;
               copyplot(index, x, y, colour);
               temp = temp - think(level-1, RED + BLACK - colour, index-1);
               if (temp > best)
                  {
                  best = temp;
                  bestx = x;
                  besty = y;
                  count = 1;
                  }
               else if (temp == best && index == MAXLOOK-1 )
                  {
                  count++;
                  if (!(rand() % count))
                     {
                     best = temp;
                     bestx = x;
                     besty = y;
                     }
                  }
               }
            }
   if (!(moved))    /* if colour cannot make a move then */
   {
      copy(index);
      best = -think(level-1, RED + BLACK - colour, index - 1);
   }
   if (index == MAXLOOK - 1)  /* if first level then */
   {
      xthought = bestx;
      ythought = besty;
   }
   return(best);
}



dumbthink(level, colour, index)
short  level, colour, index;
{
short x, y, count = 0;
int   worst = 4000, temp;   /* the initial value of worst must be greater
                     than the absolute value of the initial value of best
                     in think in order to avoid deadlock on the last few
                     moves.  */

/* this routine finds the worst move possible.  Since it is always called as
the first level ( then it calls think() ) many checks can be dispensed with.
We know there must be a move because otherwise this routine would not have
been called. */


   if (level == 0)
   {
      for ( x = 1; x <= numboxes; x++ )
         for ( y = 1; y <= numboxes; y++ )
           if (game[index][x][y] == EMPTY)
               {
               temp = move_i(x, y, colour, index);
               if (temp)
                  if (temp < worst)
                     {
                     worst = temp;
                     xthought = x;
                     ythought = y;
                     }
                  else if (temp == worst)
                     {
                     count++;
                     if (!(rand() % count))
                        {
                        worst = temp;
                        xthought = x;
                        ythought = y;
                        }
                     }
               }
      return(worst);
   }
   for ( x = 1; x <= numboxes; x++ )
      for ( y = 1; y <= numboxes; y++ )
         if (game[index][x][y] == EMPTY)
            {
            temp = move_i(x, y, colour, index);
            if (temp > 0)
               {
               copyplot(index, x, y, colour);
               temp = temp - think(level-1, RED + BLACK - colour, index-1);
               if (temp < worst)
                  {
                  worst = temp;
                  xthought = x;
                  ythought = y;
                  count = 1;
                  }
               else if (temp == worst)
                  {
                  count++;
                  if (!(rand() % count))
                     {
                     worst = temp;
                     xthought = x;
                     ythought = y;
                     }
                  }
               }
            }
   return(worst);
}



copyplot(index, x, y, colour)
short index, x, y, colour;
{
short opponent;
int   count;
short count2, dx, dy, xcopy, ycopy, i;

   opponent = BLACK + RED - colour;

   copy(index);

   count = 0;

   if (game[index-1][x][y] != EMPTY)
      quit_cleanup("Error.  Can't plot in filled box.");

   for (dx = -1; dx <= 1; dx++)
      for (dy = -1; dy <= 1; dy++)
      {
         xcopy = x + dx;
         ycopy = y + dy;
         count2 = 0;
         while ( game[index-1][xcopy][ycopy] == opponent )
         {
            count2++;
            xcopy = xcopy + dx;
            ycopy = ycopy + dy;
         }
         if (game[index-1][xcopy][ycopy] == colour)
         {
            count = count + count2;
            for ( i = 1; i <= count2; i++)
            {
               xcopy = xcopy - dx;
               ycopy = ycopy - dy;
               game[index-1][xcopy][ycopy] = colour;
            }
         }
      }
   if (count)
      game[index-1][x][y] = colour;
   else
      quit_cleanup("Error.  Illegal move by think.");
}



copy(index)
short index;
{
short dx, dy;

   for ( dx = 1; dx <= numboxes; dx++ )
      for ( dy = 1; dy <= numboxes; dy++ )
         game[index-1][dx][dy] = game[index][dx][dy];
}



waitforclick(resume,printit)
BOOL resume;    /* whether or not to resume if mode change to RACETHROUGH */
BOOL printit;   /* whether or not to print click message */
{
struct IntuiMessage *message;

   if (scores[RED] + scores[BLACK] >= numboxes * numboxes)
      return(0);
   if (printit)
      printstring(click, 0, LINEHEIGHT);
   newgame = FALSE;
   while (TRUE)
   {
      clearport();
      WaitPort(window->UserPort);
      message = (struct IntuiMessage *)GetMsg(window->UserPort);
      if ( message->Class == MOUSEBUTTONS && message->Code == SELECTDOWN )
      {
         ReplyMsg(message);
         return(0);
      }
      else
         processmessage();
      if ((guruwait == RACETHROUGH && resume) || newgame)
         return(0);
   }
}



domovered()
{
short x, y;
USHORT code;

   if (looksp2 != HUMAN)
   {
      printstring(thinking, 0, LINEHEIGHT);
      if (looksp2 < LEVELM1)
         think(looksp2, RED, MAXLOOK-1);
      else
         dumbthink(looksp2-LEVELM1, RED, MAXLOOK-1);
      flip(xthought, ythought, RED);
      clearport();
      if (guruwait == STEPTHROUGH && looksp1 != HUMAN)
         {
         showplayer(whoseturn, 141, 0);
         waitforclick(TRUE,TRUE);
         }
   }
   else
   {
      WaitPort(window->UserPort);
      message = (struct IntuiMessage *)GetMsg(window->UserPort);
      if (message->Class == MOUSEBUTTONS)
      {
         x = message->MouseX;
         y = message->MouseY;
         code = message->Code;
         ReplyMsg(message);
         mouseclick(RED, x, y, code);
      }
      else
         processmessage();
   }
}



domoveblack()
{
short x, y;
USHORT code;

   if (looksp1 != HUMAN)
   {
      printstring(thinking, 0, LINEHEIGHT);
      if (looksp1 < LEVELM1)
         think(looksp1, BLACK, MAXLOOK-1);
      else
         dumbthink(looksp1-LEVELM1, BLACK, MAXLOOK-1);
      flip(xthought, ythought, BLACK);
      clearport();
      if (guruwait == STEPTHROUGH && looksp2 != HUMAN)
         {
         showplayer(whoseturn, 141, 0);
         waitforclick(TRUE,TRUE);
         }
   }
   else
   {
      WaitPort(window->UserPort);
      message = (struct IntuiMessage *)GetMsg(window->UserPort);
      if (message->Class == MOUSEBUTTONS)
      {
         x = message->MouseX;
         y = message->MouseY;
         code = message->Code;
         ReplyMsg(message);
         mouseclick(BLACK, x, y, code);
      }
      else
         processmessage();
   }
}



mouseclick(current, x, y, code)
short  current, x, y;
USHORT code;
{
struct IntuiMessage *message;
short nx, ny;

   if (code != SELECTDOWN)
      return(0);
   nx = x - xoffset;
   ny = y - yoffset;
   x = nx / boxwidth;
   y = ny / boxheight;
   while (code != SELECTUP)
   {
      WaitPort(window->UserPort);
      message = (struct IntuiMessage *)GetMsg(window->UserPort);
      code = message->Code;
      nx = message->MouseX - xoffset;
      ny = message->MouseY - yoffset;
      ReplyMsg(message);
   }
   if (x != (nx / boxwidth))
      return(0);
   if (y != (ny / boxheight))
      return(0);
   if (nx < 0 || ny < 0 || x >= numboxes || y >= numboxes)
      return(0);
   return(flip(x+1,y+1,current));
}



flip(x,y,current)
short x, y, current;
{
int   count;
short count2, dx, dy, xcopy, ycopy, i;
short opponent;

   printstring(blank, 0 ,LINEHEIGHT);

   opponent = RED + BLACK - current;

   count = 0;

   if (game[MAXLOOK-1][x][y] != EMPTY)
   {
      printstring(notempty, 0, LINEHEIGHT);
      return(0);
   }

   for (dx = -1; dx <= 1; dx++)
      for (dy = -1; dy <= 1; dy++)
      {
         xcopy = x + dx;
         ycopy = y + dy;
         count2 = 0;
         while ( game[MAXLOOK-1][xcopy][ycopy] == opponent )
         {
            count2++;
            xcopy = xcopy + dx;
            ycopy = ycopy + dy;
         }
         if (game[MAXLOOK-1][xcopy][ycopy] == current)
         {
            count = count + count2;
            for ( i = 1; i <= count2; i++)
            {
               xcopy = xcopy - dx;
               ycopy = ycopy - dy;
               plot(xcopy,ycopy,current,NOBOXIT);
            }
         }
      }
   if (count)
   {
      scores[current] = scores[current] + count + 1;
      scores[opponent] = scores[opponent] - count;
      plot(x,y,current,BOXIT);
      whoseturn = RED + BLACK - whoseturn;
      printscores();
   }
   else
      printstring(notlegal, 0, LINEHEIGHT);
   return(count);
}



moveable(current)
{
int   moves;
short x, y;

   moves = 0;
   for ( x = 1; x <= numboxes; x++)
      for (y = 1; y <= numboxes; y++)
         moves = moves + move(x,y,current,MAXLOOK-1);
   return(moves);
}



move(x,y,current,index)
short x, y, current, index;
{
int   count;
short count2, dx, dy, xcopy, ycopy, opponent;

   opponent = RED + BLACK - current;

   count = 0;

   if (game[index][x][y] != EMPTY)
      return(0);

   for (dx = -1; dx <= 1; dx++)
      for (dy = -1; dy <= 1; dy++)
      {
         xcopy = x + dx;
         ycopy = y + dy;
         count2 = 0;
         while ( game[index][xcopy][ycopy] == opponent )
         {
            count2++;
            xcopy = xcopy + dx;
            ycopy = ycopy + dy;
         }
         if (game[index][xcopy][ycopy] == current)
            count = count + count2;
      }
   return(count);
}



move_i(x,y,current,index)
short x, y, current, index;
{
REGISTER unsigned long count, count2, opponent;
REGISTER char     *p, *p2;

   opponent = RED + BLACK - current;

   count = 0;

   p = &game[index][x][y];

/* We now look in each of the eight directions and find out how many (if
any) pieces we can flip over.  I use pointers to directly access the members
of the array and I have separate code for each direction for efficiency
reasons.  I'm only going to comment the first of the eight because the
comments for the others would be almost identical.  The original code, using
nested for loops to look in all eight directions is shown at the bottom. */

/* check in the -x, -y direction */
   p2 = p - (MAXBOXES+2 + 1); /* subtract 1 from x and y coordinates. */
   if (*p2 == opponent)       /* is neighbouring piece opponents? */
      {
      count2 = 1;             /* set temporary flipped piece counter. */
      p2 -= MAXBOXES+2 + 1;   /* subtract 1 from x and y coordinates. */
      while (*p2 == opponent) /* go to end of row of opponents. */
         {
         count2++;            /* count the number of pieces passed over. */
         p2 -=  MAXBOXES+2 + 1;  /* subtract 1 from x and y coordinate. */
         }
      if (*p2 == current)     /* if own piece ends line then, */
         count += count2;     /* we can flip count pieces. */
      }

/* check in the -y direction */
   p2 = p - 1;
   if (*p2 == opponent)
      {
      count2 = 1;
      p2--;
      while (*p2 == opponent)
         {
         count2++;
         p2--;
         }
      if (*p2 == current)
         count += count2;
      }

/* check in the +x, -y direction */
   p2 = p + (MAXBOXES+2) - 1;
   if (*p2 == opponent)
      {
      count2 = 1;
      p2 += MAXBOXES+2 - 1;
      while (*p2 == opponent)
         {
         count2++;
         p2 += MAXBOXES+2 - 1;
         }
      if (*p2 == current)
         count += count2;
      }

/* check in the -x direction */
   p2 = p - (MAXBOXES+2);
   if (*p2 == opponent)
      {
      count2 = 1;
      p2 -= MAXBOXES+2;
      while (*p2 == opponent)
         {
         count2++;
         p2 -= MAXBOXES+2;
         }
      if (*p2 == current)
         count += count2;
      }

/* check in the +x direction */
   p2 = p + MAXBOXES+2;
   if (*p2 == opponent)
      {
      count2 = 1;
      p2 += MAXBOXES+2;
      while (*p2 == opponent)
         {
         count2++;
         p2 += MAXBOXES+2;
         }
      if (*p2 == current)
         count += count2;
      }

/* check in the -x, +y direction */
   p2 = p + 1 - (MAXBOXES+2);
   if (*p2 == opponent)
      {
      count2 = 1;
      p2 += 1 - (MAXBOXES+2);
      while (*p2 == opponent)
         {
         count2++;
         p2 += 1 - (MAXBOXES+2);
         }
      if (*p2 == current)
         count += count2;
      }

/* check in the +y direction */
   p2 = p + 1;
   if (*p2 == opponent)
      {
      count2 = 1;
      p2++;
      while (*p2 == opponent)
         {
         count2++;
         p2++;
         }
      if (*p2 == current)
         count += count2;
      }

/* check in the +x, +y direction */
   p2 = p + MAXBOXES+2 + 1;
   if (*p2 == opponent)
      {
      count2 = 1;
      p2 += MAXBOXES+2 + 1;
      while (*p2 == opponent)
         {
         count2++;
         p2 += MAXBOXES+2 + 1;
         }
      if (*p2 == current)
         count += count2;
      }

/* This is the older, easier to read, but slower, move_i routine
   for (dx = -1; dx <= 1; dx++)
      for (dy = -1; dy <= 1; dy++)
      {
         xcopy = x + dx;
         ycopy = y + dy;
         count2 = 0;
         while ( game[index][xcopy][ycopy] == opponent )
         {
            count2++;
            xcopy = xcopy + dx;
            ycopy = ycopy + dy;
         }
         if (game[index][xcopy][ycopy] == current)
            count = count + count2;
      }          */

   if (count)
      return(count + bonus[x][y]);
   else
      return(0);
}



plot(x,y,current,box)
short x, y, current;
BOOL  box;
{
   if ( x < 1 || x > numboxes || y < 1 || y > numboxes)
      quit_cleanup("Illegal x or y value in plot call");
   drawboard();
   player.PlanePick = current;
   game[MAXLOOK-1][x][y] = current;
   if (box)
      highlight(x, y);
   x = xoffset + (x-1) * boxwidth;
   y = yoffset + (y-1) * boxheight;
   DrawImage(window->RPort, &player, x, y);
}



printstring(text, x, y)
char    *text;
short    x, y;
{
   string.IText = text;
   PrintIText(window->RPort, &string, x, y);
}



processmessage()
{
int    menucode;
long   class;
struct MenuItem *item;

   class = message->Class;
   menucode = message->Code;
   ReplyMsg(message);
   switch (class)
   {
      case CLOSEWINDOW :
         ClearMenuStrip(window);
         ModifyIDCMP(window,NULL);
         if ( AutoRequest(window,&Quittext,&Postext,&Negtext,
                        NULL,NULL,180,57) )
            {
            SetMenuStrip(window,Titles);
            quit_cleanup(0);
            }
         ModifyIDCMP(window,IDCMPNORMAL);
         SetMenuStrip(window,Titles);
         break;
      case MENUPICK :
         while (menucode != MENUNULL)
         {
            item = (struct MenuItem *)ItemAddress(Titles, menucode);
            processmenu(MENUNUM(menucode), ITEMNUM(menucode), SUBNUM(menucode));
            menucode = item->NextSelect;
         }
         break;
      default :
         break;
   }
}



processmenu(menu, item, subitem)
int   menu, item, subitem;
{
   switch(menu)
   {
      case PROJECT :
         switch (item)
         {
            case NEWGAME :
               whostarts = subitem + 1;
               initialize();
               break;
            case BOARDSIZE :
               if (numboxes != 6 + subitem * 2)
                  {
                  numboxes = 6 + subitem * 2;
                  initialize();
                  }
               break;
            case OPEN :
               loadgame();
               break;
            case SAVEGAME :
               savegame();
               break;
            case SAVEDEF :
               savedefaults();
               break;
            case ABOUT :
               info(menu,item,subitem);
               break;
            case HELP  :
               switch (subitem)
                  {
                  case FUNCTION :
                     helpfunction();
                     break;
                  case ALL :
                     info(menu,item,subitem);
                     break;
                  }
               break;
            case QUIT :
               ClearMenuStrip(window);
               ModifyIDCMP(window,NULL);
               if ( AutoRequest(window,&Quittext,&Postext,&Negtext,
                              NULL,NULL,180,57) )
                  {
                  SetMenuStrip(window,Titles);
                  quit_cleanup(0);
                  }
               ModifyIDCMP(window,IDCMPNORMAL);
               SetMenuStrip(window,Titles);
               break;
         }
         break;
      case PLAYER1 :
         looksp1 = item;
         break;
      case PLAYER2 :
         looksp2 = item;
         break;
      case GURUVSGURU :
         guruwait = item;
         break;
      case OTHER      :
         switch (item)
         {
            case MOVES :
               showmoves();
               break;
            case SUGGEST :
               suggest();
               break;
         }
         break;
   }
}



extern BOOL info_display();

helpfunction()
{
   struct IntuiMessage *message;
   ULONG MessageClass;
   USHORT WhichButton;

   ModifyIDCMP(window, MENUPICK);

   WaitPort(window->UserPort);
   message = (struct IntuiMessage *)GetMsg(window->UserPort);
   MessageClass = message->Class;
   WhichButton = message->Code;
   ReplyMsg(message);
   while (WhichButton != MENUNULL)
      {
      struct MenuItem *item;
      item = (struct MenuItem *)ItemAddress(Titles,WhichButton);
      if (info(MENUNUM(WhichButton),
                  ITEMNUM(WhichButton),
                  SUBNUM(WhichButton)) == FALSE)
         quit_cleanup("Info problem!!!\n");
      WhichButton = item->NextSelect;
      }

   ModifyIDCMP(window,IDCMPNORMAL);
}



info(menu,item,subitem)
int menu,item,subitem;
{
   ClearMenuStrip(window);
   ModifyIDCMP(window,NULL);

   info_display(menu,item,subitem);

   checkit();
   SetMenuStrip(window,Titles);
   ModifyIDCMP(window, IDCMPNORMAL);
}



showmoves()
{
short x, y;
BOOL  any = FALSE;

   showplayer(whoseturn, 141, 0);
   drawboard();
   for (x = 1; x <= numboxes; x++)
      for (y = 1; y <= numboxes; y++)
         if (move(x,y,whoseturn,MAXLOOK-1))
            {
            any = TRUE;
            highlight(x, y);
            }
   if (any)
      printstring(possible, 0, LINEHEIGHT);
   else
      printstring(youcant, 0, LINEHEIGHT);
   if (looksp1 != HUMAN && looksp2 != HUMAN && guruwait == RACETHROUGH)
      WaitPort(window->UserPort);
}



suggest()
{
   showplayer(whoseturn, 141, 0);
   if (moveable(whoseturn))
      {
      printstring(thinking, 0, LINEHEIGHT);
      think(2,whoseturn,MAXLOOK-1);
      drawboard();
      highlight(xthought, ythought);
      printstring(bestmove, 0, LINEHEIGHT);
      }
   else
      printstring(youcant, 0, LINEHEIGHT);
   if (looksp1 != HUMAN && looksp2 != HUMAN && guruwait == RACETHROUGH)
      WaitPort(window->UserPort);
}



highlight(x, y)
short x, y;
{
   smallsquare.FrontPen = whoseturn;
   x = xoffset + (x - 1) * boxwidth;
   y = yoffset + (y - 1) * boxheight;
   DrawBorder(window->RPort, &smallsquare, x, y);
}



checklooks(looks)
short looks;
{
   if (looks < LEVEL1 || looks > HUMAN)
      return(FALSE);
   else
      return(TRUE);
}



checksize(size)
short size;
{
   if (size != 6 && size != 8 && size != 10 && size != 12)
      return(FALSE);
   else
      return(TRUE);
}



checkguru(guru)
short guru;
{
   if (guru != STEPTHROUGH && guru != RACETHROUGH)
      return(FALSE);
   else
      return(TRUE);
}



checkwhose(whose)
short whose;
{
   if (whose != BLACK && whose != RED)
      return(FALSE);
   else
      return(TRUE);
}



loadgame()
{
   FILE *fp, *fopen();
   char *gamename, *getgamename();
   short x, y;
   short version, l_looksp1, l_looksp2, l_whoseturn, l_numboxes, l_guruwait;
   short l_scores[3];
   char  l_board[MAXBOXES][MAXBOXES];
   char  temp;

   gamename = getgamename();

   if ((fp = fopen(gamename, "r")) == NULL)
      {
      printstring(openfail, 0, LINEHEIGHT);
      return(FALSE);
      }
   if ((version = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if ((l_looksp1 = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (!checklooks(l_looksp1))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if ((l_looksp2 = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (!checklooks(l_looksp2))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if ((l_numboxes = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (!checksize(l_numboxes))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if ((l_guruwait = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (!checkguru(l_guruwait))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   l_scores[RED] = 0;
   l_scores[BLACK] = 0;
   if ((l_whoseturn = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (!checkwhose(l_whoseturn))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }

   for (x=1; x<=l_numboxes; x++)
      for (y=1; y<=l_numboxes; y++)
         {
         if ((temp = (short)(getc(fp))) == EOF)
            {
            printstring(shortfil, 0, LINEHEIGHT);
            fclose(fp);
            return(FALSE);
            }
         if (temp != EMPTY && temp != BLACK && temp != RED)
            {
            printstring(illvalue, 0, LINEHEIGHT);
            fclose(fp);
            return(FALSE);
            }
         l_board[x][y] = temp;
         l_scores[l_board[x][y]]++;
         }

   fclose(fp);

   looksp1 = l_looksp1;
   looksp2 = l_looksp2;
   whoseturn = l_whoseturn;
   guruwait = l_guruwait;
   numboxes = l_numboxes;

   initialize();

   for (x=1; x<=numboxes; x++)
      for (y=1; y<=numboxes; y++)
         {
         plot(x,y,l_board[x][y],NOBOXIT);
         }

   scores[RED] = l_scores[RED];
   scores[BLACK] = l_scores[BLACK];

   printscores();
   ClearMenuStrip(window);
   checkit();
   SetMenuStrip(window,Titles);
   printstring(loaded, 0, LINEHEIGHT);
}



savegame()
{
   FILE *fp, *fopen();
   char *gamename, *getgamename();
   short x, y;

   gamename = getgamename();

   if ((fp = fopen(gamename, "w")) == NULL)
      {
      printstring(openfail, 0, LINEHEIGHT);
      return(FALSE);
      }
   if (putc(VERSION,fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(looksp1),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(looksp2),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(numboxes),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(guruwait),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(whoseturn),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   for (x=1; x <= numboxes; x++)
      for (y=1; y <= numboxes; y++)
         if (putc(game[MAXLOOK-1][x][y],fp) == EOF)
            {
            printstring(writfail, 0, LINEHEIGHT);
            fclose(fp);
            return(FALSE);
            }
   fclose(fp);
   printstring(saved, 0, LINEHEIGHT);
   return(TRUE);
}



char *getgamename()
{
   return("Othello.sav");
}



savedefaults()
{
   FILE *fp, *fopen();

   if ((fp = fopen( DISKDEFNAME, "w")) == NULL)
      {
      printstring(openfail, 0, LINEHEIGHT);
      return(FALSE);
      }
   if (putc(VERSION,fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(looksp1),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(looksp2),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(numboxes),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   if (putc((char)(guruwait),fp) == EOF)
      {
      printstring(writfail, 0, LINEHEIGHT);
      fclose(fp);
      return(FALSE);
      }
   fclose(fp);
   printstring(defsaved, 0, LINEHEIGHT);
   return(TRUE);
}



checkit()
{
short ordinal, x;

   ordinal  = 1 + STARTP2;
   for (x = 0; x <= SQUARE12; x++)
      SubItems[ordinal+x].Flags                 &= ~CHECKED;
   SubItems[ordinal + ((numboxes-6)/2)].Flags   |= CHECKED;

   ordinal  = 1 + QUIT;
   for (x = 0; x <= HUMAN; x++)
      Items[ordinal+x].Flags                    &= ~CHECKED;
   Items[ordinal+looksp1].Flags                 |= CHECKED;

   ordinal += 1 + HUMAN;
   for (x = 0; x <= HUMAN; x++)
      Items[ordinal+x].Flags                    &= ~CHECKED;
   Items[ordinal+looksp2].Flags                 |= CHECKED;

   ordinal += 1 + HUMAN;
   for (x = 0; x <= RACETHROUGH; x++)
      Items[ordinal+x].Flags                    &= ~CHECKED;
   Items[ordinal+guruwait].Flags                |= CHECKED;
}



getdefaults()
{
   looksp1  = DEFAULTP1;
   looksp2  = DEFAULTP2;
   numboxes = DEFAULTSIZE;
   guruwait = DEFAULTGURUWAIT;

   getdiskdefaults();
   checkit();
}



getdiskdefaults()
{
   FILE *fp, *fopen();
   short version, l_looksp1, l_looksp2, l_numboxes, l_guruwait;

   if ((fp = fopen( DISKDEFNAME, "r" )) == NULL)
      return(0);
   if ((version = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      return(FALSE);
      }
   if ((l_looksp1 = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      return(FALSE);
      }
   if (!checklooks(l_looksp1))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      return(FALSE);
      }
   if ((l_looksp2 = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      return(FALSE);
      }
   if (!checklooks(l_looksp2))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      return(FALSE);
      }
   if ((l_numboxes = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      return(FALSE);
      }
   if (!checksize(l_numboxes))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      return(FALSE);
      }
   if ((l_guruwait = (short)(getc(fp))) == EOF)
      {
      printstring(shortfil, 0, LINEHEIGHT);
      return(FALSE);
      }
   if (!checkguru(l_guruwait))
      {
      printstring(illvalue, 0, LINEHEIGHT);
      return(FALSE);
      }
   fclose(fp);
   looksp1 = l_looksp1;
   looksp2 = l_looksp2;
   numboxes = l_numboxes;
   guruwait = l_guruwait;
   return(0);
}



clearport()
{
   struct IntuiMessage *message;

   while (message = (struct IntuiMessage *)GetMsg(window->UserPort))
   {
      if (message->Class == MOUSEBUTTONS)
         ReplyMsg(message);
      else
         processmessage(message);
   }
}



quit_cleanup(x)
char *x;
{
   if (circle)
      FreeRaster(circle,WIDE,HIGH);
   if (ourpointer)
      FreeRaster(ourpointer,POINTERWIDTH*2,POINTERHEIGHT*2);
   if (window)
   {
      ClearMenuStrip(window);
      CloseWindow(window);
   }
   if (GfxBase)
      CloseLibrary(GfxBase);
   if (IntuitionBase)
      CloseLibrary(IntuitionBase);
   if (!(workbench) && x)
      printf("%s\n",x);
   exit(0);
}



drawboard()
{
   short i;

   for (i = 1; i < numboxes; i++)
   {
      DrawBorder(window->RPort,&xline,xoffset,yoffset+i*boxheight);
      DrawBorder(window->RPort,&yline,xoffset+i*boxwidth,yoffset);
   }
   DrawBorder(window->RPort, &square, xoffset, yoffset);
}



initialize()
{
short x, y, r;

   newgame = TRUE;

   printstring(blank, 0, LINEHEIGHT);

   whoseturn = whostarts;

   boxheight = height / numboxes;
   boxwidth = width / numboxes;

   r = (boxheight - 2) / 2;
   player.Width = r * 4;
   player.Height = r * 2;
   generatecircle(r, circle + (r - 1) * 256);
   player.ImageData = (short *)&circle[256 * (r - 1)];

   stuck = FALSE;

   for (r = 0; r <= MAXLOOK-1; r++)
      for (x = 0; x <= numboxes + 1; x++)
         for (y = 0; y <= numboxes + 1; y++)
            game[r][x][y] = OFFSCREEN;

   for (x = 1; x <= numboxes; x++)
      for (y = 1; y <= numboxes; y++)
         game[MAXLOOK-1][x][y] = EMPTY;

   squarepoints[0] = squarepoints[1] = 0;
   squarepoints[2] = squarepoints[4] = numboxes * boxwidth;
   squarepoints[5] = squarepoints[7] = numboxes * boxheight;
   squarepoints[3] = squarepoints[6] = 0;
   squarepoints[8] = squarepoints[9] = 0;

   smallsquarepoints[0] = smallsquarepoints[1] = 0;
   smallsquarepoints[2] = smallsquarepoints[4] = boxwidth;
   smallsquarepoints[5] = smallsquarepoints[7] = boxheight;
   smallsquarepoints[3] = smallsquarepoints[6] = 0;
   smallsquarepoints[8] = smallsquarepoints[9] = 0;

   SetAPen(window->RPort, 0);
   RectFill(window->RPort,xoffset,yoffset,xoffset+width+1,yoffset+height+1);

   drawboard();

   game[MAXLOOK-1][numboxes/2][numboxes/2] = RED;
   game[MAXLOOK-1][numboxes/2+1][numboxes/2+1] = RED;
   game[MAXLOOK-1][numboxes/2+1][numboxes/2] = BLACK;
   game[MAXLOOK-1][numboxes/2][numboxes/2+1] = BLACK;

   scores[RED] = 2;
   scores[BLACK] = 2;
   printscores();

   plot(numboxes/2,numboxes/2,RED,NOBOXIT);
   plot(numboxes/2+1,numboxes/2+1,RED,NOBOXIT);
   plot(numboxes/2+1,numboxes/2,BLACK,NOBOXIT);
   plot(numboxes/2,numboxes/2+1,BLACK,NOBOXIT);

   printstring(yourmove, 0, 0);

   for (x = 0; x < numboxes+2; x++)
      for (y = 0; y < numboxes+2; y++)
         bonus[x][y] = 0;
   for (x = 1; x < numboxes+1; x++)
      for (y = 1; y < numboxes+1; y++)
         bonus[x][y] = 3;
   for (x = 2; x < numboxes; x++)
      for (y = 2; y < numboxes; y++)
         bonus[x][y] = -1;
   for (x = 3; x < numboxes-1; x++)
      for (y = 3; y < numboxes-1; y++)
         bonus[x][y] = 0;

   bonus[1][1] = bonus[numboxes][1] = 13;
   bonus[numboxes][numboxes] = bonus[1][numboxes] = 13;

   bonus[2][2] = bonus[numboxes-1][2] = -9;
   bonus[numboxes-1][numboxes-1] = bonus[2][numboxes-1] = -9;

   bonus[2][1] = bonus[numboxes-1][1] = -2;
   bonus[1][2] = bonus[numboxes][2] = -2;

   bonus[numboxes][numboxes-1] = bonus[1][numboxes-1] = -2;
   bonus[numboxes-1][numboxes] = bonus[2][numboxes] = -2;


/* This is what the original bonus array looked like for an 8 by 8 game
   board.
{  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0  },
   {  0, 13, -2,  3,  3,  3,  3, -2, 13,  0  },
   {  0, -2, -9, -1, -1, -1, -1, -9, -2,  0  },
   {  0,  3, -1,  0,  0,  0,  0, -1,  3,  0  },
   {  0,  3, -1,  0,  0,  0,  0, -1,  3,  0  },
   {  0,  3, -1,  0,  0,  0,  0, -1,  3,  0  },
   {  0,  3, -1,  0,  0,  0,  0, -1,  3,  0  },
   {  0, -2, -9, -1, -1, -1, -1, -9, -2,  0  },
   {  0, 13, -2,  3,  3,  3,  3, -2, 13,  0  },
   {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0  }
};   */
   /* Add a large enough number to make all the bonus value positive. */

   for (x = 1; x < numboxes+1; x++)
      for (y = 1; y < numboxes+1; y++)
         bonus[x][y] += 9;

}
