~noskcaj/ubuntu/vivid/four-in-a-row/3.14.2

« back to all changes in this revision

Viewing changes to src/heurist.c

  • Committer: Jackson Doak
  • Date: 2014-11-21 21:52:51 UTC
  • mfrom: (1.1.3)
  • Revision ID: noskcaj@ubuntu.com-20141121215251-jbqgpp0gc8lwmmsw
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
 *                                                                          *
3
 
 *                      Velena Source Code V1.0                             *
4
 
 *                   Written by Giuliano Bertoletti                         *
5
 
 *       Based on the knowledged approach of Louis Victor Allis             *
6
 
 *   Copyright (C) 1996-97 by Giuliano Bertoletti & GBE 32241 Software PR   *
7
 
 *                                                                          *
8
 
 ****************************************************************************
9
 
 
10
 
 Portable engine version.
11
 
 read the README file for further informations.
12
 
 
13
 
 ============================================================================
14
 
 
15
 
 Changes have been made to this code for inclusion with Gnect. It is
16
 
 released under the GNU General Public License with Giuliano's approval.
17
 
 The original and complete Velena Engine source code can be found at:
18
 
 
19
 
 http://www.ce.unipr.it/~gbe/velena.html
20
 
 
21
 
*/
22
 
 
23
 
 
24
 
#include <config.h>
25
 
#include <stdio.h>
26
 
#include <string.h>
27
 
#include <stdlib.h>
28
 
 
29
 
#include "connect4.h"
30
 
#include "con4vals.h"
31
 
#include "rules.h"
32
 
#include "pnsearch.h"
33
 
#include "proto.h"
34
 
 
35
 
#include "heurist.h"
36
 
 
37
 
 
38
 
/* FIXME: These should probably go into a header file or be defined as static */
39
 
void fight (char t);
40
 
short whatfight (void);
41
 
void her_generate_all_children (struct node *node);
42
 
void her_free_whole_tree (struct bintree *tree);
43
 
short her_evaluate (struct node *node);
44
 
short her_resources_available (long maxnodes);
45
 
struct node *her_select_most_proving_node (struct node *node,
46
 
                                           struct info *info);
47
 
void her_set_pdv_according_to_children (struct node *node);
48
 
void her_set_proof_and_disproof_numbers (struct node *node);
49
 
void her_develop_node (struct node *node);
50
 
void her_update_ancestors (struct node *node);
51
 
void her_pn_search (struct node *root, long maxnodes, struct info *info);
52
 
short heuristic_search (struct node *mynode, long maxnodenum);
53
 
short heuristic_play_best (struct board *board, long maxnodenum);
54
 
 
55
 
 
56
 
extern short nodeseq[];
57
 
struct board *auxboard;
58
 
 
59
 
 
60
 
struct bintree *streeroot;
61
 
struct node *rootnode;
62
 
 
63
 
short nodeseq[] = { 3, 2, 4, 5, 1, 0, 6 };      /* This is the sequence we follow to
64
 
                                                 * scan the seven moves available
65
 
                                                 */
66
 
 
67
 
char fight_for_win = 0;
68
 
 
69
 
 
70
 
 
71
 
void
72
 
fight (char t)
73
 
{
74
 
  fight_for_win = t;
75
 
}
76
 
 
77
 
 
78
 
 
79
 
short
80
 
whatfight (void)
81
 
{
82
 
  return (short) fight_for_win;
83
 
}
84
 
 
85
 
 
86
 
 
87
 
long her_node_expanded, her_node_not_expanded;
88
 
 
89
 
 
90
 
 
91
 
void
92
 
her_generate_all_children (struct node *node)
93
 
