Support for g++-4.1.
[gf1.git] / ai_mtdf.c
blob7f76ca0ee8975f7855e9283f4e385abdf4b3a164
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 #define min(x, y) (x < y ? x : y)
108 #define max(x, y) (x > y ? x : y)
110 movestruct * mtdf_id (board * oboard, treenode * node, int f, mtdf_info * me,
111 int type);
112 movestruct * mtdf (board * oboard, treenode * node, int f, mtdf_info * me,
113 int type);
115 movestruct * mem_ab_move (board * oboard, treenode * node, int alfa, int beta,
116 int minmax, int depth, mtdf_info * me);
117 movestruct * mem_move (board * oboard, treenode * node, int alfa, int beta,
118 int minmax, int depth, mtdf_info * me, fromto * todo,
119 saveboard * lmove);
120 movestruct * mem_ab_gipf (board * oboard, treenode * node, int alfa, int beta,
121 int minmax, int depth, mtdf_info * me);
122 movestruct * mem_rem_gipflist (board * oboard, treenode * node, int alfa,
123 int beta, int minmax, int depth,
124 mtdf_info * me, listheader * myg,
125 listheader * otherg);
126 movestruct * mem_ab_row (board * oboard, treenode * node, int alfa, int beta,
127 int minmax, int depth, mtdf_info * me);
128 movestruct * mem_rem_row (board * oboard, treenode * node, int alfa, int beta,
129 int minmax, int depth, mtdf_info * me, int rem);
130 int mem_evaluate (board * oboard, mtdf_info * me);
131 void mem_del_move (movestruct * todel);
133 void mem_deltree (treenode * node);
134 void mem_delnode (void * item);
135 treenode * mem_makeroot (board * father, mtdf_info * me);
136 treenode * mem_child (treenode * node, int nr, mtdf_info * me, int depth);
137 void mem_resetul (void * item);
139 int mem_equ_l (int nr1, int nr2, int * chance, mtdf_info * me);
140 int mem_equ_h (int nr1, int nr2, int * chance, mtdf_info * me);
142 void * mtdf_new (char colour, int game)
144 mtdf_info * me;
145 listheader * configlist;
147 me = (mtdf_info *) malloc (sizeof (mtdf_info));
148 me->colour = colour;
149 me->game = game;
150 me->lastvalue = 0;
151 me->movelist = NULL;
153 /* check for config-values from the config-file */
154 configlist = readconfigfile ("gf1.cfg");
156 me->config.searchdepth = findconfigvalue (configlist, "searchdepth",
157 colour, 3);
158 me->config.remoppgipf = findconfigvalue (configlist, "remoppgipf",
159 colour, 1);
160 me->config.maxgipf = findconfigvalue (configlist, "maxgipf",
161 colour, 3);
162 me->config.memorydepth = findconfigvalue (configlist, "memorydepth",
163 colour, 3);
164 me->config.randomchoose = findconfigvalue (configlist, "randomchoose",
165 colour, 1);
167 clearconfiglist (configlist);
169 return ((void *) me);
173 void mtdf_move (board * oboard, void * self,
174 char * type, char * from, char * to)
176 mtdf_info * me = self;
177 movestruct * move;
178 treenode * root;
180 b_nolog (oboard);
182 root = mem_makeroot (oboard, me);
184 move = mtdf (oboard, root, me->lastvalue, me, 1);
186 move = mtdf_id (oboard, root, me->lastvalue, me, 1);
188 mem_deltree (root);
190 from[0] = move->from[0];
191 from[1] = move->from[1];
192 to[0] = move->to[0];
193 to[1] = move->to[1];
194 *type = move->type;
196 me->movelist = move->movelist;
198 move->movelist = NULL;
199 mem_del_move (move);
201 return;
205 char mtdf_gipf (board * oboard, void * self, char * pos)
207 mtdf_info * me = self;
208 nextmove * movedata;
209 gipfdata * gipfd;
210 int counter;
211 char val;
212 treenode * root;
214 b_nolog (oboard);
216 /* check if movelist contains info about removing gipf-pieces */
217 if (me->movelist == NULL)
220 ** no info in movelist, my opponent made 4 in a row
221 ** with my pieces (only possible explanation)
223 movestruct * nmove;
225 /* remark: I have to start this as a min-node,
226 ** because this is really my opponents move */
227 root = mem_makeroot (oboard, me);
229 nmove = mtdf (oboard, root, me->lastvalue, me, 2);
231 nmove = mtdf_id (oboard, root, me->lastvalue, me, 2);
232 mem_deltree (root);
234 me->movelist = nmove->movelist;
235 nmove->movelist = NULL;
236 mem_del_move (nmove);
239 /* now check the movelist for the move we have to make */
240 if (((movedata = (nextmove *) llitembynr (me->movelist, 1)) == NULL) ||
241 (movedata->remtype != REM_GIPF))
243 /* very wrong */
244 exit (0);
247 /* look for the gipf to remove */
248 counter = 1;
249 while ((gipfd = (gipfdata *) llitembynr (movedata->gipflist, counter))
250 != NULL)
252 if ((gipfd->pos[0] == pos[0]) && (gipfd->pos[1] == pos[1]))
254 break;
256 counter++;
258 if (gipfd == NULL)
260 /* very wrong */
261 exit (0);
263 /* remove gipf from list */
264 gipfd = (gipfdata *) llrembynr (movedata->gipflist, counter);
266 /* remove nextmove from movelist if gipflist is empty */
267 if (llitembynr (movedata->gipflist, 1) == NULL)
269 movedata = (nextmove *) llrembynr (me->movelist, 1);
270 free (movedata->gipflist);
271 free (movedata);
273 /* remove movelist if empty */
274 if (llitembynr (me->movelist, 1) == NULL)
276 free (me->movelist);
277 me->movelist = NULL;
281 val = gipfd->flag;
282 free (gipfd);
284 return (val);
288 char mtdf_row (board * oboard, void * self, char * start, char * end)
290 mtdf_info * me = self;
291 nextmove * movedata;
292 int correct;
293 treenode * root;
295 b_nolog (oboard);
297 /* check if movelist contains info about removing rows */
298 if (me->movelist == NULL)
301 ** no info in movelist, my opponent made several "4 in a row"s
302 ** with my pieces (only possible explanation)
304 movestruct * nmove;
306 /* remark: I have to start this as a min-node,
307 ** because this is really my opponents move */
308 root = mem_makeroot (oboard, me);
310 nmove = mtdf (oboard, root, me->lastvalue, me, 3);
312 nmove = mtdf_id (oboard, root, me->lastvalue, me, 3);
313 mem_deltree (root);
315 me->movelist = nmove->movelist;
316 nmove->movelist = NULL;
317 mem_del_move (nmove);
320 /* now check the movelist for the move we have to make */
321 if (((movedata = (nextmove *) llitembynr (me->movelist, 1)) == NULL) ||
322 (movedata->remtype != REM_ROW))
324 /* very wrong */
325 exit (0);
328 correct = 0;
329 /* check if this is the correct row to be removed */
330 if ((start[0] == movedata->rowdata.start[0]) &&
331 (start[1] == movedata->rowdata.start[1]))
333 if ((end[0] == movedata->rowdata.end[0]) &&
334 (end[1] == movedata->rowdata.end[1]))
336 correct = 1;
339 else if ((start[0] == movedata->rowdata.end[0]) &&
340 (start[1] == movedata->rowdata.end[1]))
342 if ((end[0] == movedata->rowdata.start[0]) &&
343 (end[1] == movedata->rowdata.start[1]))
345 correct = 1;
349 if (correct)
351 /* remove nextmove from movelist */
352 movedata = (nextmove *) llrembynr (me->movelist, 1);
353 free (movedata->rowdata.start);
354 free (movedata->rowdata.end);
355 free (movedata);
357 /* remove movelist if empty */
358 if (llitembynr (me->movelist, 1) == NULL)
360 free (me->movelist);
361 me->movelist = NULL;
364 return ('y');
367 /* don't remove the row */
368 return ('n');
372 void mtdf_end (void * self)
374 mtdf_info * me = self;
376 /* do I have to clean up the movelist first */
378 free (me);
379 return;
384 ** iterative deepening around mtdf
386 ** REMARK: doesn't work, don't know why yet
388 movestruct * mtdf_id (board * oboard, treenode * node, int f, mtdf_info * me,
389 int type)
391 int savemaxdepth,
393 movestruct * bestmove = NULL;
395 savemaxdepth = me->config.searchdepth;
397 for (i = 1; i <= savemaxdepth; i++)
399 if (bestmove != NULL)
401 mem_del_move (bestmove);
403 /* reset upper and lower limits in the memory-tree */
404 mem_resetul (node);
407 me->config.searchdepth = i;
408 bestmove = mtdf (oboard, node, f, me, type);
411 me->config.searchdepth = savemaxdepth;
413 return (bestmove);
416 movestruct * mtdf (board * oboard, treenode * node, int f, mtdf_info * me,
417 int type)
419 int value,
420 upper,
421 lower,
422 beta;
423 movestruct * bestmove = NULL;
425 value = f;
426 upper = 1001;
427 lower = -1001;
429 while (lower < upper)
431 if (value == lower)
433 beta = value + 1;
435 else
437 beta = value;
440 if (bestmove != NULL)
442 mem_del_move (bestmove);
445 switch (type)
447 case 1:
448 bestmove = mem_ab_move (oboard, node, beta-1, beta,
449 MAXNODE, 1, me);
450 break;
452 case 2:
453 bestmove = mem_ab_gipf (oboard, node, beta-1, beta,
454 MINNODE, 1, me);
455 break;
457 case 3:
458 bestmove = mem_ab_row (oboard, node, beta-1, beta,
459 MINNODE, 1, me);
460 break;
462 value = bestmove->value;
464 if (value < beta)
466 upper = value;
468 else
470 lower = value;
474 me->lastvalue = value;
475 return (bestmove);
479 movestruct * mem_ab_move (board * oboard, treenode * node, int alfa, int beta,
480 int minmax, int depth, mtdf_info * me)
482 movestruct * nmove,
483 * bestmove = NULL;
484 fromto * allmoves;
485 int maxmoves,
486 value,
487 chance = 1,
489 saveboard lastmove;
490 treenode * childnode;
492 /* maximum search depth or end of game */
493 if ((b_game_finished (oboard)) ||
494 (depth > me->config.searchdepth))
496 nmove = (movestruct *) malloc (sizeof (movestruct));
497 nmove->from[0] = '\0';
498 nmove->to[0] = '\0';
499 nmove->type = 0;
500 nmove->movelist = NULL;
501 nmove->value = mem_evaluate (oboard, me);
502 return (nmove);
505 #ifdef WINGIPF
506 if ((depth == 1) || (depth < me->config.searchdepth))
508 checkwindowevents ();
510 #endif
512 /* list of moves to try depends on the question if we can
513 ** place a gipf or not.
514 ** cutoff after a predetermined number of gipf-pieces */
515 if ((b_colour_type (oboard, b_next_piece (oboard)) == 'g') &&
516 (b_colour_gipf (oboard, b_next_piece (oboard)) <
517 me->config.maxgipf))
519 allmoves = allmovesg;
520 maxmoves = 84;
522 else
524 allmoves = allmovesn;
525 maxmoves = 42;
528 lastmove.sboard = NULL;
530 if (minmax == MAXNODE)
532 value = -1001;
534 for (i = 0; i < maxmoves; i++)
536 childnode = mem_child (node, i+1, me, depth);
537 nmove = mem_move (oboard, childnode, alfa, beta, minmax,
538 depth, me, &(allmoves[i]), &lastmove);
539 if (nmove == NULL)
541 continue;
543 if (mem_equ_h (nmove->value, value, &chance, me))
545 value = nmove->value;
546 if (bestmove != NULL)
548 mem_del_move (bestmove);
550 bestmove = nmove;
552 else
554 mem_del_move (nmove);
556 alfa = max (alfa, value);
558 if (value > beta)
561 ** problems if value is the same as beta, this means that
562 ** when randomly selecting a move from the moves with the
563 ** same value, this one could be chosen.
564 ** solution: change value to (-1001 or 1001)
565 ** or the current value (+1 or -1)
567 ** is this correct? or does it depend on the fact if
568 ** this was called from a min- or a max-node?
570 break;
574 else
576 value = 1001;
578 for (i = 0; i < maxmoves; i++)
580 childnode = mem_child (node, i+1, me, depth);
581 nmove = mem_move (oboard, childnode, alfa, beta, minmax,
582 depth, me, &(allmoves[i]), &lastmove);
583 if (nmove == NULL)
585 continue;
587 if (mem_equ_l (nmove->value, value, &chance, me))
589 value = nmove->value;
590 if (bestmove != NULL)
592 mem_del_move (bestmove);
594 bestmove = nmove;
596 else
598 mem_del_move (nmove);
600 beta = min (beta, value);
602 if (value < alfa)
604 break;
609 if ((childnode == NULL) && (lastmove.sboard != NULL))
611 b_del (lastmove.sboard);
614 return (bestmove);
618 movestruct * mem_move (board * oboard, treenode * node, int alfa, int beta,
619 int minmax, int depth, mtdf_info * me, fromto * todo,
620 saveboard * lmove)
622 board * newboard;
623 char piece;
624 int newminmax;
625 movestruct * mymove,
626 * nmove;
628 if ((node != NULL) && (node->children != NULL))
629 { /* node already visited, reuse from memory */
630 if (node->father == NULL)
632 return (NULL);
634 newboard = node->father;
636 #if 0
638 ** removing this solves the problem of bad play
639 ** but it makes the computerplayer twice as slow as ai_minimax
641 ** it also solves the problem of iterative deepening not working
643 if (node->lower >= beta)
645 nmove = (movestruct *) malloc (sizeof (movestruct));
646 nmove->from[0] = todo->from[0];
647 nmove->from[1] = todo->from[1];
648 nmove->to[0] = todo->to[0];
649 nmove->to[1] = todo->to[1];
650 nmove->type = 0;
651 nmove->movelist = NULL;
652 nmove->value = node->lower;
653 return (nmove);
655 if (node->upper <= alfa)
657 nmove = (movestruct *) malloc (sizeof (movestruct));
658 nmove->from[0] = todo->from[0];
659 nmove->from[1] = todo->from[1];
660 nmove->to[0] = todo->to[0];
661 nmove->to[1] = todo->to[1];
662 nmove->type = todo->type;
663 nmove->movelist = NULL;
664 nmove->value = node->upper;
665 return (nmove);
667 alfa = max (alfa, node->lower);
668 beta = min (beta, node->upper);
669 #endif
671 else
673 if (node != NULL)
675 /* create children list */
676 node->children = (listheader *) malloc (sizeof (listheader));
677 newlist (node->children);
680 if (todo->type == 'g')
682 piece = b_otherpiece (b_next_piece (oboard));
684 else
686 piece = b_next_piece (oboard);
689 newboard = b_move (oboard, todo->from, todo->to, piece);
690 if (node != NULL)
692 node->father = newboard;
695 if (newboard == NULL)
697 return (NULL);
700 /* check if the result is the same as the last move */
701 if ((lmove->sboard != NULL) &&
702 ((lmove->to[0] == todo->to[0]) && (lmove->to[1] == todo->to[1])) &&
703 (b_compare (newboard, lmove->sboard) == 0))
705 b_del (newboard);
706 if (node != NULL)
708 node->father = NULL;
710 return (NULL);
712 if ((node == NULL) && (lmove->sboard != NULL))
714 b_del (lmove->sboard);
716 lmove->sboard = newboard; /* don't delete the board at the end */
717 lmove->to[0] = todo->to[0];
718 lmove->to[1] = todo->to[1];
721 /* create new movestruct */
722 mymove = (movestruct *) malloc (sizeof (movestruct));
723 mymove->from[0] = todo->from[0];
724 mymove->from[1] = todo->from[1];
725 mymove->to[0] = todo->to[0];
726 mymove->to[1] = todo->to[1];
727 mymove->type = todo->type;
728 mymove->movelist = NULL;
730 newminmax = (minmax == MINNODE ? MAXNODE : MINNODE);
731 if ((b_status (newboard) == S_NORMAL) ||
732 (b_status (newboard) == S_FINISHED))
734 nmove = mem_ab_move (newboard, node, alfa, beta, newminmax,
735 depth+1, me);
736 mymove->value = nmove->value;
737 mem_del_move (nmove);
739 else if (b_status (newboard) == S_REMOVEROW)
741 nmove = mem_ab_row (newboard, node, alfa, beta, minmax, depth, me);
742 mymove->movelist = nmove->movelist;
743 mymove->value = nmove->value;
744 nmove->movelist = NULL;
745 mem_del_move (nmove);
747 else if (b_status (newboard) == S_REMOVEGIPF)
749 nmove = mem_ab_gipf (newboard, node, alfa, beta, minmax, depth, me);
750 mymove->movelist = nmove->movelist;
751 mymove->value = nmove->value;
752 nmove->movelist = NULL;
753 mem_del_move (nmove);
755 else
756 { /* impossible */
757 exit (0);
760 if (node != NULL)
762 if (mymove->value <= alfa)
764 node->upper = mymove->value;
766 else if ((mymove->value > alfa) && (mymove->value < beta))
767 { /* this shouldn't happen with zero window searches */
768 node->upper = node->lower = mymove->value;
770 else if (mymove->value >= beta)
772 node->lower = mymove->value;
776 return (mymove);
780 movestruct * mem_ab_gipf (board * oboard, treenode * node, int alfa, int beta,
781 int minmax, int depth, mtdf_info * me)
783 movestruct * nmove,
784 * bestmove = NULL;
785 int value,
786 realminmax,
787 counter,
788 mynr,
790 maxnr;
791 unsigned char bits1,
792 bits2;
793 rem_gipf * gipfi;
794 listheader * myg,
795 * otherg;
796 char * gipfpos;
797 gipfitem * gipfflag;
798 treenode * childnode;
800 gipfi = (rem_gipf *) llitembynr (b_gipf_extra (oboard), 1);
803 ** I may have to change if I am a min or a max-node here
804 ** it's possible that my opponent won a row, so he has to
805 ** decide if gipf-pieces must be removed
807 if (b_gipf_owner(gipfi) == b_next_piece (oboard))
809 realminmax = (minmax == MINNODE ? MAXNODE : MINNODE);
811 else
813 realminmax = minmax;
816 /* always remove gipf-pieces from my opponent if the flag is set */
817 myg = (listheader *) malloc (sizeof (listheader));
818 newlist (myg);
819 otherg = (listheader *) malloc (sizeof (listheader));
820 newlist (otherg);
821 counter = 1;
822 mynr = 0;
823 while ((gipfi = (rem_gipf *) llitembynr (b_gipf_extra (oboard), counter))
824 != NULL)
826 counter++;
827 gipfflag = (gipfitem *) malloc (sizeof (gipfitem));
828 gipfflag->gipf = gipfi;
829 gipfflag->flag = 1;
831 gipfpos = b_gipf_position (gipfi);
832 if ((me->config.remoppgipf == 1) &&
833 (b_otherpiece (b_gipf_owner (gipfi)) !=
834 b_piece (oboard, gipfpos)))
836 pushll (otherg, (void *) gipfflag);
838 else
840 mynr++;
841 pushll (myg, (void *) gipfflag);
843 free (gipfpos);
846 maxnr = 1 << mynr; /* 2 ^ mynr */
848 if (realminmax == MAXNODE)
850 value = -1001;
852 for (bits1 = 0; bits1 < maxnr ; bits1++)
854 bits2 = bits1;
855 for (i = 0; i < mynr; i++)
857 gipfflag = (gipfitem *) llitembynr (myg, i+1);
858 gipfflag->flag = bits2 & 1;
859 bits2 = bits2 >> 1;
861 childnode = mem_child (node, bits1 + 1, me, depth);
862 nmove = mem_rem_gipflist (oboard, childnode, alfa, beta,
863 minmax, depth, me, myg, otherg);
865 if (nmove->value > value)
867 value = nmove->value;
868 if (bestmove != NULL)
870 mem_del_move (bestmove);
872 bestmove = nmove;
874 else
876 mem_del_move (nmove);
878 alfa = max (alfa, value);
880 if (value > beta)
882 break;
886 else
888 value = 1001;
890 for (bits1 = 0; bits1 < maxnr ; bits1++)
892 bits2 = bits1;
893 for (i = 0; i < mynr; i++)
895 gipfflag = (gipfitem *) llitembynr (myg, i+1);
896 gipfflag->flag = bits2 & 1;
897 bits2 = bits2 >> 1;
899 childnode = mem_child (node, bits1 + 1, me, depth);
900 nmove = mem_rem_gipflist (oboard, childnode, alfa, beta,
901 minmax, depth, me, myg, otherg);
903 if (nmove->value < value)
905 value = nmove->value;
906 if (bestmove != NULL)
908 mem_del_move (bestmove);
910 bestmove = nmove;
912 else
914 mem_del_move (nmove);
916 beta = min (beta, value);
918 if (value < alfa)
920 break;
925 /* cleanup temporary lists */
926 while ((gipfflag = (gipfitem *) llrembynr (myg, 1)) != NULL)
928 free (gipfflag);
930 free (myg);
931 while ((gipfflag = (gipfitem *) llrembynr (otherg, 1)) != NULL)
933 free (gipfflag);
935 free (otherg);
937 return (bestmove);
941 movestruct * mem_rem_gipflist (board * oboard, treenode * node, int alfa,
942 int beta, int minmax, int depth,
943 mtdf_info * me, listheader * myg,
944 listheader * otherg)
946 board * nboard,
947 * newboard;
948 movestruct * mymove,
949 * nmove;
950 int counter;
951 gipfitem * gipfflag;
952 listheader * remlist;
953 gipfdata * gipfd;
954 char * strpos,
955 owner;
956 nextmove * movedata;
957 int newminmax;
959 if ((node != NULL) && (node->children != NULL))
960 { /* node already visited, reuse from memory */
961 if (node->father == NULL)
963 return (NULL);
965 newboard = node->father;
967 /* I have to produce remlist here again */
968 remlist = (listheader *) malloc (sizeof (listheader));;
969 newlist (remlist);
970 /* list of gipf-pieces that may or may not have to be removed */
971 counter = 1;
972 while ((gipfflag = (gipfitem *) llitembynr (myg, counter)) != NULL)
974 counter++;
975 gipfd = (gipfdata *) malloc (sizeof (gipfdata));
976 strpos = b_gipf_position (gipfflag->gipf);
977 owner = b_gipf_owner (gipfflag->gipf);
978 gipfd->pos[0] = strpos[0];
979 gipfd->pos[1] = strpos[1];
980 gipfd->pos[2] = '\0';
981 free (strpos);
983 if (gipfflag->flag == 1)
985 gipfd->flag = 'y';
987 else
989 gipfd->flag = 'n';
991 pushll (remlist, (void *) gipfd);
993 /* list of gipf-pieces that always have to be removed */
994 counter = 1;
995 while ((gipfflag = (gipfitem *) llitembynr (otherg, counter)) != NULL)
997 counter++;
998 gipfd = (gipfdata *) malloc (sizeof (gipfdata));
999 strpos = b_gipf_position (gipfflag->gipf);
1000 owner = b_gipf_owner (gipfflag->gipf);
1001 gipfd->pos[0] = strpos[0];
1002 gipfd->pos[1] = strpos[1];
1003 gipfd->pos[2] = '\0';
1004 free (strpos);
1006 gipfd->flag = 'y';
1007 pushll (remlist, (void *) gipfd);
1011 else
1013 if (node != NULL)
1015 /* create children list */
1016 node->children = (listheader *) malloc (sizeof (listheader));
1017 newlist (node->children);
1020 newboard = oboard;
1021 remlist = (listheader *) malloc (sizeof (listheader));;
1022 newlist (remlist);
1023 /* list of gipf-pieces that may or may not have to be removed */
1024 counter = 1;
1025 while ((gipfflag = (gipfitem *) llitembynr (myg, counter)) != NULL)
1027 counter++;
1028 gipfd = (gipfdata *) malloc (sizeof (gipfdata));
1029 strpos = b_gipf_position (gipfflag->gipf);
1030 owner = b_gipf_owner (gipfflag->gipf);
1031 gipfd->pos[0] = strpos[0];
1032 gipfd->pos[1] = strpos[1];
1033 gipfd->pos[2] = '\0';
1034 free (strpos);
1036 if (gipfflag->flag == 1)
1038 gipfd->flag = 'y';
1039 nboard = b_remove_gipf (newboard, gipfflag->gipf);
1040 if (newboard != oboard)
1042 b_del (newboard);
1044 newboard = nboard;
1046 else
1048 gipfd->flag = 'n';
1050 pushll (remlist, (void *) gipfd);
1053 /* list of gipf-pieces that always have to be removed */
1054 counter = 1;
1055 while ((gipfflag = (gipfitem *) llitembynr (otherg, counter)) != NULL)
1057 counter++;
1058 gipfd = (gipfdata *) malloc (sizeof (gipfdata));
1059 strpos = b_gipf_position (gipfflag->gipf);
1060 owner = b_gipf_owner (gipfflag->gipf);
1061 gipfd->pos[0] = strpos[0];
1062 gipfd->pos[1] = strpos[1];
1063 gipfd->pos[2] = '\0';
1064 free (strpos);
1066 gipfd->flag = 'y';
1067 nboard = b_remove_gipf (newboard, gipfflag->gipf);
1068 if (newboard != oboard)
1070 b_del (newboard);
1072 newboard = nboard;
1073 pushll (remlist, (void *) gipfd);
1076 /* check again for 4 in a row */
1077 nboard = b_checkfour (newboard);
1078 if (newboard != oboard)
1080 b_del (newboard);
1083 newboard = nboard;
1084 if (node != NULL)
1086 node->father = newboard;
1090 mymove = (movestruct *) malloc (sizeof (movestruct));
1091 mymove->from[0] = '\0';
1092 mymove->to[0] = '\0';
1093 mymove->type = 0;
1094 mymove->movelist = (listheader *) malloc (sizeof (listheader));
1095 newlist (mymove->movelist);
1098 ** only add actions to the movelist if they have to be executed
1099 ** by the max-player
1100 ** this means moves for the min-player will not be executable,
1101 ** but that really isn't necessary
1103 if (me->colour == owner)
1105 movedata = (nextmove *) malloc (sizeof (nextmove));
1106 movedata->remtype = REM_GIPF;
1107 movedata->gipflist = remlist;
1108 pushll (mymove->movelist, (void *) movedata);
1110 else
1111 { /* remove remlist, we don't need it here */
1112 while ((gipfd = (gipfdata *) llrembynr (remlist, 1)) != NULL)
1114 free (gipfd);
1116 free (remlist);
1119 newminmax = (minmax == MINNODE ? MAXNODE : MINNODE);
1121 if ((b_status (newboard) == S_NORMAL) ||
1122 (b_status (newboard) == S_FINISHED))
1124 nmove = mem_ab_move (newboard, node, alfa, beta, newminmax,
1125 depth+1, me);
1126 mymove->value = nmove->value;
1127 mem_del_move (nmove);
1129 else if (b_status (newboard) == S_REMOVEROW)
1131 nmove = mem_ab_row (newboard, node, alfa, beta, minmax, depth, me);
1133 while ((movedata = (nextmove *) llrembynr (nmove->movelist, 1))
1134 != NULL)
1136 pushll (mymove->movelist, (void *) movedata);
1139 mymove->value = nmove->value;
1140 mem_del_move (nmove);
1142 else if (b_status (newboard) == S_REMOVEGIPF)
1144 nmove = mem_ab_gipf (newboard, node, alfa, beta, minmax, depth, me);
1146 while ((movedata = (nextmove *) llrembynr (nmove->movelist, 1))
1147 != NULL)
1149 pushll (mymove->movelist, (void *) movedata);
1152 mymove->value = nmove->value;
1153 mem_del_move (nmove);
1155 else
1156 { /* impossible */
1157 exit (0);
1160 /* check if the movelist of mymove contains something */
1161 if (llitembynr (mymove->movelist, 1) == NULL)
1163 free (mymove->movelist);
1164 mymove->movelist = NULL;
1167 if (node == NULL)
1169 b_del (newboard);
1171 else
1173 if (mymove->value <= alfa)
1175 node->upper = mymove->value;
1177 else if ((mymove->value > alfa) && (mymove->value < beta))
1178 { /* this shouldn't happen with zero window searches */
1179 node->upper = node->lower = mymove->value;
1181 else if (mymove->value >= beta)
1183 node->lower = mymove->value;
1188 return (mymove);
1192 movestruct * mem_ab_row (board * oboard, treenode * node, int alfa, int beta,
1193 int minmax, int depth, mtdf_info * me)
1195 int counter,
1196 value,
1197 realminmax;
1198 movestruct * nmove,
1199 * bestmove = NULL;
1200 rem_row * rowi;
1201 listheader * rowlist;
1202 treenode * childnode;
1204 rowlist = b_row_extra (oboard);
1205 rowi = (rem_row *) llitembynr (rowlist, 1);
1208 ** I may have to change if I am a min or a max-node here
1209 ** it's possible that my opponent won several rows, so he has to
1210 ** decide what row to remove
1212 if (row_owner(rowi) == b_next_piece (oboard))
1214 realminmax = (minmax == MINNODE ? MAXNODE : MINNODE);
1216 else
1218 realminmax = minmax;
1221 if (realminmax == MAXNODE)
1223 value = -1001;
1225 counter = 1;
1226 while ((rowi = (rem_row *) llitembynr (rowlist, counter))
1227 != NULL)
1229 childnode = mem_child (node, counter, me, depth);
1230 nmove = mem_rem_row (oboard, childnode, alfa, beta, minmax,
1231 depth, me, counter);
1232 counter++;
1234 if (nmove->value > value)
1236 value = nmove->value;
1237 if (bestmove != NULL)
1239 mem_del_move (bestmove);
1241 bestmove = nmove;
1243 else
1245 mem_del_move (nmove);
1247 alfa = max (alfa, value);
1249 if (value > beta)
1251 break;
1255 else
1257 value = 1001;
1259 counter = 1;
1260 while ((rowi = (rem_row *) llitembynr (rowlist, counter))
1261 != NULL)
1263 childnode = mem_child (node, counter, me, depth);
1264 nmove = mem_rem_row (oboard, childnode, alfa, beta, minmax,
1265 depth, me, counter);
1266 counter++;
1268 if (nmove->value < value)
1270 value = nmove->value;
1271 if (bestmove != NULL)
1273 mem_del_move (bestmove);
1275 bestmove = nmove;
1277 else
1279 mem_del_move (nmove);
1281 beta = min (beta, value);
1283 if (value < alfa)
1285 break;
1290 return (bestmove);
1294 movestruct * mem_rem_row (board * oboard, treenode * node, int alfa, int beta,
1295 int minmax, int depth, mtdf_info * me, int rem)
1297 board * newboard;
1298 movestruct * nmove,
1299 * mymove;
1300 rem_row * remi;
1301 nextmove * movedata;
1302 int newminmax;
1304 if ((node != NULL) && (node->children != NULL))
1305 { /* node already visited, reuse from memory */
1306 if (node->father == NULL)
1308 return (NULL);
1310 newboard = node->father;
1312 else
1314 if (node != NULL)
1316 /* create children list */
1317 node->children = (listheader *) malloc (sizeof (listheader));
1318 newlist (node->children);
1321 newboard = b_remove_row (oboard, rem);
1322 if (node != NULL)
1324 node->father = newboard;
1328 mymove = (movestruct *) malloc (sizeof (movestruct));
1329 mymove->from[0] = '\0';
1330 mymove->to[0] = '\0';
1331 mymove->type = 0;
1332 mymove->movelist = (listheader *) malloc (sizeof (listheader));
1333 newlist (mymove->movelist);
1336 ** only add actions to the movelist if they have to be executed
1337 ** by the max-player
1338 ** this means moves for the min-player will not be executable,
1339 ** but that really isn't necessary
1341 remi = (rem_row *) llitembynr (b_row_extra (oboard), rem);
1342 if (me->colour == row_owner (remi))
1344 movedata = (nextmove *) malloc (sizeof (nextmove));
1345 movedata->remtype = REM_ROW;
1346 movedata->gipflist = NULL;
1347 movedata->rowdata.start = postostr (remi->startpos);
1348 movedata->rowdata.end = postostr (remi->endpos);
1349 pushll (mymove->movelist, (void *) movedata);
1352 newminmax = (minmax == MINNODE ? MAXNODE : MINNODE);
1354 if ((b_status (newboard) == S_NORMAL) ||
1355 (b_status (newboard) == S_FINISHED))
1357 nmove = mem_ab_move (newboard, node, alfa, beta, newminmax,
1358 depth+1, me);
1359 mymove->value = nmove->value;
1360 mem_del_move (nmove);
1362 else if (b_status (newboard) == S_REMOVEROW)
1364 nmove = mem_ab_row (newboard, node, alfa, beta, minmax, depth, me);
1366 while ((movedata = (nextmove *) llrembynr (nmove->movelist, 1))
1367 != NULL)
1369 pushll (mymove->movelist, (void *) movedata);
1372 mymove->value = nmove->value;
1373 mem_del_move (nmove);
1375 else if (b_status (newboard) == S_REMOVEGIPF)
1377 nmove = mem_ab_gipf (newboard, node, alfa, beta, minmax, depth, me);
1379 while ((movedata = (nextmove *) llrembynr (nmove->movelist, 1))
1380 != NULL)
1382 pushll (mymove->movelist, (void *) movedata);
1385 mymove->value = nmove->value;
1386 mem_del_move (nmove);
1388 else
1389 { /* impossible */
1390 exit (0);
1393 /* check if the movelist of mymove contains something */
1394 if (llitembynr (mymove->movelist, 1) == NULL)
1396 free (mymove->movelist);
1397 mymove->movelist = NULL;
1400 if (node == NULL)
1402 b_del (newboard);
1404 else
1406 if (mymove->value <= alfa)
1408 node->upper = mymove->value;
1410 else if ((mymove->value > alfa) && (mymove->value < beta))
1411 { /* this shouldn't happen with zero window searches */
1412 node->upper = node->lower = mymove->value;
1414 else if (mymove->value >= beta)
1416 node->lower = mymove->value;
1421 return (mymove);
1425 ** calculate the value of a certain board position
1427 ** returns a value between 1000 and -1000 (inclusive)
1428 ** 1000 : I win
1429 ** -1000 : my opponent wins
1431 int mem_evaluate (board * oboard, mtdf_info * me)
1433 int total,
1435 value;
1436 double wvalue,
1437 bvalue;
1438 char myc,
1439 otherc;
1440 position * pos;
1442 myc = me->colour;
1443 otherc = b_opponent (myc);
1445 if (b_game_finished (oboard))
1447 if (b_winner (oboard) == myc)
1449 return (1000);
1451 else
1453 return (-1000);
1457 /* maybe I can return 1000 or -1000, but I'm not completely sure */
1458 if (b_colour (oboard, myc) == 0)
1460 return (-999);
1462 else if (b_colour (oboard, otherc) == 0)
1464 return (999);
1467 /* I need to start with a base-value, or I get a lot of
1468 ** problems at the start of tournament games */
1469 wvalue = 20;
1470 bvalue = 20;
1472 /* capturing a piece from your opponent is worth 20 points */
1473 wvalue += 20 * b_black_lost (oboard);
1474 bvalue += 20 * b_white_lost (oboard);
1476 /* 1 point for each piece in use on the board */
1477 if (b_white_gipf (oboard) == -1)
1478 total = 15;
1479 else
1480 total = 18;
1482 wvalue += total - b_white (oboard) - b_white_lost (oboard);
1483 bvalue += total - b_black (oboard) - b_black_lost (oboard);
1485 /* 2 pieces or less left is getting dangerous */
1487 /* one gipf left can be dangerous, subtract 5 points */
1488 if (b_white_gipf (oboard) == 1)
1490 wvalue -= 5;
1492 if (b_black_gipf (oboard) == 1)
1494 bvalue -= 5;
1497 /* pieces closer to the center have a higher value */
1498 for (i = 0; i < 19; i++)
1500 pos = &(mem_pos_val[i].coor);
1501 switch (b_ppiece (oboard, pos))
1503 case '.':
1504 break;
1506 case 'o':
1507 wvalue += mem_pos_val[i].value;
1508 break;
1510 case 'O':
1511 wvalue += mem_pos_val[i].value * 1.5;
1512 break;
1514 case 'x':
1515 bvalue += mem_pos_val[i].value;
1516 break;
1518 default:
1519 bvalue += mem_pos_val[i].value * 1.5;
1522 piece = b_ppiece (oboard, pos);
1523 if (piece == '.')
1525 continue;
1527 if (piece == 'o')
1529 wvalue += mem_pos_val[i].value;
1531 else if (piece == 'O')
1533 wvalue += mem_pos_val[i].value * 1.5;
1535 else if (piece == 'x')
1537 bvalue += mem_pos_val[i].value;
1539 else
1541 bvalue += mem_pos_val[i].value * 1.5;
1546 /* normalize the result, should be between 1000 and -1000 */
1547 if (myc == 'o')
1549 value = (int) ((wvalue - bvalue) * 1000 / (wvalue + bvalue));
1551 else
1553 value = (int) ((bvalue - wvalue) * 1000 / (wvalue + bvalue));
1556 return (value);
1559 void mem_del_move (movestruct * todel)
1561 nextmove * movedata;
1562 gipfdata * gipfd;
1564 if (todel->movelist != NULL)
1566 while ((movedata = (nextmove *) llrembynr (todel->movelist, 1))
1567 != NULL)
1569 if (movedata->remtype == REM_ROW)
1571 free (movedata->rowdata.start);
1572 free (movedata->rowdata.end);
1574 else
1576 while ((gipfd = (gipfdata *)
1577 llrembynr (movedata->gipflist, 1)) != NULL)
1579 free (gipfd);
1581 free (movedata->gipflist);
1584 free (movedata);
1586 free (todel->movelist);
1589 free (todel);
1590 return;
1595 ** create the root of the tree
1597 ** parameter:
1598 ** father: the board at the root of the tree
1600 treenode * mem_makeroot (board * father, mtdf_info * me)
1602 treenode * newnode;
1604 if (me->config.memorydepth == 0)
1606 return (NULL);
1609 newnode = (treenode *) malloc (sizeof (treenode));
1610 newnode->father = father;
1611 newnode->upper = 1001;
1612 newnode->lower = -1001;
1614 newnode->children = (listheader *) malloc (sizeof (listheader));
1615 newlist (newnode->children);
1617 return (newnode);
1622 ** delete a tree
1623 ** don't delete the father from the root-node
1625 void mem_deltree (treenode * node)
1627 if (node == NULL)
1629 return;
1632 emptyll (node->children, mem_delnode);
1633 free (node->children);
1634 free (node);
1636 return;
1639 void mem_delnode (void * item)
1641 treenode * node = item;
1643 b_del (node->father);
1644 emptyll (node->children, mem_delnode);
1645 free (node->children);
1646 free (node);
1648 return;
1653 ** reset upper and lower limits in the memory-tree
1655 void mem_resetul (void * item)
1657 treenode * node = item;
1659 node->upper = 1001;
1660 node->lower = -1001;
1661 doll (node->children, mem_resetul);
1663 return;
1668 ** check if a child-node already exists,
1669 ** if not, create a new one
1671 treenode * mem_child (treenode * node, int nr, mtdf_info * me, int depth)
1673 treenode * newnode;
1675 if (me->config.memorydepth < depth)
1677 return (NULL);
1680 newnode = (treenode *) llitembynr (node->children, nr);
1681 if (newnode != NULL)
1682 { /* this node has already been handled, return it */
1683 return (newnode);
1686 #if 0
1687 /* just for testing */
1688 /* check if the previous nr exists, it should */
1689 if ((nr > 1) && (llitembynr (node->children, nr-1) == NULL))
1691 printf ("\nERROR: mem_child\n\n");
1692 exit (0);
1694 #endif
1696 /* create a new node */
1697 newnode = (treenode *) malloc (sizeof (treenode));
1698 newnode->father = NULL;
1699 newnode->children = NULL;
1700 newnode->upper = 1001;
1701 newnode->lower = -1001;
1702 pushll (node->children, newnode);
1704 return (newnode);
1708 ** just like a normal compare (<)
1709 ** returns:
1710 ** 1 : nr1 < nr2
1711 ** 0: nr1 > nr2
1712 ** 0/1: when nr1 and nr2 are equal, chooses one at random
1714 ** chance is the chance that nr1 will be chosen if nr1 == nr2
1715 ** this parameter will be incremented each time an equal occurs
1716 ** and will be set to 1 if nr1 < nr2
1717 ** (it should be initialised to 1 by the caller and then left alone)
1719 int mem_equ_l (int nr1, int nr2, int * chance, mtdf_info * me)
1721 int randnr;
1723 if (me->config.randomchoose == 0)
1724 return (nr1 < nr2);
1726 if (nr1 < nr2)
1728 *chance = 1;
1729 return (1);
1731 if (nr1 > nr2)
1733 return (0);
1736 randnr = (int) ( (*chance + 1.0) * rand() / (RAND_MAX+1.0) );
1737 (*chance)++;
1739 if (randnr < 1)
1741 return (1);
1744 return (0);
1749 ** just like a normal compare (>)
1750 ** returns:
1751 ** 1 : nr1 > nr2
1752 ** 0: nr1 < nr2
1753 ** 0/1: when nr1 and nr2 are equal, chooses one at random
1755 ** chance is the chance that nr1 will be chosen if nr1 == nr2
1756 ** this parameter will be incremented each time an equal occurs
1757 ** and will be set to 1 if nr1 > nr2
1758 ** (it should be initialised to 1 by the caller and then left alone)
1760 int mem_equ_h (int nr1, int nr2, int * chance, mtdf_info * me)
1762 int randnr;
1764 if (me->config.randomchoose == 0)
1765 return (nr1 > nr2);
1767 if (nr1 > nr2)
1769 *chance = 1;
1770 return (1);
1772 if (nr1 < nr2)
1774 return (0);
1777 randnr = (int) ( (*chance + 1.0) * rand() / (RAND_MAX+1.0) );
1778 (*chance)++;
1780 if (randnr < 1)
1782 return (1);
1785 return (0);