5 ** Copyright (C) 1998 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.
23 ** keep a tree of all searched nodes
24 ** this is not useful for the normal minimax with alfabeta-pruning
25 ** but can be used for negascout or mtd(f), algoritms wich do re-searching
31 extern void checkwindowevents (void);
32 extern int interrupt_computer
;
35 /* structures for keeping my own info in */
47 listheader
* movelist
; /* list of items of type nextmove */
51 int remtype
; /* REM_GIPF or REM_ROW */
52 listheader
* gipflist
; /* list of items of type gipfdata */
66 listheader
* movelist
; /* list of items of type nextmove */
85 /* things for the node-tree */
90 listheader
* children
; /* list of treeitems */
99 {{3, 4}, 2},{{3, 5}, 2},{{4, 6}, 2},{{5, 5}, 2},{{5, 4}, 2},{{4, 4}, 2},
100 {{2, 3}, 1},{{2, 4}, 1},{{2, 5}, 1},{{3, 6}, 1},{{4, 7}, 1},{{5, 6}, 1},
101 {{6, 5}, 1},{{6, 4}, 1},{{6, 3}, 1},{{5, 3}, 1},{{4, 3}, 1},{{3, 3}, 1}
107 movestruct
* mtdf_id (board
* oboard
, treenode
* node
, int f
, mtdf_info
* me
,
109 movestruct
* mtdf (board
* oboard
, treenode
* node
, int f
, mtdf_info
* me
,
112 movestruct
* mem_ab_move (board
* oboard
, treenode
* node
, int alfa
, int beta
,
113 int minmax
, int depth
, mtdf_info
* me
);
114 movestruct
* mem_move (board
* oboard
, treenode
* node
, int alfa
, int beta
,
115 int minmax
, int depth
, mtdf_info
* me
, fromto
* todo
,
117 movestruct
* mem_ab_gipf (board
* oboard
, treenode
* node
, int alfa
, int beta
,
118 int minmax
, int depth
, mtdf_info
* me
);
119 movestruct
* mem_rem_gipflist (board
* oboard
, treenode
* node
, int alfa
,
120 int beta
, int minmax
, int depth
,
121 mtdf_info
* me
, listheader
* myg
,
122 listheader
* otherg
);
123 movestruct
* mem_ab_row (board
* oboard
, treenode
* node
, int alfa
, int beta
,
124 int minmax
, int depth
, mtdf_info
* me
);
125 movestruct
* mem_rem_row (board
* oboard
, treenode
* node
, int alfa
, int beta
,
126 int minmax
, int depth
, mtdf_info
* me
, int rem
);
127 int mem_evaluate (board
* oboard
, mtdf_info
* me
);
128 void mem_del_move (movestruct
* todel
);
130 void mem_deltree (treenode
* node
);
131 void mem_delnode (void * item
);
132 treenode
* mem_makeroot (board
* father
, mtdf_info
* me
);
133 treenode
* mem_child (treenode
* node
, int nr
, mtdf_info
* me
, int depth
);
134 void mem_resetul (void * item
);
136 int mem_equ_l (int nr1
, int nr2
, int * chance
, mtdf_info
* me
);
137 int mem_equ_h (int nr1
, int nr2
, int * chance
, mtdf_info
* me
);
139 void * mtdf_new (char colour
, int game
)
142 listheader
* configlist
;
144 me
= (mtdf_info
*) malloc (sizeof (mtdf_info
));
150 /* check for config-values from the config-file */
151 configlist
= readconfigfile ("gf1.cfg");
153 me
->config
.searchdepth
= findconfigvalue (configlist
, "searchdepth",
155 me
->config
.remoppgipf
= findconfigvalue (configlist
, "remoppgipf",
157 me
->config
.maxgipf
= findconfigvalue (configlist
, "maxgipf",
159 me
->config
.memorydepth
= findconfigvalue (configlist
, "memorydepth",
161 me
->config
.randomchoose
= findconfigvalue (configlist
, "randomchoose",
164 clearconfiglist (configlist
);
166 return ((void *) me
);
170 void mtdf_move (board
* oboard
, void * self
,
171 char * type
, char * from
, char * to
)
173 mtdf_info
* me
= self
;
179 root
= mem_makeroot (oboard
, me
);
181 move = mtdf (oboard, root, me->lastvalue, me, 1);
183 move
= mtdf_id (oboard
, root
, me
->lastvalue
, me
, 1);
187 from
[0] = move
->from
[0];
188 from
[1] = move
->from
[1];
193 me
->movelist
= move
->movelist
;
195 move
->movelist
= NULL
;
202 char mtdf_gipf (board
* oboard
, void * self
, char * pos
)
204 mtdf_info
* me
= self
;
213 /* check if movelist contains info about removing gipf-pieces */
214 if (me
->movelist
== NULL
)
217 ** no info in movelist, my opponent made 4 in a row
218 ** with my pieces (only possible explanation)
222 /* remark: I have to start this as a min-node,
223 ** because this is really my opponents move */
224 root
= mem_makeroot (oboard
, me
);
226 nmove = mtdf (oboard, root, me->lastvalue, me, 2);
228 nmove
= mtdf_id (oboard
, root
, me
->lastvalue
, me
, 2);
231 me
->movelist
= nmove
->movelist
;
232 nmove
->movelist
= NULL
;
233 mem_del_move (nmove
);
236 /* now check the movelist for the move we have to make */
237 if (((movedata
= (nextmove
*) llitembynr (me
->movelist
, 1)) == NULL
) ||
238 (movedata
->remtype
!= REM_GIPF
))
244 /* look for the gipf to remove */
246 while ((gipfd
= (gipfdata
*) llitembynr (movedata
->gipflist
, counter
))
249 if ((gipfd
->pos
[0] == pos
[0]) && (gipfd
->pos
[1] == pos
[1]))
260 /* remove gipf from list */
261 gipfd
= (gipfdata
*) llrembynr (movedata
->gipflist
, counter
);
263 /* remove nextmove from movelist if gipflist is empty */
264 if (llitembynr (movedata
->gipflist
, 1) == NULL
)
266 movedata
= (nextmove
*) llrembynr (me
->movelist
, 1);
267 free (movedata
->gipflist
);
270 /* remove movelist if empty */
271 if (llitembynr (me
->movelist
, 1) == NULL
)
285 char mtdf_row (board
* oboard
, void * self
, char * start
, char * end
)
287 mtdf_info
* me
= self
;
294 /* check if movelist contains info about removing rows */
295 if (me
->movelist
== NULL
)
298 ** no info in movelist, my opponent made several "4 in a row"s
299 ** with my pieces (only possible explanation)
303 /* remark: I have to start this as a min-node,
304 ** because this is really my opponents move */
305 root
= mem_makeroot (oboard
, me
);
307 nmove = mtdf (oboard, root, me->lastvalue, me, 3);
309 nmove
= mtdf_id (oboard
, root
, me
->lastvalue
, me
, 3);
312 me
->movelist
= nmove
->movelist
;
313 nmove
->movelist
= NULL
;
314 mem_del_move (nmove
);
317 /* now check the movelist for the move we have to make */
318 if (((movedata
= (nextmove
*) llitembynr (me
->movelist
, 1)) == NULL
) ||
319 (movedata
->remtype
!= REM_ROW
))
326 /* check if this is the correct row to be removed */
327 if ((start
[0] == movedata
->rowdata
.start
[0]) &&
328 (start
[1] == movedata
->rowdata
.start
[1]))
330 if ((end
[0] == movedata
->rowdata
.end
[0]) &&
331 (end
[1] == movedata
->rowdata
.end
[1]))
336 else if ((start
[0] == movedata
->rowdata
.end
[0]) &&
337 (start
[1] == movedata
->rowdata
.end
[1]))
339 if ((end
[0] == movedata
->rowdata
.start
[0]) &&
340 (end
[1] == movedata
->rowdata
.start
[1]))
348 /* remove nextmove from movelist */
349 movedata
= (nextmove
*) llrembynr (me
->movelist
, 1);
350 free (movedata
->rowdata
.start
);
351 free (movedata
->rowdata
.end
);
354 /* remove movelist if empty */
355 if (llitembynr (me
->movelist
, 1) == NULL
)
364 /* don't remove the row */
369 void mtdf_end (void * self
)
371 mtdf_info
* me
= self
;
373 /* do I have to clean up the movelist first */
381 ** iterative deepening around mtdf
383 ** REMARK: doesn't work, don't know why yet
385 movestruct
* mtdf_id (board
* oboard
, treenode
* node
, int f
, mtdf_info
* me
,
390 movestruct
* bestmove
= NULL
;
392 savemaxdepth
= me
->config
.searchdepth
;
394 for (i
= 1; i
<= savemaxdepth
; i
++)
396 if (bestmove
!= NULL
)
398 mem_del_move (bestmove
);
400 /* reset upper and lower limits in the memory-tree */
404 me
->config
.searchdepth
= i
;
405 bestmove
= mtdf (oboard
, node
, f
, me
, type
);
408 me
->config
.searchdepth
= savemaxdepth
;
413 movestruct
* mtdf (board
* oboard
, treenode
* node
, int f
, mtdf_info
* me
,
420 movestruct
* bestmove
= NULL
;
426 while (lower
< upper
)
437 if (bestmove
!= NULL
)
439 mem_del_move (bestmove
);
445 bestmove
= mem_ab_move (oboard
, node
, beta
-1, beta
,
450 bestmove
= mem_ab_gipf (oboard
, node
, beta
-1, beta
,
455 bestmove
= mem_ab_row (oboard
, node
, beta
-1, beta
,
459 value
= bestmove
->value
;
471 me
->lastvalue
= value
;
476 movestruct
* mem_ab_move (board
* oboard
, treenode
* node
, int alfa
, int beta
,
477 int minmax
, int depth
, mtdf_info
* me
)
487 treenode
* childnode
;
489 /* maximum search depth or end of game */
490 if ((b_game_finished (oboard
)) ||
491 (depth
> me
->config
.searchdepth
))
493 nmove
= (movestruct
*) malloc (sizeof (movestruct
));
494 nmove
->from
[0] = '\0';
497 nmove
->movelist
= NULL
;
498 nmove
->value
= mem_evaluate (oboard
, me
);
503 if ((depth
== 1) || (depth
< me
->config
.searchdepth
))
505 checkwindowevents ();
509 /* list of moves to try depends on the question if we can
510 ** place a gipf or not.
511 ** cutoff after a predetermined number of gipf-pieces */
512 if ((b_colour_type (oboard
, b_next_piece (oboard
)) == 'g') &&
513 (b_colour_gipf (oboard
, b_next_piece (oboard
)) <
516 allmoves
= allmovesg
;
521 allmoves
= allmovesn
;
525 lastmove
.sboard
= NULL
;
527 if (minmax
== MAXNODE
)
531 for (i
= 0; i
< maxmoves
; i
++)
533 childnode
= mem_child (node
, i
+1, me
, depth
);
534 nmove
= mem_move (oboard
, childnode
, alfa
, beta
, minmax
,
535 depth
, me
, &(allmoves
[i
]), &lastmove
);
540 if (mem_equ_h (nmove
->value
, value
, &chance
, me
))
542 value
= nmove
->value
;
543 if (bestmove
!= NULL
)
545 mem_del_move (bestmove
);
551 mem_del_move (nmove
);
553 alfa
= max (alfa
, value
);
558 ** problems if value is the same as beta, this means that
559 ** when randomly selecting a move from the moves with the
560 ** same value, this one could be chosen.
561 ** solution: change value to (-1001 or 1001)
562 ** or the current value (+1 or -1)
564 ** is this correct? or does it depend on the fact if
565 ** this was called from a min- or a max-node?
575 for (i
= 0; i
< maxmoves
; i
++)
577 childnode
= mem_child (node
, i
+1, me
, depth
);
578 nmove
= mem_move (oboard
, childnode
, alfa
, beta
, minmax
,
579 depth
, me
, &(allmoves
[i
]), &lastmove
);
584 if (mem_equ_l (nmove
->value
, value
, &chance
, me
))
586 value
= nmove
->value
;
587 if (bestmove
!= NULL
)
589 mem_del_move (bestmove
);
595 mem_del_move (nmove
);
597 beta
= min (beta
, value
);
606 if ((childnode
== NULL
) && (lastmove
.sboard
!= NULL
))
608 b_del (lastmove
.sboard
);
615 movestruct
* mem_move (board
* oboard
, treenode
* node
, int alfa
, int beta
,
616 int minmax
, int depth
, mtdf_info
* me
, fromto
* todo
,
625 if ((node
!= NULL
) && (node
->children
!= NULL
))
626 { /* node already visited, reuse from memory */
627 if (node
->father
== NULL
)
631 newboard
= node
->father
;
635 ** removing this solves the problem of bad play
636 ** but it makes the computerplayer twice as slow as ai_minimax
638 ** it also solves the problem of iterative deepening not working
640 if (node
->lower
>= beta
)
642 nmove
= (movestruct
*) malloc (sizeof (movestruct
));
643 nmove
->from
[0] = todo
->from
[0];
644 nmove
->from
[1] = todo
->from
[1];
645 nmove
->to
[0] = todo
->to
[0];
646 nmove
->to
[1] = todo
->to
[1];
648 nmove
->movelist
= NULL
;
649 nmove
->value
= node
->lower
;
652 if (node
->upper
<= alfa
)
654 nmove
= (movestruct
*) malloc (sizeof (movestruct
));
655 nmove
->from
[0] = todo
->from
[0];
656 nmove
->from
[1] = todo
->from
[1];
657 nmove
->to
[0] = todo
->to
[0];
658 nmove
->to
[1] = todo
->to
[1];
659 nmove
->type
= todo
->type
;
660 nmove
->movelist
= NULL
;
661 nmove
->value
= node
->upper
;
664 alfa
= max (alfa
, node
->lower
);
665 beta
= min (beta
, node
->upper
);
672 /* create children list */
673 node
->children
= (listheader
*) malloc (sizeof (listheader
));
674 newlist (node
->children
);
677 if (todo
->type
== 'g')
679 piece
= b_otherpiece (b_next_piece (oboard
));
683 piece
= b_next_piece (oboard
);
686 newboard
= b_move (oboard
, todo
->from
, todo
->to
, piece
);
689 node
->father
= newboard
;
692 if (newboard
== NULL
)
697 /* check if the result is the same as the last move */
698 if ((lmove
->sboard
!= NULL
) &&
699 ((lmove
->to
[0] == todo
->to
[0]) && (lmove
->to
[1] == todo
->to
[1])) &&
700 (b_compare (newboard
, lmove
->sboard
) == 0))
709 if ((node
== NULL
) && (lmove
->sboard
!= NULL
))
711 b_del (lmove
->sboard
);
713 lmove
->sboard
= newboard
; /* don't delete the board at the end */
714 lmove
->to
[0] = todo
->to
[0];
715 lmove
->to
[1] = todo
->to
[1];
718 /* create new movestruct */
719 mymove
= (movestruct
*) malloc (sizeof (movestruct
));
720 mymove
->from
[0] = todo
->from
[0];
721 mymove
->from
[1] = todo
->from
[1];
722 mymove
->to
[0] = todo
->to
[0];
723 mymove
->to
[1] = todo
->to
[1];
724 mymove
->type
= todo
->type
;
725 mymove
->movelist
= NULL
;
727 newminmax
= (minmax
== MINNODE
? MAXNODE
: MINNODE
);
728 if ((b_status (newboard
) == S_NORMAL
) ||
729 (b_status (newboard
) == S_FINISHED
))
731 nmove
= mem_ab_move (newboard
, node
, alfa
, beta
, newminmax
,
733 mymove
->value
= nmove
->value
;
734 mem_del_move (nmove
);
736 else if (b_status (newboard
) == S_REMOVEROW
)
738 nmove
= mem_ab_row (newboard
, node
, alfa
, beta
, minmax
, depth
, me
);
739 mymove
->movelist
= nmove
->movelist
;
740 mymove
->value
= nmove
->value
;
741 nmove
->movelist
= NULL
;
742 mem_del_move (nmove
);
744 else if (b_status (newboard
) == S_REMOVEGIPF
)
746 nmove
= mem_ab_gipf (newboard
, node
, alfa
, beta
, minmax
, depth
, me
);
747 mymove
->movelist
= nmove
->movelist
;
748 mymove
->value
= nmove
->value
;
749 nmove
->movelist
= NULL
;
750 mem_del_move (nmove
);
759 if (mymove
->value
<= alfa
)
761 node
->upper
= mymove
->value
;
763 else if ((mymove
->value
> alfa
) && (mymove
->value
< beta
))
764 { /* this shouldn't happen with zero window searches */
765 node
->upper
= node
->lower
= mymove
->value
;
767 else if (mymove
->value
>= beta
)
769 node
->lower
= mymove
->value
;
777 movestruct
* mem_ab_gipf (board
* oboard
, treenode
* node
, int alfa
, int beta
,
778 int minmax
, int depth
, mtdf_info
* me
)
795 treenode
* childnode
;
797 gipfi
= (rem_gipf
*) llitembynr (b_gipf_extra (oboard
), 1);
800 ** I may have to change if I am a min or a max-node here
801 ** it's possible that my opponent won a row, so he has to
802 ** decide if gipf-pieces must be removed
804 if (b_gipf_owner(gipfi
) == b_next_piece (oboard
))
806 realminmax
= (minmax
== MINNODE
? MAXNODE
: MINNODE
);
813 /* always remove gipf-pieces from my opponent if the flag is set */
814 myg
= (listheader
*) malloc (sizeof (listheader
));
816 otherg
= (listheader
*) malloc (sizeof (listheader
));
820 while ((gipfi
= (rem_gipf
*) llitembynr (b_gipf_extra (oboard
), counter
))
824 gipfflag
= (gipfitem
*) malloc (sizeof (gipfitem
));
825 gipfflag
->gipf
= gipfi
;
828 gipfpos
= b_gipf_position (gipfi
);
829 if ((me
->config
.remoppgipf
== 1) &&
830 (b_otherpiece (b_gipf_owner (gipfi
)) !=
831 b_piece (oboard
, gipfpos
)))
833 pushll (otherg
, (void *) gipfflag
);
838 pushll (myg
, (void *) gipfflag
);
843 maxnr
= 1 << mynr
; /* 2 ^ mynr */
845 if (realminmax
== MAXNODE
)
849 for (bits1
= 0; bits1
< maxnr
; bits1
++)
852 for (i
= 0; i
< mynr
; i
++)
854 gipfflag
= (gipfitem
*) llitembynr (myg
, i
+1);
855 gipfflag
->flag
= bits2
& 1;
858 childnode
= mem_child (node
, bits1
+ 1, me
, depth
);
859 nmove
= mem_rem_gipflist (oboard
, childnode
, alfa
, beta
,
860 minmax
, depth
, me
, myg
, otherg
);
862 if (nmove
->value
> value
)
864 value
= nmove
->value
;
865 if (bestmove
!= NULL
)
867 mem_del_move (bestmove
);
873 mem_del_move (nmove
);
875 alfa
= max (alfa
, value
);
887 for (bits1
= 0; bits1
< maxnr
; bits1
++)
890 for (i
= 0; i
< mynr
; i
++)
892 gipfflag
= (gipfitem
*) llitembynr (myg
, i
+1);
893 gipfflag
->flag
= bits2
& 1;
896 childnode
= mem_child (node
, bits1
+ 1, me
, depth
);
897 nmove
= mem_rem_gipflist (oboard
, childnode
, alfa
, beta
,
898 minmax
, depth
, me
, myg
, otherg
);
900 if (nmove
->value
< value
)
902 value
= nmove
->value
;
903 if (bestmove
!= NULL
)
905 mem_del_move (bestmove
);
911 mem_del_move (nmove
);
913 beta
= min (beta
, value
);
922 /* cleanup temporary lists */
923 while ((gipfflag
= (gipfitem
*) llrembynr (myg
, 1)) != NULL
)
928 while ((gipfflag
= (gipfitem
*) llrembynr (otherg
, 1)) != NULL
)
938 movestruct
* mem_rem_gipflist (board
* oboard
, treenode
* node
, int alfa
,
939 int beta
, int minmax
, int depth
,
940 mtdf_info
* me
, listheader
* myg
,
949 listheader
* remlist
;
956 if ((node
!= NULL
) && (node
->children
!= NULL
))
957 { /* node already visited, reuse from memory */
958 if (node
->father
== NULL
)
962 newboard
= node
->father
;
964 /* I have to produce remlist here again */
965 remlist
= (listheader
*) malloc (sizeof (listheader
));;
967 /* list of gipf-pieces that may or may not have to be removed */
969 while ((gipfflag
= (gipfitem
*) llitembynr (myg
, counter
)) != NULL
)
972 gipfd
= (gipfdata
*) malloc (sizeof (gipfdata
));
973 strpos
= b_gipf_position (gipfflag
->gipf
);
974 owner
= b_gipf_owner (gipfflag
->gipf
);
975 gipfd
->pos
[0] = strpos
[0];
976 gipfd
->pos
[1] = strpos
[1];
977 gipfd
->pos
[2] = '\0';
980 if (gipfflag
->flag
== 1)
988 pushll (remlist
, (void *) gipfd
);
990 /* list of gipf-pieces that always have to be removed */
992 while ((gipfflag
= (gipfitem
*) llitembynr (otherg
, counter
)) != NULL
)
995 gipfd
= (gipfdata
*) malloc (sizeof (gipfdata
));
996 strpos
= b_gipf_position (gipfflag
->gipf
);
997 owner
= b_gipf_owner (gipfflag
->gipf
);
998 gipfd
->pos
[0] = strpos
[0];
999 gipfd
->pos
[1] = strpos
[1];
1000 gipfd
->pos
[2] = '\0';
1004 pushll (remlist
, (void *) gipfd
);
1012 /* create children list */
1013 node
->children
= (listheader
*) malloc (sizeof (listheader
));
1014 newlist (node
->children
);
1018 remlist
= (listheader
*) malloc (sizeof (listheader
));;
1020 /* list of gipf-pieces that may or may not have to be removed */
1022 while ((gipfflag
= (gipfitem
*) llitembynr (myg
, counter
)) != NULL
)
1025 gipfd
= (gipfdata
*) malloc (sizeof (gipfdata
));
1026 strpos
= b_gipf_position (gipfflag
->gipf
);
1027 owner
= b_gipf_owner (gipfflag
->gipf
);
1028 gipfd
->pos
[0] = strpos
[0];
1029 gipfd
->pos
[1] = strpos
[1];
1030 gipfd
->pos
[2] = '\0';
1033 if (gipfflag
->flag
== 1)
1036 nboard
= b_remove_gipf (newboard
, gipfflag
->gipf
);
1037 if (newboard
!= oboard
)
1047 pushll (remlist
, (void *) gipfd
);
1050 /* list of gipf-pieces that always have to be removed */
1052 while ((gipfflag
= (gipfitem
*) llitembynr (otherg
, counter
)) != NULL
)
1055 gipfd
= (gipfdata
*) malloc (sizeof (gipfdata
));
1056 strpos
= b_gipf_position (gipfflag
->gipf
);
1057 owner
= b_gipf_owner (gipfflag
->gipf
);
1058 gipfd
->pos
[0] = strpos
[0];
1059 gipfd
->pos
[1] = strpos
[1];
1060 gipfd
->pos
[2] = '\0';
1064 nboard
= b_remove_gipf (newboard
, gipfflag
->gipf
);
1065 if (newboard
!= oboard
)
1070 pushll (remlist
, (void *) gipfd
);
1073 /* check again for 4 in a row */
1074 nboard
= b_checkfour (newboard
);
1075 if (newboard
!= oboard
)
1083 node
->father
= newboard
;
1087 mymove
= (movestruct
*) malloc (sizeof (movestruct
));
1088 mymove
->from
[0] = '\0';
1089 mymove
->to
[0] = '\0';
1091 mymove
->movelist
= (listheader
*) malloc (sizeof (listheader
));
1092 newlist (mymove
->movelist
);
1095 ** only add actions to the movelist if they have to be executed
1096 ** by the max-player
1097 ** this means moves for the min-player will not be executable,
1098 ** but that really isn't necessary
1100 if (me
->colour
== owner
)
1102 movedata
= (nextmove
*) malloc (sizeof (nextmove
));
1103 movedata
->remtype
= REM_GIPF
;
1104 movedata
->gipflist
= remlist
;
1105 pushll (mymove
->movelist
, (void *) movedata
);
1108 { /* remove remlist, we don't need it here */
1109 while ((gipfd
= (gipfdata
*) llrembynr (remlist
, 1)) != NULL
)
1116 newminmax
= (minmax
== MINNODE
? MAXNODE
: MINNODE
);
1118 if ((b_status (newboard
) == S_NORMAL
) ||
1119 (b_status (newboard
) == S_FINISHED
))
1121 nmove
= mem_ab_move (newboard
, node
, alfa
, beta
, newminmax
,
1123 mymove
->value
= nmove
->value
;
1124 mem_del_move (nmove
);
1126 else if (b_status (newboard
) == S_REMOVEROW
)
1128 nmove
= mem_ab_row (newboard
, node
, alfa
, beta
, minmax
, depth
, me
);
1130 while ((movedata
= (nextmove
*) llrembynr (nmove
->movelist
, 1))
1133 pushll (mymove
->movelist
, (void *) movedata
);
1136 mymove
->value
= nmove
->value
;
1137 mem_del_move (nmove
);
1139 else if (b_status (newboard
) == S_REMOVEGIPF
)
1141 nmove
= mem_ab_gipf (newboard
, node
, alfa
, beta
, minmax
, depth
, me
);
1143 while ((movedata
= (nextmove
*) llrembynr (nmove
->movelist
, 1))
1146 pushll (mymove
->movelist
, (void *) movedata
);
1149 mymove
->value
= nmove
->value
;
1150 mem_del_move (nmove
);
1157 /* check if the movelist of mymove contains something */
1158 if (llitembynr (mymove
->movelist
, 1) == NULL
)
1160 free (mymove
->movelist
);
1161 mymove
->movelist
= NULL
;
1170 if (mymove
->value
<= alfa
)
1172 node
->upper
= mymove
->value
;
1174 else if ((mymove
->value
> alfa
) && (mymove
->value
< beta
))
1175 { /* this shouldn't happen with zero window searches */
1176 node
->upper
= node
->lower
= mymove
->value
;
1178 else if (mymove
->value
>= beta
)
1180 node
->lower
= mymove
->value
;
1189 movestruct
* mem_ab_row (board
* oboard
, treenode
* node
, int alfa
, int beta
,
1190 int minmax
, int depth
, mtdf_info
* me
)
1198 listheader
* rowlist
;
1199 treenode
* childnode
;
1201 rowlist
= b_row_extra (oboard
);
1202 rowi
= (rem_row
*) llitembynr (rowlist
, 1);
1205 ** I may have to change if I am a min or a max-node here
1206 ** it's possible that my opponent won several rows, so he has to
1207 ** decide what row to remove
1209 if (row_owner(rowi
) == b_next_piece (oboard
))
1211 realminmax
= (minmax
== MINNODE
? MAXNODE
: MINNODE
);
1215 realminmax
= minmax
;
1218 if (realminmax
== MAXNODE
)
1223 while ((rowi
= (rem_row
*) llitembynr (rowlist
, counter
))
1226 childnode
= mem_child (node
, counter
, me
, depth
);
1227 nmove
= mem_rem_row (oboard
, childnode
, alfa
, beta
, minmax
,
1228 depth
, me
, counter
);
1231 if (nmove
->value
> value
)
1233 value
= nmove
->value
;
1234 if (bestmove
!= NULL
)
1236 mem_del_move (bestmove
);
1242 mem_del_move (nmove
);
1244 alfa
= max (alfa
, value
);
1257 while ((rowi
= (rem_row
*) llitembynr (rowlist
, counter
))
1260 childnode
= mem_child (node
, counter
, me
, depth
);
1261 nmove
= mem_rem_row (oboard
, childnode
, alfa
, beta
, minmax
,
1262 depth
, me
, counter
);
1265 if (nmove
->value
< value
)
1267 value
= nmove
->value
;
1268 if (bestmove
!= NULL
)
1270 mem_del_move (bestmove
);
1276 mem_del_move (nmove
);
1278 beta
= min (beta
, value
);
1291 movestruct
* mem_rem_row (board
* oboard
, treenode
* node
, int alfa
, int beta
,
1292 int minmax
, int depth
, mtdf_info
* me
, int rem
)
1298 nextmove
* movedata
;
1301 if ((node
!= NULL
) && (node
->children
!= NULL
))
1302 { /* node already visited, reuse from memory */
1303 if (node
->father
== NULL
)
1307 newboard
= node
->father
;
1313 /* create children list */
1314 node
->children
= (listheader
*) malloc (sizeof (listheader
));
1315 newlist (node
->children
);
1318 newboard
= b_remove_row (oboard
, rem
);
1321 node
->father
= newboard
;
1325 mymove
= (movestruct
*) malloc (sizeof (movestruct
));
1326 mymove
->from
[0] = '\0';
1327 mymove
->to
[0] = '\0';
1329 mymove
->movelist
= (listheader
*) malloc (sizeof (listheader
));
1330 newlist (mymove
->movelist
);
1333 ** only add actions to the movelist if they have to be executed
1334 ** by the max-player
1335 ** this means moves for the min-player will not be executable,
1336 ** but that really isn't necessary
1338 remi
= (rem_row
*) llitembynr (b_row_extra (oboard
), rem
);
1339 if (me
->colour
== row_owner (remi
))
1341 movedata
= (nextmove
*) malloc (sizeof (nextmove
));
1342 movedata
->remtype
= REM_ROW
;
1343 movedata
->gipflist
= NULL
;
1344 movedata
->rowdata
.start
= postostr (remi
->startpos
);
1345 movedata
->rowdata
.end
= postostr (remi
->endpos
);
1346 pushll (mymove
->movelist
, (void *) movedata
);
1349 newminmax
= (minmax
== MINNODE
? MAXNODE
: MINNODE
);
1351 if ((b_status (newboard
) == S_NORMAL
) ||
1352 (b_status (newboard
) == S_FINISHED
))
1354 nmove
= mem_ab_move (newboard
, node
, alfa
, beta
, newminmax
,
1356 mymove
->value
= nmove
->value
;
1357 mem_del_move (nmove
);
1359 else if (b_status (newboard
) == S_REMOVEROW
)
1361 nmove
= mem_ab_row (newboard
, node
, alfa
, beta
, minmax
, depth
, me
);
1363 while ((movedata
= (nextmove
*) llrembynr (nmove
->movelist
, 1))
1366 pushll (mymove
->movelist
, (void *) movedata
);
1369 mymove
->value
= nmove
->value
;
1370 mem_del_move (nmove
);
1372 else if (b_status (newboard
) == S_REMOVEGIPF
)
1374 nmove
= mem_ab_gipf (newboard
, node
, alfa
, beta
, minmax
, depth
, me
);
1376 while ((movedata
= (nextmove
*) llrembynr (nmove
->movelist
, 1))
1379 pushll (mymove
->movelist
, (void *) movedata
);
1382 mymove
->value
= nmove
->value
;
1383 mem_del_move (nmove
);
1390 /* check if the movelist of mymove contains something */
1391 if (llitembynr (mymove
->movelist
, 1) == NULL
)
1393 free (mymove
->movelist
);
1394 mymove
->movelist
= NULL
;
1403 if (mymove
->value
<= alfa
)
1405 node
->upper
= mymove
->value
;
1407 else if ((mymove
->value
> alfa
) && (mymove
->value
< beta
))
1408 { /* this shouldn't happen with zero window searches */
1409 node
->upper
= node
->lower
= mymove
->value
;
1411 else if (mymove
->value
>= beta
)
1413 node
->lower
= mymove
->value
;
1422 ** calculate the value of a certain board position
1424 ** returns a value between 1000 and -1000 (inclusive)
1426 ** -1000 : my opponent wins
1428 int mem_evaluate (board
* oboard
, mtdf_info
* me
)
1440 otherc
= b_opponent (myc
);
1442 if (b_game_finished (oboard
))
1444 if (b_winner (oboard
) == myc
)
1454 /* maybe I can return 1000 or -1000, but I'm not completely sure */
1455 if (b_colour (oboard
, myc
) == 0)
1459 else if (b_colour (oboard
, otherc
) == 0)
1464 /* I need to start with a base-value, or I get a lot of
1465 ** problems at the start of tournament games */
1469 /* capturing a piece from your opponent is worth 20 points */
1470 wvalue
+= 20 * b_black_lost (oboard
);
1471 bvalue
+= 20 * b_white_lost (oboard
);
1473 /* 1 point for each piece in use on the board */
1474 if (b_white_gipf (oboard
) == -1)
1479 wvalue
+= total
- b_white (oboard
) - b_white_lost (oboard
);
1480 bvalue
+= total
- b_black (oboard
) - b_black_lost (oboard
);
1482 /* 2 pieces or less left is getting dangerous */
1484 /* one gipf left can be dangerous, subtract 5 points */
1485 if (b_white_gipf (oboard
) == 1)
1489 if (b_black_gipf (oboard
) == 1)
1494 /* pieces closer to the center have a higher value */
1495 for (i
= 0; i
< 19; i
++)
1497 pos
= &(mem_pos_val
[i
].coor
);
1498 switch (b_ppiece (oboard
, pos
))
1504 wvalue
+= mem_pos_val
[i
].value
;
1508 wvalue
+= mem_pos_val
[i
].value
* 1.5;
1512 bvalue
+= mem_pos_val
[i
].value
;
1516 bvalue
+= mem_pos_val
[i
].value
* 1.5;
1519 piece = b_ppiece (oboard, pos);
1526 wvalue += mem_pos_val[i].value;
1528 else if (piece == 'O')
1530 wvalue += mem_pos_val[i].value * 1.5;
1532 else if (piece == 'x')
1534 bvalue += mem_pos_val[i].value;
1538 bvalue += mem_pos_val[i].value * 1.5;
1543 /* normalize the result, should be between 1000 and -1000 */
1546 value
= (int) ((wvalue
- bvalue
) * 1000 / (wvalue
+ bvalue
));
1550 value
= (int) ((bvalue
- wvalue
) * 1000 / (wvalue
+ bvalue
));
1556 void mem_del_move (movestruct
* todel
)
1558 nextmove
* movedata
;
1561 if (todel
->movelist
!= NULL
)
1563 while ((movedata
= (nextmove
*) llrembynr (todel
->movelist
, 1))
1566 if (movedata
->remtype
== REM_ROW
)
1568 free (movedata
->rowdata
.start
);
1569 free (movedata
->rowdata
.end
);
1573 while ((gipfd
= (gipfdata
*)
1574 llrembynr (movedata
->gipflist
, 1)) != NULL
)
1578 free (movedata
->gipflist
);
1583 free (todel
->movelist
);
1592 ** create the root of the tree
1595 ** father: the board at the root of the tree
1597 treenode
* mem_makeroot (board
* father
, mtdf_info
* me
)
1601 if (me
->config
.memorydepth
== 0)
1606 newnode
= (treenode
*) malloc (sizeof (treenode
));
1607 newnode
->father
= father
;
1608 newnode
->upper
= 1001;
1609 newnode
->lower
= -1001;
1611 newnode
->children
= (listheader
*) malloc (sizeof (listheader
));
1612 newlist (newnode
->children
);
1620 ** don't delete the father from the root-node
1622 void mem_deltree (treenode
* node
)
1629 emptyll (node
->children
, mem_delnode
);
1630 free (node
->children
);
1636 void mem_delnode (void * item
)
1638 treenode
* node
= item
;
1640 b_del (node
->father
);
1641 emptyll (node
->children
, mem_delnode
);
1642 free (node
->children
);
1650 ** reset upper and lower limits in the memory-tree
1652 void mem_resetul (void * item
)
1654 treenode
* node
= item
;
1657 node
->lower
= -1001;
1658 doll (node
->children
, mem_resetul
);
1665 ** check if a child-node already exists,
1666 ** if not, create a new one
1668 treenode
* mem_child (treenode
* node
, int nr
, mtdf_info
* me
, int depth
)
1672 if (me
->config
.memorydepth
< depth
)
1677 newnode
= (treenode
*) llitembynr (node
->children
, nr
);
1678 if (newnode
!= NULL
)
1679 { /* this node has already been handled, return it */
1684 /* just for testing */
1685 /* check if the previous nr exists, it should */
1686 if ((nr
> 1) && (llitembynr (node
->children
, nr
-1) == NULL
))
1688 printf ("\nERROR: mem_child\n\n");
1693 /* create a new node */
1694 newnode
= (treenode
*) malloc (sizeof (treenode
));
1695 newnode
->father
= NULL
;
1696 newnode
->children
= NULL
;
1697 newnode
->upper
= 1001;
1698 newnode
->lower
= -1001;
1699 pushll (node
->children
, newnode
);
1705 ** just like a normal compare (<)
1709 ** 0/1: when nr1 and nr2 are equal, chooses one at random
1711 ** chance is the chance that nr1 will be chosen if nr1 == nr2
1712 ** this parameter will be incremented each time an equal occurs
1713 ** and will be set to 1 if nr1 < nr2
1714 ** (it should be initialised to 1 by the caller and then left alone)
1716 int mem_equ_l (int nr1
, int nr2
, int * chance
, mtdf_info
* me
)
1720 if (me
->config
.randomchoose
== 0)
1733 randnr
= (int) ( (*chance
+ 1.0) * rand() / (RAND_MAX
+1.0) );
1746 ** just like a normal compare (>)
1750 ** 0/1: when nr1 and nr2 are equal, chooses one at random
1752 ** chance is the chance that nr1 will be chosen if nr1 == nr2
1753 ** this parameter will be incremented each time an equal occurs
1754 ** and will be set to 1 if nr1 > nr2
1755 ** (it should be initialised to 1 by the caller and then left alone)
1757 int mem_equ_h (int nr1
, int nr2
, int * chance
, mtdf_info
* me
)
1761 if (me
->config
.randomchoose
== 0)
1774 randnr
= (int) ( (*chance
+ 1.0) * rand() / (RAND_MAX
+1.0) );