4 ** functions and structures for a game of gipf
7 ** Copyright (C) 1998 Kurt Van den Branden
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License as published by
11 ** the Free Software Foundation; either version 2 of the License, or
12 ** (at your option) any later version.
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <FL/fl_draw.H>
33 #include "gettimeofday.h"
39 #include "callbacks.h"
40 #include "player_info.h"
44 char gametype
[4][15] = {"basic", "standard", "tournament", "other game"};
45 char playertype
[2][9] = {"human", "computer"};
48 ** show the window for starting a new game
50 ** if the user pressed OK, this will return a structure for starting
53 ** if you give a parameter different from NULL, then the window will be
54 ** initialised from this game, otherwise, defaults are used
56 gamestruct
* show_new (gamestruct
* oldgame
)
61 neww
= make_newwindow ();
67 switch (oldgame
->game_type
)
70 radio_basic
->setonly();
73 radio_standard
->setonly();
76 radio_tournament
->setonly();
81 whiteplayername
->value (oldgame
->player
[0].name
);
82 blackplayername
->value (oldgame
->player
[1].name
);
85 if (oldgame
->player
[0].type
)
86 radio_wcompu
->setonly();
88 radio_whuman
->setonly();
90 if (oldgame
->player
[1].type
)
91 radio_bcompu
->setonly();
93 radio_bhuman
->setonly();
96 if (oldgame
->player
[0].fulltime
== -1)
98 toggle_timedgame
->clear();
102 toggle_timedgame
->set();
103 whitetime
->value (oldgame
->player
[0].fulltime
/ 60);
104 blacktime
->value (oldgame
->player
[1].fulltime
/ 60);
109 radio_tournament
->setonly();
110 toggle_timedgame
->clear();
111 radio_whuman
->setonly();
112 radio_bcompu
->setonly();
115 // show or hide the time-counters
116 if (toggle_timedgame
->value())
118 whitetime
->activate();
119 blacktime
->activate();
123 whitetime
->deactivate();
124 blacktime
->deactivate();
134 while ((x
= Fl::readqueue()))
136 if (x
== toggle_timedgame
)
138 if (toggle_timedgame
->value())
140 whitetime
->activate();
141 blacktime
->activate();
145 whitetime
->deactivate();
146 blacktime
->deactivate();
149 else if (x
== new_ok
)
151 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
152 newgame
->state
= GAME_GO
;
153 newgame
->movecounter
= 0;
155 if (radio_whuman
->value())
156 newgame
->player
[0].type
= 0;
158 newgame
->player
[0].type
= 1;
159 if (radio_bhuman
->value())
160 newgame
->player
[1].type
= 0;
162 newgame
->player
[1].type
= 1;
164 strcpy (newgame
->player
[0].name
, whiteplayername
->value());
165 strcpy (newgame
->player
[1].name
, blackplayername
->value());
167 if (toggle_timedgame
->value())
169 newgame
->player
[0].fulltime
= 60 * (int)whitetime
->value();
170 newgame
->player
[0].timer
=
171 (float) newgame
->player
[0].fulltime
;
172 newgame
->player
[1].fulltime
= 60 * (int)blacktime
->value();
173 newgame
->player
[1].timer
=
174 (float) newgame
->player
[1].fulltime
;
178 newgame
->player
[0].fulltime
= -1;
179 newgame
->player
[0].timer
= 0.0;
180 newgame
->player
[1].fulltime
= -1;
181 newgame
->player
[1].timer
= 0.0;
184 if (radio_basic
->value ()) { newgame
->game_type
= T_BASIC
;}
185 else if (radio_standard
->value ())
186 { newgame
->game_type
= T_STANDARD
;}
187 else if (radio_tournament
->value ())
188 { newgame
->game_type
= T_TOURNAMENT
;}
189 else { return (NULL
);}
191 newgame
->boards
[0] = b_new (newgame
->game_type
);
192 newgame
->boards
[1] = NULL
;
193 newgame
->boards
[2] = NULL
;
195 // initialize players
196 newgame
->player
[0].self
=
197 (* players
[newgame
->player
[0].type
].newfunc
)
198 ('o', newgame
->game_type
);
199 newgame
->player
[1].self
=
200 (* players
[newgame
->player
[1].type
].newfunc
)
201 ('x', newgame
->game_type
);
203 newgame
->movelog
= newlog (gametype
[newgame
->game_type
],
204 newgame
->player
[0].name
,
205 newgame
->player
[1].name
);
209 setcurrentfilename ("\0");
213 else if (x
== new_cancel
)
226 ** show the window for starting a game from a gameboard
228 ** if the user pressed OK, this will return a structure for starting
231 ** the parameter is the board to start from
233 gamestruct
* show_start (board
* startboard
)
236 gamestruct
* newgame
;
239 if ((newboard
= verify_board (startboard
)) == NULL
)
244 startw
= make_startwindow ();
246 /* put default settings in window */
247 radio_white
->setonly ();
248 radio_s_whuman
->setonly ();
249 radio_s_bcompu
->setonly ();
250 if (newboard
->typewhite
== 'g')
251 toggle_s_whitegipf
->set ();
253 toggle_s_whitegipf
->deactivate ();
254 if (newboard
->typeblack
== 'g')
255 toggle_s_blackgipf
->set ();
257 toggle_s_blackgipf
->deactivate ();
266 while ((x
= Fl::readqueue()))
270 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
271 newgame
->state
= GAME_GO
;
272 newgame
->movecounter
= 0;
274 if (radio_s_whuman
->value() != 0)
275 newgame
->player
[0].type
= 0;
277 newgame
->player
[0].type
= 1;
279 if (radio_s_bhuman
->value() != 0)
280 newgame
->player
[1].type
= 0;
282 newgame
->player
[1].type
= 1;
284 strcpy (newgame
->player
[0].name
, s_whiteplayername
->value());
285 strcpy (newgame
->player
[1].name
, s_blackplayername
->value());
287 newgame
->player
[0].fulltime
= -1;
288 newgame
->player
[0].timer
= 0.0;
289 newgame
->player
[1].fulltime
= -1;
290 newgame
->player
[1].timer
= 0.0;
292 newgame
->game_type
= T_OTHER
;
294 if ((newboard
->typewhite
== 'g') &&
295 (toggle_s_whitegipf
->value () == 0))
296 newboard
->typewhite
= 'n';
297 if ((newboard
->typeblack
== 'g') &&
298 (toggle_s_blackgipf
->value () == 0))
299 newboard
->typeblack
= 'n';
301 if (radio_white
->value () != 0)
302 newboard
->nextpiece
= 'o';
304 newboard
->nextpiece
= 'x';
306 newgame
->boards
[0] = newboard
;
307 newgame
->boards
[1] = NULL
;
308 newgame
->boards
[2] = NULL
;
310 // initialize players
311 newgame
->player
[0].self
=
312 (* players
[newgame
->player
[0].type
].newfunc
)
313 ('o', newgame
->game_type
);
314 newgame
->player
[1].self
=
315 (* players
[newgame
->player
[1].type
].newfunc
)
316 ('x', newgame
->game_type
);
318 newgame
->movelog
= newlog (gametype
[newgame
->game_type
],
319 newgame
->player
[0].name
,
320 newgame
->player
[1].name
);
324 setcurrentfilename ("\0");
328 else if (x
== start_cancel
)
342 ** show the window for calculating one move starting from a gameboard
344 ** if the user pressed OK, this will return a structure for calculating
347 ** the parameter is the board to start from
349 gamestruct
* show_onemove (board
* startboard
, configvalues
* conf
)
351 Fl_Window
* onemovew
;
352 gamestruct
* newgame
;
357 if ((newboard
= verify_board (startboard
)) == NULL
)
362 onemovew
= make_onemovewindow ();
364 radio_c_white
->setonly ();
365 c_level3
->setonly ();
374 while ((x
= Fl::readqueue()))
378 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
379 newgame
->state
= GAME_GO
;
380 newgame
->movecounter
= 0;
382 if (radio_c_white
->value() != 0)
384 newgame
->player
[0].type
= 1;
385 newgame
->player
[1].type
= 0;
386 strcpy (newgame
->player
[0].name
, "Computer");
387 strcpy (newgame
->player
[1].name
, "None");
388 newboard
->nextpiece
= 'o';
392 newgame
->player
[0].type
= 0;
393 newgame
->player
[1].type
= 1;
394 strcpy (newgame
->player
[1].name
, "Computer");
395 strcpy (newgame
->player
[0].name
, "None");
396 newboard
->nextpiece
= 'x';
399 newgame
->player
[0].fulltime
= -1;
400 newgame
->player
[0].timer
= 0.0;
401 newgame
->player
[1].fulltime
= -1;
402 newgame
->player
[1].timer
= 0.0;
404 newgame
->game_type
= T_OTHER
;
406 newgame
->boards
[0] = newboard
;
407 newgame
->boards
[1] = NULL
;
408 newgame
->boards
[2] = NULL
;
410 newgame
->config
= conf
;
412 // initialize players
413 newgame
->player
[0].self
=
414 (* players
[newgame
->player
[0].type
].newfunc
)
415 ('o', newgame
->game_type
);
416 newgame
->player
[1].self
=
417 (* players
[newgame
->player
[1].type
].newfunc
)
418 ('x', newgame
->game_type
);
420 newgame
->movelog
= newlog (gametype
[newgame
->game_type
],
421 newgame
->player
[0].name
,
422 newgame
->player
[1].name
);
424 if ((c_level1
->value ()) != 0) { newlevel
= 1; }
425 else if ((c_level2
->value ()) != 0) { newlevel
= 2; }
426 else if ((c_level3
->value ()) != 0) { newlevel
= 3; }
427 else if ((c_level4
->value ()) != 0) { newlevel
= 4; }
428 else if ((c_level5
->value ()) != 0) { newlevel
= 5; }
429 else if ((c_level6
->value ()) != 0) { newlevel
= 6; }
430 else if ((c_level7
->value ()) != 0) { newlevel
= 7; }
431 else if ((c_level8
->value ()) != 0) { newlevel
= 8; }
433 oldlevel
= conf
->searchdepth
;
434 if (newlevel
!= oldlevel
)
436 conf
->searchdepth
= newlevel
;
442 setcurrentfilename ("\0");
444 /* execute the move here */
445 gameboard
->setboard (newgame
->boards
[0]);
449 newgame
->state
= GAME_STOP
;
450 changeinterface (INTERFACE_PLAY
, newgame
);
452 if (newlevel
!= oldlevel
)
454 conf
->searchdepth
= oldlevel
;
460 else if (x
== one_cancel
)
474 ** check if a gameboard can be used to start a game from
476 ** returns a copy of sboard that is correctly setup
477 ** or NULL if there is a problem
479 board
* verify_board (board
* sboard
)
488 /* check if one of the players has no pieces left */
489 if (b_colour (sboard
, 'o') == 0)
491 gf1_alert ("ERROR: no game possible from this boardsituation, player white has no pieces left.");
494 if (b_colour (sboard
, 'x') == 0)
496 gf1_alert ("ERROR: no game possible from this boardsituation, player black has no pieces left.");
500 /* count pieces on the board */
501 pos
= new_position ();
502 for (i
= 1; i
< 8; i
++)
503 for (j
= 2; j
<= b_colsize (i
); j
++)
507 switch (b_ppiece (sboard
, pos
))
524 /* check if the board is empty */
525 if ((white
== 0) && (black
== 0))
527 gf1_alert ("ERROR: no game possible from this boardsituation, the gameboard is empty.");
531 /* check for four-in-a-row */
532 for (i
= 0; i
< 21; i
++)
534 if ((row_ptr
= b_rowoffour (sboard
, i
)) != NULL
)
536 del_rem_row ((void *) row_ptr
);
537 gf1_alert ("ERROR: no game possible from this boardsituation, four-in-a-row found.");
542 /* check if this is a basic game */
543 if ((b_colour_gipf (sboard
, 'o') == 0) &&
544 (b_colour_gipf (sboard
, 'x') == 0))
546 nboard
= b_copy (sboard
);
547 nboard
->gipfwhite
= -1;
548 nboard
->gipfblack
= -1;
549 nboard
->typewhite
= 'n';
550 nboard
->typeblack
= 'n';
552 /* turn this into a real basic game (if possible) */
553 if ((b_colour (nboard
, 'o') > 3) && (b_colour (sboard
, 'x') > 3))
562 /* tournament or standard game, for me it's always tournament */
565 ** something is wrong when a player has normal pieces, but
568 /* check if one of the player has single pieces, but no gipf-pieces */
569 if ((b_colour_gipf (sboard
, 'o') == 0) && (b_colour (sboard
, 'o') < 18))
571 gf1_alert ("ERROR: no game possible from this boardsituation, player white has no gipf-pieces.");
574 if ((b_colour_gipf (sboard
, 'x') == 0) && (b_colour (sboard
, 'x') < 18))
576 gf1_alert ("ERROR: no game possible from this boardsituation, player black has no gipf-pieces.");
580 nboard
= b_copy (sboard
);
581 nboard
->typewhite
= 'n';
582 nboard
->typeblack
= 'n';
583 if ((18 - b_colour_gipf (sboard
, 'o') * 2) == b_colour (sboard
, 'o'))
584 { /* only gipf-pieces, allow player to add more */
585 nboard
->typewhite
= 'g';
587 if ((18 - b_colour_gipf (sboard
, 'x') * 2) == b_colour (sboard
, 'x'))
588 { /* only gipf-pieces, allow player to add more */
589 nboard
->typeblack
= 'g';
592 ** I don't check here if the players have 18 pieces
593 ** which means that it's not completely correct
600 void delete_game (gamestruct
* gameptr
)
607 /* ask the player to cleanup its data */
608 if (gameptr
->player
[0].self
!= NULL
)
610 (* players
[gameptr
->player
[0].type
].endfunc
) (gameptr
->player
[0].self
);
612 if (gameptr
->player
[1].self
!= NULL
)
614 (* players
[gameptr
->player
[1].type
].endfunc
) (gameptr
->player
[1].self
);
617 for (i
= 0; i
< 3; i
++)
619 b_del (gameptr
->boards
[i
]);
622 deletelog (gameptr
->movelog
);
628 ** REMARK: this is the old version
630 ** load a game from a file
632 ** return NULL if nothing loaded
634 gamestruct
* oldloadgame (const char * filename
)
641 gamestruct
* newgame
;
643 if ((fp
= fopen (filename
, "r")) == NULL
)
645 gf1_alert (" ERROR: Can't open the file");
649 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
650 newgame
->state
= GAME_GO
;
652 fgets (buffer
, 100, fp
);
653 if (strncmp (buffer
, "# saved game for gf1", 20) != 0)
655 gf1_alert (" ERROR: wrong inputfile format");
660 fgets (buffer
, 100, fp
);
661 if (sscanf (buffer
, "# gametype: %d", &(newgame
->game_type
)) != 1)
663 gf1_alert (" ERROR: wrong inputfile format");
668 for (i
= 0; i
< 2; i
++)
670 fgets (buffer
, 100, fp
);
671 if (sscanf (buffer
, "# player%d type: %d",
672 &tempnr
, &(newgame
->player
[i
].type
)) != 2)
674 gf1_alert (" ERROR: wrong inputfile format");
679 fgets (buffer
, 100, fp
);
680 sprintf (tempstr
, "# player%d name: ", i
);
681 if (strncmp (buffer
, tempstr
, 16) != 0)
683 gf1_alert (" ERROR: wrong inputfile format");
687 buffer
[strlen(buffer
) - 1] = '\0';
688 strcpy (newgame
->player
[i
].name
, buffer
+16);
690 fgets (buffer
, 100, fp
);
691 if (sscanf (buffer
, "# player%d fulltime: %d",
692 &tempnr
, &(newgame
->player
[i
].fulltime
)) != 2)
694 gf1_alert (" ERROR: wrong inputfile format");
699 fgets (buffer
, 100, fp
);
700 if (sscanf (buffer
, "# player%d timer: %f",
701 &tempnr
, &(newgame
->player
[i
].timer
)) != 2)
703 gf1_alert (" ERROR: wrong inputfile format");
708 newgame
->player
[i
].self
= NULL
;
711 fgets (buffer
, 100, fp
);
712 if ((newgame
->boards
[0] = b_from_file (fp
)) == NULL
)
714 gf1_alert (" ERROR: wrong inputfile format");
718 newgame
->boards
[1] = NULL
;
719 newgame
->boards
[2] = NULL
;
721 fgets (buffer
, 100, fp
);
722 if ((newgame
->movelog
= logfromfile (fp
)) == NULL
)
724 gf1_alert (" ERROR: wrong inputfile format");
728 newgame
->movecounter
= loglength (newgame
->movelog
);
732 // reading was succesfull, init the players
733 newgame
->player
[0].self
=
734 (* players
[newgame
->player
[0].type
].newfunc
) ('o', newgame
->game_type
);
735 newgame
->player
[1].self
=
736 (* players
[newgame
->player
[1].type
].newfunc
) ('x', newgame
->game_type
);
743 ** load a game from a file
745 ** return NULL if nothing loaded
747 gamestruct
* loadgame (void)
749 const char * filename
;
754 gamestruct
* newgame
;
755 xmlite_entity
* root
, *x1
;
756 xmlite_parser
* theparser
;
759 if ((filename
= file_chooser ("load game", "*.gf1", NULL
)) == NULL
)
764 if ((fp
= fopen (filename
, "r")) == NULL
)
766 gf1_alert (" ERROR: Can't open the file");
770 fgets (buffer
, 100, fp
);
772 if (strncmp (buffer
, "# saved game for gf1", 20) == 0)
774 return (oldloadgame (filename
));
777 theparser
= new xmlite_parser (filename
);
778 root
= theparser
->parse ();
783 gf1_alert (" ERROR: Can't parse savefile");
787 if (root
->getname() != "gipfgame")
790 gf1_alert (" ERROR: Not a savefile from gf1");
794 if (atoi (root
->getattribute("formatversion").c_str()) > 1)
797 gf1_alert (" ERROR: Don't know how to handle this fileversion");
801 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
802 newgame
->state
= GAME_GO
;
805 strcpy (tempstr
, root
->getattribute("type").c_str());
806 newgame
->game_type
= 3; // put some default value in
807 for (i
= 0; i
< 4; i
++)
809 if (strcmp (tempstr
, gametype
[i
]) == 0)
811 newgame
->game_type
= i
;
817 x1
= root
->getcontentbyname ("whiteplayer");
818 strcpy (newgame
->player
[0].name
, x1
->getvalue().c_str());
819 newgame
->player
[0].type
= x1
->getattribute ("type") == "human" ? 0 : 1;
820 newgame
->player
[0].fulltime
= atoi (x1
->getattribute ("fulltime").c_str());
821 newgame
->player
[0].timer
= atof (x1
->getattribute ("timeleft").c_str());
822 newgame
->player
[0].self
= NULL
;
823 x1
= root
->getcontentbyname ("blackplayer");
824 strcpy (newgame
->player
[1].name
, x1
->getvalue().c_str());
825 newgame
->player
[1].type
= x1
->getattribute ("type") == "human" ? 0 : 1;
826 newgame
->player
[1].fulltime
= atoi (x1
->getattribute ("fulltime").c_str());
827 newgame
->player
[1].timer
= atof (x1
->getattribute ("timeleft").c_str());
828 newgame
->player
[1].self
= NULL
;
830 // the boardsituation
831 newgame
->boards
[0] = b_from_xml (root
->getcontentbyname ("board"));
832 newgame
->boards
[1] = NULL
;
833 newgame
->boards
[2] = NULL
;
836 newgame
->movelog
= logfromxml (root
->getcontentbyname ("gamelog"));
837 newgame
->movecounter
= loglength (newgame
->movelog
);
839 // reading was succesfull, init the players
840 newgame
->player
[0].self
=
841 (* players
[newgame
->player
[0].type
].newfunc
) ('o', newgame
->game_type
);
842 newgame
->player
[1].self
=
843 (* players
[newgame
->player
[1].type
].newfunc
) ('x', newgame
->game_type
);
847 setcurrentfilename (filename
);
854 ** save a game to a file
856 void savegame (gamestruct
* gameptr
)
858 const char * filename
;
859 xmlite_entity
*x1
, *x2
;
865 gf1_alert (" no current game to be saved");
870 cfile
= getcurrentfilename ();
871 if (cfile
[0] == '\0')
872 strcpy (tempstr
, "./savegame.gf1");
874 strcpy (tempstr
, cfile
);
875 if ((filename
= file_chooser ("save game", "*.gf1", tempstr
))
882 x1
= new xmlite_entity ("gipfgame");
883 x1
->addattribute ("type", gametype
[gameptr
->game_type
]);
884 x1
->addattribute ("formatversion", "1");
887 x2
= new xmlite_entity ("whiteplayer");
888 sprintf (tempstr
, "%f", gameptr
->player
[0].timer
);
889 x2
->addattribute ("timeleft", tempstr
);
890 sprintf (tempstr
, "%d", gameptr
->player
[0].fulltime
);
891 x2
->addattribute ("fulltime", tempstr
);
892 x2
->addattribute ("type", playertype
[gameptr
->player
[0].type
]);
893 x2
->setvalue (gameptr
->player
[0].name
);
897 x2
= new xmlite_entity ("blackplayer");
898 sprintf (tempstr
, "%f", gameptr
->player
[1].timer
);
899 x2
->addattribute ("timeleft", tempstr
);
900 sprintf (tempstr
, "%d", gameptr
->player
[1].fulltime
);
901 x2
->addattribute ("fulltime", tempstr
);
902 x2
->addattribute ("type", playertype
[gameptr
->player
[1].type
]);
903 x2
->setvalue (gameptr
->player
[1].name
);
907 x2
= b_to_xml (gameptr
->boards
[0]);
911 x2
= logtoxml (gameptr
->movelog
);
914 x1
->writetofile (filename
);
917 setcurrentfilename (filename
);
923 void setupmove (gamestruct
* thegame
)
929 if ((thegame
== NULL
) || (thegame
->state
== GAME_STOP
))
931 changeinterface (INTERFACE_PLAY
, thegame
);
939 if (thegame
->player
[0].fulltime
!= -1)
941 if (thegame
->player
[0].timer
<= 0.0)
946 if (thegame
->player
[1].timer
<= 0.0)
953 if (interrupt_computer
)
956 interrupt_computer
= 0;
957 thegame
->state
= GAME_STOP
;
961 changeinterface (INTERFACE_PLAY
, thegame
);
963 if (b_status (thegame
->boards
[0]) == S_NORMAL
)
965 nextpiece
= b_next_piece (thegame
->boards
[0]);
966 /* check if gipf-pieces left */
967 if (thegame
->game_type
!= T_BASIC
)
969 if (((b_move_counter (thegame
->boards
[0]) > 1) ||
970 (thegame
->game_type
== T_OTHER
) || (nextpiece
== 'x')) &&
971 (b_white_gipf (thegame
->boards
[0]) == 0))
976 else if ((b_move_counter (thegame
->boards
[0]) > 1) &&
977 (b_black_gipf (thegame
->boards
[0]) == 0))
983 if (b_colour (thegame
->boards
[0], nextpiece
) == 0)
984 { /* game finished */
985 winner
= b_opponent (nextpiece
);
989 if (thegame
->player
[pnr(nextpiece
)].type
== 0)
991 gameboard
->setto (NULL
);
992 gameboard
->setfrom (NULL
);
993 if (b_colour_type (thegame
->boards
[0], nextpiece
) == 'g')
994 gameboard
->setgipfpossible (1);
996 gameboard
->setgipfpossible (0);
998 starttimer (thegame
, nextpiece
);
1002 { /* computer player */
1003 fl_cursor (FL_CURSOR_WAIT
);
1006 computermove (thegame
);
1008 fl_cursor (FL_CURSOR_DEFAULT
);
1011 else if (b_status (thegame
->boards
[0]) == S_REMOVEGIPF
)
1013 gipf_questions (thegame
);
1015 else if (b_status (thegame
->boards
[0]) == S_REMOVEROW
)
1017 row_questions (thegame
);
1023 sprintf (tempstr
, "Player %s, you have won after %d moves !",
1024 thegame
->player
[pnr(winner
)].name
,
1025 b_move_counter (thegame
->boards
[0]));
1026 gf1_alert (tempstr
);
1027 thegame
->state
= GAME_STOP
;
1030 changeinterface (INTERFACE_PLAY
, thegame
);
1036 void computermove (gamestruct
* thegame
)
1046 Fl_Window
* thinkwindow
;
1048 temp_board
= b_copy (thegame
->boards
[0]);
1049 nextpiece
= b_next_piece (thegame
->boards
[0]);
1050 piecetype
= b_colour_type (thegame
->boards
[0], nextpiece
);
1051 playertype
= thegame
->player
[pnr(nextpiece
)].type
;
1053 starttimer (thegame
, nextpiece
);
1055 thinkwindow
= create_thinkwindow ();
1057 (* players
[playertype
].movefunc
)
1058 (temp_board
, thegame
->player
[pnr(nextpiece
)].self
,
1059 thegame
->player
[pnr(nextpiece
)].timer
,
1060 &piecetype
, from
, to
);
1065 stoptimer (thegame
);
1066 if (interrupt_computer
)
1069 if ((b_colour_type (thegame
->boards
[0], nextpiece
) != 'g') &&
1075 piece
= piecetype
== 'g' ? b_otherpiece (nextpiece
) : nextpiece
;
1077 b_setlog (thegame
->boards
[0], thegame
->movelog
);
1078 new_board
= b_move (thegame
->boards
[0], from
, to
, piece
);
1079 b_nolog (thegame
->boards
[0]);
1080 b_nolog (new_board
);
1083 if (new_board
== NULL
)
1085 gf1_alert ("the computer-player executed an invalid move !!");
1087 // b_del (thegame->boards[0]);
1088 // (* players[thegame->player[0].type].endfunc)(thegame->player[0].self);
1089 // (* players[thegame->player[1].type].endfunc)(thegame->player[1].self);
1090 // thegame->boards[0] = NULL;
1094 b_del (thegame
->boards
[2]);
1095 thegame
->boards
[2] = thegame
->boards
[1];
1096 thegame
->boards
[1] = thegame
->boards
[0];
1097 thegame
->boards
[0] = new_board
;
1099 analysemove (thegame
, playertype
);
1101 gameboard
->setboard (thegame
->boards
[0]);
1108 int humanmove (gamestruct
* thegame
)
1113 board
* new_board
= NULL
;
1118 if (thegame
->state
== GAME_STOP
)
1121 from
= postostr (gameboard
->getfrom ());
1122 to
= postostr (gameboard
->getto ());
1123 if (gameboard
->getptype ())
1128 nextpiece
= b_next_piece (thegame
->boards
[0]);
1129 playertype
= thegame
->player
[pnr(nextpiece
)].type
;
1131 if ((b_colour_type (thegame
->boards
[0], nextpiece
) != 'g') &&
1137 piece
= piecetype
== 'g' ? b_otherpiece (nextpiece
) : nextpiece
;
1139 b_setlog (thegame
->boards
[0], thegame
->movelog
);
1140 new_board
= b_move (thegame
->boards
[0], from
, to
, piece
);
1141 b_nolog (thegame
->boards
[0]);
1142 if (new_board
!= NULL
)
1143 b_nolog (new_board
);
1148 if (new_board
== NULL
)
1153 stoptimer (thegame
);
1155 b_del (thegame
->boards
[2]);
1156 thegame
->boards
[2] = thegame
->boards
[1];
1157 thegame
->boards
[1] = thegame
->boards
[0];
1158 thegame
->boards
[0] = new_board
;
1160 analysemove (thegame
, 0);
1162 gameboard
->setto (NULL
);
1163 gameboard
->setfrom (NULL
);
1164 gameboard
->setboard (thegame
->boards
[0]);
1170 void row_questions (gamestruct
* thegame
)
1176 listheader
* rowlist
;
1185 temp_board
= b_copy (thegame
->boards
[0]);
1187 rowlist
= b_row_extra (thegame
->boards
[0]);
1188 while ((row
= (rem_row
*) llitembynr (rowlist
, counter
)) != NULL
)
1191 start
= postostr (row
->startpos
);
1192 end
= postostr (row
->endpos
);
1193 owner
= row_owner (row
);
1195 starttimer (thegame
, owner
);
1196 if (thegame
->player
[pnr(owner
)].type
== 0)
1198 gameboard
->setrow (row
->piecelist
);
1199 gameboard
->setboard (thegame
->boards
[0]);
1201 sprintf (tempstr1
, "Player %s, do you want to remove",
1202 thegame
->player
[pnr(owner
)].name
);
1203 sprintf (tempstr2
, "the row from %s to %s", start
, end
);
1208 answer
= gf1_questionsave (tempstr1
, tempstr2
);
1212 else if (answer
== 1)
1218 gameboard
->setrow (NULL
);
1222 Fl_Window
* thinkwindow
;
1224 thinkwindow
= create_thinkwindow ();
1227 (* players
[thegame
->player
[pnr(owner
)].type
].rowfunc
)
1228 (temp_board
, thegame
->player
[pnr(owner
)].self
,
1229 thegame
->player
[pnr(owner
)].timer
, start
, end
);
1233 stoptimer (thegame
);
1234 if (interrupt_computer
)
1240 if (response
== 'y')
1242 b_setlog (thegame
->boards
[0], thegame
->movelog
);
1243 new_board
= b_remove_row (thegame
->boards
[0], counter
-1);
1244 b_nolog (new_board
);
1245 b_del (thegame
->boards
[0]);
1246 thegame
->boards
[0] = new_board
;
1248 analysemove (thegame
, thegame
->player
[pnr(owner
)].type
);
1250 gameboard
->setboard (thegame
->boards
[0]);
1261 void gipf_questions (gamestruct
* thegame
)
1268 listheader
* gipflist
;
1277 gipflist
= b_gipf_extra (thegame
->boards
[0]);
1278 new_board
= thegame
->boards
[0];
1280 while ((gipf
= (rem_gipf
*) llitembynr (gipflist
, counter
)) != NULL
)
1283 strpos
= b_gipf_position (gipf
);
1284 owner
= b_gipf_owner (gipf
);
1286 starttimer (thegame
, owner
);
1287 if (thegame
->player
[pnr(owner
)].type
== 0)
1289 gameboard
->setto (gipf
->pos
);
1290 gameboard
->setboard (new_board
);
1292 sprintf (tempstr1
, "Player %s, do you want to remove",
1293 thegame
->player
[pnr(owner
)].name
);
1294 sprintf (tempstr2
, "the GIPF at %s", strpos
);
1300 ** only allow saving of the game at the first question
1301 ** for removing a gipf.
1302 ** things get fishy if you would save from here after a gipf
1303 ** has been removed already.
1304 ** (the problem doesn't occur immediatly, but when you load
1308 answer
= gf1_questionsave (tempstr1
, tempstr2
);
1310 answer
= gf1_question (tempstr1
, tempstr2
);
1315 else if (answer
== 1)
1321 gameboard
->setto (NULL
);
1325 Fl_Window
* thinkwindow
;
1327 thinkwindow
= create_thinkwindow ();
1329 temp_board
= b_copy (new_board
);
1330 response
= (* players
[thegame
->player
[pnr(owner
)].type
].gipffunc
)
1331 (temp_board
, thegame
->player
[pnr(owner
)].self
,
1332 thegame
->player
[pnr(owner
)].timer
, strpos
);
1337 stoptimer (thegame
);
1338 if (interrupt_computer
)
1341 if ((response
== 'y') || (response
== 'Y'))
1343 b_setlog (new_board
, thegame
->movelog
);
1344 nboard
= b_remove_gipf (new_board
, gipf
);
1345 b_nolog (new_board
);
1348 if (new_board
!= thegame
->boards
[0])
1353 analysemove (thegame
, thegame
->player
[pnr(owner
)].type
);
1355 gameboard
->setboard (new_board
);
1360 b_setlog (new_board
, thegame
->movelog
);
1361 nboard
= b_checkfour (new_board
);
1362 b_nolog (new_board
);
1364 if (new_board
!= thegame
->boards
[0])
1367 b_del (thegame
->boards
[0]);
1368 thegame
->boards
[0] = nboard
;
1370 analysemove (thegame
, 1);
1372 gameboard
->setboard (thegame
->boards
[0]);
1378 //time_t basetime = 0;
1379 struct timeval basetime
;
1382 void starttimer (gamestruct
* thegame
, char color
)
1386 if (thegame
->player
[0].fulltime
== -1)
1388 basetime
.tv_sec
= 0;
1392 // basetime = time (NULL);
1393 gettimeofday (&basetime
, &tz
);
1396 Fl::add_timeout (1.0, updatetimer
, (void *) thegame
);
1402 void stoptimer (gamestruct
* thegame
)
1410 if ((thegame
== NULL
) || (basetime
.tv_sec
== 0))
1413 Fl::remove_timeout (updatetimer
, (void *) thegame
);
1415 // newtime = time (NULL);
1416 gettimeofday (&tv
, &tz
);
1417 timedif
= (tv
.tv_sec
- basetime
.tv_sec
) +
1418 (float) (tv
.tv_usec
- basetime
.tv_usec
)/1000000;
1420 if (timercolor
== 'o')
1422 if (interrupt_computer
== 0)
1423 thegame
->player
[0].timer
-= timedif
;
1424 timertostr (thegame
->player
[0].timer
, tempstr
);
1425 whitetimer
->value (tempstr
);
1429 if (interrupt_computer
== 0)
1430 thegame
->player
[1].timer
-= timedif
;
1431 timertostr (thegame
->player
[1].timer
, tempstr
);
1432 blacktimer
->value (tempstr
);
1435 basetime
.tv_sec
= 0;
1440 void updatetimer (void * data
)
1442 gamestruct
* thegame
= (gamestruct
*) data
;
1450 // newtime = time (NULL);
1451 gettimeofday (&tv
, &tz
);
1452 timedif
= (tv
.tv_sec
- basetime
.tv_sec
) +
1453 (float) (tv
.tv_usec
- basetime
.tv_usec
)/1000000;
1455 if (timercolor
== 'o')
1457 newtimer
= thegame
->player
[0].timer
- timedif
;
1458 timertostr (newtimer
, tempstr
);
1459 whitetimer
->value (tempstr
);
1463 newtimer
= thegame
->player
[1].timer
- timedif
;
1464 timertostr (newtimer
, tempstr
);
1465 blacktimer
->value (tempstr
);
1469 Fl::add_timeout (1.0, updatetimer
, data
);
1471 { /* timer ran out, show if this is a human move */
1472 if (timercolor
== 'o')
1474 if (thegame
->player
[0].type
== 0)
1476 thegame
->player
[0].timer
= newtimer
;
1478 setupmove (thegame
);
1481 else if (thegame
->player
[1].type
== 0)
1483 thegame
->player
[1].timer
= newtimer
;
1485 setupmove (thegame
);
1494 ** analyse the entries added to the gamelog
1495 ** since the last time we ran this function
1496 ** show what needs to be shown to the user
1498 void analysemove (gamestruct
* thegame
, int playertype
)
1500 int counter
= thegame
->movecounter
+ 1;
1503 while ((item
= logitemnr (thegame
->movelog
, counter
)) != NULL
)
1505 switch (logitem_type (item
))
1508 showmove (thegame
, playertype
, item
);
1511 showremgipf (thegame
, playertype
, item
);
1514 showremrow (thegame
, playertype
, item
);
1519 playertype
= 1; /* necessary in case a row is removed automatically */
1521 thegame
->movecounter
= counter
- 1;
1523 /* show the correct board */
1524 gameboard
->setboard (thegame
->boards
[0]);
1530 void showmove (gamestruct
* thegame
, int playertype
, logitem
* item
)
1532 char start
[3] = " ",
1534 position
* startpos
,
1549 strncpy (start
, logitem_start (item
), 2);
1550 strncpy (end
, logitem_end (item
), 2);
1551 startpos
= strtopos (start
);
1552 endpos
= strtopos (end
);
1553 topos
= new_position ();
1556 **from the start and the end of the move we can find the to-position
1557 ** and the direction of the move
1559 if (posp_col (startpos
) == posp_col (endpos
))
1561 posp_col (topos
) = posp_col (startpos
);
1562 if (posp_row (startpos
) > posp_row (endpos
))
1564 posp_row (topos
) = posp_row (startpos
) - 1;
1569 posp_row (topos
) = posp_row (startpos
) + 1;
1573 else if (posp_col (startpos
) < posp_col (endpos
))
1575 posp_col (topos
) = posp_col (startpos
) + 1;
1576 if (posp_row (startpos
) >= posp_row (endpos
))
1578 posp_row (topos
) = posp_row (startpos
);
1583 posp_row (topos
) = posp_row (startpos
) + 1;
1589 posp_col (topos
) = posp_col (startpos
) - 1;
1590 if (posp_row (startpos
) >= posp_row (endpos
))
1592 posp_row (topos
) = posp_row (startpos
);
1597 posp_row (topos
) = posp_row (startpos
) + 1;
1603 ** reasons to wait before showing the move
1604 ** - waitcomputer > 0
1605 ** - move by the computer
1607 if ((playertype
!= 0) &&
1608 (thegame
->config
->waitcomputer
> 0))
1609 { /* computerplayer */
1610 if ((logitem_player (item
) == 'O') ||
1611 (logitem_player (item
) == 'X'))
1613 gameboard
->setgipfpossible (1);
1617 gameboard
->setgipfpossible (0);
1619 gameboard
->setfrom (startpos
);
1620 gameboard
->setto (topos
);
1622 /* the first Fl::wait is necessary to reset the start of the timer */
1624 for (float time
= thegame
->config
->waitcomputer
* 1.0; time
> 0; )
1625 time
= Fl::wait(time
);
1629 sleep (thegame
->config
->waitcomputer
* 1000);
1631 sleep (thegame
->config
->waitcomputer
);
1635 gameboard
->setto (NULL
);
1636 gameboard
->setfrom (NULL
);
1640 ** make a list of all the pieces that move
1641 ** + from and to position
1643 plist
= (listheader
*) malloc (sizeof (listheader
));
1645 mpiece
= (struct movepiece
*) malloc (sizeof (struct movepiece
));
1646 mpiece
->piece
= logitem_player (item
);
1647 mpiece
->from
= (position
*) copy_position ((void *) startpos
);
1648 mpiece
->to
= (position
*) copy_position ((void *) topos
);
1649 pushll (plist
, mpiece
);
1650 while ((posp_col (topos
) != posp_col (endpos
)) ||
1651 (posp_row (topos
) != posp_row (endpos
)))
1653 posp_col (startpos
) = posp_col (topos
);
1654 posp_row (startpos
) = posp_row (topos
);
1656 b_buren
[posp_col (startpos
)][posp_row (startpos
)][dir
][0];
1658 b_buren
[posp_col (startpos
)][posp_row (startpos
)][dir
][1];
1660 mpiece
= (struct movepiece
*) malloc (sizeof (struct movepiece
));
1661 mpiece
->piece
= b_ppiece (gameboard
->getboard (), startpos
);
1662 mpiece
->from
= (position
*) copy_position ((void *) startpos
);
1663 mpiece
->to
= (position
*) copy_position ((void *) topos
);
1664 pushll (plist
, mpiece
);
1668 ** reason to animate the move
1671 if (thegame
->config
->animate
> 0)
1674 switch (thegame
->config
->animate
)
1679 case 2: /* medium */
1686 gameboard
->initanim (steps
, plist
);
1689 for (int i
= 0; i
<= steps
; i
++)
1691 gameboard
->animstep (i
);
1693 /* this timing looks a little better on ms windows */
1694 for (float time
= 0.02; time
> 0; )
1695 time
= Fl::wait(time
);
1697 for (float time
= 0.03; time
> 0; )
1698 time
= Fl::wait(time
);
1704 nboard
= oldboard
= gameboard
->getboard ();
1706 while ((mpiece
= (struct movepiece
*) llitembynr (plist
, counter
))
1710 newboard
= b_edit_piece (nboard
, mpiece
->to
, mpiece
->piece
);
1711 if (nboard
!= oldboard
)
1715 gameboard
->setboard (nboard
);
1716 if (nboard
!= oldboard
)
1720 while ((mpiece
= (struct movepiece
*) llrembynr (plist
, 1)) != NULL
)
1722 free (mpiece
->from
);
1727 del_position (startpos
);
1728 del_position (endpos
);
1729 del_position (topos
);
1735 void showremgipf (gamestruct
* thegame
, int playertype
, logitem
* item
)
1737 listheader
* piecelist
;
1744 piecelist
= logitem_plist (item
);
1745 piece
= (char *) llitembynr (piecelist
, 1);
1746 strncpy (posstr
, piece
, 2);
1747 ppos
= strtopos (posstr
);
1750 ** reasons for showing the removal of a gipf
1752 ** - gipf removed by a computer-player
1754 if ((playertype
!= 0) &&
1755 (thegame
->config
->waitremove
> 0))
1756 { /* computerplayer */
1757 gameboard
->setfrom (NULL
);
1758 gameboard
->setto (ppos
);
1760 /* the first Fl::wait is necessary to reset the start of the timer */
1762 for (float time
= thegame
->config
->waitremove
* 1.0; time
> 0; )
1763 time
= Fl::wait(time
);
1767 sleep (thegame
->config
->waitremove
* 1000);
1769 sleep (thegame
->config
->waitremove
);
1773 gameboard
->setto (NULL
);
1775 /* now we update the gameboard */
1776 oldboard
= gameboard
->getboard ();
1777 newboard
= b_edit_piece (oldboard
, ppos
, '.');
1778 gameboard
->setboard (newboard
);
1781 del_position (ppos
);
1787 void showremrow (gamestruct
* thegame
, int playertype
, logitem
* item
)
1789 listheader
* poslist
,
1791 char start
[3] = " ",
1805 strncpy (start
, logitem_start (item
), 2);
1806 strncpy (end
, logitem_end (item
), 2);
1807 startpos
= strtopos (start
);
1808 endpos
= strtopos (end
);
1810 /* find the direction between start and end */
1811 if (posp_col (startpos
) == posp_col (endpos
))
1813 if (posp_row (startpos
) > posp_row (endpos
))
1818 else if (posp_col (startpos
) < posp_col (endpos
))
1820 if (posp_row (startpos
) > posp_row (endpos
))
1822 else if (posp_row (startpos
) < posp_row (endpos
))
1826 if (posp_col (startpos
) < 4)
1834 if (posp_row (startpos
) > posp_row (endpos
))
1836 else if (posp_row (startpos
) < posp_row (endpos
))
1840 if (posp_col (startpos
) > 4)
1848 /* make a list with all positions between start and end */
1849 piecelist
= logitem_plist (item
);
1850 poslist
= (listheader
*) malloc (sizeof (listheader
));
1853 pushll (poslist
, startpos
);
1856 while ((b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][0]
1857 != posp_col(endpos
)) ||
1858 (b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][1]
1859 != posp_row(endpos
)))
1861 ppos
= new_position ();
1862 posp_col(ppos
) = b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][0];
1863 posp_row(ppos
) = b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][1];
1865 pushll (poslist
, ppos
);
1868 pushll (poslist
, endpos
);
1871 ** reasons for showing the removal of a row
1873 ** - row automatically removed
1874 ** or row removed by a computer-player
1876 if ((playertype
!= 0) &&
1877 (thegame
->config
->waitremove
> 0))
1878 { /* computerplayer */
1879 gameboard
->setrow (poslist
);
1881 /* the first Fl::wait is necessary to reset the start of the timer */
1883 for (float time
= thegame
->config
->waitremove
* 1.0; time
> 0; )
1884 time
= Fl::wait(time
);
1888 sleep (thegame
->config
->waitremove
* 1000);
1890 sleep (thegame
->config
->waitremove
);
1894 gameboard
->setrow (NULL
);
1897 while ((ppos
= (position
*) llrembynr (poslist
, 1)) != NULL
)
1903 /* now we update the gameboard */
1904 poslist
= logitem_plist (item
);
1905 oldboard
= gameboard
->getboard ();
1908 while ((ptr
= (char *) llitembynr (poslist
, counter
)) != 0)
1911 strncpy (posstr
, ptr
, 2);
1912 ppos
= strtopos (posstr
);
1913 newboard
= b_edit_piece (nboard
, ppos
, '.');
1914 if (nboard
!= oldboard
)
1919 gameboard
->setboard (nboard
);
1921 if (nboard
!= oldboard
)
1929 ** this doesn't make gif-files anymore, but png-files
1931 void show_makegif (board
* game
)
1938 static int def_size
= 300,
1941 gifw
= make_gifwindow ();
1943 // set default values
1944 gif_filename
->value ("./game.png");
1945 gif_size
->value (def_size
);
1947 gif_colour
->setonly ();
1950 gif_extratext
->value (NULL
);
1959 while ((x
= Fl::readqueue()))
1961 if (x
== gif_choose
)
1963 if ((str
= file_chooser ("Filename", "*.gif",
1964 gif_filename
->value ())) != NULL
)
1966 gif_filename
->value (str
);
1969 else if (x
== gif_ok
)
1971 drawing
.filename (gif_filename
->value ());
1972 def_size
= (int) gif_size
->value ();
1973 drawing
.gifsize (def_size
);
1974 drawing
.gifboard (game
);
1975 if (gif_colour
->value ())
1979 drawing
.gifcolour (def_colour
);
1981 str
= gif_extratext
->value ();
1982 // check if the string contains something
1983 for (i
= 0; i
< strlen (str
); i
++)
1985 if (! isspace ((int) str
[i
]))
1987 drawing
.addtext (str
);
1996 else if (x
== gif_cancel
)