/********************************************************************/
/*                                                                  */
/*  Hoser BackGammon version 1.0                                    */
/*                                                                  */
/*      Robert Pfister                                              */
/*                                                                  */
/*      Rfd#3 Box 2340                home:(207)-873-3520           */
/*      Waterville, Maine 04901                                     */
/*                                                                  */
/*      Pfister_rob%dneast@dec.decwrl                               */
/*                                                                  */
/*                                                                  */
/*  Copyright  June,1987 all rights reserved.                       */
/*                                                                  */
/*  This program will play a game of backgammon at the novice level */
/*                                                                  */
/*  The code is in 4 parts...                                       */
/*                                                                  */
/*       1) back.c     - main driver                                */
/*   /   2) eval.c     - evaluation of moves                        */
/* \/    3) backscn.c  - screen stuff..                             */
/*       4) backmenu.c - menu stuff, help text, and ``decoder''     */
/*                                                                  */
/* this was compiled under Manx 3.20a, using long integers          */
/*                                                                  */
/********************************************************************/

extern int Uside,Cside;

#include <stdio.h>
#include <exec/types.h>
#include <graphics/gfxmacros.h>
#include <graphics/rastport.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <functions.h>

#undef  NULL
#define NULL ((void *) 0)
#define NL 0

/* color index's */
#define tm1       0L
#define tm2       1L
#define back      2L
#define spike1    3L
#define spike2    4L
#define peice1    5L
#define peice2    6L
#define dice      7L

/* now define those colors */
#define backc    0x0F0L
#define spike1c  0xFF0L
#define spike2c  0xF00L
#define peice1c  0x000L
#define peice2c  0x00FL
#define dicec    0xFFFL
#define tm1c     0x606L
#define tm2c     0xDDDL

static UWORD colors[8];

/* describe the playing field */
#define maxX   637L
#define minX     3L
#define maxY   189L
#define minY    25L
#define PerSpike 6L
#define MyTitle "Hoser BackGammon     Copyright June 1987     Robert Pfister"

       struct  GfxBase         *GfxBase;
       struct  IntuitionBase   *IntuitionBase;
static struct  RastPort        *rp;
static struct  ViewPort        *vp;
static struct  Window          *w;
static struct  Screen          *screen;

extern struct Menu *MyMenu;  /* get the menu somewhere else */

struct  NewScreen       ns = {
    0L,0L,640L,200L,3L,
    0,1,HIRES,
    CUSTOMSCREEN,NULL,
    (UBYTE *)MyTitle,
    NULL,NULL };

struct  NewWindow       nw = {
    0L,10L,640L,190L,0L,1L,
    CLOSEWINDOW|MOUSEBUTTONS|MENUPICK,
    SMART_REFRESH|ACTIVATE|WINDOWDRAG|WINDOWDEPTH,
    NULL,NULL,
    (UBYTE *)"BackGammon anyone?",
    NULL,NULL,
    0L,0L,640L,200L,CUSTOMSCREEN };

struct  NewWindow       crnw = {
    20L,20L,600L,170L,0L,1L,
    CLOSEWINDOW|MOUSEBUTTONS|MENUPICK,
    WINDOWCLOSE|SMART_REFRESH|ACTIVATE|WINDOWDRAG|WINDOWDEPTH,
    NULL,NULL,
    (UBYTE *)"BackGammon credits",
    NULL,NULL,
    0L,0L,640L,200L,CUSTOMSCREEN };

static UWORD AreaBuf[1000];
static PLANEPTR TBuf;
static struct TmpRas TRas;
static struct AreaInfo AInfo;

