/* xgammon version 0.97a, a backgammon program Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See COPYING for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xgammon.h" #include "gammon.h" #include "icon.h" /* allow.c */ extern int test_move (); extern int move_is_allowed (); /* desicion.c */ extern MOVE *find_best_move (); extern float evaluate (); extern int do_double (); extern void set_binom (); extern void set_naufm (); /* drawing.c */ extern void DrawBoard (); extern void DrawEmptyBoard (); extern void DrawDice (); extern void DeleteDice (); extern void DrawEmptyDice (); extern void DrawDiceValues (); extern void DrawDoubler (); extern void DrawStone (); extern void RedrawAllStones (); extern void CreatePixmaps (); extern void FreePixmaps (); /* edit.c */ extern void EditPosition (); /* filemenu.c */ extern void File (); extern void CreateSaveDialog (void); /* popup.c */ extern void Info (); extern void CreateXGammonPopup (); extern void ShowComputerAnswerToDoubling (); extern int DoublePopup (); /* misc.c */ extern void init_game (); extern void RollDice (); extern int end_of_game_test (int color); extern int complete_blockade (void); extern void AppendMoveString (); extern void AddResult (int whom); static void PipCount (); extern int EventToPin (); extern XPoint PinToPosition (int pin); extern void maildump (); extern void open_protokol (); /* load.l */ extern void load (); extern void load_config (); /* save.c */ extern void save (); extern void save_config (); extern void sig_save (); /* rollout.c */ extern void RollOut (); extern void exec_rollout (); /* xgammon.c */ void Redraw (); void restart (); void Resign (int how); void ReplayGame (); void Quit (); void MenuSelect (); void UndoMove (); void set_game_kind (); static void CompiFinish (); static void setup_gc (); static void cp_back (); static void PopupButtonShell (); static void ResizeBoard (); static void CreateBoard (); static void checkcmdline (int argc, char *argv[]); static void PlayerInit (); static void TournamentInit (); static void ButtonMove (); static void TakeStone (); static void MoveStone (); static void PlaceStone (); static int HandleHumanDoubling (); static int HandleCompiDoubling (); static void GetHumanMoveEvents (); void HumanStoneMove (); static void CompiLoop (); void HumanLoop (); static void BearOff (void); void ShowCompiMove (); void XGammonGameLoop (); void XGammonAppTournamentLoop (); #ifdef IRIX /* ?? */ void usleep (unsigned long delay) { sginap (80*delay); } #endif #ifdef SUNOS4 /* ?? */ #define usleep(a) sleep((a/10)) #endif XtAppContext app_con; int width, height; /* of the board */ int stone_width, stone_height; static int old_place_x, old_place_y; /* for moving stones */ Doubler doubler; BOARD board; unsigned long delaytime; /* gammon_resource.delaytime * 100000 (microsec / tsec) */ int font_width; static int get_moves = 0, took_one = 0; /* glabal flags */ int end_of_tournament = 0, end_of_game; int initialize = 0, break_loop = 0, doubling_done = 1; int replaying = 0; int turn, other, pash, to_move, roll[4]; int direction, start_pin, end_pin; int from_pin, pip_count_request = 0; int done_hit, current_hit[4]; /* for UndoMove () */ extern int done_yet; extern MOVE current_move[]; MOVE *compi_choice; FILE* protokol_file = NULL; char * greetings = "Welcome to xgammon version 0.98\n (C) 1994 Lambert Klasen Detlef Steuer\n We hope you enjoy it\n\n"; XtActionsRec gammon_actions[] = { {"PipCount", PipCount}, {"CompiFinish", CompiFinish}, {"Redraw", Redraw}, {"UndoMove", UndoMove}, {"ResizeBoard", ResizeBoard}, {"Quit", Quit}, {"save", save}, {"load", load}, {"restart", restart}, }; static XtResource gammon_resources[] = { #define offset(field) XtOffsetOf(struct _gammon_resource, field) {"otherdisplay", "OtherDisplay", XtRString, sizeof (char *), offset (other_display), XtRString, (caddr_t) NULL}, {"boardGeometry", "Geometry", XtRString, sizeof (char *), offset (board_geometry), XtRString, (caddr_t) &gammon_resource.board_geometry}, {"boardColor", "Background", XtRPixel, sizeof (Pixel), offset (board_Pixel), XtRPixel, (caddr_t) &gammon_resource.board_Pixel}, {"boardColor", "Background", XtRString, sizeof (char *), offset (board_color), XtRString, (caddr_t) NULL}, {"lightColor", "Background", XtRPixel, sizeof (Pixel), offset (light_Pixel), XtRPixel, (caddr_t) &gammon_resource.light_Pixel}, {"lightColor", "Background", XtRString, sizeof (char *), offset (light_color), XtRString, (caddr_t) NULL}, {"darkColor", "Background", XtRPixel, sizeof (Pixel), offset (dark_Pixel), XtRPixel, (caddr_t) &gammon_resource.dark_Pixel}, {"darkColor", "Background", XtRString, sizeof (char *), offset (dark_color), XtRString, (caddr_t) NULL}, {"barColor", "Foreground", XtRPixel, sizeof (Pixel), offset (bar_Pixel), XtRPixel, (caddr_t) &gammon_resource.bar_Pixel}, {"barColor", "Foreground", XtRString, sizeof (char *), offset (bar_color), XtRString, (caddr_t) NULL}, {"whiteColor", "Background", XtRPixel, sizeof (Pixel), offset (white_Pixel), XtRPixel, (caddr_t) &gammon_resource.white_Pixel}, {"whiteColor", "Background", XtRString, sizeof (char *), offset (white_color), XtRString, (caddr_t) NULL}, {"blackColor", "Foreground", XtRPixel, sizeof (Pixel), offset (black_Pixel), XtRPixel, (caddr_t) &gammon_resource.black_Pixel}, {"blackColor", "Foreground", XtRString, sizeof (char *), offset (black_color), XtRString, (caddr_t) NULL}, {"smallFont", "Font", XtRString, sizeof (char *), offset (small_font), XtRString, (caddr_t) "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*"}, {"doublerFont", "Font", XtRString, sizeof (char *), offset (doubler_font), XtRString, (caddr_t) "-*-helvetica-medium-r-normal-*-24-*-*-*-*-*-*-*"}, {"humanStones", "String", XtRString, sizeof (char *), offset (human_stone), XtRString, (caddr_t) "black"}, {"gamekind", "Gamekind", XtRString, sizeof (char *), offset (gamekind), XtRString, (caddr_t) "hvc"}, {"protokol", "Protokol", XtRBoolean, sizeof (int), offset (protokol), XtRString, "0"}, {"stonesteps", "Stonesteps", XtRInt, sizeof (int), offset (stone_steps), XtRString, "5"}, {"delaytime", "delaytime", XtRInt, sizeof (int), offset (delaytime), XtRString, "10"}, {"watchmove", "Watchmove", XtRBoolean, sizeof (int), offset (watchmove), XtRString, "1"}, {"autoplay", "Autoplay", XtRBoolean, sizeof (int), offset (autoplay), XtRString, "1"}, {"doubling", "Doubling", XtRBoolean, sizeof (int), offset (doubling), XtRString, "1"}, {"getdice", "Getdice", XtRBoolean, sizeof (int), offset (getdice), XtRString, "0"}, {"moneygame", "Moneygame", XtRBoolean, sizeof (int), offset (moneygame), XtRString, "1"}, {"winat", "Winat", XtRInt, sizeof (int), offset (winat), XtRString, "0"}, {"numberOfGames", "NumberOfGames", XtRInt, sizeof (int), offset (number_of_games), XtRString, (caddr_t) &gammon_resource.number_of_games}, {"mutations", "Mutations", XtRInt, sizeof (int), offset (mutations), XtRString, (caddr_t) &gammon_resource.mutations}, {"rollout", "Rollout", XtRBoolean, sizeof (int), offset (rollout), XtRString, "0"}, {"numrollouts", "NumRollouts", XtRInt, sizeof (int), offset (num_rollouts), XtRString, "100"}, {"positionfile", "PositionFile", XtRString, sizeof (char *), offset (position_file), XtRString, "xgammon.save"}, {"database", "Database", XtRString, sizeof (char *), offset (database), XtRString, DATABASE}, {"server", "Server", XtRString, sizeof (char *), offset (server), XtRString, "fibs.com"}, {"port", "Port", XtRInt, sizeof (int), offset (port), XtRString, "4321"}, {"buttonmove", "ButtonMove", XtRBoolean, sizeof (int), offset (button_move), XtRString, "0"} #undef offset }; static XrmOptionDescRec options[] = { {"-otherdisplay", ".otherdisplay", XrmoptionSepArg, NULL}, {"-boardgeometry", ".boardGeometry", XrmoptionSepArg, NULL}, {"-boardcolor", ".boardColor", XrmoptionSepArg, NULL}, {"-bc", ".boardColor", XrmoptionSepArg, NULL}, {"-darkcolor", ".darkColor", XrmoptionSepArg, NULL}, {"-dc", ".darkColor", XrmoptionSepArg, NULL}, {"-lightcolor", ".lightColor", XrmoptionSepArg, NULL}, {"-lc", ".lightColor", XrmoptionSepArg, NULL}, {"-barcolor", ".barColor", XrmoptionSepArg, NULL}, {"-b", ".barColor", XrmoptionSepArg, NULL}, {"-whitecolor", ".whiteColor", XrmoptionSepArg, NULL}, {"-blackcolor", ".blackColor", XrmoptionSepArg, NULL}, {"-doublerfont", ".doublerFont", XrmoptionSepArg, NULL}, {"-smallfont", ".smallFont", XrmoptionSepArg, NULL}, {"-h", ".humanStones", XrmoptionSepArg, NULL}, {"-g", ".gamekind", XrmoptionSepArg, NULL}, {"-gamekind", ".gamekind", XrmoptionSepArg, NULL}, {"-learn", ".gamekind", XrmoptionNoArg, "3"}, {"-play", ".gamekind", XrmoptionNoArg, "4"}, {"-winat", ".winat", XrmoptionSepArg, NULL}, {"-rollout", ".rollout", XrmoptionNoArg, "1"}, {"-n", ".numberOfGames", XrmoptionSepArg, "10"}, {"-m", ".mutations", XrmoptionSepArg, "100"}, {"-nr", ".numrollouts", XrmoptionSepArg, NULL}, {"-f", ".positionfile", XrmoptionSepArg, NULL}, {"-stonesteps", ".stonesteps", XrmoptionSepArg, NULL}, {"-delaytime", ".delaytime", XrmoptionSepArg, NULL}, {"-protokol", ".protokol", XrmoptionNoArg, "1"}, {"-moneygame", ".moneygame", XrmoptionNoArg, "0"}, {"+moneygame", ".moneygame", XrmoptionNoArg, "1"}, {"-watchmove", ".watchmove", XrmoptionNoArg, "0"}, {"+watchmove", ".watchmove", XrmoptionNoArg, "1"}, {"-autoplay", ".autoplay", XrmoptionNoArg, "0"}, {"+autoplay", ".autoplay", XrmoptionNoArg, "1"}, {"-getdice", ".getdice", XrmoptionNoArg, "1"}, {"-doubling", ".doubling", XrmoptionNoArg, "0"}, {"+doubling", ".doubling", XrmoptionNoArg, "1"}, {"-database", ".database", XrmoptionSepArg, NULL}, {"-server", ".server", XrmoptionSepArg, NULL}, {"-port", ".port", XrmoptionSepArg, NULL}, {"-buttonmove", ".buttonmove", XrmoptionNoArg, "0"}, {"+buttonmove", ".buttonmove", XrmoptionNoArg, "1"}, {"-bm", ".buttonmove", XrmoptionNoArg, "0"}, {"+bm", ".buttonmove", XrmoptionNoArg, "1"}, }; int main (int argc, char **argv) { signal (SIGHUP, sig_save); signal (SIGINT, sig_save); signal (SIGQUIT, sig_save); signal (SIGSEGV, sig_save); signal (SIGFPE, sig_save); signal (SIGPIPE, sig_save); signal (SIGTERM, sig_save); /* for debugging */ Player[0].X11Set.toplevel = XtAppInitialize (&app_con, "XGammon", options, XtNumber (options), &argc, argv, NULL, NULL, ZERO); XtGetApplicationResources (Player[0].X11Set.toplevel, (caddr_t) &gammon_resource, gammon_resources, XtNumber (gammon_resources), NULL, (Cardinal) 0); XtAppAddActions (app_con, gammon_actions, XtNumber (gammon_actions)); Player[0].X11Set.dpy = XtDisplay (Player[0].X11Set.toplevel); checkcmdline (argc, argv); /* initialize */ /*load_config ();*/ /* decision config */ set_binom (); /* decision ... */ set_naufm (); srandom (time (NULL)); /* rolling */ delaytime = ((unsigned long) gammon_resource.delaytime) * 100000; endgame_database = fopen (gammon_resource.database, "rb"); if (!endgame_database) fprintf (stderr, "endgame database not found\nyou should create one\n"); if (gammon_resource.protokol) open_protokol (); if (gammon_resource.rollout) RollOut (); CreateBoard (0); CreateXGammonPopup (&(Player[0].X11Set)); XtRealizeWidget (Player[0].X11Set.toplevel); PopupButtonShell (Player[0].X11Set.toplevel, Player[0].X11Set.button_shell); Player[0].X11Set.board.window = XtWindow (Player[0].X11Set.board.widget); setup_gc (&Player[0].X11Set); { Arg arg[1]; Pixmap icon; icon = XCreateBitmapFromData (Player[0].X11Set.dpy, RootWindowOfScreen (XtScreen (Player[0].X11Set.toplevel)), xgammon_bits, xgammon_width, xgammon_height); XtSetArg (arg[0], XtNiconPixmap, icon); XtSetValues (Player[0].X11Set.toplevel, arg, 1); } if (gammon_resource.other_display) { /* XtToolkitInitialize (); is already done */ /* app_con = XtCreateApplicationContext (); exists already */ Player[1].X11Set.dpy = XtOpenDisplay (app_con, gammon_resource.other_display, argv[0], argv[0], options, XtNumber (options), &argc, argv); Player[1].X11Set.toplevel = XtAppCreateShell (argv[0], "applicationShellWidgetClass", applicationShellWidgetClass, Player[1].X11Set.dpy, NULL, 0); CreateBoard (1); CreateXGammonPopup (&(Player[1].X11Set)); XtRealizeWidget (Player[1].X11Set.toplevel); PopupButtonShell (Player[1].X11Set.toplevel, Player[1].X11Set.button_shell); Player[1].X11Set.board.window = XtWindow (Player[1].X11Set.board.widget); setup_gc (&Player[1].X11Set); { Arg arg[1]; Pixmap icon; icon = XCreateBitmapFromData (Player[1].X11Set.dpy, RootWindowOfScreen (XtScreen (Player[1].X11Set.toplevel)), xgammon_bits, xgammon_width, xgammon_height); XtSetArg (arg[0], XtNiconPixmap, icon); XtSetValues (Player[1].X11Set.toplevel, arg, 1); } } CreatePixmaps (0); if (gammon_resource.other_display) CreatePixmaps (1); AppendDialogText (UPPER, greetings); PlayerInit (); TournamentInit (); if (!gammon_resource.other_display) { Player[1].X11Set = Player[0].X11Set; } while (1) { XGammonAppTournamentLoop (); restart (); } return 0; } /* XGammonAppTournamentLoop: the main event loop for xgammon */ void XGammonAppTournamentLoop (void) { end_of_tournament = 0; while (!end_of_tournament) { init_game (); XGammonGameLoop (); if (initialize != EDITED_POSITION && initialize != LOADED_POSITION && initialize != REPLAY_GAME) AddResult (turn); if (tournament.winning_point && gammon_resource.winat) { if (Player[0].points >= tournament.winning_point || Player[1].points >= tournament.winning_point) { end_of_tournament = 1; sleep (3); } } } } /* XGammonGameLoop: event loop for a single game */ void XGammonGameLoop (void) { end_of_game = 0; if (initialize != EDITED_POSITION && initialize != LOADED_POSITION) { if (tournament.game_number == 1 && /* make startup look a little nicer */ ((Player[0].beginner_of_game && Player[0].type == COMPUTER) || (Player[1].beginner_of_game && Player[1].type == COMPUTER))) { while (1) { XEvent event; XtAppNextEvent(app_con, &event); if(event.type == Expose && event.xexpose.window == Player[turn-1].X11Set.board.window) { XtDispatchEvent(&event); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); break; } XtDispatchEvent(&event); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); } } Player[turn-1].MoveFunction (FIRSTMOVE); } else { DrawDice (turn); DrawDoubler (doubler.value, doubler.owner); initialize = NORMAL_GAME; Player[turn-1].MoveFunction (FIRSTMOVE); } while (!end_of_game) { switch_turn (); Player[turn-1].MoveFunction (DOUBLE); } } /* HumanLoop: event loop for a human player */ void HumanLoop (int with_double) { if (Pin[BAR].count && complete_blockade ()) { sprintf (add_text, "%s can't move.\n\n", Player[turn-1].name); AppendDialogText (LOWER, add_text); return; } if (with_double != FIRSTMOVE && gammon_resource.doubling) { doubling_done = 0; if (doubler.owner != turn) { DeleteDice (); DrawEmptyDice (turn); do { if (pip_count_request) pip_count_request = 0; if (HandleHumanDoubling () == RESIGN) { end_of_game = 1; return; } } while (pip_count_request); } doubling_done = 1; } if (with_double != FIRSTMOVE) RollDice (); HumanStoneMove (); } static int HandleHumanDoubling (void) { int double_result; int p = 0; if (doubler.owner == turn || doubler.value == 64) return 0; while (1) { XEvent event; XtAppNextEvent (app_con, &event); if (event.type == ButtonRelease) { /* not Press */ if (event.xbutton.window == Player[turn-1].X11Set.board.window) { p = EventToPin (event.xbutton.x, event.xbutton.y); break; /* other can't break */ } XtDispatchEvent (&event); } else if (event.type == KeyPress) { KeySym k; Modifiers m; k = XtGetActionKeysym (&event, &m); if (k == 'd') p = DOUBLER; XtDispatchEvent (&event); if (event.xkey.window == Player[turn-1].X11Set.board.window) break; } XtDispatchEvent (&event); } if (p == DOUBLER) { doubler.owner = turn; if (Player[other-1].type == COMPUTER) { /* check opponent */ double_result = do_double (ANSWER); ShowComputerAnswerToDoubling (double_result); if (!double_result) return RESIGN; } else { return DoublePopup (); /* human doubles human */ } } if (end_of_game) return RESIGN; /* resign ... menu pressed prevents rolling */ return 0; } void GetHumanMoveEvents (void) { get_moves = 1; while (roll[0]) { XEvent event; XtAppNextEvent (app_con, &event); if (event.type == KeyPress) { KeySym k; Modifiers m; k = XtGetActionKeysym (&event, &m); if (k == 'o' || k == ' ' || k == '\n') { /* want to move off */ BearOff (); } } XtDispatchEvent (&event); if (break_loop) { /* computer shall finish */ break_loop = 0; break; } } get_moves = 0; } void HumanStoneMove (void) { int mc; DrawDice (turn); if ((mc = test_move () )) { if (mc == 1 && gammon_resource.autoplay) { compi_choice = possible_moves; ShowCompiMove (); AppendMoveString (compi_choice); } else GetHumanMoveEvents (); } else AppendMoveString (NULL); } /* CompiLoop: event loop for a computer player */ void CompiLoop (int with_double) { if (Pin[BAR].count && complete_blockade ()) { AppendMoveString (NULL); return; } if (with_double && gammon_resource.doubling) { if (HandleCompiDoubling () == RESIGN) { /* other resigned */ end_of_game = 1; return; } } if (with_double != FIRSTMOVE) RollDice (); DrawDice (turn); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); if (!gammon_resource.watchmove) usleep (delaytime); if (test_move ()) { compi_choice = find_best_move (); ShowCompiMove (); AppendMoveString (compi_choice); } else AppendMoveString (NULL); } static int HandleCompiDoubling (void) { int ret = 0; if (doubler.owner == turn || doubler.value == 64) return 0; if (! do_double (OFFER)) return 0; doubler.owner = turn; if (Player[other-1].type == HUMAN) /* check opponent */ return DoublePopup (); else { /* opponent is computer */ if (! do_double (ANSWER)) { /* resigned */ sprintf (add_text, "%s gives up. %s wins %d point\n\n", Player[other-1].name, Player[turn-1].name, doubler.value); ret = RESIGN; } else { /* accepted */ doubler.value *= 2; DrawDoubler (doubler.value, doubler.owner); sprintf (add_text,"%s accepts the double.\n\n", Player[other-1].name); ret = ACCEPT; } AppendDialogText (LOWER, add_text); } return ret; } void ShowCompiMove (void) { XPoint move_start, move_end; int x, y, dx, dy, steps; int i, j; for (i=0; ifrom); if (gammon_resource.watchmove) { move_start = PinToPosition ((compi_choice+i)->from); if ((compi_choice+i)->to != end_pin) move_end = PinToPosition ((compi_choice+i)->to); else move_end = PinToPosition (FINISHED); x = move_start.x; y = move_start.y; if (abs ((move_start.x - move_end.x)) > abs ((move_start.y - move_end.y))) steps = abs (move_start.x - move_end.x)/gammon_resource.stone_steps; else steps = abs (move_start.y - move_end.y)/gammon_resource.stone_steps; DrawStone (x,y); old_place_x = x; old_place_y = y; dx = (move_start.x - move_end.x) * -1 / steps; dy = (move_start.y - move_end.y) * -1 / steps; for (j=0; jto == end_pin) { /* endpin check must be first cause of removing other from endpin, i.e. bar */ PutStone (turn, FINISHED); if ((end_of_game = end_of_game_test (turn))) return; } else if (Pin[ (compi_choice+i)->to].color == other) { current_hit[i] = (compi_choice+i)->to; RemoveStone ((compi_choice+i)->to); PutStone (other, OTHER_BAR); PutStone (turn, (compi_choice+i)->to); } else PutStone (turn, (compi_choice+i)->to); XSync (Player[0].X11Set.dpy, 0); if (gammon_resource.other_display) XSync (Player[1].X11Set.dpy, 0); if (!gammon_resource.watchmove) usleep (delaytime); /* look for events happened while moving */ while (XtAppPending (app_con)) { XEvent event; XtAppNextEvent (app_con, &event); XtDispatchEvent (&event); } } } void cp_back (int x, int y) { Display *dpy = Player[0].X11Set.dpy; Pixmap p = Player[0].X11Set.board.pixmap; Window w = Player[0].X11Set.board.window; GC gc = Player[0].X11Set.board.gc; XCopyArea (dpy, p, w, gc, x, y, stone_width, stone_width, x, y); if (gammon_resource.other_display) { dpy = Player[1].X11Set.dpy; p = Player[1].X11Set.board.pixmap; w = Player[1].X11Set.board.window; gc = Player[1].X11Set.board.gc; XCopyArea (dpy, p, w, gc, x, y, stone_width, stone_width, x, y); } } static void CreateBoard (int player_index) { Display *dpy = Player[player_index].X11Set.dpy; WidgetClass board_class; Arg args[2]; int screen_num = DefaultScreen (dpy); static XtActionsRec board_actions[] = { {"Redraw", Redraw}, {"ResizeBoard", ResizeBoard}, {"TakeStone", TakeStone}, {"MoveStone", MoveStone}, {"PlaceStone", PlaceStone}, {"ButtonMove", ButtonMove}, {NULL, NULL} }; static String no_bm_translations = "#override \n\ : Redraw() \n\ : ResizeBoard() \n\ Button1: MoveStone() \n\ : PlaceStone() \n\ : TakeStone() \n\ "; static String bm_translations = "#override \n\ : Redraw() \n\ : ResizeBoard() \n\ : ButtonMove() \n\ "; static String translations; if (gammon_resource.button_move) translations = bm_translations; else translations = no_bm_translations; /* the board width x height is arbitraryly 15 x 12 that fast I couldn't get separated board geometry and normal Xt -geometry option, so there is this strange and ugly boardgeometry, the reason is, that there is no toplevel width and height before XtRealize. further XParseGeometry doesn't parse very low values like 10x10 or 0x0 */ { int dummy_x, dummy_y; /* of no interest, at least yet */ (void) XParseGeometry (gammon_resource.board_geometry, &dummy_x, &dummy_y, &width, &height); if (width < 150 || height < 120) { width = 150; height = 120; fprintf (stderr,"boardsize should at least be 150x120 pixel\ngeometry values changed\n"); } } if (width > DisplayWidth (dpy, screen_num) - 50 || height > DisplayHeight (dpy, screen_num) - 50) { width = DisplayWidth (dpy, screen_num) - 50; height = DisplayHeight (dpy, screen_num) - 50; } stone_width = stone_height = width/15; if (height < stone_width * 12) stone_width = height/12; /* some kinda screens there are */ width = stone_width * 15; height = stone_width * 12; XtSetArg (args[0], XtNwidth, width); XtSetArg (args[1], XtNheight, height); Player[player_index].X11Set.board.widget = XtCreateManagedWidget ("board", simpleWidgetClass, Player[player_index].X11Set.toplevel, args, 2); if (player_index == 0) { /* first players displays board */ XtOverrideTranslations (Player[player_index].X11Set.board.widget, XtParseTranslationTable (translations)); XtAppAddActions (app_con, board_actions, XtNumber (board_actions)); } else { /* other players displays board */ Arg t[1]; XtTranslations first_board_translations; /* this ensures both board have the same base of translations (via .Xdefaults) */ XtSetArg (t[0], XtNtranslations, first_board_translations); XtGetValues (Player[0].X11Set.board.widget, t, 1); XtSetValues (Player[1].X11Set.board.widget, t, 1); /* now add the hard wired ones of this function */ XtOverrideTranslations (Player[player_index].X11Set.board.widget, XtParseTranslationTable (translations)); XtAppAddActions (app_con, board_actions, XtNumber (board_actions)); } board_class = (WidgetClass) XtClass (Player[player_index].X11Set.board.widget); board_class->core_class.compress_exposure = XtExposeCompressMaximal; board_class->core_class.compress_motion = True; } static void PlayerInit (void) { extern char *UserName(); if (!strcmp (gammon_resource.gamekind, "hvc")) { if (!strcmp (gammon_resource.human_stone, "black")) { Player[0].type = HUMAN; Player[1].type = COMPUTER; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = CompiLoop; strcpy (Player[0].name, UserName()); strcpy (Player[1].name, "xgammon"); } else if (!strcmp (gammon_resource.human_stone, "white")) { Player[0].type = COMPUTER; Player[1].type = HUMAN; Player[0].MoveFunction = CompiLoop; Player[1].MoveFunction = HumanLoop; strcpy (Player[0].name, "xgammon"); strcpy (Player[1].name, UserName()); } } else if (!strcmp (gammon_resource.gamekind, "cvc")) { Player[0].type = COMPUTER; Player[1].type = COMPUTER; Player[0].MoveFunction = CompiLoop; Player[1].MoveFunction = CompiLoop; strcpy (Player[0].name, "black"); strcpy (Player[1].name, "white"); initialize = COMPUTER_TOURNAMENT; } else if (!strcmp (gammon_resource.gamekind, "hvh")) { Player[0].type = HUMAN; Player[1].type = HUMAN; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = HumanLoop; strcpy (Player[0].name, UserName()); strcpy (Player[1].name, "other"); } Player[0].color = BLACK; Player[1].color = WHITE; } /* TournamentInit; a little too big a name, only set a label and set the cursor */ static void TournamentInit () { Display *dpy = Player[0].X11Set.dpy; Arg c[1]; char *s; static int once = 0; if (gammon_resource.moneygame) { s = "money-game"; tournament.winning_point = 0; sprintf (add_text, "%s and %s start a %s match.\n", Player[0].name, Player[1].name, s); } if (gammon_resource.winat) { s = "points"; tournament.winning_point = gammon_resource.winat; gammon_resource.moneygame = 0; sprintf (add_text, "%s and %s start a %d %s match.\n", Player[0].name, Player[1].name, tournament.winning_point, s); } AppendDialogText (UPPER, add_text); if (once) return; /* prepare the cursor, looks like the stones you move */ Player[0].X11Set.fg_col.pixel = gammon_resource.black_Pixel; Player[0].X11Set.bg_col.pixel = gammon_resource.white_Pixel; XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[0].X11Set.fg_col); XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[0].X11Set.bg_col); XtSetArg (c[0], XtNcursor, &Player[0].X11Set.cursor); XtGetValues (Player[0].X11Set.board.widget, c, 1); if (!gammon_resource.other_display) { if (Player[0].type == HUMAN) XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col); else if (Player[1].type == HUMAN) XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.bg_col, &Player[0].X11Set.fg_col); else XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col); } else { XRecolorCursor (dpy, Player[0].X11Set.cursor, &Player[0].X11Set.fg_col, &Player[0].X11Set.bg_col); dpy = Player[1].X11Set.dpy; Player[1].X11Set.bg_col.pixel = gammon_resource.black_Pixel; Player[1].X11Set.fg_col.pixel = gammon_resource.white_Pixel; XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[1].X11Set.fg_col); XQueryColor (dpy, DefaultColormapOfScreen (DefaultScreenOfDisplay (dpy)), &Player[1].X11Set.bg_col); XtSetArg (c[0], XtNcursor, &Player[1].X11Set.cursor); XtGetValues (Player[1].X11Set.board.widget, c, 1); XRecolorCursor (Player[1].X11Set.dpy, Player[1].X11Set.cursor, &Player[1].X11Set.fg_col, &Player[1].X11Set.bg_col); } once = 1; } /* Quit is both, Callback and Action routine. I'm too lazy to invent an extra Callback */ void Quit (Widget w, XEvent *e, String *vector, Cardinal *count) { if (endgame_database) fclose (endgame_database); if (protokol_file) fclose (protokol_file); XtDestroyApplicationContext (XtWidgetToApplicationContext (w)); exit (0); } static void checkcmdline (int argc, char *argv[]) { int option; for (option=1; option 0 with watchmove\n"); } } void setup_gc (X11SET *X11Set) { XGCValues values; XtGCMask valuemask; valuemask = GCForeground|GCBackground|GCFunction; values.function = GXcopy; values.foreground = gammon_resource.black_Pixel; values.background = gammon_resource.board_Pixel; X11Set->gc = XtGetGC (X11Set->board.widget, valuemask, &values); values.foreground = gammon_resource.board_Pixel; values.background = gammon_resource.board_Pixel; X11Set->board.gc = XtGetGC (X11Set->board.widget, valuemask, &values); values.foreground = gammon_resource.black_Pixel; /* black stone */ values.background = gammon_resource.white_Pixel; X11Set->stoneGC[0] = XtGetGC (X11Set->board.widget, valuemask, &values); values.foreground = gammon_resource.white_Pixel; values.background = gammon_resource.black_Pixel; X11Set->stoneGC[1] = XtGetGC (X11Set->board.widget, valuemask, &values); valuemask ^= GCLineWidth|GCCapStyle|GCFont; values.foreground = gammon_resource.black_Pixel; values.background = gammon_resource.white_Pixel; values.line_width = 3; values.cap_style = CapRound; /* the fonts actually used */ if ((X11Set->doubler_font = XLoadQueryFont (X11Set->dpy, gammon_resource.doubler_font)) == NULL) { fprintf (stderr, "couldn't load doubler dice font, using default, sorry\n"); } else values.font = X11Set->doubler_font->fid; X11Set->diceGC = XtGetGC (X11Set->board.widget, valuemask, &values); X11Set->small_font = XLoadQueryFont (X11Set->dpy, gammon_resource.small_font); } void Redraw (Widget w, XEvent *e, String *vector, Cardinal *count) { DrawEmptyBoard (); DrawBoard (); RedrawAllStones (); DrawEmptyDice (turn); if (doubling_done) DrawDiceValues (turn); DrawDoubler (doubler.value, doubler.owner); } static void ResizeBoard (Widget w, XConfigureEvent *e, String *vector, Cardinal *count) { Arg arg[2]; Dimension new_stone_width, new_stone_height; Dimension new_width, new_height; if (gammon_resource.other_display) return; XClearArea (Player[0].X11Set.dpy, Player[0].X11Set.board.window, 0, 0, width, height, 0); /* if (gammon_resource.other_display) XClearArea (Player[0].X11Set.dpy, Player[1].X11Set.board.window, 0, 0, width, height, 0); */ new_stone_width = new_stone_height = e->width/15; new_width = new_stone_width * 15; if (e->height < new_stone_width * 12) { new_stone_width = e->height/12; new_height = new_stone_width * 12; new_width = new_stone_width * 15; } else new_height = new_stone_width * 12; width += (new_width-width); height += (new_height-height); stone_width = new_stone_width; XtSetArg (arg[0], XtNwidth, width); XtSetArg (arg[1], XtNheight, height); XtSetValues (Player[0].X11Set.board.widget, arg, 2); FreePixmaps (); CreatePixmaps (0); if (gammon_resource.other_display) CreatePixmaps (1); Redraw (0L, 0L, (char**) 0L, 0); } void MenuSelect (Widget w, XtPointer junk, XtPointer garbage) { XEvent event; char name[64]; char *v[] = {"p", NULL}; strcpy (name, XtName (w)); if (strncmp (name, "save position", 13) == 0) save (w, 0L, v, 0); else if (strncmp (name, "load position", 13) == 0) load (w, 0L, v, 0); else if (strncmp (name, "load game", 9) == 0) { v[0] = "g"; load (w, 0L, v, 0); } else if (strncmp (name, "save game", 9) == 0 ) { v[0] = "g"; save (w, 0L, v, 0); } else if (strcmp (name, "save as .." ) == 0) CreateSaveDialog (); else if (strcmp (name, "load .." ) == 0) File (); else if (strncmp (name, "restart", 7) == 0) restart (); else if (strncmp (name, "undo move", 9) == 0) UndoMove (0L, 0L, (char **) 0L, 0); else if (strcmp (name, "compi vs. compi" ) == 0) set_game_kind (COMPI_VS_COMPI); else if (strcmp (name, "human vs. compi" ) == 0) set_game_kind (HUMAN_VS_COMPI); else if (strcmp (name, "human vs. human" ) == 0) set_game_kind (HUMAN_VS_HUMAN); else if (strcmp (name, "computer finish" ) == 0) CompiFinish (); else if (strcmp (name, "rollout" ) == 0) exec_rollout (); else if (strcmp (name, "edit position" ) == 0) EditPosition (); else if (strcmp (name, "mail dump" ) == 0) maildump (); else if (strcmp (name, "replay game" ) == 0) ReplayGame (); else if (strcmp (name, "resign normal" ) == 0) Resign (NORMAL); else if (strcmp (name, "resign gammon" ) == 0) Resign (GAMMON); else if (strcmp (name, "resign backgammon") == 0) Resign (BACKGAMMON); while (XtAppPending (app_con)) XtAppNextEvent (app_con, &event); } void ButtonMove (Widget w, XButtonEvent *e) { int p, dp, to; if (!gammon_resource.button_move) return; if (!get_moves) return; p = EventToPin (e->x, e->y); if ((Pin[BAR].count && p != BAR) || ! (Pin[p].count && Pin[p].color == turn)) return; if (pash) { if (turn==BLACK) to = (p+roll[1] < end_pin) ? p+roll[1] : end_pin; else to = (p+roll[1] > end_pin) ? p+roll[1] : end_pin; if (move_is_allowed (p, to)) { /* roll[0] is used as a flag (sorry) */ RemoveStone (p); if (to != end_pin) { if (Pin[to].color == other) { RemoveStone (to); current_hit [done_hit] = to; done_hit++; PutStone (other, OTHER_BAR); } PutStone (turn, to); } else PutStone (turn, FINISHED); } } else { if (e->button == 1) { dp = (roll[0] > roll[1]) ? roll[1] : roll[0]; if (turn==BLACK) { to = (p+dp < end_pin) ? p+dp : end_pin; } else { to = (p+dp > end_pin) ? p+dp : end_pin; } if (move_is_allowed (p, to)) { RemoveStone (p); if (to != end_pin) { if (Pin[to].color == other) { RemoveStone (to); current_hit [done_hit] = to; done_hit++; PutStone (other, OTHER_BAR); } PutStone (turn, to); } else PutStone (turn, FINISHED); } } else if (e->button == 3) { dp = (roll[0] > roll[1]) ? roll[0] : roll[1]; if (turn==BLACK) to = ( p+dp < end_pin) ? p+dp : end_pin; else to = ( p+dp > end_pin) ? p+dp : end_pin; if (move_is_allowed (p, to)) { RemoveStone (p); if (to != end_pin) { if (Pin[to].color == other) { RemoveStone (to); current_hit [done_hit] = to; done_hit++; PutStone (other, OTHER_BAR); } PutStone (turn, to); } else PutStone (turn, FINISHED); } } else if (e->button == 2) { } } } void TakeStone (Widget w, XButtonEvent *e) { int p; if (!get_moves) return; if (gammon_resource.button_move) return; if (gammon_resource.other_display) { if (Player[turn-1].X11Set.board.window != e->window) return; } p = EventToPin (e->x, e->y); if (Pin[BAR].count && p != BAR) { from_pin = 0; return; } if (Pin[p].count && Pin[p].color == turn) { from_pin = p; RemoveStone (p); old_place_x = e->x - stone_width/2; old_place_y = e->y - stone_width/2; DrawStone (old_place_x, old_place_y, turn); took_one = 1; } else { from_pin = 0; } } void MoveStone (Widget w, XButtonEvent *e) { int x, y; if (!took_one) return; if (gammon_resource.button_move) return; x = e->x - stone_width/2; y = e->y - stone_width/2; if (x<0) x = 0; else if (x > width - stone_width) x = width - stone_width; if (y<0) y = 0; else if (y > height - stone_width) y = height - stone_width; cp_back (old_place_x, old_place_y); DrawStone (x, y, turn); old_place_x = x; old_place_y = y; } void PlaceStone (Widget w, XButtonEvent *e) { int p; if (!get_moves) return; if (gammon_resource.button_move) return; if (!took_one) return; took_one = 0; cp_back (old_place_x, old_place_y); p = EventToPin (e->x, e->y); if (!move_is_allowed (from_pin, p)) { PutStone (turn, from_pin); return; } if (p == end_pin) { /* check this first, cause possible removing other from endpin (other bar) */ PutStone (turn, FINISHED); if ((end_of_game = end_of_game_test (turn))) return; } else if (Pin[p].color == other) { RemoveStone (p); current_hit [done_hit] = p; done_hit++; PutStone (other, OTHER_BAR); PutStone (turn, p); } else { PutStone (turn, p); } } void UndoMove (Widget w, XEvent *e, String *vector, Cardinal *count) { int i; for (i=done_yet-1; i> -1; i--) { if (current_move[i].to == end_pin) RemoveStone (FINISHED); else RemoveStone (current_move[i].to); PutStone (turn, current_move[i].from); } for (i=0; ito == end_pin && (m+1)->to == end_pin) { if (pash && (m+2)->to == end_pin && (m+3)->to == end_pin) { can_off = 1; break; } else { can_off = 1; break; } } m += 4; } if (can_off) { compi_choice = m; ShowCompiMove (); AppendMoveString (compi_choice); roll[0] = 0; done_yet = 0; done_hit = 0; } } static void PipCount (Widget w, XEvent *e, String *vector, Cardinal *count) { extern void simple_pipcount (); float pip_count[3]; simple_pipcount (&pip_count); sprintf (add_text, " picount:\n black: %d, white: %d ", abs ((int) pip_count[BLACK]), abs ((int) pip_count[WHITE])); Info (add_text); pip_count_request = 1; } void PopupButtonShell (Widget parent, Widget button_shell) { Position x, y; Dimension w; Arg args[2]; XtSetArg (args[0], XtNwidth, &w); XtGetValues (parent, args, 1); XtSetArg (args[0], XtNx, &x); XtSetArg (args[1], XtNy, &y); XtGetValues (parent, args, 2); x += (Position) (w + 40); if (x<0) x=0; if (y<0) y=0; XtSetArg (args[0], XtNx, x); XtSetArg (args[1], XtNy, y); XtSetValues (button_shell, args, 2); XtPopup (button_shell, XtGrabNone); } void restart (void) { tournament.game_number = 1; Player[0].points = 0; Player[1].points = 0; AppendDialogText (UPPER, "tournament restart:\n"); end_of_tournament = 1; end_of_game = 1; initialize = NORMAL_GAME; break_loop = 1; TournamentInit (); } void Resign (int how) { sprintf (add_text, "%s wants to resign\n", Player[turn-1].name); AppendDialogText (LOWER, add_text); Info ("accept"); AppendDialogText (LOWER, "xgammon accepts\n\n"); switch_turn (); /* for AddResult () */ end_of_game = how; /* for AddResult () */ initialize = NORMAL_GAME; break_loop = 1; } void set_game_kind (int to) { if (to == HUMAN_VS_COMPI) { Player[0].type = HUMAN; Player[1].type = COMPUTER; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = CompiLoop; } else if (to == COMPI_VS_COMPI) { Player[0].type = COMPUTER; Player[1].type = COMPUTER; Player[0].MoveFunction = CompiLoop; Player[1].MoveFunction = CompiLoop; } else if (to == HUMAN_VS_HUMAN) { Player[0].type = HUMAN; Player[1].type = HUMAN; Player[0].MoveFunction = HumanLoop; Player[1].MoveFunction = HumanLoop; } }