[gnome-games] Fix up SAN and FAN notation



commit fe3a6de19def03383deee68d5f2a5acbac5f093a
Author: Robert Ancell <robert ancell canonical com>
Date:   Tue Jan 18 10:14:59 2011 +1100

    Fix up SAN and FAN notation

 glchess/src/chess-engine-cecp.vala |    2 +-
 glchess/src/chess-engine-uci.vala  |    2 +-
 glchess/src/chess-game.vala        |  138 +++++++++++++++++++++++++++++------
 glchess/src/glchess.vala           |    8 +-
 4 files changed, 120 insertions(+), 30 deletions(-)
---
diff --git a/glchess/src/chess-engine-cecp.vala b/glchess/src/chess-engine-cecp.vala
index 15d30e3..c0b561c 100644
--- a/glchess/src/chess-engine-cecp.vala
+++ b/glchess/src/chess-engine-cecp.vala
@@ -82,7 +82,7 @@ public class ChessEngineCECP : ChessEngine
         {
             /* Stop the AI from automatically moving in response to this one */
             write_line ("force");
-            write_line (move.lan);
+            write_line (move.engine);
         }
         moving = false;
     }
diff --git a/glchess/src/chess-engine-uci.vala b/glchess/src/chess-engine-uci.vala
index ebadcc2..93f10d5 100644
--- a/glchess/src/chess-engine-uci.vala
+++ b/glchess/src/chess-engine-uci.vala
@@ -31,7 +31,7 @@ public class ChessEngineUCI : ChessEngine
     {
         if (position_command == "position startpos")
             position_command += " moves";
-        position_command += " " + move.lan;
+        position_command += " " + move.engine;
         write_line (position_command);
     }
 
diff --git a/glchess/src/chess-game.vala b/glchess/src/chess-game.vala
index 47d5dde..81a0536 100644
--- a/glchess/src/chess-game.vala
+++ b/glchess/src/chess-game.vala
@@ -101,24 +101,79 @@ public class ChessMove
 {
     public int number;
     public ChessPiece piece;
+    public ChessPiece? promotion_piece;
     public ChessPiece? moved_rook;
     public ChessPiece? victim;
     public int r0;
     public int f0;
     public int r1;
     public int f1;
-    public string lan = "";
-    public string san = "";
-    public string human = "";
-    
-    public string fan
+    public bool ambiguous_rank;
+    public bool ambiguous_file;
+
+    public string get_lan ()
+    {
+        const char promotion_symbols[] = {' ', 'R', 'N', 'B', 'Q', 'K'};
+        if (promotion_piece != null)
+        {
+            if (victim != null)
+                return "%c%dx%c%d=%c".printf ('a' + f0, r0 + 1, 'a' + f1, r1 + 1, promotion_symbols[promotion_piece.type]);
+            else
+                return "%c%d-%c%d=%c".printf ('a' + f0, r0 + 1, 'a' + f1, r1 + 1, promotion_symbols[promotion_piece.type]);
+        }
+        else
+        {
+            if (victim != null)
+                return "%c%dx%c%d".printf ('a' + f0, r0 + 1, 'a' + f1, r1 + 1);
+            else
+                return "%c%d-%c%d".printf ('a' + f0, r0 + 1, 'a' + f1, r1 + 1);
+        }
+    }
+
+    public string get_san ()
+    {
+        const string piece_names[] = {"", "R", "N", "B", "Q", "K"};
+        return make_san ((string[]) piece_names);
+    }
+
+    public string get_fan ()
+    {
+        const string white_piece_names[] = {"", "â??", "â??", "â??", "â??", "â??"};
+        const string black_piece_names[] = {"", "â??", "â??", "â??", "â??", "â??"};
+        if (piece.player.color == Color.WHITE)
+            return make_san ((string[]) white_piece_names);
+        else
+            return make_san ((string[]) black_piece_names);
+    }
+
+    private string make_san (string[] piece_names)
+    {
+        var builder = new StringBuilder ();
+        builder.append (piece_names[piece.type]);
+        if (ambiguous_file)
+            builder.append_printf ("%c", 'a' + f0);
+        if (ambiguous_rank)
+            builder.append_printf ("%d", r0 + 1);
+        if (victim != null)
+            builder.append ("x");
+        builder.append_printf ("%c%d", 'a' + f1, r1 + 1);
+        if (promotion_piece != null)
+            builder.append_printf ("=%s", piece_names[promotion_piece.type]);
+        return builder.str;
+    }
+
+    /* Move suitable for a chess engine (CECP/UCI) */
+    public string engine
     {
         get
         {
-            // FIXME: Translate the san move
-            //â??â??â??â??â??â??
-            //â??â??â??â??â??â??
-            return san;
+            var builder = new StringBuilder ();
+            const char promotion_symbols[] = {' ', 'r', 'n', 'b', 'q', ' '};
+            if (promotion_piece != null)
+                builder.append_printf ("%c%d%c%d%c", 'a' + f0, r0 + 1, 'a' + f1, r1 + 1, promotion_symbols[promotion_piece.type]);
+            else
+                builder.append_printf ("%c%d%c%d", 'a' + f0, r0 + 1, 'a' + f1, r1 + 1);
+            return builder.str;
         }
     }
 
@@ -127,15 +182,15 @@ public class ChessMove
         var move = new ChessMove ();
         move.number = number;
         move.piece = piece;
+        move.promotion_piece = promotion_piece;
         move.moved_rook = moved_rook;
         move.victim = victim;
         move.r0 = r0;
         move.f0 = f0;
         move.r1 = r1;
         move.f1 = f1;
-        move.lan = lan;        
-        move.san = san;
-        move.human = human;
+        move.ambiguous_rank = ambiguous_rank;
+        move.ambiguous_file = ambiguous_file;
         return move;
     }
 }