{
94
 
  struct node *dummy, *symm;
95
 
  short x, y, x1, y1, backtrace;
96
 
 
97
 
 
98
 
  for (x = 0; x < BOARDX; x++) {
99
 
    if (node->child[x])
100
 
      fatal_error ("Tried to allocate a node twice!");
101
 
    else if (node->stack[x] < BOARDY) {
102
 
      node->child[x] = (struct node *) malloc (sizeof (struct node));
103
 
      symm = (struct node *) malloc (sizeof (struct node));
104
 
 
105
 
      if (!node->child[x] || !symm)
106
 
        fatal_error ("Not enough memory to build the tree");
107
 
 
108
 
      memcpy (node->child[x]->square, node->square,
109
 
              (BOARDX + 1) * (BOARDY + 2));
110
 
      memcpy (node->child[x]->stack, node->stack, BOARDX + 1);
111
 
      backtrace = x;
112
 
 
113
 
      node->child[x]->square[ELM (x, node->child[x]->stack[x]++)] =
114
 
        node->turn;
115
 
      node->child[x]->turn = node->turn ^ SWITCHSIDE;
116
 
      symm->turn = node->turn ^ SWITCHSIDE;
117
 
 
118
 
      for (y1 = 0; y1 < BOARDY; y1++) {
119
 
        symm->square[ELM (BOARDX, y1)] =
120
 
          node->child[x]->square[ELM (BOARDX, y1)];
121
 
        for (x1 = 0; x1 < BOARDX; x1++)
122
 
          symm->square[ELM (x1, y1)] =
123
 
            node->child[x]->square[ELM (BOARDX - x1 - 1, y1)];
124
 
      }
125
 
 
126
 
      symm->stack[BOARDX] = node->child[x]->stack[BOARDX];
127
 
      for (x1 = 0; x1 < BOARDX; x1++)
128
 
        symm->stack[x1] = node->child[x]->stack[BOARDX - x1 - 1];
129
 
 
130
 
      if (bin_compare (symm->square, node->child[x]->square) > 0) {
131
 
        dummy = symm;
132
 
        symm = node->child[x];
133
 
        node->child[x] = dummy;
134
 
        backtrace = BOARDX - x - 1;
135
 
      }
136
 
 
137
 
      dummy = fast_check_node (streeroot, node->child[x], 0);
138
 
      if (dummy) {
139
 
        free (node->child[x]);
140
 
        node->child[x] = dummy;
141
 
        node->child[x]->parent[backtrace] = node;
142
 
        her_node_not_expanded++;
143
 
      } else {
144
 
        node->child[x]->expanded = NO;
145
 
        node->child[x]->evaluated = NO;
146
 
 
147
 
        for (y = 0; y < BOARDX; y++)
148
 
          node->child[x]->parent[y] = NULL;
149
 
 
150
 
        node->child[x]->parent[backtrace] = node;
151
 
 
152
 
        for (y = 0; y < BOARDX; y++)
153
 
          node->child[x]->child[y] = NULL;
154
 
 
155
 
        her_node_expanded++;
156
 
 
157
 
        if (node->type == AND_TYPE)
158
 
          node->child[x]->type = OR_TYPE;
159
 
        else if (node->type == OR_TYPE)
160
 
          node->child[x]->type = AND_TYPE;
161
 
        else
162
 
          fatal_error ("Could not recognize node type!");
163
 
 
164
 
        /*add_node(streeroot,node->child[x]); */
165
 
      }
166
 
 
167
 
      node->symmetric[x] = backtrace;
168
 
      free (symm);
169
 
    }
170
 
 
171
 
    else
172
 
      node->child[x] = NULL;
173
 
  }
174
 
}
175
 
 
176
 
 
177
 
 
178
 
void
179
 
her_free_whole_tree (struct bintree *tree)
180
 
{
181
 
  if (!tree)
182
 
    return;
183
 
  if (tree->lson)
184
 
    her_free_whole_tree (tree->lson);
185
 
  if (tree->rson)
186
 
    her_free_whole_tree (tree->rson);
187
 
 
188
 
  free (tree->node);
189
 
}
190
 
 
191
 
 
192
 
 
193
 
short
194
 
her_evaluate (struct node *node)
195
 
{
196
 
  short x, bestmove;
197
 
 
198
 
 
199
 
  node->evaluated = YES;
200
 
 
201
 
  for (x = 0; x < 64; x++)
202
 
    auxboard->square[x] = (short) node->square[x];
203
 
 
204
 
  auxboard->turn = node->turn;
205
 
  auxboard->filled = 0;
206
 
 
207
 
  for (x = 0; x < BOARDX + 1; x++) {
208
 
    auxboard->stack[x] = (short) node->stack[x];
209
 
    if (x < BOARDX)
210
 
      auxboard->filled += auxboard->stack[x];
211
 
  }
212
 
 
213
 
  if (auxboard->filled == MAXMEN) {
214
 
    if (rootnode->turn == WHITE) {
215
 
      if (!fight_for_win) {
216
 
        if (rootnode->type == OR_TYPE)
217
 
          node->value = DISPROVED;
218
 
        else
219
 
          node->value = PROVED;
220
 
      } else {
221
 
        if (rootnode->type == OR_TYPE)
222
 
          node->value = PROVED;
223
 
        else
224
 
          node->value = DISPROVED;
225
 
      }
226
 
    } else {
227
 
      if (!fight_for_win) {
228
 
        if (rootnode->type == OR_TYPE)
229
 
          node->value = PROVED;
230
 
        else
231
 
          node->value = DISPROVED;
232
 
      } else {
233
 
        if (rootnode->type == OR_TYPE)
234
 
          node->value = DISPROVED;
235
 
        else
236
 
          node->value = PROVED;
237
 
      }
238
 
    }
239
 
    return -1;
240
 
  }
241
 
 
242
 
  bestmove = fast_try_to_win (auxboard);
243
 
  if (bestmove != -1) {
244
 
    if (node->type == OR_TYPE)
245
 
      node->value = PROVED;
246
 
    if (node->type == AND_TYPE)
247
 
      node->value = DISPROVED;
248
 
  }
249
 
 
250
 
  else
251
 
    node->value = UNKNOWN;
252
 
 
253
 
  return bestmove;
254
 
}
255
 
 
256
 
 
257
 
 
258
 
