(Temporarily) set "animate" to "none" by default (broken feature).
[gf1.git] / ai_mtdf.c
blob5a56e3ca7d9ab3af04d965d576e25c2e15b4da85
1 /*
2 ** $Id$
3 */
4 /*
5 ** Copyright (C) 1998 Kurt Van den Branden
6 **
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.
11 **
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.
16 **
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
28 #include "ai_mtdf.h"
30 #ifdef WINGIPF
31 extern void checkwindowevents (void);
32 extern int interrupt_computer;
33 #endif
35 /* structures for keeping my own info in */
36 typedef struct {
37 char colour;
38 int game;
39 int lastvalue;
40 struct {
41 int searchdepth;
42 int remoppgipf;
43 int maxgipf;
44 int memorydepth;
45 int randomchoose;
46 } config;
47 listheader * movelist; /* list of items of type nextmove */
48 } mtdf_info;
50 typedef struct {
51 int remtype; /* REM_GIPF or REM_ROW */
52 listheader * gipflist; /* list of items of type gipfdata */
53 struct {
54 char * start;
55 char * end;
56 } rowdata;
57 } nextmove;
59 #define REM_GIPF 1
60 #define REM_ROW 2
62 typedef struct {
63 char from[3];
64 char to[3];
65 char type;
66 listheader * movelist; /* list of items of type nextmove */
67 int value;
68 } movestruct;
70 typedef struct {
71 board * sboard;
72 char to[3];
73 } saveboard;
75 typedef struct {
76 char pos[3];
77 char flag;
78 } gipfdata;
80 typedef struct {
81 rem_gipf * gipf;
82 int flag;
83 } gipfitem;
85 /* things for the node-tree */
86 typedef struct {
87 board * father;
88 int upper;
89 int lower;
90 listheader * children; /* list of treeitems */
91 } treenode;
94 struct {
95 position coor;
96 int value;
97 } mem_pos_val[] = {
98 {{4, 5}, 5},
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}
104 #define MINNODE 1
105 #define MAXNODE 2
107 movestruct * mtdf_id (board * oboard, treenode * node, int f, mtdf_info * me,
108 int type);
109 movestruct * mtdf (board * oboard, treenode * node, int f, mtdf_info * me,
110 int type);
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,
116 saveboard * lmove);
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)
141 mtdf_info * me;
142 listheader * configlist;
144 me = (mtdf_info *) malloc (sizeof (mtdf_info));
145 me->colour = colour;
146 me->game = game;
147 me->lastvalue = 0;
148 me->movelist = NULL;
150 /* check for config-values from the config-file */
151 configlist = readconfigfile ("gf1.cfg");
153 me->config.searchdepth = findconfigvalue (configlist, "searchdepth",
154 colour, 3);
155 me->config.remoppgipf = findconfigvalue (configlist, "remoppgipf",
156 colour, 1);
157 me->config.maxgipf = findconfigvalue (configlist, "maxgipf",
158 colour, 3);
159 me->config.memorydepth = findconfigvalue (configlist, "memorydepth",
160 colour, 3);
161 me->config.randomchoose = findconfigvalue (configlist, "randomchoose",
162 colour, 1);
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;
174 movestruct * move;
175 treenode * root;
177 b_nolog (oboard);
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);
185 mem_deltree (root);
187 from[0] = move->from[0];
188 from[1] = move->from[1];
189 to[0] = move->to[0];
190 to[1] = move->to[1];
191 *type = move->type;
193 me->movelist = move->movelist;
195 move->movelist = NULL;
196 mem_del_move (move);
198 return;
202 char mtdf_gipf (board * oboard, void * self, char * pos)
204 mtdf_info * me = self;
205 nextmove * movedata;
206 gipfdata * gipfd;
207 int counter;
208 char val;
209 treenode * root;
211 b_nolog (oboard);
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)
220 movestruct * nmove;
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);
229 mem_deltree (root);
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))
240 /* very wrong */
241 exit (0);
244 /* look for the gipf to remove */
245 counter = 1;
246 while ((gipfd = (gipfdata *) llitembynr (movedata->gipflist, counter))
247 != NULL)
249 if ((gipfd->pos[0] == pos[0]) && (gipfd->pos[1] == pos[1]))
251 break;
253 counter++;
255 if (gipfd == NULL)
257 /* very wrong */
258 exit (0);
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);
268 free (movedata);
270 /* remove movelist if empty */
271 if (llitembynr (me->movelist, 1) == NULL)
273 free (me->movelist);
274 me->movelist = NULL;
278 val = gipfd->flag;
279 free (gipfd);
281 return (val);
285 char mtdf_row (board * oboard, void * self, char * start, char * end)
287 mtdf_info * me = self;
288 nextmove * movedata;
289 int correct;
290 treenode * root;
292 b_nolog (oboard);
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)
301 movestruct * nmove;
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);
310 mem_deltree (root);
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))
321 /* very wrong */
322 exit (0);
325 correct = 0;
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]))
333 correct = 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]))
342 correct = 1;
346 if (correct)
348 /* remove nextmove from movelist */
349 movedata = (nextmove *) llrembynr (me->movelist, 1);
350 free (movedata->rowdata.start);
351 free (movedata->rowdata.end);
352 free (movedata);
354 /* remove movelist if empty */
355 if (llitembynr (me->movelist, 1) == NULL)
357 free (me->movelist);
358 me->movelist = NULL;
361 return ('y');
364 /* don't remove the row */
365 return ('n');
369 void mtdf_end (void * self)
371 mtdf_info * me = self;
373 /* do I have to clean up the movelist first */
375 free (me);
376 return;
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,
386 int type)
388 int savemaxdepth,
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 */
401 mem_resetul (node);
404 me->config.searchdepth = i;
405 bestmove = mtdf (oboard, node, f, me, type);
408 me->config.searchdepth = savemaxdepth;
410 return (bestmove);
413 movestruct * mtdf (board * oboard, treenode * node, int f, mtdf_info * me,
414 int type)
416 int value,
417 upper,
418 lower,
419 beta;
420 movestruct * bestmove = NULL;
422 value = f;
423 upper = 1001;
424 lower = -1001;
426 while (lower < upper)
428 if (value == lower)
430 beta = value + 1;
432 else
434 beta = value;
437 if (bestmove != NULL)
439 mem_del_move (bestmove);
442 switch (type)
444 case 1:
445 bestmove = mem_ab_move (oboard, node, beta-1, beta,
446 MAXNODE, 1, me);
447 break;
449 case 2:
450 bestmove = mem_ab_gipf (oboard, node, beta-1, beta,
451 MINNODE, 1, me);
452 break;
454 case 3:
455 bestmove = mem_ab_row (oboard, node, beta-1, beta,
456 MINNODE, 1, me);
457 break;
459 value = bestmove->value;
461 if (value < beta)
463 upper = value;
465 else
467 lower = value;
471 me->lastvalue = value;
472 return (bestmove);
476 movestruct * mem_ab_move (board * oboard, treenode * node, int alfa, int beta,
477 int minmax, int depth, mtdf_info * me)
479 movestruct * nmove,
480 * bestmove = NULL;
481 fromto * allmoves;
482 int maxmoves,
483 value,
484 chance = 1,
486 saveboard lastmove;
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';
495 nmove->to[0] = '\0';
496 nmove->type = 0;
497 nmove->movelist = NULL;
498 nmove->value = mem_evaluate (oboard, me);
499 return (nmove);
502 #ifdef WINGIPF
503 if ((depth == 1) || (depth < me->config.searchdepth))
505 checkwindowevents ();
507 #endif
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)) <
514 me->config.maxgipf))
516 allmoves = allmovesg;
517 maxmoves = 84;
519 else
521 allmoves = allmovesn;
522 maxmoves = 42;
525 lastmove.sboard = NULL;
527 if (minmax == MAXNODE)
529 value = -1001;
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);
536 if (nmove == NULL)
538 continue;
540 if (mem_equ_h (nmove->value, value, &chance, me))
542 value = nmove->value;
543 if (bestmove != NULL)
545 mem_del_move (bestmove);
547 bestmove = nmove;
549 else
551 mem_del_move (nmove);
553 alfa = max (alfa, value);
555 if (value > beta)
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?
567 break;
571 else
573 value = 1001;
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);
580 if (nmove == NULL)
582 continue;
584 if (mem_equ_l (nmove->value, value, &chance, me))
586 value = nmove->value;
587 if (bestmove != NULL)
589 mem_del_move (bestmove);
591 bestmove = nmove;
593 else
595 mem_del_move (nmove);
597 beta = min (beta, value);
599 if (value < alfa)
601 break;
606 if ((childnode == NULL) && (lastmove.sboard != NULL))
608 b_del (lastmove.sboard);
611 return (bestmove);
615 movestruct * mem_move (board * oboard, treenode * node, int alfa, int beta,
616 int minmax, int depth, mtdf_info * me, fromto * todo,
617 saveboard * lmove)
619 board * newboard;
620 char piece;
621 int newminmax;
622 movestruct * mymove,
623 * nmove;
625 if ((node != NULL) && (node->children != NULL))
626 { /* node already visited, reuse from memory */
627 if (node->father == NULL)
629 return (NULL);
631 newboard = node->father;
633 #if 0
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];
647 nmove->type = 0;
648 nmove->movelist = NULL;
649 nmove->value = node->lower;
650 return (nmove);
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;
662 return (nmove);
664 alfa = max (alfa, node->lower);
665 beta = min (beta, node->upper);
666 #endif
668 else
670 if (node != NULL)
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));
681 else
683 piece = b_next_piece (oboard);
686 newboard = b_move (oboard, todo->from, todo->to, piece);
687 if (node != NULL)
689 node->father = newboard;
692 if (newboard == NULL)
694 return (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))
702 b_del (newboard);
703 if (node != NULL)
705 node->father = NULL;
707 return (NULL);
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,
732 depth+1, me);
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);
752 else
753 { /* impossible */
754 exit (0);
757 if (node != NULL)
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;
773 return (mymove);
777 movestruct * mem_ab_gipf (board * oboard, treenode * node, int alfa, int beta,
778 int minmax, int depth, mtdf_info * me)
780 movestruct * nmove,
781 * bestmove = NULL;
782 int value,
783 realminmax,
784 counter,
785 mynr,
787 maxnr;
788 unsigned char bits1,
789 bits2;
790 rem_gipf * gipfi;
791 listheader * myg,
792 * otherg;
793 char * gipfpos;
794 gipfitem * gipfflag;
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);
808 else
810 realminmax = minmax;
813 /* always remove gipf-pieces from my opponent if the flag is set */
814 myg = (listheader *) malloc (sizeof (listheader));
815 newlist (myg);
816 otherg = (listheader *) malloc (sizeof (listheader));
817 newlist (otherg);
818 counter = 1;
819 mynr = 0;
820 while ((gipfi = (rem_gipf *) llitembynr (b_gipf_extra (oboard), counter))
821 != NULL)
823 counter++;
824 gipfflag = (gipfitem *) malloc (sizeof (gipfitem));
825 gipfflag->gipf = gipfi;
826 gipfflag->flag = 1;
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);
835 else
837 mynr++;
838 pushll (myg, (void *) gipfflag);
840 free (gipfpos);
843 maxnr = 1 << mynr; /* 2 ^ mynr */
845 if (realminmax == MAXNODE)
847 value = -1001;
849 for (bits1 = 0; bits1 < maxnr ; bits1++)
851 bits2 = bits1;
852 for (i = 0; i < mynr; i++)
854 gipfflag = (gipfitem *) llitembynr (myg, i+1);
855 gipfflag->flag = bits2 & 1;
856 bits2 = 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);
869 bestmove = nmove;
871 else
873 mem_del_move (nmove);
875 alfa = max (alfa, value);
877 if (value > beta)
879 break;
883 else
885 value = 1001;
887 for (bits1 = 0; bits1 < maxnr ; bits1++)
889 bits2 = bits1;
890 for (i = 0; i < mynr; i++)
892 gipfflag = (gipfitem *) llitembynr (myg, i+1);
893 gipfflag->flag = bits2 & 1;
894 bits2 = 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);
907 bestmove = nmove;
909 else
911 mem_del_move (nmove);
913 beta = min (beta, value);
915 if (value < alfa)
917 break;
922 /* cleanup temporary lists */
923 while ((gipfflag = (gipfitem *) llrembynr (myg, 1)) != NULL)
925 free (gipfflag);
927 free (myg);
928 while ((gipfflag = (gipfitem *) llrembynr (otherg, 1)) != NULL)
930 free (gipfflag);
932 free (otherg);
934 return (bestmove);
938 movestruct * mem_rem_gipflist (board * oboard, treenode * node, int alfa,
939 int beta, int minmax, int depth,
940 mtdf_info * me, listheader * myg,
941 listheader * otherg)
943 board * nboard,
944 * newboard;
945 movestruct * mymove,
946 * nmove;
947 int counter;
948 gipfitem * gipfflag;
949 listheader * remlist;
950 gipfdata * gipfd;
951 char * strpos,
952 owner;
953 nextmove * movedata;
954 int newminmax;
956 if ((node != NULL) && (node->children != NULL))
957 { /* node already visited, reuse from memory */
958 if (node->father == NULL)
960 return (NULL);
962 newboard = node->father;
964 /* I have to produce remlist here again */
965 remlist = (listheader *) malloc (sizeof (listheader));;
966 newlist (remlist);
967 /* list of gipf-pieces that may or may not have to be removed */
968 counter = 1;
969 while ((gipfflag = (gipfitem *) llitembynr (myg, counter)) != NULL)
971 counter++;
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';
978 free (strpos);
980 if (gipfflag->flag == 1)
982 gipfd->flag = 'y';
984 else
986 gipfd->flag = 'n';
988 pushll (remlist, (void *) gipfd);
990 /* list of gipf-pieces that always have to be removed */
991 counter = 1;
992 while ((gipfflag = (gipfitem *) llitembynr (otherg, counter)) != NULL)
994 counter++;
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';
1001 free (strpos);
1003 gipfd->flag = 'y';
1004 pushll (remlist, (void *) gipfd);
1008 else
1010 if (node != NULL)
1012 /* create children list */
1013 node->children = (listheader *) malloc (sizeof (listheader));
1014 newlist (node->children);
1017 newboard = oboard;
1018 remlist = (listheader *) malloc (sizeof (listheader));;
1019 newlist (remlist);
1020 /* list of gipf-pieces that may or may not have to be removed */
1021 counter = 1;
1022 while ((gipfflag = (gipfitem *) llitembynr (myg, counter)) != NULL)
1024 counter++;
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';
1031 free (strpos);
1033 if (gipfflag->flag == 1)
1035 gipfd->flag = 'y';
1036 nboard = b_remove_gipf (newboard, gipfflag->gipf);
1037 if (newboard != oboard)
1039 b_del (newboard);
1041 newboard = nboard;
1043 else
1045 gipfd->flag = 'n';
1047 pushll (remlist, (void *) gipfd);
1050 /* list of gipf-pieces that always have to be removed */
1051 counter = 1;
1052 while ((gipfflag = (gipfitem *) llitembynr (otherg, counter)) != NULL)
1054 counter++;
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';
1061 free (strpos);
1063 gipfd->flag = 'y';
1064 nboard = b_remove_gipf (newboard, gipfflag->gipf);
1065 if (newboard != oboard)
1067 b_del (newboard);
1069 newboard = nboard;
1070 pushll (remlist, (void *) gipfd);
1073 /* check again for 4 in a row */
1074 nboard = b_checkfour (newboard);
1075 if (newboard != oboard)
1077 b_del (newboard);
1080 newboard = nboard;
1081 if (node != NULL)
1083 node->father = newboard;
1087 mymove = (movestruct *) malloc (sizeof (movestruct));
1088 mymove->from[0] = '\0';
1089 mymove->to[0] = '\0';
1090 mymove->type = 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);
1107 else
1108 { /* remove remlist, we don't need it here */
1109 while ((gipfd = (gipfdata *) llrembynr (remlist, 1)) != NULL)
1111 free (gipfd);
1113 free (remlist);
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,
1122 depth+1, me);
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))
1131 != NULL)
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))
1144 != NULL)
1146 pushll (mymove->movelist, (void *) movedata);
1149 mymove->value = nmove->value;
1150 mem_del_move (nmove);
1152 else
1153 { /* impossible */
1154 exit (0);
1157 /* check if the movelist of mymove contains something */
1158 if (llitembynr (mymove->movelist, 1) == NULL)
1160 free (mymove->movelist);
1161 mymove->movelist = NULL;
1164 if (node == NULL)
1166 b_del (newboard);
1168 else
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;
1185 return (mymove);
1189 movestruct * mem_ab_row (board * oboard, treenode * node, int alfa, int beta,
1190 int minmax, int depth, mtdf_info * me)
1192 int counter,
1193 value,
1194 realminmax;
1195 movestruct * nmove,
1196 * bestmove = NULL;
1197 rem_row * rowi;
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);
1213 else
1215 realminmax = minmax;
1218 if (realminmax == MAXNODE)
1220 value = -1001;
1222 counter = 1;
1223 while ((rowi = (rem_row *) llitembynr (rowlist, counter))
1224 != NULL)
1226 childnode = mem_child (node, counter, me, depth);
1227 nmove = mem_rem_row (oboard, childnode, alfa, beta, minmax,
1228 depth, me, counter);
1229 counter++;
1231 if (nmove->value > value)
1233 value = nmove->value;
1234 if (bestmove != NULL)
1236 mem_del_move (bestmove);
1238 bestmove = nmove;
1240 else
1242 mem_del_move (nmove);
1244 alfa = max (alfa, value);
1246 if (value > beta)
1248 break;
1252 else
1254 value = 1001;
1256 counter = 1;
1257 while ((rowi = (rem_row *) llitembynr (rowlist, counter))
1258 != NULL)
1260 childnode = mem_child (node, counter, me, depth);
1261 nmove = mem_rem_row (oboard, childnode, alfa, beta, minmax,
1262 depth, me, counter);
1263 counter++;
1265 if (nmove->value < value)
1267 value = nmove->value;
1268 if (bestmove != NULL)
1270 mem_del_move (bestmove);
1272 bestmove = nmove;
1274 else
1276 mem_del_move (nmove);
1278 beta = min (beta, value);
1280 if (value < alfa)
1282 break;
1287 return (bestmove);
1291 movestruct * mem_rem_row (board * oboard, treenode * node, int alfa, int beta,
1292 int minmax, int depth, mtdf_info * me, int rem)
1294 board * newboard;
1295 movestruct * nmove,
1296 * mymove;
1297 rem_row * remi;
1298 nextmove * movedata;
1299 int newminmax;
1301 if ((node != NULL) && (node->children != NULL))
1302 { /* node already visited, reuse from memory */
1303 if (node->father == NULL)
1305 return (NULL);
1307 newboard = node->father;
1309 else
1311 if (node != NULL)
1313 /* create children list */
1314 node->children = (listheader *) malloc (sizeof (listheader));
1315 newlist (node->children);
1318 newboard = b_remove_row (oboard, rem);
1319 if (node != NULL)
1321 node->father = newboard;
1325 mymove = (movestruct *) malloc (sizeof (movestruct));
1326 mymove->from[0] = '\0';
1327 mymove->to[0] = '\0';
1328 mymove->type = 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,
1355 depth+1, me);
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))
1364 != NULL)
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))
1377 != NULL)
1379 pushll (mymove->movelist, (void *) movedata);
1382 mymove->value = nmove->value;
1383 mem_del_move (nmove);
1385 else
1386 { /* impossible */
1387 exit (0);
1390 /* check if the movelist of mymove contains something */
1391 if (llitembynr (mymove->movelist, 1) == NULL)
1393 free (mymove->movelist);
1394 mymove->movelist = NULL;
1397 if (node == NULL)
1399 b_del (newboard);
1401 else
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;
1418 return (mymove);
1422 ** calculate the value of a certain board position
1424 ** returns a value between 1000 and -1000 (inclusive)
1425 ** 1000 : I win
1426 ** -1000 : my opponent wins
1428 int mem_evaluate (board * oboard, mtdf_info * me)
1430 int total,
1432 value;
1433 double wvalue,
1434 bvalue;
1435 char myc,
1436 otherc;
1437 position * pos;
1439 myc = me->colour;
1440 otherc = b_opponent (myc);
1442 if (b_game_finished (oboard))
1444 if (b_winner (oboard) == myc)
1446 return (1000);
1448 else
1450 return (-1000);
1454 /* maybe I can return 1000 or -1000, but I'm not completely sure */
1455 if (b_colour (oboard, myc) == 0)
1457 return (-999);
1459 else if (b_colour (oboard, otherc) == 0)
1461 return (999);
1464 /* I need to start with a base-value, or I get a lot of
1465 ** problems at the start of tournament games */
1466 wvalue = 20;
1467 bvalue = 20;
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)
1475 total = 15;
1476 else
1477 total = 18;
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)
1487 wvalue -= 5;
1489 if (b_black_gipf (oboard) == 1)
1491 bvalue -= 5;
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))
1500 case '.':
1501 break;
1503 case 'o':
1504 wvalue += mem_pos_val[i].value;
1505 break;
1507 case 'O':
1508 wvalue += mem_pos_val[i].value * 1.5;
1509 break;
1511 case 'x':
1512 bvalue += mem_pos_val[i].value;
1513 break;
1515 default:
1516 bvalue += mem_pos_val[i].value * 1.5;
1519 piece = b_ppiece (oboard, pos);
1520 if (piece == '.')
1522 continue;
1524 if (piece == 'o')
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;
1536 else
1538 bvalue += mem_pos_val[i].value * 1.5;
1543 /* normalize the result, should be between 1000 and -1000 */
1544 if (myc == 'o')
1546 value = (int) ((wvalue - bvalue) * 1000 / (wvalue + bvalue));
1548 else
1550 value = (int) ((bvalue - wvalue) * 1000 / (wvalue + bvalue));
1553 return (value);
1556 void mem_del_move (movestruct * todel)
1558 nextmove * movedata;
1559 gipfdata * gipfd;
1561 if (todel->movelist != NULL)
1563 while ((movedata = (nextmove *) llrembynr (todel->movelist, 1))
1564 != NULL)
1566 if (movedata->remtype == REM_ROW)
1568 free (movedata->rowdata.start);
1569 free (movedata->rowdata.end);
1571 else
1573 while ((gipfd = (gipfdata *)
1574 llrembynr (movedata->gipflist, 1)) != NULL)
1576 free (gipfd);
1578 free (movedata->gipflist);
1581 free (movedata);
1583 free (todel->movelist);
1586 free (todel);
1587 return;
1592 ** create the root of the tree
1594 ** parameter:
1595 ** father: the board at the root of the tree
1597 treenode * mem_makeroot (board * father, mtdf_info * me)
1599 treenode * newnode;
1601 if (me->config.memorydepth == 0)
1603 return (NULL);
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);
1614 return (newnode);
1619 ** delete a tree
1620 ** don't delete the father from the root-node
1622 void mem_deltree (treenode * node)
1624 if (node == NULL)
1626 return;
1629 emptyll (node->children, mem_delnode);
1630 free (node->children);
1631 free (node);
1633 return;
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);
1643 free (node);
1645 return;
1650 ** reset upper and lower limits in the memory-tree
1652 void mem_resetul (void * item)
1654 treenode * node = item;
1656 node->upper = 1001;
1657 node->lower = -1001;
1658 doll (node->children, mem_resetul);
1660 return;
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)
1670 treenode * newnode;
1672 if (me->config.memorydepth < depth)
1674 return (NULL);
1677 newnode = (treenode *) llitembynr (node->children, nr);
1678 if (newnode != NULL)
1679 { /* this node has already been handled, return it */
1680 return (newnode);
1683 #if 0
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");
1689 exit (0);
1691 #endif
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);
1701 return (newnode);
1705 ** just like a normal compare (<)
1706 ** returns:
1707 ** 1 : nr1 < nr2
1708 ** 0: nr1 > nr2
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)
1718 int randnr;
1720 if (me->config.randomchoose == 0)
1721 return (nr1 < nr2);
1723 if (nr1 < nr2)
1725 *chance = 1;
1726 return (1);
1728 if (nr1 > nr2)
1730 return (0);
1733 randnr = (int) ( (*chance + 1.0) * rand() / (RAND_MAX+1.0) );
1734 (*chance)++;
1736 if (randnr < 1)
1738 return (1);
1741 return (0);
1746 ** just like a normal compare (>)
1747 ** returns:
1748 ** 1 : nr1 > nr2
1749 ** 0: nr1 < nr2
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)
1759 int randnr;
1761 if (me->config.randomchoose == 0)
1762 return (nr1 > nr2);
1764 if (nr1 > nr2)
1766 *chance = 1;
1767 return (1);
1769 if (nr1 < nr2)
1771 return (0);
1774 randnr = (int) ( (*chance + 1.0) * rand() / (RAND_MAX+1.0) );
1775 (*chance)++;
1777 if (randnr < 1)
1779 return (1);
1782 return (0);