5 ** Copyright (C) 1999 Kurt Van den Branden
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "ai_player.h"
31 ai_player::ai_player ()
47 ai_player::~ai_player ()
53 vector
<basemove
*> * ai_player::minimax_ab (void * startgame
, int starttype
)
55 searchnode
* firstnode
;
56 vector
<basemove
*> * move
;
64 firstnode
= new searchnode
;
66 firstnode
->gameposition
= startgame
;
67 firstnode
->finished
= 0;
70 firstnode
->upper
= 1001;
71 firstnode
->lower
= -1001;
72 firstnode
->type
= starttype
;
73 // firstnode->movelist = NULL;
74 // firstnode->childlist = NULL;
76 // move = minimax_ab (firstnode, -1001, 1001);
77 move
= ab_mem (firstnode
, -1001, 1001);
78 lastvalue
= firstnode
->value
;
80 delmemtree (firstnode
, 0);
83 reverse (move
->begin(), move
->end());
90 ** correct, but replaced by ab_mem
92 listheader
* ai_player::minimax_ab (searchnode
* node
, int alfa
, int beta
)
98 listheader
* movel
= NULL
,
101 searchnode
* newnode
;
103 // check for leafnode
104 // (end-of-game or maxdepth exceeded)
105 if ((node
->finished
) ||
106 (node
->depth
> maxdepth
))
108 value
= evalfunc (node
->gameposition
, player
);
110 // create an empty move
111 movel
= (listheader
*) malloc (sizeof (listheader
));
117 if (node
->movelist
== NULL
)
119 node
->movelist
= listfunc (node
->gameposition
);
120 node
->childlist
= (listheader
*) malloc (sizeof (listheader
));
121 newlist (node
->childlist
);
124 if (node
->type
== MAX
)
129 while ((moveitem
= llitembynr (node
->movelist
, counter
)) != NULL
)
131 // generate child (if necessary)
132 newnode
= nodechild (node
, counter
);
136 if (newnode
->finished
== -1)
137 { // calculate new position
138 newnode
->finished
= 0;
139 newnode
->gameposition
=
140 newfunc (node
->gameposition
, moveitem
,
141 &(newnode
->finished
), &ddelta
,
143 newnode
->depth
+= ddelta
;
146 if (newnode
->gameposition
== NULL
)
149 newmovel
= minimax_ab (newnode
, alfa
, beta
);
151 // is the new move better then the previous best
152 // if (equ_h (newnode->value, value, &chance))
153 if (((node
->depth
== 1) &&
154 (equ_h (newnode
->value
, value
, &chance
))) ||
155 ((node
->depth
> 1) && (newnode
->value
> value
)))
157 value
= newnode
->value
;
160 unshiftll (movel
, copymovefunc (moveitem
));
164 delmovelist (newmovel
);
167 alfa
= max (alfa
, value
);
170 // if (value >= beta)
181 while ((moveitem
= llitembynr (node
->movelist
, counter
)) != NULL
)
183 // generate child (if necessary)
184 newnode
= nodechild (node
, counter
);
188 if (newnode
->finished
== -1)
189 { // calculate new position
190 newnode
->finished
= 0;
191 newnode
->gameposition
=
192 newfunc (node
->gameposition
, moveitem
,
193 &(newnode
->finished
), &ddelta
,
195 newnode
->depth
+= ddelta
;
198 if (newnode
->gameposition
== NULL
)
201 newmovel
= minimax_ab (newnode
, alfa
, beta
);
203 // is the new move better then the previous best
204 // if (equ_l (newnode->value, value, &chance))
205 if (((node
->depth
== 1) &&
206 (equ_l (newnode
->value
, value
, &chance
))) ||
207 ((node
->depth
> 1) && (newnode
->value
< value
)))
209 value
= newnode
->value
;
212 unshiftll (movel
, copymovefunc (moveitem
));
216 delmovelist (newmovel
);
219 beta
= min (beta
, value
);
222 // if (value <= alfa)
232 // cleanup children-nodes
233 while ((newnode
= (searchnode
*) llrembynr (node
->childlist
, 1))
236 delmemtree (newnode
);
239 // what if no valid move ?
240 // is it enough that movel contains NULL in that case ?
247 vector
<basemove
*> * ai_player::ab_mem (searchnode
* node
, int alfa
, int beta
)
254 vector
<basemove
*> * movel
= NULL
,
256 searchnode
* newnode
;
258 if (node
->lower
> beta
) // >=
260 node
->value
= node
->lower
;
261 // create an empty move
262 movel
= new vector
<basemove
*>;
265 if (node
->upper
< alfa
) // <=
267 node
->value
= node
->upper
;
268 // create an empty move
269 movel
= new vector
<basemove
*>;
272 alfa
= max (alfa
, node
->lower
);
273 beta
= min (beta
, node
->upper
);
275 // check for leafnode
276 // (end-of-game or maxdepth exceeded)
277 if ((node
->finished
== 1) ||
278 ((node
->depth
> maxdepth
) && (node
->finished
!= 2)))
280 value
= evalfunc (node
->gameposition
, player
);
282 // create an empty move
283 movel
= new vector
<basemove
*>;
288 if (node
->movelist
.empty())
290 listfunc (node
->gameposition
, node
->movelist
);
293 if (node
->type
== MAX
)
298 len
= node
->movelist
.size();
299 for (i
= 0; i
< len
; i
++)
300 // while ((moveitem = llitembynr (node->movelist, counter)) != NULL)
302 // generate child (if necessary)
303 newnode
= nodechild (node
, i
);
305 if (newnode
->finished
== -1)
306 { // calculate new position
307 newnode
->finished
= 0;
308 newnode
->gameposition
=
309 newfunc (node
->gameposition
, node
->movelist
[i
],
310 &(newnode
->finished
), &ddelta
,
312 newnode
->depth
+= ddelta
;
315 if (newnode
->gameposition
== NULL
)
318 newmovel
= ab_mem (newnode
, a
, beta
);
323 delmovelist (newmovel
);
331 delmovelist (newmovel
);
334 if (stopfunc () == 1)
338 delmovelist (newmovel
);
342 // is the new move better then the previous best
343 if (((node
->depth
== 1) &&
344 (equ_h (newnode
->value
, value
, &chance
))) ||
345 ((node
->depth
> 1) && (newnode
->value
> value
)))
347 value
= newnode
->value
;
350 // unshiftll (movel, node->movelist[i]->copy());
351 movel
->push_back (node
->movelist
[i
]->copy());
362 delmovelist (newmovel
);
371 len
= node
->movelist
.size();
372 for (i
= 0; i
< len
; i
++)
373 // while ((moveitem = llitembynr (node->movelist, counter)) != NULL)
375 // generate child (if necessary)
376 newnode
= nodechild (node
, i
);
378 if (newnode
->finished
== -1)
379 { // calculate new position
380 newnode
->finished
= 0;
381 newnode
->gameposition
=
382 newfunc (node
->gameposition
, node
->movelist
[i
],
383 &(newnode
->finished
), &ddelta
,
385 newnode
->depth
+= ddelta
;
388 if (newnode
->gameposition
== NULL
)
391 newmovel
= ab_mem (newnode
, alfa
, b
);
396 delmovelist (newmovel
);
404 delmovelist (newmovel
);
407 if (stopfunc () == 1)
411 delmovelist (newmovel
);
415 // is the new move better then the previous best
416 // if (equ_l (newnode->value, value, &chance))
417 if (((node
->depth
== 1) &&
418 (equ_l (newnode
->value
, value
, &chance
))) ||
419 ((node
->depth
> 1) && (newnode
->value
< value
)))
421 value
= newnode
->value
;
424 // unshiftll (movel, node->movelist[i]->copy());
425 movel
->push_back (node
->movelist
[i
]->copy());
436 delmovelist (newmovel
);
446 if ((value
> alfa
) && (value
< beta
))
447 node
->lower
= node
->upper
= value
;
451 // cleanup children-nodes if past maximum memory-depth
452 if (node
->depth
> memorydepth
)
454 for (int i
= node
->childlist
.size() - 1; i
>= 0; i
--)
456 delmemtree (node
->childlist
[i
]);
457 node
->childlist
.pop_back();
461 // what if no valid move ?
462 // is it enough that movel contains NULL in that case ?
468 vector
<basemove
*> * ai_player::mtdf (void * startgame
, int starttype
)
470 searchnode
* firstnode
;
471 vector
<basemove
*> * move
;
479 firstnode
= new searchnode
;
481 firstnode
->gameposition
= startgame
;
482 firstnode
->finished
= 0;
483 firstnode
->depth
= 1;
484 firstnode
->value
= 0;
485 firstnode
->upper
= 1001;
486 firstnode
->lower
= -1001;
487 firstnode
->type
= starttype
;
488 // firstnode->movelist = NULL;
489 // firstnode->childlist = NULL;
491 move
= mtdf (firstnode
);
492 lastvalue
= firstnode
->value
;
494 delmemtree (firstnode
, 0);
497 reverse (move
->begin(), move
->end());
502 vector
<basemove
*> * ai_player::mtdf (searchnode
* node
)
508 vector
<basemove
*> * bestmove
= NULL
;
514 while ((lower
< upper
) && (stopnow
== 0))
525 delmovelist (bestmove
);
527 // bestmove = mt (node, gamma); // werkt niet
528 // bestmove = minimax_ab (node, gamma-1, gamma); // werkt wel
529 bestmove
= ab_mem (node
, gamma
-1, gamma
); // werkt ook, en goed
546 // iterative deepening mtdf
547 vector
<basemove
*> * ai_player::mtdf_id (void * startgame
,
551 searchnode
* firstnode
;
556 vector
<basemove
*> * bestmove
= NULL
,
561 gettimeofday (&basetime
, &tz
);
568 firstnode
= new searchnode
;
570 firstnode
->gameposition
= startgame
;
571 firstnode
->finished
= 0;
572 firstnode
->depth
= 1;
573 firstnode
->value
= 0;
574 firstnode
->upper
= 1001;
575 firstnode
->lower
= -1001;
576 firstnode
->type
= starttype
;
577 // firstnode->movelist = NULL;
578 // firstnode->childlist = NULL;
580 savedepth
= maxdepth
;
581 oldvalue
= newvalue
= 0;
582 for (i
= 1; i
<= savedepth
; i
++)
585 // each mtdf-call is not started with the value from the previous run
586 // but with the one before that
587 firstnode
->value
= oldvalue
;
588 reset_ul (firstnode
);
590 newmove
= mtdf (firstnode
);
594 delmovelist (newmove
);
599 newvalue
= firstnode
->value
;
601 delmovelist (bestmove
);
604 if (halfoutoftime ())
611 maxdepth
= savedepth
;
612 lastvalue
= firstnode
->value
;
614 delmemtree (firstnode
, 0);
616 if (bestmove
!= NULL
)
617 reverse (bestmove
->begin(), bestmove
->end());
624 ** if flag is 0, then the gameposition will not be deleted
625 ** this should be used for the root of the nodetree
627 void ai_player::delmemtree (searchnode
* node
, int flag
)
629 // searchnode * child;
635 delgamefunc (node
->gameposition
);
638 if (!node
->movelist
.empty())
640 len
= node
->movelist
.size();
641 for (i
= 0; i
< len
; i
++)
643 delete node
->movelist
[i
];
647 if (!node
->childlist
.empty())
649 len
= node
->childlist
.size();
650 for (i
= 0; i
< len
; i
++)
652 delmemtree (node
->childlist
[i
]);
663 ** reset upper and lower limits in all nodes from the memory tree
665 void ai_player::reset_ul (searchnode
* node
)
667 // searchnode * child;
673 if (!node
->childlist
.empty())
675 len
= node
->childlist
.size();
676 for (i
= 0; i
< len
; i
++)
678 reset_ul (node
->childlist
[i
]);
686 inline void ai_player::delmovelist (vector
<basemove
*> * todel
)
690 int len
= todel
->size(),
693 for (i
= 0; i
< len
; i
++)
704 ** just like a normal compare (<)
708 ** 0/1: when nr1 and nr2 are equal, chooses one at random
710 ** chance is the chance that nr1 will be chosen if nr1 == nr2
711 ** this parameter will be incremented each time an equal occurs
712 ** and will be set to 1 if nr1 < nr2
713 ** (it should be initialised to 1 by the caller and then left alone)
715 int ai_player::equ_l (int nr1
, int nr2
, int * chance
)
719 if (randomchoose
== 0)
732 randnr
= (int) ( (*chance
+ 1.0) * rand() / (RAND_MAX
+1.0) );
745 ** just like a normal compare (>)
749 ** 0/1: when nr1 and nr2 are equal, chooses one at random
751 ** chance is the chance that nr1 will be chosen if nr1 == nr2
752 ** this parameter will be incremented each time an equal occurs
753 ** and will be set to 1 if nr1 > nr2
754 ** (it should be initialised to 1 by the caller and then left alone)
756 int ai_player::equ_h (int nr1
, int nr2
, int * chance
)
760 if (randomchoose
== 0)
773 randnr
= (int) ( (*chance
+ 1.0) * rand() / (RAND_MAX
+1.0) );
786 ** check if a child-node already exists,
787 ** if not, create a new one
789 inline searchnode
* ai_player::nodechild (searchnode
* node
, unsigned nr
)
791 searchnode
* newnode
;
793 if (nr
< node
->childlist
.size())
794 return (node
->childlist
[nr
]);
798 /* just for testing */
799 /* check if the previous nr exists, it should */
800 if ((nr
> 1) && (llitembynr (node
->childlist
, nr
-1) == NULL
))
802 printf ("\nERROR: ai_player::nodechild\n\n");
807 /* create a new node */
808 newnode
= new searchnode
;
809 newnode
->gameposition
= NULL
;
810 newnode
->finished
= -1;
811 newnode
->depth
= node
->depth
;
813 newnode
->upper
= 1001;
814 newnode
->lower
= -1001;
815 newnode
->type
= node
->type
;
816 // newnode->movelist = NULL;
817 // newnode->childlist = NULL;
819 node
->childlist
.push_back (newnode
);
825 inline int ai_player::outoftime ()
834 gettimeofday (&tv
, &tz
);
836 timedif
= (tv
.tv_sec
- basetime
.tv_sec
) +
837 (float) (tv
.tv_usec
- basetime
.tv_usec
) / 1000000;
839 if ((maxtime
- timedif
) < 0.0)
841 //cout << "hard timeout\n";
849 inline int ai_player::halfoutoftime ()
858 gettimeofday (&tv
, &tz
);
860 timedif
= (tv
.tv_sec
- basetime
.tv_sec
) +
861 (float) (tv
.tv_usec
- basetime
.tv_usec
) / 1000000;
863 if ((maxtime
/2 - timedif
) < 0.0)
865 //cout << "soft timeout\n";