Gsetup()
{

long  x,size;
int   i;

    GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L);
    if (GfxBase == NULL) Gerror("no graphics lib");
    IntuitionBase =
        (struct IntuitionBase *)OpenLibrary("intuition.library",0L);
    if (IntuitionBase == NULL) {
        CloseLibrary(GfxBase);
        Gerror("no intuition");
        }

    screen = (struct Screen *)OpenScreen(&ns);
    if (screen == NULL) {
        CloseLibrary(IntuitionBase);
        CloseLibrary(GfxBase);
        Gerror("no screen");
        }

    nw.Screen = screen;
    w         = (struct Window *)OpenWindow(&nw);
    if (w == NULL) {
        CloseScreen(screen);
            CloseLibrary(IntuitionBase);
        CloseLibrary(GfxBase);
        Gerror("no window");
        }

    vp = &screen->ViewPort;
    rp = w->RPort;

    /* intialize temporary area space */
    InitArea(&AInfo,AreaBuf,200L);
    rp->AreaInfo=&AInfo;
    TBuf=(PLANEPTR)AllocRaster(640L,200L);
    if (TBuf==NULL)
        {
        ClearMenuStrip(w);  /* do this to avoid nasty's */
        CloseWindow(w);
        CloseScreen(screen);
        CloseLibrary(IntuitionBase);
        CloseLibrary(GfxBase);
        Gerror("no raster");
        }

    SetMenuStrip(w,MyMenu);

    size=RASSIZE(640L,200L);
    rp->TmpRas=(struct TmpRas *)InitTmpRas(&TRas,TBuf,size);

    /* load in the colors */
    colors[back]  =backc;
    colors[spike1]=spike1c;
    colors[spike2]=spike2c;
    colors[peice1]=peice1c;
    colors[peice2]=peice2c;
    colors[tm1]   =tm1c;
    colors[tm2]   =tm2c;
    colors[dice]  =dicec;

    for (i=0;i<8;i++)
       {
        SetRGB4(vp,(long) i,(long)((colors[i] >>8) & 0xF),
                            (long)((colors[i] >>4) & 0xF),
                            (long)((colors[i]    ) & 0xF));
        }

    SetDrMd(rp,JAM1);

    SetAPen(rp,back);
    RectFill(rp,minX,minY,maxX,maxY);

    for (i=1;i<=24;i++)
       {
         PutSpike(i,0);
         }

    x=((maxX+minX)/2);
    SetAPen(rp,tm1);
    RectFill(rp,(long)(x-2),minY,(long)(x+2),maxY);
    Move(rp,4L,(long)minY-6);
    SetAPen(rp,peice1);
    Text(rp,(char *)"Number of Moves Evaluated",25L);
    }



int l1,l2,r1,r2;  /* saved dice positions */

/* swap the dice positions on the screen */
SwapDice()
{
 int di[4];
 int sr1,sr2;
 
 di[0]=l1;
 di[1]=l2;

 sr1  =r1;
 sr2  =r2;
 
 Uside=-Uside;
 Cside=-Cside;
  
 ShowDice(di,Cside);

 di[0]=sr1;
 di[1]=sr2;

 ShowDice(di,Uside);
 }


/* put dice on the screen */

ShowDice(d,c)
int  d[4],c;
{
 int y,x1,x2;
 char Line[6];
 y =(maxY+minY)/2;
 
 if (c==Cside)
    {
    l1=d[0];
    l2=d[1];
    x1=40+(maxX+minX)/2; 
    x2=30+x1;
     }
  else
    {
     r1=d[0];
     r2=d[1];
     x1=-40+(maxX+minX)/2;
     x2=-30+x1;
     }
 
 /* cover up dice with dice color */

 SetAPen(rp,dice);
 RectFill(rp,(long) x2-12,(long) y-4,(long) x2+12,(long) y+4);
 RectFill(rp,(long) x1-12,(long) y-4,(long) x1+12,(long) y+4);

 if ( (d[0]!=0) && (d[1]!=0))
    {
     /* put in the numbers for the left and right die */

     if (c==Uside) SetAPen(rp,peice1);
              else SetAPen(rp,peice2);

     Move(rp,(long) x2,(long) y+3);
     Line[0]='0'+d[0];
     Line[1]='\0';
     Text(rp,Line,1L);

     Move(rp,(long) x1,(long) y+3);
     Line[0]='0'+d[1];
     Line[1]='\0';
     Text(rp,Line,1L);
     }
 }


