5 ** Copyright (C) 1998-1999 Kurt Van den Branden
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "configfile.h"
30 extern "C" void checkwindowevents (void);
31 extern int interrupt_computer
;
34 #define TIMEDIVIDER 20
36 /* 84 different possible moves, with gipf-pieces */
38 {"b1","b2",'g'}, {"a1","b2",'g'}, {"a2","b2",'g'},
39 {"a2","b3",'g'}, {"a3","b3",'g'},
40 {"a3","b4",'g'}, {"a4","b4",'g'},
41 {"a4","b5",'g'}, {"a5","b5",'g'}, {"b6","b5",'g'},
42 {"b6","c6",'g'}, {"c7","c6",'g'},
43 {"c7","d7",'g'}, {"d8","d7",'g'},
44 {"d8","e8",'g'}, {"e9","e8",'g'}, {"f8","e8",'g'},
45 {"f8","f7",'g'}, {"g7","f7",'g'},
46 {"g7","g6",'g'}, {"h6","g6",'g'},
47 {"h6","h5",'g'}, {"i5","h5",'g'}, {"i4","h5",'g'},
48 {"i4","h4",'g'}, {"i3","h4",'g'},
49 {"i3","h3",'g'}, {"i2","h3",'g'},
50 {"i2","h2",'g'}, {"i1","h2",'g'}, {"h1","h2",'g'},
51 {"h1","g2",'g'}, {"g1","g2",'g'},
52 {"g1","f2",'g'}, {"f1","f2",'g'},
53 {"f1","e2",'g'}, {"e1","e2",'g'}, {"d1","e2",'g'},
54 {"d1","d2",'g'}, {"c1","d2",'g'},
55 {"c1","c2",'g'}, {"b1","c2",'g'},
56 {"b1","b2",'n'}, {"a1","b2",'n'}, {"a2","b2",'n'},
57 {"a2","b3",'n'}, {"a3","b3",'n'},
58 {"a3","b4",'n'}, {"a4","b4",'n'},
59 {"a4","b5",'n'}, {"a5","b5",'n'}, {"b6","b5",'n'},
60 {"b6","c6",'n'}, {"c7","c6",'n'},
61 {"c7","d7",'n'}, {"d8","d7",'n'},
62 {"d8","e8",'n'}, {"e9","e8",'n'}, {"f8","e8",'n'},
63 {"f8","f7",'n'}, {"g7","f7",'n'},
64 {"g7","g6",'n'}, {"h6","g6",'n'},
65 {"h6","h5",'n'}, {"i5","h5",'n'}, {"i4","h5",'n'},
66 {"i4","h4",'n'}, {"i3","h4",'n'},
67 {"i3","h3",'n'}, {"i2","h3",'n'},
68 {"i2","h2",'n'}, {"i1","h2",'n'}, {"h1","h2",'n'},
69 {"h1","g2",'n'}, {"g1","g2",'n'},
70 {"g1","f2",'n'}, {"f1","f2",'n'},
71 {"f1","e2",'n'}, {"e1","e2",'n'}, {"d1","e2",'n'},
72 {"d1","d2",'n'}, {"c1","d2",'n'},
73 {"c1","c2",'n'}, {"b1","c2",'n'}
77 ai_gipf::ai_gipf (char playercolour
, int gametype
)
79 listheader
* configlist
;
85 colour
= playercolour
;
93 /* check for config-values from the config-file */
94 configlist
= readconfigfile ("gf1.cfg");
96 sd
= findconfigvalue (configlist
, "searchdepth", colour
, 3);
98 md
= findconfigvalue (configlist
, "memorydepth", colour
, 2);
100 rc
= findconfigvalue (configlist
, "randomchoose", colour
, 1);
103 remoppgipf
= findconfigvalue (configlist
, "remoppgipf", colour
, 0);
104 maxgipf
= findconfigvalue (configlist
, "maxgipf", colour
, 3);
105 randomfirstmove
= findconfigvalue (configlist
, "randomfirstmove",
108 clearconfiglist (configlist
);
117 if (movelist
!= NULL
)
119 int len
= movelist
->size(),
122 for (i
= 0; i
< len
; i
++)
123 delete (*movelist
)[i
];
137 {{3, 4}, 2},{{3, 5}, 2},{{4, 6}, 2},{{5, 5}, 2},{{5, 4}, 2},{{4, 4}, 2},
138 {{2, 3}, 1},{{2, 4}, 1},{{2, 5}, 1},{{3, 6}, 1},{{4, 7}, 1},{{5, 6}, 1},
139 {{6, 5}, 1},{{6, 4}, 1},{{6, 3}, 1},{{5, 3}, 1},{{4, 3}, 1},{{3, 3}, 1}
142 int ai_gipf::evalfunc (void * game
, int maxplayer
)
144 board
* oboard
= (board
*) game
;
155 myc
= (maxplayer
== PLAYER1
? 'o': 'x');
156 otherc
= b_opponent (myc
);
158 if (b_game_finished (oboard
))
160 if (b_winner (oboard
) == myc
)
170 /* maybe I can return 1000 or -1000, but I'm not completely sure */
172 ** not sure at all anymore
173 ** what if you start with only GIPF-pieces and remove a GIPF
174 ** only at the start of your move
176 if (b_colour (oboard
, myc
) == 0)
180 else if (b_colour (oboard
, otherc
) == 0)
185 /* I need to start with a base-value, or I get a lot of
186 ** problems at the start of tournament games */
190 /* capturing a piece from your opponent is worth 20 points */
191 wvalue
+= 20 * b_black_lost (oboard
);
192 bvalue
+= 20 * b_white_lost (oboard
);
194 /* 1 point for each piece in use on the board */
195 if (b_white_gipf (oboard
) == -1)
200 wvalue
+= total
- b_white (oboard
) - b_white_lost (oboard
);
201 bvalue
+= total
- b_black (oboard
) - b_black_lost (oboard
);
203 /* 2 pieces or less left is getting dangerous */
205 /* one gipf left can be dangerous, subtract 5 points */
206 if (b_white_gipf (oboard
) == 1)
210 if (b_black_gipf (oboard
) == 1)
215 /* pieces closer to the center have a higher value */
216 for (i
= 0; i
< 19; i
++)
218 pos
= &(pos_val
[i
].coor
);
219 piece
= b_ppiece (oboard
, pos
);
226 wvalue
+= pos_val
[i
].value
;
228 else if (piece
== 'O')
230 wvalue
+= pos_val
[i
].value
* 1.5;
232 else if (piece
== 'x')
234 bvalue
+= pos_val
[i
].value
;
238 bvalue
+= pos_val
[i
].value
* 1.5;
242 /* normalize the result, should be between 1000 and -1000 */
245 value
= (int) ((wvalue
- bvalue
) * 1000 / (wvalue
+ bvalue
));
249 value
= (int) ((bvalue
- wvalue
) * 1000 / (wvalue
+ bvalue
));
256 int ai_gipf::stopfunc (void)
258 checkwindowevents ();
260 if (interrupt_computer
)
267 void ai_gipf::listfunc (void * game
, vector
<basemove
*> & movelist
)
269 board
* oboard
= (board
*) game
;
271 listheader
* movelist
;
273 movelist
= (listheader
*) malloc (sizeof (listheader
));
277 switch (b_status (oboard
))
285 if ((b_colour_type (oboard
, b_next_piece (oboard
)) == 'g') &&
286 (b_colour_gipf (oboard
, b_next_piece (oboard
)) < maxgipf
))
295 for (i
= firstmove
; i
< 84; i
++)
297 if ((i
> firstmove
) &&
298 (newmoves
[i
].to
[0] == newmoves
[i
-1].to
[0]) &&
299 (newmoves
[i
].to
[1] == newmoves
[i
-1].to
[1]) &&
300 (b_piece (oboard
, newmoves
[i
].to
) == '.'))
302 ** don't add this move, it would have exactly the same
303 ** result as the previous one
307 move
= new gipf_move
;
312 // pushll (movelist, (void *) move);
313 movelist
.push_back (move
);
320 listheader
* rowlist
;
326 rowlist
= b_row_extra (oboard
);
327 while ((rowi
= (rem_row
*) llitembynr (rowlist
, counter
))
332 move
= new gipf_move
;
334 move
->type
= G_REMROW
;
335 move
->remrow
.owner
= row_owner (rowi
);
337 tempstr
= postostr (row_start(rowi
));
338 move
->remrow
.from
[0] = tempstr
[0];
339 move
->remrow
.from
[1] = tempstr
[1];
340 move
->remrow
.from
[2] = '\0';
343 tempstr
= postostr (row_end(rowi
));
344 move
->remrow
.to
[0] = tempstr
[0];
345 move
->remrow
.to
[1] = tempstr
[1];
346 move
->remrow
.to
[2] = '\0';
349 // pushll (movelist, (void *) move);
350 movelist
.push_back (move
);
365 while ((gipfi
= (rem_gipf
*)
366 llitembynr (b_gipf_extra (oboard
) ,counter
)) != NULL
)
372 if (b_otherpiece (b_ppiece (oboard
, gipfi
->pos
))
384 maxnr
= 1 << mypieces
; /* 2 ^ mynr */
386 for (bits1
= 0; bits1
< maxnr
; bits1
++)
390 move
= new gipf_move
;
392 move
->type
= G_REMGIPF
;
394 // move->remgipf.gipflist =
395 // (listheader *) malloc (sizeof (listheader));
396 // newlist (move->remgipf.gipflist);
399 while ((gipfi
= (rem_gipf
*)
400 llitembynr (b_gipf_extra (oboard
) ,counter
)) != NULL
)
403 move
->remgipf
.owner
= gipfi
->owner
;
405 tempstr
= b_gipf_position (gipfi
);
406 tempstr
= (char *) realloc (tempstr
, 4);
410 if ((b_otherpiece (b_ppiece (oboard
, gipfi
->pos
))
411 == gipfi
->owner
) || (remoppgipf
== 0))
423 // pushll (move->remgipf.gipflist, tempstr);
424 move
->remgipf
.gipflist
.push_back (tempstr
);
427 // pushll (movelist, (void *) move);
428 movelist
.push_back (move
);
433 case S_FINISHED
: // not normal
441 void * ai_gipf::newfunc (void * game
, basemove
* move
, int * finished
,
442 int * depthdelta
, int * nodetype
)
444 board
* oboard
= (board
*) game
,
446 gipf_move
* gmove
= (gipf_move
*) move
;
454 piece
= b_next_piece (oboard
);
456 if (newmoves
[gmove
->piece
.nr
].type
== 'g')
457 piece
= b_otherpiece (piece
);
458 nboard
= b_move (oboard
, newmoves
[gmove
->piece
.nr
].from
,
459 newmoves
[gmove
->piece
.nr
].to
, piece
);
475 vector
<char *>::iterator curg
, lastg
;
478 while ((gipfi
= (rem_gipf
*)
479 llitembynr (b_gipf_extra (oboard
) ,counter1
)) != NULL
)
483 tempstr
= b_gipf_position (gipfi
);
486 curg
= gmove
->remgipf
.gipflist
.begin();
487 lastg
= gmove
->remgipf
.gipflist
.end();
488 while (curg
!= lastg
)
489 // while ((str = (char *)
490 // llitembynr (gmove->remgipf.gipflist, counter2)) != NULL)
493 if (((*curg
)[0] == tempstr
[0]) && ((*curg
)[1] == tempstr
[1]))
495 if ((*curg
)[2] == 'y')
497 tboard
= b_remove_gipf (nboard
, gipfi
);
498 if (nboard
!= oboard
)
510 /* check again for 4 in a row */
511 tboard
= b_checkfour (nboard
);
512 if (nboard
!= oboard
)
523 listheader
* rowlist
;
528 rowlist
= b_row_extra (oboard
);
529 while ((rowi
= (rem_row
*) llitembynr (rowlist
, counter
))
534 tempstr
= postostr (rowi
->startpos
);
535 if ((tempstr
[0] != gmove
->remrow
.from
[0]) ||
536 (tempstr
[1] != gmove
->remrow
.from
[1]))
543 tempstr
= postostr (rowi
->endpos
);
544 if ((tempstr
[0] != gmove
->remrow
.to
[0]) ||
545 (tempstr
[1] != gmove
->remrow
.to
[1]))
554 nboard
= b_remove_row (oboard
, counter
- 1);
561 switch (b_status (nboard
))
564 *finished
= b_game_finished (nboard
);
567 if (((b_next_piece (nboard
) == 'o') && (maxplayer () == PLAYER1
)) ||
568 ((b_next_piece (nboard
) == 'x') && (maxplayer () == PLAYER2
)))
576 listheader
* rowlist
= b_row_extra (nboard
);
577 rem_row
* rowi
= (rem_row
*) llitembynr (rowlist
, 1);
582 if (((row_owner (rowi
) == 'o') && (maxplayer () == PLAYER1
)) ||
583 ((row_owner (rowi
) == 'x') && (maxplayer () == PLAYER2
)))
593 rem_gipf
* gipfi
= (rem_gipf
*) llitembynr (b_gipf_extra (nboard
) ,1);
598 if (((b_gipf_owner (gipfi
) == 'o') && (maxplayer () == PLAYER1
)) ||
599 ((b_gipf_owner (gipfi
) == 'x') && (maxplayer () == PLAYER2
)))
606 case S_FINISHED
: // not normal
611 return ((void *) nboard
);
616 //void * ai_gipf::copymovefunc (void * move)
617 gipf_move::gipf_move (gipf_move
& tocopy
)
619 // gipf_move * omove = (gipf_move *) move,
625 // nmove = (gipf_move *) malloc (sizeof (gipf_move));
627 this->type
= tocopy
.type
;
631 this->piece
.nr
= tocopy
.piece
.nr
;
634 this->remrow
.from
[0] = tocopy
.remrow
.from
[0];
635 this->remrow
.from
[1] = tocopy
.remrow
.from
[1];
636 this->remrow
.from
[2] = '\0';
637 this->remrow
.to
[0] = tocopy
.remrow
.to
[0];
638 this->remrow
.to
[1] = tocopy
.remrow
.to
[1];
639 this->remrow
.to
[2] = '\0';
640 this->remrow
.owner
= tocopy
.remrow
.owner
;
643 this->remgipf
.owner
= tocopy
.remgipf
.owner
;
645 this->remgipf
.gipflist
= (listheader
*) malloc (sizeof (listheader
));
646 newlist (this->remgipf
.gipflist
);
648 while ((opos
= (char *)
649 llitembynr (tocopy
.remgipf
.gipflist
, counter
)) != NULL
)
652 npos
= (char *) malloc (4);
657 pushll (this->remgipf
.gipflist
, (void *) npos
);
667 basemove
* gipf_move::copy (void)
669 gipf_move
* nmove
= new gipf_move
;
673 vector
<char *>::iterator curg
, lastg
;
675 nmove
->type
= this->type
;
679 nmove
->piece
.nr
= this->piece
.nr
;
682 nmove
->remrow
.from
[0] = this->remrow
.from
[0];
683 nmove
->remrow
.from
[1] = this->remrow
.from
[1];
684 nmove
->remrow
.from
[2] = '\0';
685 nmove
->remrow
.to
[0] = this->remrow
.to
[0];
686 nmove
->remrow
.to
[1] = this->remrow
.to
[1];
687 nmove
->remrow
.to
[2] = '\0';
688 nmove
->remrow
.owner
= this->remrow
.owner
;
691 nmove
->remgipf
.owner
= this->remgipf
.owner
;
693 curg
= this->remgipf
.gipflist
.begin();
694 lastg
= this->remgipf
.gipflist
.end();
695 // nmove->remgipf.gipflist = (listheader *) malloc (sizeof (listheader));
696 // newlist (nmove->remgipf.gipflist);
698 // while ((opos = (char *)
699 // llitembynr (this->remgipf.gipflist, counter)) != NULL)
700 while (curg
!= lastg
)
703 npos
= (char *) malloc (4);
704 npos
[0] = (*curg
)[0];
705 npos
[1] = (*curg
)[1];
706 npos
[2] = (*curg
)[2];
708 // pushll (nmove->remgipf.gipflist, (void *) npos);
709 nmove
->remgipf
.gipflist
.push_back(npos
);
719 //void ai_gipf::delmovefunc (void * move)
720 gipf_move::~gipf_move ()
724 if ((type
== G_REMGIPF
) && (!remgipf
.gipflist
.empty()))
726 // while ((opos = (char *)
727 // llrembynr (remgipf.gipflist, 1)) != NULL)
730 // free (remgipf.gipflist);
731 vector
<char *>::iterator curg
= remgipf
.gipflist
.begin(),
732 lastg
= remgipf
.gipflist
.end();
733 while (curg
!= lastg
)
744 void ai_gipf::delgamefunc (void * game
)
746 board
* oboard
= (board
*) game
;
757 void ai_gipf::game_move (board
* oboard
, float timeleft
,
758 char * type
, char * from
, char * to
)
760 vector
<basemove
*> * newmovelist
;
764 if (movelist
!= NULL
)
767 ** this is probably a problem
768 ** signal it and then ignore it
770 cout
<< "\n WARNING (ai_gipf::game_move):\n";
771 cout
<< " movelist is not empty!!\n\n";
773 int len
= movelist
->size(),
776 for (i
= 0; i
< len
; i
++)
777 delete (*movelist
)[i
];
784 ** if this is the first move of the game, reduce memorydepth
785 ** to 1, it's not necessary to waste time when there are really
786 ** only 2 possible moves
788 /* question: should I only do this for tournament games ? */
789 if (randomfirstmove
&& // flag must be one
790 (b_move_counter (oboard
) == 0) && // first move
791 (((b_white_gipf (oboard
) == 0) &&
792 (b_white (oboard
) == 18) && (b_black (oboard
) == 18)) ||
793 ((b_white_gipf (oboard
) == 3) &&
794 (b_white (oboard
) == 12) && (b_black (oboard
) == 12)) ||
795 ((b_white_gipf (oboard
) == -1) &&
796 (b_white (oboard
) == 12) && (b_black (oboard
) == 12))))
798 savedepth
= searchdepth ();
802 newmovelist
= mtdf_id ((void *) oboard
, MAX
, timeleft
/TIMEDIVIDER
);
804 /* reset the correct searchdepth if necessary */
807 searchdepth (savedepth
);
810 if (newmovelist
== NULL
)
812 // have to check what happened here
813 if (status () == AI_STOPPED
)
817 cleanupmovelist (newmovelist
);
818 movelist
= newmovelist
;
820 // remove the first item from the movelist
821 move
= (gipf_move
*) (*movelist
)[0];
822 movelist
->erase (movelist
->begin());
823 // move = (gipf_move *) llrembynr (movelist, 1);
825 if (movelist
->empty())
830 // if (llitembynr (movelist, 1) == NULL)
831 // { // delete movelist if empty
836 if (move
->type
!= G_MOVE
)
837 { // very wrong, what happened here ?
840 from
[0] = newmoves
[move
->piece
.nr
].from
[0];
841 from
[1] = newmoves
[move
->piece
.nr
].from
[1];
842 to
[0] = newmoves
[move
->piece
.nr
].to
[0];
843 to
[1] = newmoves
[move
->piece
.nr
].to
[1];
844 *type
= newmoves
[move
->piece
.nr
].type
;
852 char ai_gipf::game_gipf (board
* oboard
, float timeleft
,
855 vector
<basemove
*> * newmovelist
;
860 vector
<char *>::iterator curg
,
863 if (movelist
== NULL
)
865 newmovelist
= mtdf_id ((void *) oboard
, MAX
, timeleft
/TIMEDIVIDER
);
867 if (newmovelist
== NULL
)
869 // have to check what happened here
870 if (status () == AI_STOPPED
)
874 cleanupmovelist (newmovelist
);
875 movelist
= newmovelist
;
878 // move = (gipf_move *) llitembynr (movelist, 1);
879 move
= (gipf_move
*) (*movelist
)[0];
880 if ((move
== NULL
) || (move
->type
!= G_REMGIPF
))
881 { // very wrong, what happened here ?
885 // while ((gipfpos = (char *)
886 // llitembynr (move->remgipf.gipflist, counter)) != NULL)
887 curg
= move
->remgipf
.gipflist
.begin();
888 lastg
= move
->remgipf
.gipflist
.end();
889 while (curg
!= lastg
)
891 if (strncmp (*curg
, pos
, 2) == 0)
899 // if (gipfpos == NULL)
901 { // very wrong, gipf-position not found
906 move
->remgipf
.gipflist
.erase (curg
);
907 // result = gipfpos[2];
908 // gipfpos = (char *) llrembynr (move->remgipf.gipflist, counter);
911 // if (llitembynr (move->remgipf.gipflist, 1) == NULL)
912 if (move
->remgipf
.gipflist
.empty())
916 movelist
->erase (movelist
->begin());
918 if (movelist
->empty())
919 { // delete movelist if empty
929 char ai_gipf::game_row (board
* oboard
, float timeleft
,
930 char * start
, char * end
)
932 vector
<basemove
*> * newmovelist
;
936 if (movelist
== NULL
)
938 newmovelist
= mtdf_id ((void *) oboard
, MAX
, timeleft
/TIMEDIVIDER
);
940 if (newmovelist
== NULL
)
942 // have to check what happened here
943 if (status () == AI_STOPPED
)
947 cleanupmovelist (newmovelist
);
948 movelist
= newmovelist
;
951 move
= (gipf_move
*) (*movelist
)[0];
952 // move = (gipf_move *) llitembynr (movelist, 1);
953 if ((move
== NULL
) || (move
->type
!= G_REMROW
))
954 { // very wrong, what happened here ?
957 if (strncmp (start
, move
->remrow
.from
, 2) == 0)
959 if (strncmp (end
, move
->remrow
.to
, 2) == 0)
962 else if (strncmp (start
, move
->remrow
.to
, 2) == 0)
964 if (strncmp (end
, move
->remrow
.from
, 2) == 0)
972 movelist
->erase (movelist
->begin());
974 if (movelist
->empty())
975 { // delete movelist if empty
986 ** cleanup a list of moves as returned by minimax_ab, mtdf or mtdf_id
987 ** keep only the necessary moves.
989 ** - remove G_MOVE if it is not the first item in the list and remove
990 ** everything after it. (only keep everything for the first move)
991 ** - remove everything that is not an action for the current player.
993 void ai_gipf::cleanupmovelist (vector
<basemove
*> * mlist
)
995 int counter
= 1, /* skip the first item */
998 gipf_move
* moveitem
;
1000 /* look for the first item that can be deleted */
1001 for (; counter
< len
; counter
++)
1002 // while ((moveitem = (gipf_move *) llitembynr (mlist, counter)) != NULL)
1004 moveitem
= (gipf_move
*) (*mlist
)[counter
];
1005 if ((moveitem
->type
== G_MOVE
) ||
1006 ((moveitem
->type
== G_REMGIPF
) &&
1007 (moveitem
->remgipf
.owner
!= colour
)) ||
1008 ((moveitem
->type
== G_REMROW
) &&
1009 (moveitem
->remrow
.owner
!= colour
)))
1016 /* delete everything from now on */
1017 for (i
= len
- 1; i
>= counter
; i
--)
1018 // while ((item = (gipf_move *) llrembynr (mlist, counter)) != NULL)
1020 delete (* mlist
)[i
];
1029 ** C-functions for calling from the main program
1032 void * ai_gipf_new (char colour
, int game
)
1036 newgame
= new ai_gipf (colour
, game
);
1038 return ((void *) newgame
);
1041 void ai_gipf_move (board
* oboard
, void * self
, float timeleft
,
1042 char * type
, char * from
, char * to
)
1044 ai_gipf
* game
= (ai_gipf
*) self
;
1046 game
->game_move (oboard
, timeleft
, type
, from
, to
);
1050 char ai_gipf_gipf (board
* oboard
, void * self
, float timeleft
,
1053 ai_gipf
* game
= (ai_gipf
*) self
;
1055 return (game
->game_gipf (oboard
, timeleft
, pos
));
1058 char ai_gipf_row (board
* oboard
, void * self
, float timeleft
,
1059 char * start
, char * end
)
1061 ai_gipf
* game
= (ai_gipf
*) self
;
1063 return (game
->game_row (oboard
, timeleft
, start
, end
));
1066 void ai_gipf_end (void * self
)
1068 ai_gipf
* delgame
= (ai_gipf
*) self
;