[iagno] Introduce mainlines.



commit 28c533a86f861f87733bc7212960894b28ac4ae8
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Wed Aug 14 23:33:12 2019 +0200

    Introduce mainlines.
    
    Since last patch the
    hard AI is sometimes
    making hard mistakes
    by easily offering a
    corner. Fix that, by
    introducing a simple
    "penalty" mechanism.

 src/computer-reversi.vala | 75 +++++++++++++++++++++++++++++++++++++++++++++--
 src/game.vala             | 30 +++++++++++++++++++
 src/iagno.vala            |  2 +-
 3 files changed, 103 insertions(+), 4 deletions(-)
---
diff --git a/src/computer-reversi.vala b/src/computer-reversi.vala
index 5021a1b..cce25d4 100644
--- a/src/computer-reversi.vala
+++ b/src/computer-reversi.vala
@@ -124,7 +124,7 @@ private class ComputerReversiHard : ComputerReversi
         calculate_dir_heuristic (ref comparator, move.x, move.y, -1,  1, move.n_tiles_so);
         calculate_dir_heuristic (ref comparator, move.x, move.y, -1,  0, move.n_tiles_o );
         calculate_dir_heuristic (ref comparator, move.x, move.y, -1, -1, move.n_tiles_no);
-        if (medium_ai)  /* we artificially decrease the medium difficulty level 1/3 */
+        if (medium_ai)  /* we artificially decrease the medium difficulty level 1/4 */
             return comparator + (int) heuristic [move.x, move.y] - 8 * (int) neighbor_tiles [move.x, move.y];
         else
             return 2 * comparator + (int) heuristic [move.x, move.y] - 8 * (int) neighbor_tiles [move.x, 
move.y];
@@ -163,7 +163,7 @@ private class ComputerReversiHard : ComputerReversi
                 {
                     if (even_depth)
                         count -= tile_heuristic / 2;
-                    else if (!medium_ai)    /* we artificially decrease the medium difficulty level 2/3 */
+                    else if (!medium_ai)    /* we artificially decrease the medium difficulty level 2/4 */
                         count += tile_heuristic / 2;
                 }
                 else if (g.is_current_color (x, y))
@@ -172,9 +172,78 @@ private class ComputerReversiHard : ComputerReversi
                     count -= tile_heuristic;
             }
 
+        if (medium_ai)
+            return count;   /* we artificially decrease the medium difficulty level 3/4 */
+
+        mainline_penalty (g, border_penalty, ref count, MainLine.TOP);
+        mainline_penalty (g, border_penalty, ref count, MainLine.LEFT);
+        mainline_penalty (g, border_penalty, ref count, MainLine.RIGHT);
+        mainline_penalty (g, border_penalty, ref count, MainLine.BOTTOM);
+        mainline_penalty (g, corner_penalty, ref count, MainLine.TOPLEFT);
+        mainline_penalty (g, corner_penalty, ref count, MainLine.TOPRIGHT);
+
         return count;
     }
 
+    private const int16 border_penalty = 22;
+    private const int16 corner_penalty = 23;
+    private static void mainline_penalty (GameStateStruct g, int16 penalty, ref int16 count, MainLine 
mainline_id)
+    {
+        Player [] mainline = g.get_mainline (mainline_id);
+        if (mainline [1] == g.current_color
+         && mainline [0] == Player.NONE)
+        {
+            uint8 i = 1;
+            do { i++; if (i == g.size - 2) break; }
+            while (mainline [i] == g.current_color);
+            if (i != g.size - 2)
+            {
+                count -= penalty;
+                if (mainline [i + 1] == g.current_color)
+                    count -= penalty;
+            }
+        }
+        else if (mainline [1] == g.opponent_color
+              && mainline [0] == Player.NONE)
+        {
+            uint8 i = 1;
+            do { i++; if (i == g.size - 2) break; }
+            while (mainline [i] == g.opponent_color);
+            if (i != g.size - 2)
+            {
+                count += penalty;
+                if (mainline [i + 1] == g.opponent_color)
+                    count += penalty;
+            }
+        }
+        if (mainline [g.size - 2] == g.current_color
+         && mainline [g.size - 1] == Player.NONE)
+        {
+            uint8 i = 1;
+            do { i++; if (i == g.size - 2) break; }
+            while (mainline [g.size - 1 - i] == g.current_color);
+            if (i != g.size - 2)
+            {
+                count -= penalty;
+                if (mainline [g.size - 2 - i] == g.current_color)
+                    count -= penalty;
+            }
+        }
+        else if (mainline [g.size - 2] == g.opponent_color
+              && mainline [g.size - 1] == Player.NONE)
+        {
+            uint8 i = 1;
+            do { i++; if (i == g.size - 2) break; }
+            while (mainline [g.size - 1 - i] == g.opponent_color);
+            if (i != g.size - 2)
+            {
+                count += penalty;
+                if (mainline [g.size - 2 - i] == g.opponent_color)
+                    count += penalty;
+            }
+        }
+    }
+
     /*\
     * * heuristic table
     \*/