i2s(n1,Line)
int n1;
char Line[6];
{
 int i,n;

 n=n1;

 for(i=0;i<=4;i++) Line[i]=' ';
 Line[5]='/0';
 Line[4]='0';

 /* convert into a string */
 for(i=4;(i>=0)&&(n>0);i--)
  {
   Line[i]=(n % 10) + '0';
   n/=10;
   }
}


PutMoveNumber(Number)
int Number;
{
 char Line[6];
 long x,y;

 y= minY-6;
 x= 210;

 SetAPen(rp,tm1);
 RectFill(rp,x,(long) y-6,(long) x+40,(long) y+4);
 i2s(Number,Line);
 SetAPen(rp,dice);
 Move(rp,x,y);
 Text(rp,Line,5L);
}

static struct IntuiMessage *message;

/* return any interesting input from the mouse...note that the window
   close is automatic  */

Whats_up(x)
int  *x;
  {
   unsigned long Class;
   unsigned short Code;
   char  code;
   int   xm,ym;

        for (;;)
          {
           Wait(1L<< w->UserPort->mp_SigBit);
           message=(struct IntuiMessage *) GetMsg(w->UserPort);
           Code =message->Code;
           Class=message->Class;
           ReplyMsg(message);

           if (Class==MENUPICK)
              {
               if (Code!=MENUNULL)
                   {
                    *x=(MENUNUM(Code)*100)+(ITEMNUM(Code)*10)+SUBNUM(Code);
                    return('C');
                   }
               return(' '); /* aint nothing, better reset */
               } 

           /* check if mouse pressed..... */
           if ((Class==MOUSEBUTTONS)&&
               (Code==SELECTDOWN))
              {
                xm=(w->MouseX);
                ym=(w->MouseY);
                *x=decode(xm,ym);
                if (*x==-1)  return('D');
                        else return('P');
                }
            }    /* end for ever */
    }  /* end main */

finit()
{
  FreeRaster(TBuf,640L,200L);
  CloseWindow(w);
  CloseScreen(screen);
  CloseLibrary(IntuitionBase);
  CloseLibrary(GfxBase);
 }

/* return the 'spike' number given the screen point relative to upper left
   corner of the window */

decode(x,y)
int x,y;
{
 int peice,mid,midy,height,disp;
     mid=(minX+maxX)/2;
     if (x>mid) disp=8;
           else disp=0;

     height=(maxY-minY)/2.5;
     midy=(minY+maxY)/2;

     /* check if dice 'clicked'...indicates unusual end of turn */
     if ((y>midy-5)&&(y<midy+5)&&(x<mid-28)&&(x>mid-82)) return(-1);

     /* check if 'bar' selected */
     if ( (x>(mid-10)) && (x<(mid+10))
          && (y>height) && (y<(maxY-height))    ) peice=0;

        else peice= 1+(12*(x+disp))/(maxX-minX);

     if ( y < (maxY+minY)/2) peice=25-peice;
     return(peice);
 }

static int ErrSet=FALSE;

DoMenuStrip(errmsg)
char errmsg[];
{
 ErrSet=TRUE;
 SetWindowTitles(w,-1L,errmsg);
 }

UnDoMenuStrip()
{
 if (ErrSet==TRUE)
    {
     SetWindowTitles(w,-1L,MyTitle);
     ErrSet=FALSE;
     }
}

/* put up a plain old requestor given 3 strings
           name...the question/statement of the requestor
           yes....the positive response
           no.....the negative response

    this returns 'true' for the yes, 'false' for the no  */