short
259
 
her_resources_available (long maxnodes)
260
 
{
261
 
  if (her_node_expanded > maxnodes)
262
 
    return NO;
263
 
  return YES;
264
 
}
265
 
 
266
 
 
267
 
 
268
 
struct node *
269
 
her_select_most_proving_node (struct node *node, struct info *info)
270
 
{
271
 
  short i, flag, depth = 0;
272
 
 
273
 
 
274
 
  while (node->expanded) {
275
 
    i = 0;
276
 
    flag = FALSE;
277
 
 
278
 
    switch (node->type) {
279
 
    case OR_TYPE:
280
 
      do {
281
 
        if (node->child[nodeseq[i]] &&
282
 
            node->child[nodeseq[i]]->proof == node->proof)
283
 
          flag = TRUE;
284
 
        else
285
 
          i++;
286
 
      } while (i < BOARDX && !flag);
287
 
 
288
 
      if (!flag)
289
 
        fatal_error ("Could not find a good OR child!");
290
 
      break;
291
 
 
292
 
    case AND_TYPE:
293
 
      do {
294
 
        if (node->child[nodeseq[i]] &&
295
 
            node->child[nodeseq[i]]->disproof == node->disproof)
296
 
          flag = TRUE;
297
 
        else
298
 
          i++;
299
 
      } while (i < BOARDX && !flag);
300
 
 
301
 
      if (!flag)
302
 
        fatal_error ("Could not find a good AND child!");
303
 
      break;
304
 
 
305
 
    default:
306
 
      fatal_error ("Unknown node type!");
307
 
      break;
308
 
 
309
 
    }
310
 
    if (!flag)
311
 
      fatal_error ("Null node found!");
312
 
    else {
313
 
      if (depth == 0)
314
 
        info->bestmove = nodeseq[i];
315
 
      node = node->child[nodeseq[i]];
316
 
    }
317
 
 
318
 
    depth++;
319
 
  }
320
 
 
321
 
  info->max_tree_depth = max (info->max_tree_depth, depth + 1);
322
 
  return node;
323
 
}
324
 
 
325
 
 
326
 
 
327
 
void
328
 
her_set_pdv_according_to_children (struct node *node)
329
 
{
330
 
  short x, children = 0;
331
 
 
332
 
 
333
 
  for (x = 0; x < BOARDX; x++)
334
 
    if (node->stack[x] < BOARDY)
335
 
      children++;
336
 
 
337
 
  if (children == 0)
338
 
    fatal_error ("Father without children but of value unknown");
339
 
 
340
 
  switch (node->type) {
341
 
  case AND_TYPE:
342
 
    node->proof = children;
343
 
    node->disproof = 1;
344
 
    break;
345
 
 
346
 
  case OR_TYPE:
347
 
    node->proof = 1;
348
 
    node->disproof = children;
349
 
    break;
350
 
  }
351
 
}
352
 
 
353
 
 
354
 
 
355
 
void
356
 
her_set_proof_and_disproof_numbers (struct node *node)
357
 
