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.
30 #include <FL/fl_draw.H>
34 #include "gettimeofday.h"
40 #include "callbacks.h"
41 #include "player_info.h"
45 char gametype
[4][15] = {"basic", "standard", "tournament", "other game"};
46 char playertype
[2][9] = {"human", "computer"};
49 ** show the window for starting a new game
51 ** if the user pressed OK, this will return a structure for starting
54 ** if you give a parameter different from NULL, then the window will be
55 ** initialised from this game, otherwise, defaults are used
57 gamestruct
* show_new (gamestruct
* oldgame
)
62 neww
= make_newwindow ();
68 switch (oldgame
->game_type
)
71 radio_basic
->setonly();
74 radio_standard
->setonly();
77 radio_tournament
->setonly();
82 whiteplayername
->value (oldgame
->player
[0].name
);
83 blackplayername
->value (oldgame
->player
[1].name
);
86 if (oldgame
->player
[0].type
)
87 radio_wcompu
->setonly();
89 radio_whuman
->setonly();
91 if (oldgame
->player
[1].type
)
92 radio_bcompu
->setonly();
94 radio_bhuman
->setonly();
97 if (oldgame
->player
[0].fulltime
== -1)
99 toggle_timedgame
->clear();
103 toggle_timedgame
->set();
104 whitetime
->value (oldgame
->player
[0].fulltime
/ 60);
105 blacktime
->value (oldgame
->player
[1].fulltime
/ 60);
110 radio_tournament
->setonly();
111 toggle_timedgame
->clear();
112 radio_whuman
->setonly();
113 radio_bcompu
->setonly();
116 // show or hide the time-counters
117 if (toggle_timedgame
->value())
119 whitetime
->activate();
120 blacktime
->activate();
124 whitetime
->deactivate();
125 blacktime
->deactivate();
135 while ((x
= Fl::readqueue()))
137 if (x
== toggle_timedgame
)
139 if (toggle_timedgame
->value())
141 whitetime
->activate();
142 blacktime
->activate();
146 whitetime
->deactivate();
147 blacktime
->deactivate();
150 else if (x
== new_ok
)
152 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
153 newgame
->state
= GAME_GO
;
154 newgame
->movecounter
= 0;
156 if (radio_whuman
->value())
157 newgame
->player
[0].type
= 0;
159 newgame
->player
[0].type
= 1;
160 if (radio_bhuman
->value())
161 newgame
->player
[1].type
= 0;
163 newgame
->player
[1].type
= 1;
165 strcpy (newgame
->player
[0].name
, whiteplayername
->value());
166 strcpy (newgame
->player
[1].name
, blackplayername
->value());
168 if (toggle_timedgame
->value())
170 newgame
->player
[0].fulltime
= 60 * (int)whitetime
->value();
171 newgame
->player
[0].timer
=
172 (float) newgame
->player
[0].fulltime
;
173 newgame
->player
[1].fulltime
= 60 * (int)blacktime
->value();
174 newgame
->player
[1].timer
=
175 (float) newgame
->player
[1].fulltime
;
179 newgame
->player
[0].fulltime
= -1;
180 newgame
->player
[0].timer
= 0.0;
181 newgame
->player
[1].fulltime
= -1;
182 newgame
->player
[1].timer
= 0.0;
185 if (radio_basic
->value ()) { newgame
->game_type
= T_BASIC
;}
186 else if (radio_standard
->value ())
187 { newgame
->game_type
= T_STANDARD
;}
188 else if (radio_tournament
->value ())
189 { newgame
->game_type
= T_TOURNAMENT
;}
190 else { return (NULL
);}
192 newgame
->boards
[0] = b_new (newgame
->game_type
);
193 newgame
->boards
[1] = NULL
;
194 newgame
->boards
[2] = NULL
;
196 // initialize players
197 newgame
->player
[0].self
=
198 (* players
[newgame
->player
[0].type
].newfunc
)
199 ('o', newgame
->game_type
);
200 newgame
->player
[1].self
=
201 (* players
[newgame
->player
[1].type
].newfunc
)
202 ('x', newgame
->game_type
);
204 newgame
->movelog
= newlog (gametype
[newgame
->game_type
],
205 newgame
->player
[0].name
,
206 newgame
->player
[1].name
);
210 setcurrentfilename ("\0");
214 else if (x
== new_cancel
)
227 ** show the window for starting a game from a gameboard
229 ** if the user pressed OK, this will return a structure for starting
232 ** the parameter is the board to start from
234 gamestruct
* show_start (board
* startboard
)
237 gamestruct
* newgame
;
240 if ((newboard
= verify_board (startboard
)) == NULL
)
245 startw
= make_startwindow ();
247 /* put default settings in window */
248 radio_white
->setonly ();
249 radio_s_whuman
->setonly ();
250 radio_s_bcompu
->setonly ();
251 if (newboard
->typewhite
== 'g')
252 toggle_s_whitegipf
->set ();
254 toggle_s_whitegipf
->deactivate ();
255 if (newboard
->typeblack
== 'g')
256 toggle_s_blackgipf
->set ();
258 toggle_s_blackgipf
->deactivate ();
267 while ((x
= Fl::readqueue()))
271 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
272 newgame
->state
= GAME_GO
;
273 newgame
->movecounter
= 0;
275 if (radio_s_whuman
->value() != 0)
276 newgame
->player
[0].type
= 0;
278 newgame
->player
[0].type
= 1;
280 if (radio_s_bhuman
->value() != 0)
281 newgame
->player
[1].type
= 0;
283 newgame
->player
[1].type
= 1;
285 strcpy (newgame
->player
[0].name
, s_whiteplayername
->value());
286 strcpy (newgame
->player
[1].name
, s_blackplayername
->value());
288 newgame
->player
[0].fulltime
= -1;
289 newgame
->player
[0].timer
= 0.0;
290 newgame
->player
[1].fulltime
= -1;
291 newgame
->player
[1].timer
= 0.0;
293 newgame
->game_type
= T_OTHER
;
295 if ((newboard
->typewhite
== 'g') &&
296 (toggle_s_whitegipf
->value () == 0))
297 newboard
->typewhite
= 'n';
298 if ((newboard
->typeblack
== 'g') &&
299 (toggle_s_blackgipf
->value () == 0))
300 newboard
->typeblack
= 'n';
302 if (radio_white
->value () != 0)
303 newboard
->nextpiece
= 'o';
305 newboard
->nextpiece
= 'x';
307 newgame
->boards
[0] = newboard
;
308 newgame
->boards
[1] = NULL
;
309 newgame
->boards
[2] = NULL
;
311 // initialize players
312 newgame
->player
[0].self
=
313 (* players
[newgame
->player
[0].type
].newfunc
)
314 ('o', newgame
->game_type
);
315 newgame
->player
[1].self
=
316 (* players
[newgame
->player
[1].type
].newfunc
)
317 ('x', newgame
->game_type
);
319 newgame
->movelog
= newlog (gametype
[newgame
->game_type
],
320 newgame
->player
[0].name
,
321 newgame
->player
[1].name
);
325 setcurrentfilename ("\0");
329 else if (x
== start_cancel
)
343 ** show the window for calculating one move starting from a gameboard
345 ** if the user pressed OK, this will return a structure for calculating
348 ** the parameter is the board to start from
350 gamestruct
* show_onemove (board
* startboard
, configvalues
* conf
)
352 Fl_Window
* onemovew
;
353 gamestruct
* newgame
;
358 if ((newboard
= verify_board (startboard
)) == NULL
)
363 onemovew
= make_onemovewindow ();
365 radio_c_white
->setonly ();
366 c_level3
->setonly ();
375 while ((x
= Fl::readqueue()))
379 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
380 newgame
->state
= GAME_GO
;
381 newgame
->movecounter
= 0;
383 if (radio_c_white
->value() != 0)
385 newgame
->player
[0].type
= 1;
386 newgame
->player
[1].type
= 0;
387 strcpy (newgame
->player
[0].name
, "Computer");
388 strcpy (newgame
->player
[1].name
, "None");
389 newboard
->nextpiece
= 'o';
393 newgame
->player
[0].type
= 0;
394 newgame
->player
[1].type
= 1;
395 strcpy (newgame
->player
[1].name
, "Computer");
396 strcpy (newgame
->player
[0].name
, "None");
397 newboard
->nextpiece
= 'x';
400 newgame
->player
[0].fulltime
= -1;
401 newgame
->player
[0].timer
= 0.0;
402 newgame
->player
[1].fulltime
= -1;
403 newgame
->player
[1].timer
= 0.0;
405 newgame
->game_type
= T_OTHER
;
407 newgame
->boards
[0] = newboard
;
408 newgame
->boards
[1] = NULL
;
409 newgame
->boards
[2] = NULL
;
411 newgame
->config
= conf
;
413 // initialize players
414 newgame
->player
[0].self
=
415 (* players
[newgame
->player
[0].type
].newfunc
)
416 ('o', newgame
->game_type
);
417 newgame
->player
[1].self
=
418 (* players
[newgame
->player
[1].type
].newfunc
)
419 ('x', newgame
->game_type
);
421 newgame
->movelog
= newlog (gametype
[newgame
->game_type
],
422 newgame
->player
[0].name
,
423 newgame
->player
[1].name
);
425 if ((c_level1
->value ()) != 0) { newlevel
= 1; }
426 else if ((c_level2
->value ()) != 0) { newlevel
= 2; }
427 else if ((c_level3
->value ()) != 0) { newlevel
= 3; }
428 else if ((c_level4
->value ()) != 0) { newlevel
= 4; }
429 else if ((c_level5
->value ()) != 0) { newlevel
= 5; }
430 else if ((c_level6
->value ()) != 0) { newlevel
= 6; }
431 else if ((c_level7
->value ()) != 0) { newlevel
= 7; }
432 else if ((c_level8
->value ()) != 0) { newlevel
= 8; }
434 oldlevel
= conf
->searchdepth
;
435 if (newlevel
!= oldlevel
)
437 conf
->searchdepth
= newlevel
;
443 setcurrentfilename ("\0");
445 /* execute the move here */
446 gameboard
->setboard (newgame
->boards
[0]);
450 newgame
->state
= GAME_STOP
;
451 changeinterface (INTERFACE_PLAY
, newgame
);
453 if (newlevel
!= oldlevel
)
455 conf
->searchdepth
= oldlevel
;
461 else if (x
== one_cancel
)
475 ** check if a gameboard can be used to start a game from
477 ** returns a copy of sboard that is correctly setup
478 ** or NULL if there is a problem
480 board
* verify_board (board
* sboard
)
489 /* check if one of the players has no pieces left */
490 if (b_colour (sboard
, 'o') == 0)
492 gf1_alert ("ERROR: no game possible from this boardsituation, player white has no pieces left.");
495 if (b_colour (sboard
, 'x') == 0)
497 gf1_alert ("ERROR: no game possible from this boardsituation, player black has no pieces left.");
501 /* count pieces on the board */
502 pos
= new_position ();
503 for (i
= 1; i
< 8; i
++)
504 for (j
= 2; j
<= b_colsize (i
); j
++)
508 switch (b_ppiece (sboard
, pos
))
525 /* check if the board is empty */
526 if ((white
== 0) && (black
== 0))
528 gf1_alert ("ERROR: no game possible from this boardsituation, the gameboard is empty.");
532 /* check for four-in-a-row */
533 for (i
= 0; i
< 21; i
++)
535 if ((row_ptr
= b_rowoffour (sboard
, i
)) != NULL
)
537 del_rem_row ((void *) row_ptr
);
538 gf1_alert ("ERROR: no game possible from this boardsituation, four-in-a-row found.");
543 /* check if this is a basic game */
544 if ((b_colour_gipf (sboard
, 'o') == 0) &&
545 (b_colour_gipf (sboard
, 'x') == 0))
547 nboard
= b_copy (sboard
);
548 nboard
->gipfwhite
= -1;
549 nboard
->gipfblack
= -1;
550 nboard
->typewhite
= 'n';
551 nboard
->typeblack
= 'n';
553 /* turn this into a real basic game (if possible) */
554 if ((b_colour (nboard
, 'o') > 3) && (b_colour (sboard
, 'x') > 3))
563 /* tournament or standard game, for me it's always tournament */
566 ** something is wrong when a player has normal pieces, but
569 /* check if one of the player has single pieces, but no gipf-pieces */
570 if ((b_colour_gipf (sboard
, 'o') == 0) && (b_colour (sboard
, 'o') < 18))
572 gf1_alert ("ERROR: no game possible from this boardsituation, player white has no gipf-pieces.");
575 if ((b_colour_gipf (sboard
, 'x') == 0) && (b_colour (sboard
, 'x') < 18))
577 gf1_alert ("ERROR: no game possible from this boardsituation, player black has no gipf-pieces.");
581 nboard
= b_copy (sboard
);
582 nboard
->typewhite
= 'n';
583 nboard
->typeblack
= 'n';
584 if ((18 - b_colour_gipf (sboard
, 'o') * 2) == b_colour (sboard
, 'o'))
585 { /* only gipf-pieces, allow player to add more */
586 nboard
->typewhite
= 'g';
588 if ((18 - b_colour_gipf (sboard
, 'x') * 2) == b_colour (sboard
, 'x'))
589 { /* only gipf-pieces, allow player to add more */
590 nboard
->typeblack
= 'g';
593 ** I don't check here if the players have 18 pieces
594 ** which means that it's not completely correct
601 void delete_game (gamestruct
* gameptr
)
608 /* ask the player to cleanup its data */
609 if (gameptr
->player
[0].self
!= NULL
)
611 (* players
[gameptr
->player
[0].type
].endfunc
) (gameptr
->player
[0].self
);
613 if (gameptr
->player
[1].self
!= NULL
)
615 (* players
[gameptr
->player
[1].type
].endfunc
) (gameptr
->player
[1].self
);
618 for (i
= 0; i
< 3; i
++)
620 b_del (gameptr
->boards
[i
]);
623 deletelog (gameptr
->movelog
);
629 ** REMARK: this is the old version
631 ** load a game from a file
633 ** return NULL if nothing loaded
635 gamestruct
* oldloadgame (const char * filename
)
642 gamestruct
* newgame
;
644 if ((fp
= fopen (filename
, "r")) == NULL
)
646 gf1_alert (" ERROR: Can't open the file");
650 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
651 newgame
->state
= GAME_GO
;
653 fgets (buffer
, 100, fp
);
654 if (strncmp (buffer
, "# saved game for gf1", 20) != 0)
656 gf1_alert (" ERROR: wrong inputfile format");
661 fgets (buffer
, 100, fp
);
662 if (sscanf (buffer
, "# gametype: %d", &(newgame
->game_type
)) != 1)
664 gf1_alert (" ERROR: wrong inputfile format");
669 for (i
= 0; i
< 2; i
++)
671 fgets (buffer
, 100, fp
);
672 if (sscanf (buffer
, "# player%d type: %d",
673 &tempnr
, &(newgame
->player
[i
].type
)) != 2)
675 gf1_alert (" ERROR: wrong inputfile format");
680 fgets (buffer
, 100, fp
);
681 sprintf (tempstr
, "# player%d name: ", i
);
682 if (strncmp (buffer
, tempstr
, 16) != 0)
684 gf1_alert (" ERROR: wrong inputfile format");
688 buffer
[strlen(buffer
) - 1] = '\0';
689 strcpy (newgame
->player
[i
].name
, buffer
+16);
691 fgets (buffer
, 100, fp
);
692 if (sscanf (buffer
, "# player%d fulltime: %d",
693 &tempnr
, &(newgame
->player
[i
].fulltime
)) != 2)
695 gf1_alert (" ERROR: wrong inputfile format");
700 fgets (buffer
, 100, fp
);
701 if (sscanf (buffer
, "# player%d timer: %f",
702 &tempnr
, &(newgame
->player
[i
].timer
)) != 2)
704 gf1_alert (" ERROR: wrong inputfile format");
709 newgame
->player
[i
].self
= NULL
;
712 fgets (buffer
, 100, fp
);
713 if ((newgame
->boards
[0] = b_from_file (fp
)) == NULL
)
715 gf1_alert (" ERROR: wrong inputfile format");
719 newgame
->boards
[1] = NULL
;
720 newgame
->boards
[2] = NULL
;
722 fgets (buffer
, 100, fp
);
723 if ((newgame
->movelog
= logfromfile (fp
)) == NULL
)
725 gf1_alert (" ERROR: wrong inputfile format");
729 newgame
->movecounter
= loglength (newgame
->movelog
);
733 // reading was succesfull, init the players
734 newgame
->player
[0].self
=
735 (* players
[newgame
->player
[0].type
].newfunc
) ('o', newgame
->game_type
);
736 newgame
->player
[1].self
=
737 (* players
[newgame
->player
[1].type
].newfunc
) ('x', newgame
->game_type
);
744 ** load a game from a file
746 ** return NULL if nothing loaded
748 gamestruct
* loadgame (void)
750 const char * filename
;
755 gamestruct
* newgame
;
756 xmlite_entity
* root
, *x1
;
757 xmlite_parser
* theparser
;
760 if ((filename
= file_chooser ("load game", "*.gf1", NULL
)) == NULL
)
765 if ((fp
= fopen (filename
, "r")) == NULL
)
767 gf1_alert (" ERROR: Can't open the file");
771 fgets (buffer
, 100, fp
);
773 if (strncmp (buffer
, "# saved game for gf1", 20) == 0)
775 return (oldloadgame (filename
));
778 theparser
= new xmlite_parser (filename
);
779 root
= theparser
->parse ();
784 gf1_alert (" ERROR: Can't parse savefile");
788 if (root
->getname() != "gipfgame")
791 gf1_alert (" ERROR: Not a savefile from gf1");
795 if (atoi (root
->getattribute("formatversion").c_str()) > 1)
798 gf1_alert (" ERROR: Don't know how to handle this fileversion");
802 newgame
= (gamestruct
*) malloc (sizeof (gamestruct
));
803 newgame
->state
= GAME_GO
;
806 strcpy (tempstr
, root
->getattribute("type").c_str());
807 newgame
->game_type
= 3; // put some default value in
808 for (i
= 0; i
< 4; i
++)
810 if (strcmp (tempstr
, gametype
[i
]) == 0)
812 newgame
->game_type
= i
;
818 x1
= root
->getcontentbyname ("whiteplayer");
819 strcpy (newgame
->player
[0].name
, x1
->getvalue().c_str());
820 newgame
->player
[0].type
= x1
->getattribute ("type") == "human" ? 0 : 1;
821 newgame
->player
[0].fulltime
= atoi (x1
->getattribute ("fulltime").c_str());
822 newgame
->player
[0].timer
= atof (x1
->getattribute ("timeleft").c_str());
823 newgame
->player
[0].self
= NULL
;
824 x1
= root
->getcontentbyname ("blackplayer");
825 strcpy (newgame
->player
[1].name
, x1
->getvalue().c_str());
826 newgame
->player
[1].type
= x1
->getattribute ("type") == "human" ? 0 : 1;
827 newgame
->player
[1].fulltime
= atoi (x1
->getattribute ("fulltime").c_str());
828 newgame
->player
[1].timer
= atof (x1
->getattribute ("timeleft").c_str());
829 newgame
->player
[1].self
= NULL
;
831 // the boardsituation
832 newgame
->boards
[0] = b_from_xml (root
->getcontentbyname ("board"));
833 newgame
->boards
[1] = NULL
;
834 newgame
->boards
[2] = NULL
;
837 newgame
->movelog
= logfromxml (root
->getcontentbyname ("gamelog"));
838 newgame
->movecounter
= loglength (newgame
->movelog
);
840 // reading was succesfull, init the players
841 newgame
->player
[0].self
=
842 (* players
[newgame
->player
[0].type
].newfunc
) ('o', newgame
->game_type
);
843 newgame
->player
[1].self
=
844 (* players
[newgame
->player
[1].type
].newfunc
) ('x', newgame
->game_type
);
848 setcurrentfilename (filename
);
855 ** save a game to a file
857 void savegame (gamestruct
* gameptr
)
859 const char * filename
;
860 xmlite_entity
*x1
, *x2
;
866 gf1_alert (" no current game to be saved");
871 cfile
= getcurrentfilename ();
872 if (cfile
[0] == '\0')
873 strcpy (tempstr
, "./savegame.gf1");
875 strcpy (tempstr
, cfile
);
876 if ((filename
= file_chooser ("save game", "*.gf1", tempstr
))
883 x1
= new xmlite_entity ("gipfgame");
884 x1
->addattribute ("type", gametype
[gameptr
->game_type
]);
885 x1
->addattribute ("formatversion", "1");
888 x2
= new xmlite_entity ("whiteplayer");
889 sprintf (tempstr
, "%f", gameptr
->player
[0].timer
);
890 x2
->addattribute ("timeleft", tempstr
);
891 sprintf (tempstr
, "%d", gameptr
->player
[0].fulltime
);
892 x2
->addattribute ("fulltime", tempstr
);
893 x2
->addattribute ("type", playertype
[gameptr
->player
[0].type
]);
894 x2
->setvalue (gameptr
->player
[0].name
);
898 x2
= new xmlite_entity ("blackplayer");
899 sprintf (tempstr
, "%f", gameptr
->player
[1].timer
);
900 x2
->addattribute ("timeleft", tempstr
);
901 sprintf (tempstr
, "%d", gameptr
->player
[1].fulltime
);
902 x2
->addattribute ("fulltime", tempstr
);
903 x2
->addattribute ("type", playertype
[gameptr
->player
[1].type
]);
904 x2
->setvalue (gameptr
->player
[1].name
);
908 x2
= b_to_xml (gameptr
->boards
[0]);
912 x2
= logtoxml (gameptr
->movelog
);
915 x1
->writetofile (filename
);
918 setcurrentfilename (filename
);
924 void setupmove (gamestruct
* thegame
)
930 if ((thegame
== NULL
) || (thegame
->state
== GAME_STOP
))
932 changeinterface (INTERFACE_PLAY
, thegame
);
940 if (thegame
->player
[0].fulltime
!= -1)
942 if (thegame
->player
[0].timer
<= 0.0)
947 if (thegame
->player
[1].timer
<= 0.0)
954 if (interrupt_computer
)
957 interrupt_computer
= 0;
958 thegame
->state
= GAME_STOP
;
962 changeinterface (INTERFACE_PLAY
, thegame
);
964 if (b_status (thegame
->boards
[0]) == S_NORMAL
)
966 nextpiece
= b_next_piece (thegame
->boards
[0]);
967 /* check if gipf-pieces left */
968 if (thegame
->game_type
!= T_BASIC
)
970 if (((b_move_counter (thegame
->boards
[0]) > 1) ||
971 (thegame
->game_type
== T_OTHER
) || (nextpiece
== 'x')) &&
972 (b_white_gipf (thegame
->boards
[0]) == 0))
977 else if ((b_move_counter (thegame
->boards
[0]) > 1) &&
978 (b_black_gipf (thegame
->boards
[0]) == 0))
984 if (b_colour (thegame
->boards
[0], nextpiece
) == 0)
985 { /* game finished */
986 winner
= b_opponent (nextpiece
);
990 if (thegame
->player
[pnr(nextpiece
)].type
== 0)
992 gameboard
->setto (NULL
);
993 gameboard
->setfrom (NULL
);
994 if (b_colour_type (thegame
->boards
[0], nextpiece
) == 'g')
995 gameboard
->setgipfpossible (1);
997 gameboard
->setgipfpossible (0);
999 starttimer (thegame
, nextpiece
);
1003 { /* computer player */
1004 fl_cursor (FL_CURSOR_WAIT
);
1007 computermove (thegame
);
1009 fl_cursor (FL_CURSOR_DEFAULT
);
1012 else if (b_status (thegame
->boards
[0]) == S_REMOVEGIPF
)
1014 gipf_questions (thegame
);
1016 else if (b_status (thegame
->boards
[0]) == S_REMOVEROW
)
1018 row_questions (thegame
);
1024 sprintf (tempstr
, "Player %s, you have won after %d moves !",
1025 thegame
->player
[pnr(winner
)].name
,
1026 b_move_counter (thegame
->boards
[0]));
1027 gf1_alert (tempstr
);
1028 thegame
->state
= GAME_STOP
;
1031 changeinterface (INTERFACE_PLAY
, thegame
);
1037 void computermove (gamestruct
* thegame
)
1047 Fl_Window
* thinkwindow
;
1049 temp_board
= b_copy (thegame
->boards
[0]);
1050 nextpiece
= b_next_piece (thegame
->boards
[0]);
1051 piecetype
= b_colour_type (thegame
->boards
[0], nextpiece
);
1052 playertype
= thegame
->player
[pnr(nextpiece
)].type
;
1054 starttimer (thegame
, nextpiece
);
1056 thinkwindow
= create_thinkwindow ();
1058 (* players
[playertype
].movefunc
)
1059 (temp_board
, thegame
->player
[pnr(nextpiece
)].self
,
1060 thegame
->player
[pnr(nextpiece
)].timer
,
1061 &piecetype
, from
, to
);
1066 stoptimer (thegame
);
1067 if (interrupt_computer
)
1070 if ((b_colour_type (thegame
->boards
[0], nextpiece
) != 'g') &&
1076 piece
= piecetype
== 'g' ? b_otherpiece (nextpiece
) : nextpiece
;
1078 b_setlog (thegame
->boards
[0], thegame
->movelog
);
1079 new_board
= b_move (thegame
->boards
[0], from
, to
, piece
);
1080 b_nolog (thegame
->boards
[0]);
1081 b_nolog (new_board
);
1084 if (new_board
== NULL
)
1086 gf1_alert ("the computer-player executed an invalid move !!");
1088 // b_del (thegame->boards[0]);
1089 // (* players[thegame->player[0].type].endfunc)(thegame->player[0].self);
1090 // (* players[thegame->player[1].type].endfunc)(thegame->player[1].self);
1091 // thegame->boards[0] = NULL;
1095 b_del (thegame
->boards
[2]);
1096 thegame
->boards
[2] = thegame
->boards
[1];
1097 thegame
->boards
[1] = thegame
->boards
[0];
1098 thegame
->boards
[0] = new_board
;
1100 analysemove (thegame
, playertype
);
1102 gameboard
->setboard (thegame
->boards
[0]);
1109 int humanmove (gamestruct
* thegame
)
1114 board
* new_board
= NULL
;
1119 if (thegame
->state
== GAME_STOP
)
1122 from
= postostr (gameboard
->getfrom ());
1123 to
= postostr (gameboard
->getto ());
1124 if (gameboard
->getptype ())
1129 nextpiece
= b_next_piece (thegame
->boards
[0]);
1130 playertype
= thegame
->player
[pnr(nextpiece
)].type
;
1132 if ((b_colour_type (thegame
->boards
[0], nextpiece
) != 'g') &&
1138 piece
= piecetype
== 'g' ? b_otherpiece (nextpiece
) : nextpiece
;
1140 b_setlog (thegame
->boards
[0], thegame
->movelog
);
1141 new_board
= b_move (thegame
->boards
[0], from
, to
, piece
);
1142 b_nolog (thegame
->boards
[0]);
1143 if (new_board
!= NULL
)
1144 b_nolog (new_board
);
1149 if (new_board
== NULL
)
1154 stoptimer (thegame
);
1156 b_del (thegame
->boards
[2]);
1157 thegame
->boards
[2] = thegame
->boards
[1];
1158 thegame
->boards
[1] = thegame
->boards
[0];
1159 thegame
->boards
[0] = new_board
;
1161 analysemove (thegame
, 0);
1163 gameboard
->setto (NULL
);
1164 gameboard
->setfrom (NULL
);
1165 gameboard
->setboard (thegame
->boards
[0]);
1171 void row_questions (gamestruct
* thegame
)
1177 listheader
* rowlist
;
1186 temp_board
= b_copy (thegame
->boards
[0]);
1188 rowlist
= b_row_extra (thegame
->boards
[0]);
1189 while ((row
= (rem_row
*) llitembynr (rowlist
, counter
)) != NULL
)
1192 start
= postostr (row
->startpos
);
1193 end
= postostr (row
->endpos
);
1194 owner
= row_owner (row
);
1196 starttimer (thegame
, owner
);
1197 if (thegame
->player
[pnr(owner
)].type
== 0)
1199 gameboard
->setrow (row
->piecelist
);
1200 gameboard
->setboard (thegame
->boards
[0]);
1202 sprintf (tempstr1
, "Player %s, do you want to remove",
1203 thegame
->player
[pnr(owner
)].name
);
1204 sprintf (tempstr2
, "the row from %s to %s", start
, end
);
1209 answer
= gf1_questionsave (tempstr1
, tempstr2
);
1213 else if (answer
== 1)
1219 gameboard
->setrow (NULL
);
1223 Fl_Window
* thinkwindow
;
1225 thinkwindow
= create_thinkwindow ();
1228 (* players
[thegame
->player
[pnr(owner
)].type
].rowfunc
)
1229 (temp_board
, thegame
->player
[pnr(owner
)].self
,
1230 thegame
->player
[pnr(owner
)].timer
, start
, end
);
1234 stoptimer (thegame
);
1235 if (interrupt_computer
)
1241 if (response
== 'y')
1243 b_setlog (thegame
->boards
[0], thegame
->movelog
);
1244 new_board
= b_remove_row (thegame
->boards
[0], counter
-1);
1245 b_nolog (new_board
);
1246 b_del (thegame
->boards
[0]);
1247 thegame
->boards
[0] = new_board
;
1249 analysemove (thegame
, thegame
->player
[pnr(owner
)].type
);
1251 gameboard
->setboard (thegame
->boards
[0]);
1262 void gipf_questions (gamestruct
* thegame
)
1269 listheader
* gipflist
;
1278 gipflist
= b_gipf_extra (thegame
->boards
[0]);
1279 new_board
= thegame
->boards
[0];
1281 while ((gipf
= (rem_gipf
*) llitembynr (gipflist
, counter
)) != NULL
)
1284 strpos
= b_gipf_position (gipf
);
1285 owner
= b_gipf_owner (gipf
);
1287 starttimer (thegame
, owner
);
1288 if (thegame
->player
[pnr(owner
)].type
== 0)
1290 gameboard
->setto (gipf
->pos
);
1291 gameboard
->setboard (new_board
);
1293 sprintf (tempstr1
, "Player %s, do you want to remove",
1294 thegame
->player
[pnr(owner
)].name
);
1295 sprintf (tempstr2
, "the GIPF at %s", strpos
);
1301 ** only allow saving of the game at the first question
1302 ** for removing a gipf.
1303 ** things get fishy if you would save from here after a gipf
1304 ** has been removed already.
1305 ** (the problem doesn't occur immediatly, but when you load
1309 answer
= gf1_questionsave (tempstr1
, tempstr2
);
1311 answer
= gf1_question (tempstr1
, tempstr2
);
1316 else if (answer
== 1)
1322 gameboard
->setto (NULL
);
1326 Fl_Window
* thinkwindow
;
1328 thinkwindow
= create_thinkwindow ();
1330 temp_board
= b_copy (new_board
);
1331 response
= (* players
[thegame
->player
[pnr(owner
)].type
].gipffunc
)
1332 (temp_board
, thegame
->player
[pnr(owner
)].self
,
1333 thegame
->player
[pnr(owner
)].timer
, strpos
);
1338 stoptimer (thegame
);
1339 if (interrupt_computer
)
1342 if ((response
== 'y') || (response
== 'Y'))
1344 b_setlog (new_board
, thegame
->movelog
);
1345 nboard
= b_remove_gipf (new_board
, gipf
);
1346 b_nolog (new_board
);
1349 if (new_board
!= thegame
->boards
[0])
1354 analysemove (thegame
, thegame
->player
[pnr(owner
)].type
);
1356 gameboard
->setboard (new_board
);
1361 b_setlog (new_board
, thegame
->movelog
);
1362 nboard
= b_checkfour (new_board
);
1363 b_nolog (new_board
);
1365 if (new_board
!= thegame
->boards
[0])
1368 b_del (thegame
->boards
[0]);
1369 thegame
->boards
[0] = nboard
;
1371 analysemove (thegame
, 1);
1373 gameboard
->setboard (thegame
->boards
[0]);
1379 //time_t basetime = 0;
1380 struct timeval basetime
;
1383 void starttimer (gamestruct
* thegame
, char color
)
1387 if (thegame
->player
[0].fulltime
== -1)
1389 basetime
.tv_sec
= 0;
1393 // basetime = time (NULL);
1394 gettimeofday (&basetime
, &tz
);
1397 Fl::add_timeout (1.0, updatetimer
, (void *) thegame
);
1403 void stoptimer (gamestruct
* thegame
)
1411 if ((thegame
== NULL
) || (basetime
.tv_sec
== 0))
1414 Fl::remove_timeout (updatetimer
, (void *) thegame
);
1416 // newtime = time (NULL);
1417 gettimeofday (&tv
, &tz
);
1418 timedif
= (tv
.tv_sec
- basetime
.tv_sec
) +
1419 (float) (tv
.tv_usec
- basetime
.tv_usec
)/1000000;
1421 if (timercolor
== 'o')
1423 if (interrupt_computer
== 0)
1424 thegame
->player
[0].timer
-= timedif
;
1425 timertostr (thegame
->player
[0].timer
, tempstr
);
1426 whitetimer
->value (tempstr
);
1430 if (interrupt_computer
== 0)
1431 thegame
->player
[1].timer
-= timedif
;
1432 timertostr (thegame
->player
[1].timer
, tempstr
);
1433 blacktimer
->value (tempstr
);
1436 basetime
.tv_sec
= 0;
1441 void updatetimer (void * data
)
1443 gamestruct
* thegame
= (gamestruct
*) data
;
1451 // newtime = time (NULL);
1452 gettimeofday (&tv
, &tz
);
1453 timedif
= (tv
.tv_sec
- basetime
.tv_sec
) +
1454 (float) (tv
.tv_usec
- basetime
.tv_usec
)/1000000;
1456 if (timercolor
== 'o')
1458 newtimer
= thegame
->player
[0].timer
- timedif
;
1459 timertostr (newtimer
, tempstr
);
1460 whitetimer
->value (tempstr
);
1464 newtimer
= thegame
->player
[1].timer
- timedif
;
1465 timertostr (newtimer
, tempstr
);
1466 blacktimer
->value (tempstr
);
1470 Fl::add_timeout (1.0, updatetimer
, data
);
1472 { /* timer ran out, show if this is a human move */
1473 if (timercolor
== 'o')
1475 if (thegame
->player
[0].type
== 0)
1477 thegame
->player
[0].timer
= newtimer
;
1479 setupmove (thegame
);
1482 else if (thegame
->player
[1].type
== 0)
1484 thegame
->player
[1].timer
= newtimer
;
1486 setupmove (thegame
);
1495 ** analyse the entries added to the gamelog
1496 ** since the last time we ran this function
1497 ** show what needs to be shown to the user
1499 void analysemove (gamestruct
* thegame
, int playertype
)
1501 int counter
= thegame
->movecounter
+ 1;
1504 while ((item
= logitemnr (thegame
->movelog
, counter
)) != NULL
)
1506 switch (logitem_type (item
))
1509 showmove (thegame
, playertype
, item
);
1512 showremgipf (thegame
, playertype
, item
);
1515 showremrow (thegame
, playertype
, item
);
1520 playertype
= 1; /* necessary in case a row is removed automatically */
1522 thegame
->movecounter
= counter
- 1;
1524 /* show the correct board */
1525 gameboard
->setboard (thegame
->boards
[0]);
1531 void showmove (gamestruct
* thegame
, int playertype
, logitem
* item
)
1533 char start
[3] = " ",
1535 position
* startpos
,
1550 strncpy (start
, logitem_start (item
), 2);
1551 strncpy (end
, logitem_end (item
), 2);
1552 startpos
= strtopos (start
);
1553 endpos
= strtopos (end
);
1554 topos
= new_position ();
1557 **from the start and the end of the move we can find the to-position
1558 ** and the direction of the move
1560 if (posp_col (startpos
) == posp_col (endpos
))
1562 posp_col (topos
) = posp_col (startpos
);
1563 if (posp_row (startpos
) > posp_row (endpos
))
1565 posp_row (topos
) = posp_row (startpos
) - 1;
1570 posp_row (topos
) = posp_row (startpos
) + 1;
1574 else if (posp_col (startpos
) < posp_col (endpos
))
1576 posp_col (topos
) = posp_col (startpos
) + 1;
1577 if (posp_row (startpos
) >= posp_row (endpos
))
1579 posp_row (topos
) = posp_row (startpos
);
1584 posp_row (topos
) = posp_row (startpos
) + 1;
1590 posp_col (topos
) = posp_col (startpos
) - 1;
1591 if (posp_row (startpos
) >= posp_row (endpos
))
1593 posp_row (topos
) = posp_row (startpos
);
1598 posp_row (topos
) = posp_row (startpos
) + 1;
1604 ** reasons to wait before showing the move
1605 ** - waitcomputer > 0
1606 ** - move by the computer
1608 if ((playertype
!= 0) &&
1609 (thegame
->config
->waitcomputer
> 0))
1610 { /* computerplayer */
1611 if ((logitem_player (item
) == 'O') ||
1612 (logitem_player (item
) == 'X'))
1614 gameboard
->setgipfpossible (1);
1618 gameboard
->setgipfpossible (0);
1620 gameboard
->setfrom (startpos
);
1621 gameboard
->setto (topos
);
1623 /* the first Fl::wait is necessary to reset the start of the timer */
1625 for (float time
= thegame
->config
->waitcomputer
* 1.0; time
> 0; )
1626 time
= Fl::wait(time
);
1630 sleep (thegame
->config
->waitcomputer
* 1000);
1632 sleep (thegame
->config
->waitcomputer
);
1636 gameboard
->setto (NULL
);
1637 gameboard
->setfrom (NULL
);
1641 ** make a list of all the pieces that move
1642 ** + from and to position
1644 plist
= (listheader
*) malloc (sizeof (listheader
));
1646 mpiece
= (struct movepiece
*) malloc (sizeof (struct movepiece
));
1647 mpiece
->piece
= logitem_player (item
);
1648 mpiece
->from
= (position
*) copy_position ((void *) startpos
);
1649 mpiece
->to
= (position
*) copy_position ((void *) topos
);
1650 pushll (plist
, mpiece
);
1651 while ((posp_col (topos
) != posp_col (endpos
)) ||
1652 (posp_row (topos
) != posp_row (endpos
)))
1654 posp_col (startpos
) = posp_col (topos
);
1655 posp_row (startpos
) = posp_row (topos
);
1657 b_buren
[posp_col (startpos
)][posp_row (startpos
)][dir
][0];
1659 b_buren
[posp_col (startpos
)][posp_row (startpos
)][dir
][1];
1661 mpiece
= (struct movepiece
*) malloc (sizeof (struct movepiece
));
1662 mpiece
->piece
= b_ppiece (gameboard
->getboard (), startpos
);
1663 mpiece
->from
= (position
*) copy_position ((void *) startpos
);
1664 mpiece
->to
= (position
*) copy_position ((void *) topos
);
1665 pushll (plist
, mpiece
);
1669 ** reason to animate the move
1672 if (thegame
->config
->animate
> 0)
1675 switch (thegame
->config
->animate
)
1680 case 2: /* medium */
1687 gameboard
->initanim (steps
, plist
);
1690 for (int i
= 0; i
<= steps
; i
++)
1692 gameboard
->animstep (i
);
1694 /* this timing looks a little better on ms windows */
1695 for (float time
= 0.02; time
> 0; )
1696 time
= Fl::wait(time
);
1698 for (float time
= 0.03; time
> 0; )
1699 time
= Fl::wait(time
);
1705 nboard
= oldboard
= gameboard
->getboard ();
1707 while ((mpiece
= (struct movepiece
*) llitembynr (plist
, counter
))
1711 newboard
= b_edit_piece (nboard
, mpiece
->to
, mpiece
->piece
);
1712 if (nboard
!= oldboard
)
1716 gameboard
->setboard (nboard
);
1717 if (nboard
!= oldboard
)
1721 while ((mpiece
= (struct movepiece
*) llrembynr (plist
, 1)) != NULL
)
1723 free (mpiece
->from
);
1728 del_position (startpos
);
1729 del_position (endpos
);
1730 del_position (topos
);
1736 void showremgipf (gamestruct
* thegame
, int playertype
, logitem
* item
)
1738 listheader
* piecelist
;
1745 piecelist
= logitem_plist (item
);
1746 piece
= (char *) llitembynr (piecelist
, 1);
1747 strncpy (posstr
, piece
, 2);
1748 ppos
= strtopos (posstr
);
1751 ** reasons for showing the removal of a gipf
1753 ** - gipf removed by a computer-player
1755 if ((playertype
!= 0) &&
1756 (thegame
->config
->waitremove
> 0))
1757 { /* computerplayer */
1758 gameboard
->setfrom (NULL
);
1759 gameboard
->setto (ppos
);
1761 /* the first Fl::wait is necessary to reset the start of the timer */
1763 for (float time
= thegame
->config
->waitremove
* 1.0; time
> 0; )
1764 time
= Fl::wait(time
);
1768 sleep (thegame
->config
->waitremove
* 1000);
1770 sleep (thegame
->config
->waitremove
);
1774 gameboard
->setto (NULL
);
1776 /* now we update the gameboard */
1777 oldboard
= gameboard
->getboard ();
1778 newboard
= b_edit_piece (oldboard
, ppos
, '.');
1779 gameboard
->setboard (newboard
);
1782 del_position (ppos
);
1788 void showremrow (gamestruct
* thegame
, int playertype
, logitem
* item
)
1790 listheader
* poslist
,
1792 char start
[3] = " ",
1806 strncpy (start
, logitem_start (item
), 2);
1807 strncpy (end
, logitem_end (item
), 2);
1808 startpos
= strtopos (start
);
1809 endpos
= strtopos (end
);
1811 /* find the direction between start and end */
1812 if (posp_col (startpos
) == posp_col (endpos
))
1814 if (posp_row (startpos
) > posp_row (endpos
))
1819 else if (posp_col (startpos
) < posp_col (endpos
))
1821 if (posp_row (startpos
) > posp_row (endpos
))
1823 else if (posp_row (startpos
) < posp_row (endpos
))
1827 if (posp_col (startpos
) < 4)
1835 if (posp_row (startpos
) > posp_row (endpos
))
1837 else if (posp_row (startpos
) < posp_row (endpos
))
1841 if (posp_col (startpos
) > 4)
1849 /* make a list with all positions between start and end */
1850 piecelist
= logitem_plist (item
);
1851 poslist
= (listheader
*) malloc (sizeof (listheader
));
1854 pushll (poslist
, startpos
);
1857 while ((b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][0]
1858 != posp_col(endpos
)) ||
1859 (b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][1]
1860 != posp_row(endpos
)))
1862 ppos
= new_position ();
1863 posp_col(ppos
) = b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][0];
1864 posp_row(ppos
) = b_buren
[posp_col(prevpos
)][posp_row(prevpos
)][dir
][1];
1866 pushll (poslist
, ppos
);
1869 pushll (poslist
, endpos
);
1872 ** reasons for showing the removal of a row
1874 ** - row automatically removed
1875 ** or row removed by a computer-player
1877 if ((playertype
!= 0) &&
1878 (thegame
->config
->waitremove
> 0))
1879 { /* computerplayer */
1880 gameboard
->setrow (poslist
);
1882 /* the first Fl::wait is necessary to reset the start of the timer */
1884 for (float time
= thegame
->config
->waitremove
* 1.0; time
> 0; )
1885 time
= Fl::wait(time
);
1889 sleep (thegame
->config
->waitremove
* 1000);
1891 sleep (thegame
->config
->waitremove
);
1895 gameboard
->setrow (NULL
);
1898 while ((ppos
= (position
*) llrembynr (poslist
, 1)) != NULL
)
1904 /* now we update the gameboard */
1905 poslist
= logitem_plist (item
);
1906 oldboard
= gameboard
->getboard ();
1909 while ((ptr
= (char *) llitembynr (poslist
, counter
)) != 0)
1912 strncpy (posstr
, ptr
, 2);
1913 ppos
= strtopos (posstr
);
1914 newboard
= b_edit_piece (nboard
, ppos
, '.');
1915 if (nboard
!= oldboard
)
1920 gameboard
->setboard (nboard
);
1922 if (nboard
!= oldboard
)
1930 ** this doesn't make gif-files anymore, but png-files
1932 void show_makegif (board
* game
)
1939 static int def_size
= 300,
1942 gifw
= make_gifwindow ();
1944 // set default values
1945 gif_filename
->value ("./game.png");
1946 gif_size
->value (def_size
);
1948 gif_colour
->setonly ();
1951 gif_extratext
->value (NULL
);
1960 while ((x
= Fl::readqueue()))
1962 if (x
== gif_choose
)
1964 if ((str
= file_chooser ("Filename", "*.gif",
1965 gif_filename
->value ())) != NULL
)
1967 gif_filename
->value (str
);
1970 else if (x
== gif_ok
)
1972 drawing
.filename (gif_filename
->value ());
1973 def_size
= (int) gif_size
->value ();
1974 drawing
.gifsize (def_size
);
1975 drawing
.gifboard (game
);
1976 if (gif_colour
->value ())
1980 drawing
.gifcolour (def_colour
);
1982 str
= gif_extratext
->value ();
1983 // check if the string contains something
1984 for (i
= 0; i
< strlen (str
); i
++)
1986 if (! isspace ((int) str
[i
]))
1988 drawing
.addtext (str
);
1997 else if (x
== gif_cancel
)