@@ -284,7 +339,7 @@ public class ChessState
             int skip_count = 0;
             for (int file = 0; file < 8; file++)
             {
-                ChessPiece? p = board[get_index (rank, file)];
+                var p = board[get_index (rank, file)];
                 if (p == null)
                     skip_count++;
                 else
@@ -372,14 +427,14 @@ public class ChessState
     public bool move_with_coords (ChessPlayer player, int r0, int f0, int r1, int f1, PieceType promotion_type = PieceType.QUEEN, bool apply = true, bool test_check = true)
     {
         // FIXME: Make this use indexes to be faster
-        int start = get_index (r0, f0);
-        int end = get_index (r1, f1);
+        var start = get_index (r0, f0);
+        var end = get_index (r1, f1);
 
         var color = player.color;
         var opponent_color = color == Color.WHITE ? Color.BLACK : Color.WHITE;
 
         /* Must be moving own piece */
-        ChessPiece? piece = board[start];
+        var piece = board[start];
         if (piece == null || piece.player != player)
             return false;
 
@@ -395,8 +450,8 @@ public class ChessState
             return false;
 
         /* Get victim of move */
-        ChessPiece? victim = board[end];
-        int victim_index = end;
+        var victim = board[end];
+        var victim_index = end;
 
         /* Can't take own pieces */
         if (victim != null && victim.player == player)
@@ -411,6 +466,9 @@ public class ChessState
 
         /* Check special moves */
         int rook_start = -1, rook_end = -1;
+        bool is_promotion = false;
+        bool ambiguous_rank = false;
+        bool ambiguous_file = false;
         switch (piece.type)
         {
         case PieceType.PAWN:
@@ -426,6 +484,11 @@ public class ChessState
                 if (victim != null)
                     return false;
             }
+            is_promotion = r1 == 0 || r1 == 7;
+            
+            /* Always show the file of a pawn capturing */
+            if (victim != null)
+                ambiguous_file = true;
             break;
         case PieceType.KING:
             /* If moving more than one square must be castling */
@@ -447,7 +510,7 @@ public class ChessState
                         return false;                
                 }
 
-                ChessPiece? rook = board[rook_start];
+                var rook = board[rook_start];
                 if (rook == null)
                     return false;
 
@@ -475,6 +538,33 @@ public class ChessState
         if (!apply && !test_check)
             return true;
 
+        /* Check if other pieces of the same type can make this move - this is required for SAN notation */
+        if (apply)
+        {
+            for (int i = 0; i < 64; i++)
+            {
+                /* Ignore our move */
+                if (i == start)
+                    continue;
+
+                /* Check for a friendly piece of the same type */
+                var p = board[i];
+                if (p == null || p.player != player || p.type != piece.type)
+                    continue;
+
+                /* If more than one piece can move then the rank and/or file are ambiguous */
+                var r = get_rank (i);
+                var f = get_file (i);
+                if (move_with_coords (player, r, f, r1, f1, PieceType.QUEEN, false))
+                {
+                    if (r != r0)
+                        ambiguous_rank = true;
+                    if (f != f0)
+                        ambiguous_file = true;
+                }
+            }
+        }
+
         var old_white_mask = piece_masks[Color.WHITE];
         var old_black_mask = piece_masks[Color.BLACK];
         var old_white_can_castle_kingside = can_castle_kingside[Color.WHITE];
@@ -488,7 +578,7 @@ public class ChessState
         board[start] = null;
         if (victim != null)
             board[victim_index] = null;
-        if (piece.type == PieceType.PAWN && (r1 == 0 || r1 == 7))
+        if (is_promotion)
             board[end] = new ChessPiece (player, promotion_type);
         else
             board[end] = piece;
@@ -570,6 +660,8 @@ public class ChessState
         last_move = new ChessMove ();
         last_move.number = number;
         last_move.piece = piece;
+        if (is_promotion)
+            last_move.promotion_piece = board[end];
         last_move.victim = victim;
         if (rook_end >= 0)
             last_move.moved_rook = board[rook_end];
@@ -577,10 +669,8 @@ public class ChessState
         last_move.f0 = f0;
         last_move.r1 = r1;
         last_move.f1 = f1;
-        // FIXME: Promotion
-        last_move.lan = "%c%d%c%d".printf ('a' + f0, r0 + 1, 'a' + f1, r1 + 1);
-        // FIXME: Generate SAN move
-        last_move.san = last_move.lan;
+        last_move.ambiguous_rank = ambiguous_rank;
+        last_move.ambiguous_file = ambiguous_file;
 
         return true;
     }
diff --git a/glchess/src/glchess.vala b/glchess/src/glchess.vala
index 8f8e6c2..a436213 100644
--- a/glchess/src/glchess.vala
+++ b/glchess/src/glchess.vala
@@ -497,16 +497,16 @@ public class Application
             break;
 
         case "san":
-            move_text = move.san;
+            move_text = move.get_san ();
             break;
 
         case "fan":
-            move_text = move.fan;
+            move_text = move.get_fan ();
             break;
 
         default:
         case "lan":
-            move_text = move.lan;
+            move_text = move.get_lan ();
             break;
         }
 
@@ -518,7 +518,7 @@ public class Application
     private void game_move_cb (ChessGame game, ChessMove move)
     {
         if (move.number > pgn_game.moves.length ())
-            pgn_game.moves.append (move.san);
+            pgn_game.moves.append (move.get_san ());
 
         Gtk.TreeIter iter;
         var model = (Gtk.ListStore) history_combo.model;



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