Ticket #199: gunnar_9_1.8b.diff

File gunnar_9_1.8b.diff, 29.3 KB (added by gunnar, 22 months ago)

Same as gunnar_9_1.8, rediffed after gunnar_9_1.12.

  • engine/liberty.h

    diff --git a/engine/liberty.h b/engine/liberty.h
    index 8bddec0..f85c11d 100644
    a b void compute_eyes_pessimistic(int pos, struct eyevalue *value, 
    10311031                              int *pessimistic_min, 
    10321032                              int *attack_point, int *defense_point, 
    10331033                              struct eye_data eye[BOARDMAX], 
    1034                               struct half_eye_data heye[BOARDMAX]); 
     1034                              struct half_eye_data heye[BOARDMAX], 
     1035                              int eyefilling_points[BOARDMAX]); 
    10351036void propagate_eye(int pos, struct eye_data eye[BOARDMAX]); 
    10361037int find_eye_dragons(int origin, struct eye_data eye[BOARDMAX], int eye_color, 
    10371038                     int dragons[], int max_dragons); 
  • engine/optics.c

    diff --git a/engine/optics.c b/engine/optics.c
    index fb3faaf..5f68b39 100644
    a b static int read_eye(int pos, int *attack_point, int *defense_point, 
    5959                    struct eyevalue *value, 
    6060                    struct eye_data eye[BOARDMAX], 
    6161                    struct half_eye_data heye[BOARDMAX], 
     62                    int eyefilling_points[BOARDMAX], 
    6263                    int add_moves); 
    6364static int recognize_eye(int pos, int *attack_point, int *defense_point, 
    6465                         struct eyevalue *value, 
    6566                         struct eye_data eye[BOARDMAX], 
    6667                         struct half_eye_data heye[BOARDMAX], 
    67                          struct vital_points *vp); 
     68                         struct vital_points *vp, 
     69                         int eyefilling_points[BOARDMAX]); 
    6870static void guess_eye_space(int pos, int effective_eyesize, int margins, 
    6971                            int bulk_score, struct eye_data eye[BOARDMAX], 
    7072                            struct eyevalue *value, int *pessimistic_min); 
     73static struct eye_graph *optical_graph_matcher(int *vpos, 
     74                                               signed char *marginal, 
     75                                               signed char *edge, 
     76                                               signed char *neighbors, 
     77                                               signed char *stone, 
     78                                               int eye_size, int num_marginals, 
     79                                               int *map, 
     80                                               struct half_eye_data *heye); 
    7181static void reset_map(int size); 
    7282static void first_map(int *map_value); 
    7383static int next_map(int *q, int map[MAXEYE]); 
    compute_eyes(int pos, struct eyevalue *value, 
    743753  } 
    744754   
    745755  /* Look up the eye space in the graphs database. */ 
    746   if (read_eye(pos, attack_point, defense_point, value, eye, heye, add_moves)) 
     756  if (read_eye(pos, attack_point, defense_point, value, eye, heye, 
     757               NULL, add_moves)) 
    747758    return; 
    748759 
    749760  /* Ideally any eye space that hasn't been matched yet should be two 
    compute_eyes_pessimistic(int pos, struct eyevalue *value, 
    771782                         int *pessimistic_min, 
    772783                         int *attack_point, int *defense_point, 
    773784                         struct eye_data eye[BOARDMAX], 
    774                          struct half_eye_data heye[BOARDMAX]) 
     785                         struct half_eye_data heye[BOARDMAX], 
     786                         int eyefilling_points[BOARDMAX]) 
    775787{ 
    776788  static int bulk_coefficients[5] = {-1, -1, 1, 4, 12}; 
    777789 
    compute_eyes_pessimistic(int pos, struct eyevalue *value, 
    882894   
    883895  /* Look up the eye space in the graphs database. */ 
    884896  if (read_eye(pos, attack_point, defense_point, value, 
    885                eye, heye, 0)) { 
     897               eye, heye, eyefilling_points, 0)) { 
    886898    *pessimistic_min = min_eyes(value) - margins; 
    887899 
    888900    /* A single point eye which is part of a ko can't be trusted. */ 
    guess_eye_space(int pos, int effective_eyesize, int margins, 
    10771089static int 
    10781090read_eye(int pos, int *attack_point, int *defense_point, 
    10791091         struct eyevalue *value, struct eye_data eye[BOARDMAX],  
    1080          struct half_eye_data heye[BOARDMAX],  
     1092         struct half_eye_data heye[BOARDMAX], int eyefilling_points[BOARDMAX], 
    10811093         int add_moves) 
    10821094{ 
    10831095  int eye_color; 
    read_eye(int pos, int *attack_point, int *defense_point, 
    10931105  struct vital_points *best_vp = &vp; 
    10941106 
    10951107  eye_color = recognize_eye(pos, attack_point, defense_point, value, 
    1096                             eye, heye, &vp); 
     1108                            eye, heye, &vp, eyefilling_points); 
    10971109  if (!eye_color) 
    10981110    return 0; 
    10991111 
    read_eye(int pos, int *attack_point, int *defense_point, 
    11461158 
    11471159    heye[combination_halfeye].type = 0; 
    11481160    result = recognize_eye(pos, &apos, &dpos, &combination_value, eye, 
    1149                            heye, &combination_vp); 
     1161                           heye, &combination_vp, NULL); 
    11501162    heye[combination_halfeye].type = HALF_EYE; 
    11511163 
    11521164    if (result) { 
    read_eye(int pos, int *attack_point, int *defense_point, 
    12111223 
    12121224    heye[ko_halfeye].type = 0; 
    12131225    result = recognize_eye(pos, &apos, &dpos, &ko_value, eye, 
    1214                            heye, &ko_vp); 
     1226                           heye, &ko_vp, NULL); 
    12151227    heye[ko_halfeye].type = HALF_EYE; 
    12161228 
    12171229    if (result && max_eyes(value) < max_eyes(&ko_value)) { 
    recognize_eye(int pos, int *attack_point, int *defense_point, 
    12541266              struct eyevalue *value, 
    12551267              struct eye_data eye[BOARDMAX],  
    12561268              struct half_eye_data heye[BOARDMAX],  
    1257               struct vital_points *vp) 
     1269              struct vital_points *vp, 
     1270              int eyefilling_points[BOARDMAX]) 
    12581271{ 
    12591272  int pos2; 
    12601273  int eye_color; 
    12611274  int eye_size = 0; 
    12621275  int num_marginals = 0; 
    12631276  int vpos[MAXEYE]; 
    1264   signed char marginal[MAXEYE], edge[MAXEYE], neighbors[MAXEYE]; 
    1265   int graph; 
     1277  signed char marginal[MAXEYE]; 
     1278  signed char edge[MAXEYE]; 
     1279  signed char neighbors[MAXEYE]; 
     1280  signed char stone[MAXEYE]; 
     1281  struct eye_graph *graph; 
    12661282  int map[MAXEYE]; 
    12671283  int best_score; 
    12681284  int r; 
    12691285 
    12701286  gg_assert(attack_point != NULL); 
    12711287  gg_assert(defense_point != NULL); 
    1272      
     1288 
    12731289  /* Set `eye_color' to the owner of the eye. */ 
    12741290  eye_color = eye[pos].color; 
    12751291 
    recognize_eye(int pos, int *attack_point, int *defense_point, 
    12891305      if (marginal[eye_size]) 
    12901306        num_marginals++; 
    12911307      neighbors[eye_size] = eye[pos2].neighbors; 
     1308      stone[eye_size] = IS_STONE(board[pos2]); 
    12921309      if (0) { 
    12931310        if (marginal[eye_size]) 
    12941311          TRACE("(%1m)", vpos[eye_size]); 
    recognize_eye(int pos, int *attack_point, int *defense_point, 
    13171334        num_marginals++; 
    13181335        edge[eye_size] = 0; 
    13191336        neighbors[eye_size] = 1; 
     1337        stone[eye_size] = 0; 
    13201338      } 
    13211339       
    13221340      eye_size++; 
    13231341    } 
    13241342  } 
    1325    
     1343 
     1344  graph = optical_graph_matcher(vpos, marginal, edge, neighbors, stone, 
     1345                                eye_size, num_marginals, map, heye); 
     1346 
     1347  if (!graph) 
     1348    return 0; 
     1349 
     1350  /* We have found a match! Now sort out the vital moves. */ 
     1351  *value = graph->value; 
     1352  vp->num_attacks = 0; 
     1353  vp->num_defenses = 0; 
     1354 
     1355  if (eye_move_urgency(value) > 0) { 
     1356    /* Collect all attack and defense points in the pattern. */ 
     1357    int k; 
     1358 
     1359    for (k = 0; k < eye_size; k++) { 
     1360      struct eye_vertex *ev = &graph->vertex[k]; 
     1361 
     1362      if (ev->flags & EYE_ATTACK_POINT) { 
     1363        /* Check for a marginal vertex matching a half eye virtual 
     1364         * marginal. This is the case if a half eye preceeds the 
     1365         * current vertex in the list. 
     1366         */ 
     1367        if (ev->marginal 
     1368            && map[k] > 0 
     1369            && vpos[map[k] - 1] != NO_MOVE 
     1370            && is_halfeye(heye, vpos[map[k] - 1])) { 
     1371          /* Add all diagonals as vital. */ 
     1372          int ix; 
     1373          struct half_eye_data *he = &heye[vpos[map[k] - 1]]; 
     1374 
     1375          for (ix = 0; ix < he->num_attacks; ix++) 
     1376            vp->attacks[vp->num_attacks++] = he->attack_point[ix]; 
     1377        } 
     1378        else 
     1379          vp->attacks[vp->num_attacks++] = vpos[map[k]]; 
     1380      } 
     1381 
     1382      if (ev->flags & EYE_DEFENSE_POINT) { 
     1383        /* Check for a half eye virtual marginal vertex. */ 
     1384        if (ev->marginal 
     1385            && map[k] > 0 
     1386            && vpos[map[k] - 1] != NO_MOVE 
     1387            && is_halfeye(heye, vpos[map[k] - 1])) { 
     1388          /* Add all diagonals as vital. */ 
     1389          int ix; 
     1390          struct half_eye_data *he = &heye[vpos[map[k] - 1]]; 
     1391 
     1392          for (ix = 0; ix < he->num_defenses; ix++) 
     1393            vp->defenses[vp->num_defenses++] = he->defense_point[ix]; 
     1394        } 
     1395        else 
     1396          vp->defenses[vp->num_defenses++] = vpos[map[k]]; 
     1397      } 
     1398    } 
     1399 
     1400    gg_assert(vp->num_attacks > 0 && vp->num_defenses > 0); 
     1401 
     1402    /* We now have all vital attack and defense points listed but 
     1403     * we are also expected to single out of one of each to return 
     1404     * in *attack_point and *defense_point. Since sometimes those 
     1405     * are the only vital points considered, we want to choose the 
     1406     * best ones, in the sense that they minimize the risk for 
     1407     * error in the eye space analysis. 
     1408     * 
     1409     * One example is this position 
     1410     * 
     1411     * |..XXXX 
     1412     * |XXX..X 
     1413     * |..!O.X 
     1414     * |OO.O.X 
     1415     * |.O.!XX 
     1416     * +------ 
     1417     * 
     1418     * where O has an eyespace of the !..! type. The graph 
     1419     * matching finds that both marginal vertices are vital points 
     1420     * but here the one at 3-3 fails to defend. (For attack both 
     1421     * points work but the 3-3 one is still worse since it leaves 
     1422     * a ko threat.) 
     1423     * 
     1424     * In order to differentiate between the marginal points we 
     1425     * count the number of straight and diagonal neighbors within 
     1426     * the eye space. In the example above both have one straight 
     1427     * neighbor each but the edge margin wins because it also has 
     1428     * a diagonal margin. 
     1429     */ 
     1430 
     1431    best_score = -10; 
     1432    for (k = 0; k < vp->num_attacks; k++) { 
     1433      int apos = vp->attacks[k]; 
     1434      int score = 0; 
     1435      for (r = 0; r < 8; r++) 
     1436        if (ON_BOARD(apos + delta[r]) 
     1437            && eye[apos + delta[r]].color == eye[pos].color 
     1438            && !eye[apos + delta[r]].marginal) { 
     1439          score++; 
     1440          if (r < 4) { 
     1441            score++; 
     1442            if (board[apos + delta[r]] != EMPTY) 
     1443              score++; 
     1444          } 
     1445        } 
     1446 
     1447      /* If a vital point is not adjacent to any point in the eye 
     1448       * space, it must be a move to capture or defend a string 
     1449       * related to a halfeye, e.g. the move * in this position, 
     1450       * 
     1451       * ......| 
     1452       * .XXXX.| 
     1453       * .X.O..| 
     1454       * .XO.OO| 
     1455       * .*XO..| 
     1456       * ------+ 
     1457       * 
     1458       * Playing this is probably a good idea. 
     1459       */ 
     1460      if (score == 0) 
     1461        score += 2; 
     1462 
     1463      if (0) 
     1464        gprintf("attack point %1m score %d\n", apos, score); 
     1465 
     1466      if (score > best_score) { 
     1467        *attack_point = apos; 
     1468        best_score = score; 
     1469      } 
     1470    } 
     1471 
     1472    best_score = -10; 
     1473    for (k = 0; k < vp->num_defenses; k++) { 
     1474      int dpos = vp->defenses[k]; 
     1475      int score = 0; 
     1476      for (r = 0; r < 8; r++) 
     1477        if (ON_BOARD(dpos + delta[r]) 
     1478            && eye[dpos + delta[r]].color == eye[pos].color 
     1479            && !eye[dpos + delta[r]].marginal) { 
     1480          score++; 
     1481          if (r < 4) { 
     1482            score++; 
     1483            if (board[dpos + delta[r]] != EMPTY) 
     1484              score++; 
     1485          } 
     1486        } 
     1487 
     1488      /* If possible, choose a non-sacrificial defense point. 
     1489       * Compare white T8 and T6 in lazarus:21. 
     1490       */ 
     1491      if (safe_move(dpos, eye_color) != WIN) 
     1492        score -= 5; 
     1493 
     1494      /* See comment to the same code for attack points. */ 
     1495      if (score == 0) 
     1496        score += 2; 
     1497 
     1498      if (0) 
     1499        gprintf("defense point %1m score %d\n", dpos, score); 
     1500 
     1501      if (score > best_score) { 
     1502        *defense_point = dpos; 
     1503        best_score = score; 
     1504      } 
     1505    } 
     1506 
     1507    DEBUG(DEBUG_EYES, "  vital points: %1m (attack) %1m (defense)\n", 
     1508          *attack_point, *defense_point); 
     1509    DEBUG(DEBUG_EYES, "  pattern matched:  %d\n", graph->patnum); 
     1510 
     1511  } 
     1512 
     1513  /* In certain types of semeais it is necessary to fill in nakade 
     1514   * shapes, e.g. in a position like this: 
     1515   * 
     1516   * OOOOOXXXXXX 
     1517   * OXXXXOOOOOX 
     1518   * OX.OXXO..OX 
     1519   * OX.OOXO..OX 
     1520   * ----------- 
     1521   * 
     1522   * However, only one of the lower left liberties leaves a nakade 
     1523   * shape when O plays there. The code below tries adding a stone at 
     1524   * each empty vertex in the eyespace and do graph matching to find 
     1525   * the eyevalue of the resulting eyespace. If it's still only worth 
     1526   * one eye it is a valid eyefilling point. 
     1527   * 
     1528   * In some positions a subset of the eyefilling points give the 
     1529   * opponent a ko threat. If this can be avoided we prefer the points 
     1530   * which don't. One example is 
     1531   * 
     1532   * XXXX 
     1533   * XabXX 
     1534   * XcOdX 
     1535   * ----- 
     1536   * 
     1537   * where playing at the empty vertices a and d leaves a ko threat to 
     1538   * make two eyes, whereas b and c don't. 
     1539   * 
     1540   * We only do this analysis if the information is requested (when 
     1541   * called from semeai reading), the eyeshape is worth exactly one 
     1542   * eye, and there are no marginal points (then generally better to 
     1543   * play those first). 
     1544   */ 
     1545  if (eyefilling_points 
     1546      && min_eyes(value) == 1 && max_eyes(value) == 1 && num_marginals == 0) { 
     1547    int k; 
     1548    int num_empty = 0; 
     1549    /* Count the number of empty points in the eyespace. */ 
     1550    for (k = 0; k < eye_size; k++) { 
     1551      if (!stone[k]) 
     1552        num_empty++; 
     1553    } 
     1554 
     1555    /* We can't fill in an eyespace with only one liberty. It would 
     1556     * either be suicide or capture the surrounding stones. 
     1557     */ 
     1558    if (num_empty > 1) { 
     1559      int valid_point[MAXEYE]; 
     1560      int threat[MAXEYE]; 
     1561      int min_threat = 2; 
     1562      /* For each empty point, add a stone and do the graph matching 
     1563       * again. 
     1564       */ 
     1565      for (k = 0; k < eye_size; k++) { 
     1566        if (!stone[k]) { 
     1567          struct eye_graph *graph2; 
     1568          stone[k] = 1; 
     1569          valid_point[k] = 0; 
     1570          graph2 = optical_graph_matcher(vpos, marginal, edge, neighbors, stone, 
     1571                                         eye_size, num_marginals, map, heye); 
     1572          if (graph2 && max_eyes(&graph2->value) < 2) { 
     1573            /* This is an effective eyefilling point. Also check 
     1574             * whether it leaves a ko threat. 
     1575             */ 
     1576            valid_point[k] = 1; 
     1577            threat[k] = max_eye_threat(&graph2->value); 
     1578            if (threat[k] < min_threat) 
     1579              min_threat = threat[k]; 
     1580          } 
     1581          stone[k] = 0; 
     1582        } 
     1583      } 
     1584      /* Loop through the points once more to record those which are 
     1585       * both effective eyefilling points and don't leave a ko threat 
     1586       * if it can be avoided. 
     1587       */ 
     1588      for (k = 0; k < eye_size; k++) { 
     1589        if (!stone[k] && valid_point[k]) { 
     1590          int pos = vpos[k]; 
     1591          if (threat[k] == min_threat) { 
     1592            eyefilling_points[pos] = 1; 
     1593            TRACE("Eyefilling point at %1m\n", pos); 
     1594          } 
     1595        } 
     1596      } 
     1597    } 
     1598  } 
     1599 
     1600  TRACE("eye space at %1m of type %d\n", pos, graph->patnum); 
     1601  return eye_color; 
     1602} 
     1603 
     1604 
     1605/* Perform the actual matching of the graphs in eyes.db. */ 
     1606static struct eye_graph * 
     1607optical_graph_matcher(int *vpos, signed char *marginal, signed char *edge, 
     1608                      signed char *neighbors, signed char *stone, int eye_size, 
     1609                      int num_marginals, int *map, 
     1610                      struct half_eye_data *heye) 
     1611{ 
    13261612  /* We attempt to construct a map from the graph to the eyespace 
    13271613   * preserving the adjacency structure. If this can be done, we've 
    13281614   * identified the eyeshape. 
    13291615   */ 
     1616  int n; 
    13301617 
    1331   for (graph = 0; graphs[graph].vertex != NULL; graph++) { 
     1618  for (n = 0; graphs[n].vertex != NULL; n++) { 
    13321619    int q; 
    13331620 
    1334     if (graphs[graph].esize != eye_size 
    1335         || graphs[graph].msize != num_marginals) 
     1621    if (graphs[n].esize != eye_size 
     1622        || graphs[n].msize != num_marginals) 
    13361623      continue; 
    13371624 
    13381625    reset_map(eye_size); 
    recognize_eye(int pos, int *attack_point, int *defense_point, 
    13401627    first_map(&map[0]); 
    13411628 
    13421629    while (1) { 
    1343       struct eye_vertex *gv = &graphs[graph].vertex[q]; 
     1630      struct eye_vertex *gv = &graphs[n].vertex[q]; 
    13441631      int mv = map[q]; 
    13451632      int ok = 1; 
    13461633 
    recognize_eye(int pos, int *attack_point, int *defense_point, 
    13541641        ok = 0; 
    13551642 
    13561643      if (ok) { 
    1357         if (IS_STONE(board[vpos[mv]])) { 
     1644        if (stone[mv]) { 
    13581645          if (!(gv->flags & CAN_CONTAIN_STONE)) 
    13591646            ok = 0; 
    13601647        } 
    recognize_eye(int pos, int *attack_point, int *defense_point, 
    14111698      } 
    14121699    } 
    14131700 
    1414     if (q == eye_size) { 
    1415       /* We have found a match! Now sort out the vital moves. */ 
    1416       *value = graphs[graph].value; 
    1417       vp->num_attacks = 0; 
    1418       vp->num_defenses = 0; 
    1419        
    1420       if (eye_move_urgency(value) > 0) { 
    1421         /* Collect all attack and defense points in the pattern. */ 
    1422         int k; 
    1423  
    1424         for (k = 0; k < eye_size; k++) { 
    1425           struct eye_vertex *ev = &graphs[graph].vertex[k]; 
    1426  
    1427           if (ev->flags & EYE_ATTACK_POINT) { 
    1428             /* Check for a marginal vertex matching a half eye virtual 
    1429              * marginal. This is the case if a half eye preceeds the 
    1430              * current vertex in the list. 
    1431              */ 
    1432             if (ev->marginal 
    1433                 && map[k] > 0 
    1434                 && vpos[map[k] - 1] != NO_MOVE 
    1435                 && is_halfeye(heye, vpos[map[k] - 1])) { 
    1436               /* Add all diagonals as vital. */ 
    1437               int ix; 
    1438               struct half_eye_data *he = &heye[vpos[map[k] - 1]]; 
    1439                
    1440               for (ix = 0; ix < he->num_attacks; ix++) 
    1441                 vp->attacks[vp->num_attacks++] = he->attack_point[ix]; 
    1442             } 
    1443             else 
    1444               vp->attacks[vp->num_attacks++] = vpos[map[k]]; 
    1445           } 
    1446            
    1447           if (ev->flags & EYE_DEFENSE_POINT) { 
    1448             /* Check for a half eye virtual marginal vertex. */ 
    1449             if (ev->marginal 
    1450                 && map[k] > 0 
    1451                 && vpos[map[k] - 1] != NO_MOVE 
    1452                 && is_halfeye(heye, vpos[map[k] - 1])) { 
    1453               /* Add all diagonals as vital. */ 
    1454               int ix; 
    1455               struct half_eye_data *he = &heye[vpos[map[k] - 1]]; 
    1456                
    1457               for (ix = 0; ix < he->num_defenses; ix++) 
    1458                 vp->defenses[vp->num_defenses++] = he->defense_point[ix]; 
    1459             } 
    1460             else 
    1461               vp->defenses[vp->num_defenses++] = vpos[map[k]]; 
    1462           } 
    1463         } 
    1464          
    1465         gg_assert(vp->num_attacks > 0 && vp->num_defenses > 0); 
    1466  
    1467         /* We now have all vital attack and defense points listed but 
    1468          * we are also expected to single out of one of each to return 
    1469          * in *attack_point and *defense_point. Since sometimes those 
    1470          * are the only vital points considered, we want to choose the 
    1471          * best ones, in the sense that they minimize the risk for 
    1472          * error in the eye space analysis. 
    1473          * 
    1474          * One example is this position 
    1475          * 
    1476          * |..XXXX 
    1477          * |XXX..X 
    1478          * |..!O.X 
    1479          * |OO.O.X 
    1480          * |.O.!XX 
    1481          * +------ 
    1482          * 
    1483          * where O has an eyespace of the !..! type. The graph 
    1484          * matching finds that both marginal vertices are vital points 
    1485          * but here the one at 3-3 fails to defend. (For attack both 
    1486          * points work but the 3-3 one is still worse since it leaves 
    1487          * a ko threat.) 
    1488          * 
    1489          * In order to differentiate between the marginal points we 
    1490          * count the number of straight and diagonal neighbors within 
    1491          * the eye space. In the example above both have one straight 
    1492          * neighbor each but the edge margin wins because it also has 
    1493          * a diagonal margin. 
    1494          */ 
    1495  
    1496         best_score = -10; 
    1497         for (k = 0; k < vp->num_attacks; k++) { 
    1498           int apos = vp->attacks[k]; 
    1499           int score = 0; 
    1500           for (r = 0; r < 8; r++) 
    1501             if (ON_BOARD(apos + delta[r]) 
    1502                 && eye[apos + delta[r]].color == eye[pos].color 
    1503                 && !eye[apos + delta[r]].marginal) { 
    1504               score++; 
    1505               if (r < 4) { 
    1506                 score++; 
    1507                 if (board[apos + delta[r]] != EMPTY) 
    1508                   score++; 
    1509               } 
    1510             } 
    1511  
    1512           /* If a vital point is not adjacent to any point in the eye 
    1513            * space, it must be a move to capture or defend a string 
    1514            * related to a halfeye, e.g. the move * in this position, 
    1515            * 
    1516            * ......| 
    1517            * .XXXX.| 
    1518            * .X.O..| 
    1519            * .XO.OO| 
    1520            * .*XO..| 
    1521            * ------+ 
    1522            * 
    1523            * Playing this is probably a good idea. 
    1524            */ 
    1525           if (score == 0) 
    1526             score += 2; 
    1527            
    1528           if (0) 
    1529             gprintf("attack point %1m score %d\n", apos, score); 
    1530            
    1531           if (score > best_score) { 
    1532             *attack_point = apos; 
    1533             best_score = score; 
    1534           } 
    1535         } 
    1536  
    1537         best_score = -10; 
    1538         for (k = 0; k < vp->num_defenses; k++) { 
    1539           int dpos = vp->defenses[k]; 
    1540           int score = 0; 
    1541           for (r = 0; r < 8; r++) 
    1542             if (ON_BOARD(dpos + delta[r]) 
    1543                 && eye[dpos + delta[r]].color == eye[pos].color 
    1544                 && !eye[dpos + delta[r]].marginal) { 
    1545               score++; 
    1546               if (r < 4) { 
    1547                 score++; 
    1548                 if (board[dpos + delta[r]] != EMPTY) 
    1549                   score++; 
    1550               } 
    1551             } 
    1552  
    1553           /* If possible, choose a non-sacrificial defense point. 
    1554            * Compare white T8 and T6 in lazarus:21. 
    1555            */ 
    1556           if (safe_move(dpos, eye_color) != WIN) 
    1557             score -= 5; 
    1558  
    1559           /* See comment to the same code for attack points. */ 
    1560           if (score == 0) 
    1561             score += 2; 
    1562  
    1563           if (0) 
    1564             gprintf("defense point %1m score %d\n", dpos, score); 
    1565            
    1566           if (score > best_score) { 
    1567             *defense_point = dpos; 
    1568             best_score = score; 
    1569           } 
    1570         } 
    1571          
    1572         DEBUG(DEBUG_EYES, "  vital points: %1m (attack) %1m (defense)\n", 
    1573               *attack_point, *defense_point); 
    1574         DEBUG(DEBUG_EYES, "  pattern matched:  %d\n", graphs[graph].patnum); 
    1575          
    1576       } 
    1577       TRACE("eye space at %1m of type %d\n", pos, graphs[graph].patnum); 
    1578        
    1579       return eye_color; 
    1580     } 
     1701    /* Successful match. */ 
     1702    if (q == eye_size) 
     1703      return &graphs[n]; 
    15811704  } 
    15821705 
    1583   return 0; 
     1706  return NULL; 
    15841707} 
    15851708 
    15861709 
  • engine/owl.c

    diff --git a/engine/owl.c b/engine/owl.c
    index f44e3e9..7ba2d4c 100644
    a b static void owl_determine_life(struct local_owl_data *owl, 
    209209                               int does_attack, 
    210210                               struct owl_move_data *moves, 
    211211                               struct eyevalue *probable_eyes, 
    212                                int *eyemin, int *eyemax); 
     212                               int *eyemin, int *eyemax, 
     213                               int eyefilling_points[BOARDMAX]); 
    213214static void owl_find_relevant_eyespaces(struct local_owl_data *owl, 
    214215                                        int mw[BOARDMAX], int mz[BOARDMAX]); 
    215216static int owl_estimate_life(struct local_owl_data *owl, 
    static int owl_estimate_life(struct local_owl_data *owl, 
    218219                             const char **live_reason, 
    219220                             int does_attack, 
    220221                             struct eyevalue *probable_eyes, 
    221                              int *eyemin, int *eyemax); 
     222                             int *eyemin, int *eyemax, 
     223                             int eyefilling_points[BOARDMAX]); 
    222224static int modify_stupid_eye_vital_point(struct local_owl_data *owl, 
    223225                                         int *vital_point, 
    224226                                         int is_attack_point); 
    do_owl_analyze_semeai(int apos, int bpos, 
    642644  struct matched_patterns_list_data shape_defensive_patterns; 
    643645  struct owl_move_data moves[MAX_SEMEAI_MOVES]; 
    644646  struct owl_move_data outside_liberty; 
     647  struct owl_move_data eyefilling_liberty; 
    645648  struct owl_move_data common_liberty; 
    646649  struct owl_move_data backfill_outside_liberty; 
    647650  struct owl_move_data backfill_common_liberty; 
    648651  int safe_outside_liberty_found = 0; 
     652  int eyefilling_liberty_found = 0; 
    649653  int safe_common_liberty_found = 0; 
    650654  int riskless_move_found = 0; 
    651655  signed char mw[BOARDMAX];   
    do_owl_analyze_semeai(int apos, int bpos, 
    674678  struct eyevalue probable_eyes_b; 
    675679  struct eyevalue dummy_eyes; 
    676680  int I_have_more_eyes; 
     681  int eyefilling_points[BOARDMAX]; 
    677682   
    678683  SETUP_TRACE_INFO2("do_owl_analyze_semeai", apos, bpos); 
    679684 
    do_owl_analyze_semeai(int apos, int bpos, 
    717722#endif 
    718723   
    719724  outside_liberty.pos = NO_MOVE; 
     725  eyefilling_liberty.pos = NO_MOVE; 
    720726  common_liberty.pos = NO_MOVE; 
    721727  backfill_outside_liberty.pos = NO_MOVE; 
    722728  backfill_common_liberty.pos = NO_MOVE; 
    do_owl_analyze_semeai(int apos, int bpos, 
    847853 
    848854    if (owl_estimate_life(owla, owlb, vital_defensive_moves, 
    849855                          &live_reasona, 0, &probable_eyes_a, 
    850                           &eyemin_a, &eyemax_a)) 
     856                          &eyemin_a, &eyemax_a, NULL)) 
    851857      I_look_alive = 1; 
    852858    else if (stackp > 2 && owl_escape_route(owla) >= 5) { 
    853859      live_reasona = "escaped"; 
    854860      I_look_alive = 1; 
    855861    } 
    856862 
     863    memset(eyefilling_points, 0, sizeof(eyefilling_points)); 
    857864    if (owl_estimate_life(owlb, owla, vital_offensive_moves, 
    858865                          &live_reasonb, 1, &probable_eyes_b, 
    859                           &eyemin_b, &eyemax_b)) 
     866                          &eyemin_b, &eyemax_b, eyefilling_points)) 
    860867      you_look_alive = 1; 
    861868    else if (stackp > 2 && owl_escape_route(owlb) >= 5) { 
    862869      live_reasonb = "escaped"; 
    do_owl_analyze_semeai(int apos, int bpos, 
    964971      include_semeai_worms_in_eyespace = 1; 
    965972      if (!owl_estimate_life(owlb, owla, vital_offensive_moves, 
    966973                             &live_reasonb, 1, &dummy_eyes, 
    967                              &eyemin_b, &eyemax_b)) 
     974                             &eyemin_b, &eyemax_b, NULL)) 
    968975        semeai_review_owl_moves(vital_offensive_moves, owla, owlb, color, 
    969976                                &safe_outside_liberty_found, 
    970977                                &safe_common_liberty_found, 
    do_owl_analyze_semeai(int apos, int bpos, 
    10271034       
    10281035      if (board[pos] == EMPTY && !mw[pos]) { 
    10291036        if (liberty_of_goal(pos, owlb)) { 
     1037          int origin = owlb->my_eye[pos].origin; 
    10301038          if (!liberty_of_goal(pos, owla)) { 
    1031             /* outside liberty */ 
    1032             if (safe_move(pos, color) == WIN) { 
    1033               safe_outside_liberty_found = 1; 
    1034               outside_liberty.pos = pos; 
    1035               break; 
     1039            if (!(owlb->my_eye[origin].color == owlb->color 
     1040                  && max_eyes(&owlb->my_eye[origin].value) > 0)) { 
     1041              /* outside liberty */ 
     1042              if (safe_move(pos, color) == WIN) { 
     1043                safe_outside_liberty_found = 1; 
     1044                outside_liberty.pos = pos; 
     1045                break; 
     1046              } 
     1047              else if (backfill_outside_liberty.pos == NO_MOVE) 
     1048                backfill_outside_liberty.pos = find_semeai_backfilling_move(bpos, 
     1049                                                                            pos); 
     1050            } 
     1051            else { 
     1052              /* eye-filling liberty */ 
     1053              if (eyefilling_points[pos]) { 
     1054                eyefilling_liberty_found = 1; 
     1055                eyefilling_liberty.pos = pos; 
     1056              } 
    10361057            } 
    1037             else if (backfill_outside_liberty.pos == NO_MOVE) 
    1038               backfill_outside_liberty.pos = find_semeai_backfilling_move(bpos, 
    1039                                                                           pos); 
    10401058          } 
    10411059          else { 
    10421060            /* common liberty */ 
    do_owl_analyze_semeai(int apos, int bpos, 
    10561074  /* Add the best liberty filling move available. We first want to 
    10571075   * play outer liberties, second backfilling moves required before 
    10581076   * filling an outer liberty. If no such moves are available we try 
    1059    * to fill a mutual liberty or play a corresponding backfilling 
    1060    * move. 
     1077   * to locate an eyefilling move. After that we try to fill a mutual 
     1078   * liberty or play a corresponding backfilling move. 
    10611079   */ 
    10621080  if (!you_look_alive || we_might_be_inessential) { 
    10631081    if (safe_outside_liberty_found 
    do_owl_analyze_semeai(int apos, int bpos, 
    10811099      riskless_move_found = 1; 
    10821100      TRACE("Added %1m %d (6)\n", backfill_outside_liberty.pos, move_value); 
    10831101    } 
     1102    else if (eyefilling_liberty_found 
     1103             && eyefilling_liberty.pos != NO_MOVE) { 
     1104      move_value = semeai_move_value(eyefilling_liberty.pos, 
     1105                                     owla, owlb, 30, 
     1106                                     critical_semeai_worms); 
     1107      owl_add_move(moves, eyefilling_liberty.pos, move_value, 
     1108                   "safe eyefilling liberty", SAME_DRAGON_NOT_CONNECTED, 
     1109                   NO_MOVE, 0, NO_MOVE, MAX_SEMEAI_MOVES, NULL); 
     1110      riskless_move_found = 1; 
     1111      TRACE("Added %1m %d (5)\n", eyefilling_liberty.pos, move_value); 
     1112    } 
    10841113    else if (safe_common_liberty_found 
    10851114             && common_liberty.pos != NO_MOVE) { 
    10861115      move_value = semeai_move_value(common_liberty.pos, 
    do_owl_analyze_semeai(int apos, int bpos, 
    12321261      include_semeai_worms_in_eyespace = 1; 
    12331262      if (!owl_estimate_life(owla, owlb, vital_defensive_moves, 
    12341263                             &live_reasona, 0, &dummy_eyes, 
    1235                              &eyemin_a, &eyemax_a) 
     1264                             &eyemin_a, &eyemax_a, NULL) 
    12361265          && eyemax_a < 2) { 
    12371266        include_semeai_worms_in_eyespace = 0; 
    12381267        *resulta = 0; 
    do_owl_analyze_semeai(int apos, int bpos, 
    13191348  if (!pass && k == 1) { 
    13201349    if ((best_resulta == WIN && best_resultb == 0 
    13211350         && best_move != NO_MOVE 
    1322          && best_move == common_liberty.pos 
     1351         && (best_move == common_liberty.pos || best_move == eyefilling_liberty.pos) 
    13231352         && stackp == 0) 
    13241353        || (best_resulta == KO_B && best_resultb == KO_B 
    13251354            && is_ko(best_move, owla->color, NULL))) { 
    do_owl_attack(int str, int *move, int *wormid, 
    20962125 
    20972126  /* First see whether there is any chance to kill. */ 
    20982127  if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 1, 
    2099                         &probable_eyes, &eyemin, &eyemax)) { 
     2128                        &probable_eyes, &eyemin, &eyemax, NULL)) { 
    21002129    /* 
    21012130     * We need to check here if there's a worm under atari. If yes, 
    21022131     * locate it and report a (gote) GAIN. 
    do_owl_defend(int str, int *move, int *wormid, struct local_owl_data *owl, 
    27632792  /* First see whether we might already be alive. */ 
    27642793  if (escape < MAX_ESCAPE) { 
    27652794    if (owl_estimate_life(owl, NULL, vital_moves, &live_reason, 0, 
    2766                           &probable_eyes, &eyemin, &eyemax)) { 
     2795                          &probable_eyes, &eyemin, &eyemax, NULL)) { 
    27672796      SGFTRACE(0, WIN, live_reason); 
    27682797      TRACE("%oVariation %d: ALIVE (%s)\n", 
    27692798            this_variation_number, live_reason); 
    owl_threaten_defense(int target, int *defend1, int *defend2) 
    30893118/* 
    30903119 * This function calls owl_determine_life() to get an eye estimate, 
    30913120 * and matchpat() for vital attack moves, and decides according to 
    3092  * various policies (depth-dependant) whether the dragon should thus 
     3121 * various policies (depth-dependent) whether the dragon should thus 
    30933122 * be considered alive. 
    30943123 */ 
    30953124static int 
    owl_estimate_life(struct local_owl_data *owl, 
    30973126                  struct local_owl_data *second_owl, 
    30983127                  struct owl_move_data vital_moves[MAX_MOVES], 
    30993128                  const char **live_reason, int does_attack, 
    3100                   struct eyevalue *probable_eyes, int *eyemin, int *eyemax) 
     3129                  struct eyevalue *probable_eyes, int *eyemin, int *eyemax, 
     3130                  int eyefilling_points[BOARDMAX]) 
    31013131{ 
    31023132  SGFTree *save_sgf_dumptree = sgf_dumptree; 
    31033133  int save_count_variations = count_variations; 
    owl_estimate_life(struct local_owl_data *owl, 
    31083138  count_variations = 0; 
    31093139 
    31103140  owl_determine_life(owl, second_owl, does_attack, vital_moves, 
    3111                      probable_eyes, eyemin, eyemax); 
     3141                     probable_eyes, eyemin, eyemax, eyefilling_points); 
    31123142 
    31133143  matches_found = 0; 
    31143144  memset(found_matches, 0, sizeof(found_matches)); 
    owl_estimate_life(struct local_owl_data *owl, 
    32043234 * 
    32053235 * For use in the semeai code, a second dragon can be provided. Set 
    32063236 * this to NULL when only one dragon is involved. 
     3237 * 
     3238 * For use from the semeai code it is also possible to find eyefilling 
     3239 * points, which adds stones to nakade shapes. Set eyefilling_points 
     3240 * to NULL if this information is not of interest. 
    32073241 */ 
    32083242 
    32093243static void 
    owl_determine_life(struct local_owl_data *owl, 
    32113245                   struct local_owl_data *second_owl, 
    32123246                   int does_attack, 
    32133247                   struct owl_move_data *moves, 
    3214                    struct eyevalue *probable_eyes, int *eyemin, int *eyemax) 
     3248                   struct eyevalue *probable_eyes, int *eyemin, int *eyemax, 
     3249                   int eyefilling_points[BOARDMAX]) 
    32153250{ 
    32163251  int color = owl->color; 
    32173252  struct eye_data *eye = owl->my_eye; 
    owl_determine_life(struct local_owl_data *owl, 
    32903325      const char *reason = ""; 
    32913326      compute_eyes_pessimistic(pos, &eyevalue, &pessimistic_min, 
    32923327                               &attack_point, &defense_point, 
    3293                                eye, owl->half_eye); 
     3328                               eye, owl->half_eye, eyefilling_points); 
    32943329 
    32953330      /* If the eyespace is more in contact with own stones not in the goal, 
    32963331       * than with ones in the goal, there is a risk that we can be cut off