static struct IntuiText RB = {tm1   ,tm2   ,JAM2, 50, 10,NL,(UBYTE *)"   ",NL};
static struct IntuiText RY = {spike2,spike1,JAM1,  8,  3,NL,(UBYTE *)"Yes",NL};
static struct IntuiText RN = {spike2,spike1,JAM1,  8,  3,NL,(UBYTE *)"No ",NL};

requestor(name,yes,no)
char name[],yes[],no[];
{
  RB.IText=(UBYTE *)name;
  RY.IText=(UBYTE *)yes;
  RN.IText=(UBYTE *)no;
  return(AutoRequest(w,&RB,&RY,&RN,NULL,NULL,300L,90L));

  }


Gerror(msg)
char *msg;
    {
    if (msg) {
        puts("ERROR: ");
        puts(msg);
        puts("\n");
        }
    if (msg) exit(-1);
    else     exit(0);
    }


PutSpike(spk,peices)
int spk,peices;
  {
   long color,x,y,x1,y1,x2,y2,x3;
   int disp,n,i,sign;
   char line[10];

  /* pick color of the peices */
   if (peices<0) color=peice1;
            else color=peice2;
 
   /* plot the ones on the 'bar' */
   x1=-20+(minX+maxX)/2;
   x2=x1+40;
   y1=(maxY+minY)/2;
   if (spk==0)
       {
       SetAPen(rp,back);
       RectFill(rp,x1,y1,x2,(long)(y1+20));
       x=((maxX+minX)/2);
       SetAPen(rp,tm1);
       RectFill(rp,(long)(x-2),y1,(long)(x+2),maxY);
       if (peices>0)
             {
             PutPeice((long)(x1+20),(long)(y1+10),color);
             line[0]=('0'+peices);
             line[1]='\0';
             Move(rp,(long)(x1+18),(long)(y1+12));
             SetAPen(rp,dice);
             Text(rp,line,1L);
             }
       return(0);
       }

   if (spk==25)
       {
       SetAPen(rp,back);
       RectFill(rp,x1,(long)(y1-20),x2,y1);
       SetAPen(rp,tm1);
       x=((maxX+minX)/2);
       RectFill(rp,(long)(x-2),minY,(long)(x+2),y1);
       if (peices<0)
             {
             PutPeice((long)(x1+20),(long)(y1-10),color);
             line[0]=('0'-peices);
             line[1]='\0';
             Move(rp,(long)(x1+18),(long)(y1-8));
             SetAPen(rp,dice);
             Text(rp,line,1L);
             }
       return(0);
       }


   n=(maxX-minX)/ 12;
   y=(maxY-minY)/ 2.5;

   x=spk;
   if (x>12) x=25-x;
   if (x>6)  disp=8;
        else disp=0;

   x1=(x*n)    -(n/2)+minX+disp;
   x2=(x*n)          +minX+disp;
   x3=((x-1)*n)      +minX+disp;

   /* box in the area around the spike with background color...*/

   SetAPen(rp,(long)back);

   if (spk<13)
      {
        sign=-1;
        y1=maxY-y;
        y2=maxY;
        RectFill(rp,x3,y1,x2,y2);
    }
     else
       {
        sign=1;
        y1=minY+y;
        y2=minY;
        RectFill(rp,x3,y2,x2,y1);
       }


   /* color in spike */
   if (spk%2 ==1) SetAPen(rp,(long)spike1);
             else SetAPen(rp,(long)spike2);

   AreaMove(rp,x1,y1);
   AreaDraw(rp,x2,y2);
   AreaDraw(rp,x3,y2);
   AreaDraw(rp,x1,y1);
   AreaEnd(rp);

   if (peices<0) peices=-peices;
   /* go through number of peices, up to "PerSpike" */
   for(i=0;(i<peices)&&(i<PerSpike);i++)
      {
       y=(y2+(sign*( (i*10)+6 )));
       PutPeice(x1,y,color);
       }

  /* put some fancy numbers on it if >PerSpike peices */

   if (peices>=PerSpike)
       {
         line[0]=('0'+peices);
         line[1]='\0';
         if (spk<13)  y2=y2-3;
                else  y2=y2+9;
         Move(rp,x1,y2);
         SetAPen(rp,dice);
         Text(rp,line,1L);
        }

   }  /* end of PutSpike */