{
358
 
  short x;
359
 
 
360
 
 
361
 
  if (!node)
362
 
    fatal_error ("Invalid node chosen");
363
 
  else if (node->expanded) {
364
 
    switch (node->type) {
365
 
    case AND_TYPE:
366
 
      node->proof = 0;
367
 
      node->disproof = MAXVALUE;
368
 
      for (x = 0; x < BOARDX; x++)
369
 
        if (node->child[x]) {
370
 
          node->proof += node->child[x]->proof;
371
 
          node->disproof = min (node->disproof, node->child[x]->disproof);
372
 
        }
373
 
      if (node->disproof == 0)
374
 
        node->proof = MAXVALUE;
375
 
      break;
376
 
 
377
 
    case OR_TYPE:
378
 
      node->proof = MAXVALUE;
379
 
      node->disproof = 0;
380
 
      for (x = 0; x < BOARDX; x++)
381
 
        if (node->child[x]) {
382
 
          node->proof = min (node->proof, node->child[x]->proof);
383
 
          node->disproof += node->child[x]->disproof;
384
 
        }
385
 
      if (node->proof == 0)
386
 
        node->disproof = MAXVALUE;
387
 
      break;
388
 
 
389
 
    default:
390
 
      fatal_error ("I don't know what to prove or disprove!");
391
 
      break;
392
 
    }
393
 
 
394
 
    if (node->proof < 0 || node->disproof < 0)
395
 
      fatal_error ("Proof and disproof numbers cannot be lower than zero");
396
 
 
397
 
  } else if (node->evaluated) {
398
 
    switch (node->value) {
399
 
    case PROVED:
400
 
      node->proof = 0;
401
 
      node->disproof = MAXVALUE;
402
 
      break;
403
 
 
404
 
    case DISPROVED:
405
 
      node->proof = MAXVALUE;
406
 
      node->disproof = 0;
407
 
      break;
408
 
 
409
 
    case UNKNOWN:
410
 
      her_set_pdv_according_to_children (node);
411
 
      break;
412
 
    }
413
 
  } else
414
 
    fatal_error ("Asked to set a node never evaluated!");
415
 
}
416
 
 
417
 
 
418
 
 
419
 
void
420
 
her_develop_node (struct node *node)
421
 
{
422
 
  short i;
423
 
 
424
 
 
425
 
  node->expanded = YES;
426
 
  her_generate_all_children (node);
427
 
 
428
 
  for (i = 0; i < BOARDX; i++) {
429
 
    if (node->child[i]) {
430
 
      her_evaluate (node->child[i]);
431
 
      her_set_proof_and_disproof_numbers (node->child[i]);
432
 
    }
433
 
  }
434
 
}
435
 
 
436
 
 
437
 
 
438
 
void
439
 
her_update_ancestors (struct node *node)
440
 
{
441
 
  short x;
442
 
 
443
 
 
444
 
  if (node) {
445
 
    her_set_proof_and_disproof_numbers (node);
446
 
 
447
 
    for (x = 0; x < BOARDX; x++)
448
 
      if (node->parent[x])
449
 
        her_update_ancestors (node->parent[x]);
450
 
  }
451
 
}
452
 
 
453
 
 
454
 
 
455
 
void
456
 
her_pn_search (struct node *root, long maxnodes, struct info *info)
457
 
{
458
 
  struct node *her_most_proving_node;
459
 
 
460
 
 
461
 
  info->max_tree_depth = 1;
462
 
  info->bestmove = her_evaluate (root);
463
 
  her_set_proof_and_disproof_numbers (root);
464
 
 
465
 
  while (root->proof != 0 && root->disproof != 0
466
 
         && her_resources_available (maxnodes)) {
467
 
    her_most_proving_node = her_select_most_proving_node (root, info);
468
 
    her_develop_node (her_most_proving_node);
469
 
    her_update_ancestors (her_most_proving_node);
470
 
  }
471
 
 
472
 
  if (root->proof == 0)
473
 
    root->value = PROVED;
474
 
  else if (root->disproof == 0)
475
 
    root->value = DISPROVED;
476
 
  else
477
 
    root->value = UNKNOWN;
478
 
}
479
 
 
480
 
 
481
 
 
482
 
short
483
 
heuristic_search (struct node *mynode, long maxnodenum)
484
 
{
485
 
  struct info info;
486
 
  short x;
487
 
 
488
 
 
489
 
  if (mynode->expanded || mynode->evaluated)
490
 
    fatal_error ("Request to evaluate a node already evaluated or expanded!");
491
 
 
492
 
  mynode->evaluated = YES;
493
 
 
494
 
  rootnode = (struct node *) malloc (sizeof (struct node));
495
 
  if (!rootnode)
496
 
    fatal_error ("Not enough memory");
497
 
 
498
 
  memcpy (rootnode, mynode, sizeof (struct node));
499
 
 
500
 
  her_node_expanded = 0L;
501
 
  her_node_not_expanded = 0L;
502
 
 
503
 
  for (x = 0; x < BOARDX; x++)
504
 
    rootnode->parent[x] = NULL;
505
 
 
506
 
  streeroot = fast_init_bin_tree (rootnode);
507
 
  her_pn_search (rootnode, maxnodenum, &info);
508
 
 
509
 
  mynode->value = rootnode->value;
510
 
  mynode->proof = rootnode->proof;
511
 
  mynode->disproof = rootnode->disproof;
512
 
 
513
 
  her_free_whole_tree (streeroot);
514
 
  fast_free_bin_tree (streeroot);
515
 
 
516
 
  if (mynode->value != UNKNOWN)
517
 
    return YES;
518
 
  return NO;
519
 
}
520
 
 
521
 
 
522
 
 
523
 