@@ -201,7 +270,7 @@ private class ComputerReversiHard : ComputerReversi
         else
             create_heuristic (size, out heuristic);
 
-        if (medium_ai)  /* we artificially decrease the medium difficulty level 3/3 */
+        if (medium_ai)  /* we artificially decrease the medium difficulty level 4/4 */
             return;
 
         /* that part is fun */
diff --git a/src/game.vala b/src/game.vala
index 11d8b21..deaffbc 100644
--- a/src/game.vala
+++ b/src/game.vala
@@ -20,6 +20,16 @@
    along with GNOME Reversi.  If not, see <https://www.gnu.org/licenses/>.
 */
 
+private enum MainLine
+{
+    TOP,
+    LEFT,
+    RIGHT,
+    BOTTOM,
+    TOPLEFT,
+    TOPRIGHT;
+}
+
 private struct GameStateStruct
 {
     public Player   current_color;
@@ -427,6 +437,26 @@ private struct GameStateStruct
             if (ypp_is_valid) empty_neighbors [xpp, ypp] -= 1;
         }
     }
+
+    /*\
+    * * mainlines
+    \*/
+
+    internal Player [] get_mainline (MainLine mainline_id)  // keeping an updated copy of each mainline is a 
bit slower
+    {
+        Player [] mainline = new Player [size];
+        switch (mainline_id)
+        {
+            case MainLine.TOP:      for (uint8 i = 0; i < size; i++) mainline [i] = tiles [i, 0];            
break;
+            case MainLine.LEFT:     for (uint8 i = 0; i < size; i++) mainline [i] = tiles [0, i];            
break;
+            case MainLine.RIGHT:    for (uint8 i = 0; i < size; i++) mainline [i] = tiles [size - 1, i];     
break;
+            case MainLine.BOTTOM:   for (uint8 i = 0; i < size; i++) mainline [i] = tiles [i, size - 1];     
break;
+            case MainLine.TOPLEFT:  for (uint8 i = 0; i < size; i++) mainline [i] = tiles [i, i];            
break;
+            case MainLine.TOPRIGHT: for (uint8 i = 0; i < size; i++) mainline [i] = tiles [size - 1 - i, i]; 
break;
+            default: assert_not_reached ();
+        }
+        return mainline;
+    }
 }
 
 private class GameStateObject : Object
diff --git a/src/iagno.vala b/src/iagno.vala
index 6502301..120e59f 100644
--- a/src/iagno.vala
+++ b/src/iagno.vala
@@ -449,7 +449,7 @@ private class Iagno : Gtk.Application, BaseApplication
             {
                 case 1 : computer = new ComputerReversiEasy (game);                break;
                 case 2 : computer = new ComputerReversiHard (game, /* depth */ 1); break;
-                case 3 : computer = new ComputerReversiHard (game, /* depth */ 2); break; /* FIXME AI makes 
mistakes like #LLL#LL# on a border */
+                case 3 : computer = new ComputerReversiHard (game, /* depth */ 2); break;
                 default: assert_not_reached ();
             }
         }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]