BlinkPeice(board,pos)
int board[26],pos;
{
 int part,n,x1,y,disp,sign,i;

 PutSpike(pos,board[pos]);

 if (board[pos]==0) return(0); /* Dont bother if nothing there */

 part=(maxX-minX)/ 12;

 n=board[pos];

 if (n<0) n=0-n;

 if (n>PerSpike) n=PerSpike;

 if (pos<13)
          {
           i=pos;
           sign=+1;
           y=maxY-(n*10)+4;
           }
       else
          {
           i=25-pos;
           y=minY+(n*10)-4;
           }

 if (i>6)  disp=8;
      else disp=0;

 /* this is the x-coord */

  x1=(i*part) - (part/2)+minX+disp;

 /* if the bar, do something different */

  if (pos==0)
      {
       y=((maxY+minY)/2)+10;
       x1=((maxX+minX)/2);
       }

   if (pos==25)
       {
       y=((maxY+minY)/2)-10;
       x1=((maxX+minX)/2);
       }

   if (board[pos]<0) n=peice1;
               else  n=peice2;

   for(i=1;i<=5;i++)
    {
     Delay(1);
     PutPeice(x1,y,dice);
     Delay(1);
     PutPeice(x1,y,n);
     }

}

static WORD shapeX[9]={15,15,4,-4,-15,-15,-4,4,15};
static WORD shapeY[9]={-2,2,4,4,2,-2,-4,-4,-2};

PutPeice(x,y,color)
long x,y,color;
  {
   int i;
   long x1,y1;
   SetAPen(rp,color);
   AreaMove(rp,(long)(x+shapeX[0]),(long)(y+shapeY[0]));

   for (i=1;i<=8;i++)
     {
     x1=x+shapeX[i];
     y1=y+shapeY[i];
     AreaDraw(rp,x1,y1);
     }
   AreaEnd(rp);
  }

TextScreen(stuff,num)

char *stuff[];
int num;


{
   int i;

   unsigned long Class;
   unsigned short Code;

   struct  IOStdReq    *re ,*wr;
   struct  MsgPort     *rep,*wrp;
   struct  RastPort    *crp;
   struct  Window      *crw;

   crnw.Screen=screen;
   crnw.Title=(UBYTE *) stuff[0];

   crw         = (struct Window *)OpenWindow(&crnw);

   if (crw != NULL)
       {
        crp=w->RPort;

        rep=CreatePort("my.con.read",0);
        re=CreateStdIO(rep);

        wrp=CreatePort("my.con.write",0);
        wr=CreateStdIO(wrp);

        wr->io_Data=(APTR) crw;
        wr->io_Length=sizeof(*crw);

        if (OpenDevice("console.device",0,wr,0)==0)
           {
            re->io_Device = wr->io_Device;
            re->io_Unit   = wr->io_Unit;

           /* loop through all the stuff and put it to the open'd console */

              for (i=1;i<=num; i++) 
                {
                 wr->io_Command=CMD_WRITE;
                 wr->io_Data   =(UBYTE *) stuff[i];
                 wr->io_Length =-1;

                 DoIO(wr);
                 }

            /* close the console up */

               DeleteStdIO(re);
               DeletePort(rep);

               DeleteStdIO(wr);
               DeletePort(wrp);

           }/* end-if console created */
  
           for (;;)
             {
              Wait(1L<< crw->UserPort->mp_SigBit);
              message=(struct IntuiMessage *) GetMsg(crw->UserPort);
              Code =message->Code;
              Class=message->Class;
              ReplyMsg(message);
              if (Class==CLOSEWINDOW) break;
              }

         CloseWindow(crw);

      }  /* end-if window opened */

     return;
}
