/************************************************************************/ /* 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 */ /* */ /* This file contains: */ /* gen_points PutIntuiText ITextLen Gsetup */ /* ShowDice PutMoveNumber PutPiece decode */ /* DoMenuStrip UndoMenuStrip requestor finit */ /* PutBarPiece PutSpike BlinkPiece TextScreen */ /************************************************************************/ /* Most recent modification: 3/ 8/93 */ /* Most recent modification: 11/28/94 */ /* Most recent modification: 2/24/95 */ #include #include #include #include #include #include #include #include #include #include #include #include "back.h" #define max_vector 16 /* for AreaMove/Draw */ #define piece_width 32 #define sign(x) (x < 0 ? -1 : +1) typedef struct { SHORT x,y;} coord; typedef /* order of points in box[] is upper left, lower right or */ /* left, top, right, bottom as individual values */ /* Spike entry is coordinates of spike point */ struct { coord box[2]; coord spike;} point_rec; typedef struct { short count, height; coord point[13];} shape_rec; static const shape_rec laced_piece = {12, 23, {{ 13, 2}, { 11, 6}, { 4,10}, { -4,10}, {-11, 6}, {-13, 2}, {-13,-2}, {-11,-6}, { -4,-10}, { 4,-10}, { 11,-6}, { 13,-2}}}, norm_piece = {12, 11, {{ 13, 1}, { 11, 3}, { 3, 5}, { -3, 5}, {-11, 3}, {-13, 1}, {-13,-1}, {-11,-3}, { -3,-5}, { 3,-5}, { 11,-3}, { 13,-1}}}; static point_rec point[26]; int minY; /* has to be global */ static int xc, yc, /* center of board */ minX, maxX, /* horizontal limits */ /*minY,*/ maxY, /* vertical limits */ h_pitch, /* width of spike */ height, /* spike height */ move_num_left, /* where move number starts */ move_num_len, /* how long it plots */ bar_left, bar_right; /* limits of bar */ static shape_rec *piece_ptr = &norm_piece; UWORD color_table[] = {0x407,0xDDD,0x0F0,0xFF0,0xF00,0x000,0x00F,0xEEE}; struct ColorMap color_map = {0,0,sizeof(color_table) / 2,(APTR)&color_table}; char MyTitle[] = "Hoser BackGammon Copyright June 1987 Robert Pfister"; struct RastPort *rp; struct Screen *screen = NULL; static struct ViewPort *vp; extern struct Menu MyMenu[]; /* get the menu somewhere else */ struct Window *w = NULL; struct TextAttr font[] = {{"topaz",8,0,0},{"courier.font",13,0,0}}; struct TextFont *tf = NULL; struct NewScreen ns = { 0,0,-1,-1,3, 0,1, HIRES, CUSTOMSCREEN,font, MyTitle, NULL,NULL}; struct NewWindow nw = { 0,10,-1,190,0,1, CLOSEWINDOW | MOUSEBUTTONS | MENUPICK, SMART_REFRESH | ACTIVATE | WINDOWDRAG | WINDOWDEPTH, NULL,NULL, "Backgammon anyone?", NULL,NULL, 0,0,640,200,CUSTOMSCREEN }; struct NewWindow crnw = { 20,0,405,0,0,1, /* top and height set when used */ MOUSEBUTTONS, SMART_REFRESH | ACTIVATE | WINDOWDRAG, NULL,NULL, "Backgammon credits", NULL,NULL, 0,0,640,200,CUSTOMSCREEN }; static short AreaBuf[max_vector * 5 / sizeof(short)]; static APTR TBuf; static struct TmpRas TRas; static struct AreaInfo AInfo; BOOL laced; void gen_points(struct Window *wp) { /* adjust board for screen/window size */ int bar_width, /* the obvious */ d, n; point_rec *prp; minX = 3; maxX = wp->Width - 3; bar_width = 8; h_pitch = (maxX - minX - bar_width) / 12; bar_width = maxX - minX - 12 * h_pitch; if (bar_width > 10) { minX += (bar_width - 10) / 2; maxX -= (bar_width - 10) / 2; bar_width = maxX - minX - 12 * h_pitch; } xc = (minX + maxX) / 2; bar_left = xc - bar_width / 2; bar_right = bar_left + bar_width; minY = screen->Font->ta_YSize * 3 + 1; maxY = wp->Height - 4; height = ((maxY - minY) * 3 / 7); yc = (minY + maxY) / 2; d = 0; prp = point + 1; for (n = 0; n < 12; n++) { prp->box[1].x = (prp->box[0].x = minX + n * h_pitch + d) + h_pitch - 1; prp->spike.y = prp->box[0].y = (prp->box[1].y = maxY) - height; prp->spike.x = prp->box[0].x + h_pitch / 2; if (n == 5) d = bar_width; prp++; } for (n = 11; n >= 0; n--) { prp->box[1].x = (prp->box[0].x = minX + n * h_pitch + d) + h_pitch - 1; prp->box[0].y = minY; prp->spike.y = prp->box[1].y = (prp->box[0].y = minY) + height; prp->spike.x = prp->box[0].x + h_pitch / 2; if (n == 6) d = 0; prp++; } prp = point; prp->box[0].x = xc - 10; prp->box[0].y = maxY - height; prp->box[1].x = xc + 10; prp->box[1].y = yc + 5; prp->spike.x = xc; prp->spike.y = yc + 9; prp = point + 25; prp->box[0].x = xc - 10; prp->box[0].y = maxY + height; prp->box[1].x = xc + 10; prp->box[1].y = yc - 5; prp->spike.x = xc; prp->spike.y = yc - 9; } void PutIntuiText(char *s, int x, int y, int color) { struct IntuiText it = {1, 0, JAM2, 0, 0, NULL, NULL, NULL}; it.FrontPen = color; it.LeftEdge = x; it.TopEdge = y; it.IText = s; PrintIText(w->RPort, &it, 0, 0); } int ITextLen(char *s) { struct IntuiText it = {1, 0, JAM2, 0, 0, NULL, NULL, NULL}; it.IText = s; return IntuiTextLength(&it); } void Gsetup(void) { struct Preferences prefs; GetPrefs(&prefs, sizeof prefs); if (laced = (prefs.LaceWB & LACEWB)) { ns.ViewModes |= LACE; ns.Font = &font[1]; tf = OpenDiskFont(&font[1]); piece_ptr = &laced_piece; } if (!(nw.Screen = screen = OpenScreen(&ns))) { finit(); Alert(1); exit(1); } nw.Width = screen->Width; nw.TopEdge = screen->TopEdge + screen->Font->ta_YSize + 2; nw.Height = screen->Height - nw.TopEdge; if (!(w = OpenWindow(&nw))) { finit(); Alert(2); exit(2); } vp = &screen->ViewPort; rp = w->RPort; /* intialize temporary area space */ InitArea(&AInfo, AreaBuf, max_vector); rp->AreaInfo = &AInfo; if (!(TBuf = (APTR)AllocRaster(screen->Width, screen->Height))) { finit(); Alert(3); exit(3); } gen_points(w); SetMenuStrip(w,MyMenu); rp->TmpRas = &TRas; InitTmpRas(&TRas, (char *)TBuf, RASSIZE(screen->Width, screen->Height)); LoadRGB4(vp, color_table, 8); SetDrMd(rp, JAM1); SetAPen(rp, back_color); RectFill(rp, minX, minY, maxX - 1, maxY); SetAPen(rp, tm1_color); RectFill(rp, bar_left, minY, bar_right, maxY); /* write evaluation count at top of window */ move_num_len = ITextLen("Number of Moves Evaluated: "); move_num_left = minX + 2 + move_num_len; PutIntuiText("Number of Moves Evaluated:", minX + 2, minY - screen->Font->ta_YSize - 2, dice_color); { struct DateStamp time; DateStamp(&time); srand(time.ds_Tick); } } void ShowDice(BYTE d[4], int c) { /* put dice on the screen */ int yu, yl; char line[] = " "; struct IntuiText it = {1, 0, JAM1, 0, 0, NULL, NULL, NULL}; /* cover up dice with dice color */ yu = yc - screen->Font->ta_YSize / 2; yl = yu + screen->Font->ta_YSize; SetAPen(rp, dice_color); RectFill(rp, xc-27, yu , xc+27, yl); if (d[0] && d[1]) { /* put in the numbers for the left and right die */ it.FrontPen = piece2_color; if (c == Uside) it.FrontPen = piece1_color; line[0] = '0' + d[0]; line[4] = '0' + d[1]; it.LeftEdge = xc - piece_width / 2; it.TopEdge = yu + 1; it.IText = line; PrintIText(w->RPort, &it, 0, 0); SetAPen(rp, tm1_color); RectFill(rp, bar_left, yu, bar_right - 1, yl); } } void PutMoveNumber(int Number) { /* only calls are from EVAL */ char Line[8]; sprintf(Line,"%5d ",Number); PutIntuiText(Line, move_num_left, minY - screen->Font->ta_YSize - 2, dice_color); } void PutPiece(long x, long y, long color) { /* coords are for center of piece */ int i; shape_rec *sp = piece_ptr; SetAPen(rp,color); AreaMove(rp, x + sp->point[sp->count - 1].x, y + sp->point[sp->count - 1].y); for (i = 0; i < sp->count; i++) AreaDraw(rp, x + sp->point[i].x, y + sp->point[i].y); AreaEnd(rp); } int decode(int x, int y) /* return the 'spike' number given the screen */ { /* point relative to upper left corner of the window */ int point, disp = 0, font_height = screen->Font->ta_YSize; if (x > xc) disp = bar_right - bar_left; /* check if dice 'clicked'...indicate unusual end of turn */ if ((y > (yc - font_height / 2)) && (y < (yc + font_height / 2)) && (x > xc - 27) && (x < xc + 27)) return(-1); /* check if 'bar' selected */ if ((x > (xc - piece_width / 2)) && (x < (xc + piece_width / 2)) && ( y > (font_height - 2 - piece_ptr->height)) && (y < (yc - font_height / 2 - 2))) point = 0; else point = 1 + (x + disp - minX) / h_pitch; if ( y < yc) point = 25 - point; return(point); } static int ErrSet=FALSE; void DoMenuStrip(char errmsg[]) { ErrSet=TRUE; SetWindowTitles(w, (char *)-1, errmsg); } void UnDoMenuStrip(void) { if (ErrSet == TRUE) { SetWindowTitles(w, (char *)-1, MyTitle); ErrSet = FALSE; } } /* put up a plain old requestor given three strings name... the question/statement of the requestor yes... the affirmative response no... the negative response this returns 'true' for the yes, 'false' for the no */ BOOL requestor(char name[], char yes[], char no[]) { const static struct IntuiText Rt = {tm1_color, tm2_color, JAM2, 50, 10, NL, (char *)0, NL}, Rr = {spike2_color, spike1_color, JAM1, 8, 3, NL, (char *)0, NL}; struct IntuiText Rbody, Rright, Rleft; Rbody = Rt; Rright = Rr; Rleft = Rr; Rleft.IText = no; Rright.IText = yes; Rbody.IText = name; return(AutoRequest(w, &Rbody, &Rleft, &Rright, 0, 0, 300, 90)); } extern you_me_rec you, me; extern USHORT total_games; void finit(void) { char *s[] = { "Running totals", "\n", "\n", " Total games xxxxxx\n", " You Me\n", " Dice total xxxxxxxxxx xxxxxxxxxx\n", " Average roll xx.x xx.x\n", " Incomplete xxxxxxxxxx xxxxxxxxxx\n", " Wasted xxxxxxxxxx xxxxxxxxxx\n", "\n", " [click in window to terminate] \n"}; if (total_games) { sprintf(&s[3][13], "%6d\n", total_games); sprintf(&s[5][14], "%10d %10d\n", you.total.roll, me.total.roll); sprintf(&s[6][20], "%4.1f %4.1f\n", (float)you.total.average_roll / total_games, (float)me.total.average_roll / total_games); sprintf(&s[7][14], "%10d %10d\n", you.total.incomplete, me.total.incomplete); sprintf(&s[8][14], "%10d %10d\n", you.total.wasted, me.total.wasted); TextScreen(s, 11); } if (TBuf) FreeRaster(TBuf, screen->Width, screen->Height); if (w) CloseWindow(w); if (screen) CloseScreen(screen); if (laced) CloseFont(tf); } void PutBarPiece(int y, int pieces, int inc, int color) { char line[4]; struct IntuiText it = {1, 0, JAM1, 0, 0, NULL, NULL, NULL}; SetAPen(rp, back_color); RectFill(rp, xc - piece_width, y, xc + piece_width, y + inc); SetAPen(rp, tm1_color); RectFill(rp, bar_left, y, bar_right - 1, y + inc); pieces = abs(pieces); if (pieces != 0) { PutPiece(xc, y + inc / 2, color); if (pieces > 1) { sprintf(line, "%d", pieces); it.FrontPen = dice_color; it.LeftEdge = bar_left; it.TopEdge = y + 2; it.IText = line; PrintIText(w->RPort, &it, 0, 0); } } } void PutSpike(int spk, int pieces) { long color, inc, x, y; char line[4]; /* pick color of the pieces */ if (pieces < 0) color = piece1_color; else color = piece2_color; inc = - piece_ptr->height; if (spk > 12) inc = -inc; if (spk == 0) /* plot my ones on the bar */ PutBarPiece(yc + screen->Font->ta_YSize, pieces, -inc, color); else if (spk == 25) /* plot yours on the bar */ PutBarPiece(yc - screen->Font->ta_YSize - inc, pieces, inc, color); else { /* all the rest */ int i; point_rec *pp; pp = &point[spk]; /* box in the area around the spike with background color...*/ SetAPen(rp, back_color); RectFill(rp, pp->box[0].x, pp->box[0].y, pp->box[1].x, pp->box[1].y); if (spk & 1) SetAPen(rp, spike1_color); else SetAPen(rp, spike2_color); if (spk < 13) { /* lower spikes */ AreaMove(rp,pp->box[0].x,pp->box[1].y); /* lower left corner */ AreaDraw(rp,pp->box[1].x,pp->box[1].y); /* lower right corner */ AreaDraw(rp,pp->spike.x,pp->spike.y); /* point of spike */ AreaDraw(rp,pp->box[0].x,pp->box[1].y); /* lower left corner */ AreaEnd(rp); } else { /* upper spikes */ AreaMove(rp,pp->box[0].x,pp->box[0].y); /* upper left corner */ AreaDraw(rp,pp->box[1].x,pp->box[0].y); /* upper right corner */ AreaDraw(rp,pp->spike.x,pp->spike.y); /* point of spike */ AreaDraw(rp,pp->box[0].x,pp->box[0].y); /* upper left corner */ AreaEnd(rp); } if (pieces < 0) pieces = -pieces; /* go through number of pieces, up to "PerSpike" */ x = pp->spike.x; y = pp->box[1].y; if (spk > 12) y = pp->box[0].y; y += inc / 2; inc += 2 * sign(inc); for(i = 0; (i < pieces) && (i < PerSpike); i++) { PutPiece(x, y, color); y += inc; } /* put some fancy numbers on it if > PerSpike pieces */ if (pieces > PerSpike) { sprintf(line,"%2d",pieces); y = pp->box[1].y - 2; if (spk > 12) y = pp->box[0].y + 8; Move(rp, x - screen->Font->ta_YSize, y); SetAPen(rp, dice_color); Text(rp, line, 2); } } } /* end of PutSpike */ void BlinkPiece(BYTE board[], int pos) { int x, y, i, color, inc; point_rec *pp; if (board[pos]) { /* Don't bother if nothing there */ pp = &point[pos]; x = pp->spike.x; inc = piece_ptr->height; if ((pos == 0) || (pos == 25)) y = pp->spike.y; else { inc = -piece_ptr->height; y = pp->box[1].y; if (pos > 12) { inc = -inc; y = pp->box[0].y; } y += inc / 2; y += 2 * sign(inc); } if ((pos != 0) && (pos != 25)) y += (min(abs(board[pos]), PerSpike) - 1) * inc; color = piece2_color; if (board[pos] < 0) color = piece1_color; for(i = 2; i >= 0; i--) { Delay(1); switch (pos) { case 0: PutBarPiece(yc + screen->Font->ta_YSize, board[0], inc, color); break; case 25: PutBarPiece(yc - screen->Font->ta_YSize - inc, board[25], inc, color); break; default: PutPiece(x, y, dice_color); } Delay(1); switch (pos) { case 0: PutBarPiece(yc + screen->Font->ta_YSize, board[0], inc, color); break; case 25: PutBarPiece(yc - screen->Font->ta_YSize - inc, board[25], inc, color); break; default: PutPiece(x, y, color); } } PutSpike(pos, board[pos]); } } void TextScreen(char *stuff[], int num) { int i, n, longest = 0; unsigned long Class; struct IOStdReq *wr; struct MsgPort *wrp; struct Window *crw; struct IntuiMessage *message; const char cons_init[] = "\2330 p"; struct IntuiText it = {1, 0, JAM1, 0, 0, NULL, NULL, NULL}; for (i = 1; i <= num; i++) { it.IText = stuff[i]; if ((n = IntuiTextLength(&it)) > longest) longest = n; } crnw.Width = min(longest +10, screen->Width); crnw.LeftEdge = (screen->Width - crnw.Width) / 2; crnw.Height = (num + 1) * screen->Font->ta_YSize; crnw.TopEdge = (maxY - crnw.Height) / 2; crnw.Screen = screen; crnw.Title = stuff[0]; crw = (struct Window *)OpenWindow(&crnw); if (crw != NULL) { wrp = CreatePort("my.con.write",0); wr = CreateStdIO(wrp); wr->io_Data = (APTR) crw; wr->io_Length = sizeof(struct Window); if (OpenDevice("console.device", 0, (struct IORequest *)wr, 0) == 0) { wr->io_Command = CMD_WRITE; wr->io_Length = -1; wr->io_Data = (APTR)cons_init; DoIO((struct IORequest *)wr); /* loop through all the stuff and put it to the open'd console */ for (i = 1; i < num; i++) { wr->io_Length = -1; wr->io_Data = (APTR)stuff[i]; DoIO((struct IORequest *)wr); } /* close the console */ CloseDevice((struct IORequest *)wr); DeleteStdIO(wr); DeletePort(wrp); }/* end-if console created */ for (;;) { Wait(1L << crw->UserPort->mp_SigBit); message = (struct IntuiMessage *) GetMsg(crw->UserPort); Class = message->Class; ReplyMsg((struct Message *)message); if (Class == MOUSEBUTTONS) break; } CloseWindow(crw); } /* end-if window opened */ }