/* Avoid tricks */
524
 
 
525
 
short
526
 
heuristic_play_best (struct board *board, long maxnodenum)
527
 
{
528
 
  struct board *tempboard;
529
 
  struct info info;
530
 
  short mymove;
531
 
  struct node *symmetric;
532
 
  short x, y, issymm = NO;
533
 
 
534
 
 
535
 
  auxboard = board;
536
 
  tempboard = (struct board *) malloc (sizeof (struct board));
537
 
  if (!tempboard)
538
 
    fatal_error ("Cannot store temporary board");
539
 
  memcpy (tempboard, board, sizeof (struct board));
540
 
 
541
 
  rootnode = (struct node *) malloc (sizeof (struct node));
542
 
  symmetric = (struct node *) malloc (sizeof (struct node));
543
 
  if (!rootnode || !symmetric)
544
 
    fatal_error ("Not enough memory");
545
 
 
546
 
  for (y = 0; y < BOARDY; y++) {
547
 
    rootnode->square[ELM (BOARDX, y)] =
548
 
      (unsigned char) (board->square[ELM (BOARDX, y)] & 0xff);
549
 
    symmetric->square[ELM (BOARDX, y)] =
550
 
      (unsigned char) (board->square[ELM (BOARDX, y)] & 0xff);
551
 
    for (x = 0; x < BOARDX; x++) {
552
 
      rootnode->square[ELM (x, y)] =
553
 
        (unsigned char) (board->square[ELM (x, y)] & 0xff);
554
 
      symmetric->square[ELM (x, y)] =
555
 
        (unsigned char) (board->square[ELM (BOARDX - x - 1, y)] & 0xff);
556
 
    }
557
 
  }
558
 
 
559
 
  rootnode->turn = board->turn;
560
 
  symmetric->turn = board->turn;
561
 
 
562
 
  for (x = 0; x < BOARDX; x++) {
563
 
    rootnode->stack[x] = (unsigned char) (board->stack[x] & 0xff);
564
 
    symmetric->stack[x] =
565
 
      (unsigned char) (board->stack[BOARDX - 1 - x] & 0xff);
566
 
  }
567
 
 
568
 
  rootnode->stack[BOARDX] = (unsigned char) (board->stack[BOARDX] & 0xff);
569
 
  symmetric->stack[BOARDX] = (unsigned char) (board->stack[BOARDX] & 0xff);
570
 
 
571
 
  if (bin_compare (symmetric->square, rootnode->square) > 0) {
572
 
    free (rootnode);
573
 
    rootnode = symmetric;
574
 
    issymm = YES;
575
 
  } else
576
 
    free (symmetric);
577
 
 
578
 
  her_node_expanded = 0L;
579
 
  her_node_not_expanded = 0L;
580
 
 
581
 
  for (x = 0; x < BOARDX; x++) {
582
 
    rootnode->parent[x] = NULL;
583
 
    rootnode->child[x] = NULL;
584
 
  }
585
 
 
586
 
  rootnode->evaluated = NO;
587
 
  rootnode->expanded = NO;
588
 
  rootnode->value = UNKNOWN;
589
 
  rootnode->type = OR_TYPE;
590
 
 
591
 
  streeroot = fast_init_bin_tree (rootnode);
592
 
  her_pn_search (rootnode, maxnodenum, &info);
593
 
  mymove = info.bestmove;
594
 
 
595
 
  if (rootnode->value == UNKNOWN)
596
 
    mymove = -1;
597
 
  else if (rootnode->value == DISPROVED)
598
 
    mymove = -2;
599
 
  else if (issymm)
600
 
    mymove = BOARDX - 1 - mymove;
601
 
 
602
 
  her_free_whole_tree (streeroot);
603
 
  fast_free_bin_tree (streeroot);
604
 
 
605
 
  memcpy (board, tempboard, sizeof (struct board));
606
 
  free (tempboard);
607
 
 
608
 
  board->nodes_visited = her_node_expanded + her_node_not_expanded;
609
 
  board->maxtreedepth = info.max_tree_depth;
610
 
  return mymove;
611
 
}