[gnome-games/glchess-fics] Start work on a FICS interface for chess



commit dee691d7f9b0ad381fc52cca79c4c224a6bc9b83
Author: Robert Ancell <robert ancell canonical com>
Date:   Sat Feb 19 15:03:50 2011 +1100

    Start work on a FICS interface for chess

 glchess/src/Makefile.am      |    1 +
 glchess/src/fics-client.vala |  507 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 508 insertions(+), 0 deletions(-)
---
diff --git a/glchess/src/Makefile.am b/glchess/src/Makefile.am
index 2fb8831..4cdee33 100644
--- a/glchess/src/Makefile.am
+++ b/glchess/src/Makefile.am
@@ -21,6 +21,7 @@ glchess_SOURCES = \
 	chess-view-2d.vala \
 	chess-view-3d.vala \
 	chess-view-options.vala \
+	fics-client.vala \
 	history.vala
 
 test_chess_game_SOURCES = \
diff --git a/glchess/src/fics-client.vala b/glchess/src/fics-client.vala
new file mode 100644
index 0000000..9795cc2
--- /dev/null
+++ b/glchess/src/fics-client.vala
@@ -0,0 +1,507 @@
+public class FICSClient
+{
+    private Socket socket;
+
+    //private string buffer = "";
+    //longChat = None
+
+    /* Yuck, regular expression is just horrible. I plan to replace this with something readable
+     * (that compiles to regexp if regexp is faster) */
+    private Regex name_assign_pattern;
+    private Regex chat_pattern;
+    private Regex tell_pattern;
+    private Regex say_pattern;
+    private Regex challenge_pattern;
+    private Regex seek_pattern;
+    private Regex end_seek_pattern;
+    private Regex announce_pattern;
+    private Regex game_result_pattern;
+    private Regex example_game_pattern;
+    private Regex game_pattern;
+
+    public FICSClient()
+    {
+        /* Press return to enter the server as "GuestVRDG": */
+        name_assign_pattern = make_regex ("Press return to enter the server as \"(\\S+)\":");
+
+        /* jibbjibb(U)(53): i like cheese */
+        chat_pattern = make_regex ("^(\\S+)[(](\\d+)[)]: (.*)$");
+        /* GuestTLNX(U) tells you: hello! */
+        tell_pattern = make_regex ("^(\\S+)[(](\\S+)[)] tells you: (.*)$");
+        /* GuestTLNX(U)[26] says: hello */
+        say_pattern = make_regex ("^(\\S+)[(](\\S+)[)][[](\\d+)[]] says: (.*)$");
+
+        /* Challenge: GuestKWWN (----) GuestDRJK (----) unrated blitz 2 12. */
+        challenge_pattern = make_regex ("Challenge: (\\S+) [(](\\S{4})[)] \\S+ [(]\\S{4}[)] (\\w+) (\\w+) (\\d+) (\\d+)[.]$");
+
+        /* 19  716 milkhope            5  14 unrated blitz                  0-9999 mf */
+        /* 41 1812 CrazyBeukiBot(C)    2  12 unrated blitz                  0-9999 */
+        /* 50 1190 rauschdesign       10   0 unrated blitz      [white]     0-9999 f */
+        /* 70 1157 stshot             12   1 unrated blitz                  0-1300 */
+        seek_pattern = make_regex ("^\\s*(\\d+)\\s+(\\S{4}) (\\S+)\\s+(\\d+)\\s+(\\d+) (\\S+) (\\S+)\\s+(\\S*)\\s+(\\d+)-\\s*(\\d+)\\s*(\\S*)$");
+
+        /* 1 ad displayed. */
+        /* 9 ads displayed. */
+        end_seek_pattern = make_regex ("^(\\d+) ads? displayed.$");
+
+        /* GuestJXJT (++++) seeking 0 1 unrated lightning ("play 15" to respond) */
+        announce_pattern = make_regex ("^(\\S+) [(](\\S{4})[)] seeking (\\d+) (\\d+) (\\w+) (\\w+)(.*) [(]\"play (\\d+)\" to respond[)]$");
+
+        /* {Game 109 (GuestKSBS vs. GuestXKQX) Creating unrated blitz match.} */
+        /* {Game 109 (GuestKSBS vs. GuestXKQX) GuestXKQX forfeits by disconnection} 1-0 */
+        /* {Game 109 (GuestXKQX vs. GuestKSBS) GuestKSBS resigns} 1-0 */
+        game_result_pattern = make_regex ("^{Game (\\d+) [(](\\S+) vs. (\\S+)[)] (.+)}\\s*(.*)$");
+
+        /* 1 (Exam.    0 Kupreichik     0 talpa     ) [ uu  0   0] W: 22 */
+        /* 2 2274 OldManII    ++++ Peshkin    [ bu  2  12]   2:34 -  1:47 (39-39) B:  3 */
+        example_game_pattern = make_regex ("\\s*(\\d+) [(]Exam[.] (\\S{4}) (\\S+)\\s+(\\S{4}) (\\S+)\\s+ [)] [[]\\s*(\\S+)\\s+(\\d+)\\s+(\\d+)[]] ([WB]):\\s+(\\d+)$");
+        game_pattern = make_regex ("\\s*(\\d+) (\\S{4}) (\\S+)\\s+(\\S{4}) (\\S+)\\s+[[]\\s*(\\S+)\\s+(\\d+)\\s+(\\d+)[]]\\s+(\\d+):(\\d+) -\\s+(\\d+):(\\d+) [(](\\d+)-(\\d+)[)] ([WB]):\\s+(\\d+)$");
+
+        /* TODO: */
+        /* GuestDRJK, whom you were challenging, has departed. */
+        /* Challenge to GuestDRJK withdrawn. */
+    }
+    
+    private Regex? make_regex (string pattern)
+    {
+        try
+        {
+            return new Regex (pattern);
+        }
+        catch (RegexError e)
+        {
+            critical ("Failed to make regular expression: %s", e.message);
+            return null;
+        }
+    }
+
+    public void connect (string host = "freechess.org", uint16 port = 5000) throws Error
+    {
+        socket = new Socket (SocketFamily.IPV4, SocketType.STREAM, SocketProtocol.TCP);
+        socket.connect (new InetSocketAddress (new InetAddress.from_string (host), port));
+        var channel = new IOChannel.unix_new (socket.fd);
+        channel.add_watch (IOCondition.IN, read_cb);
+    }
+    
+    private bool read_cb (IOChannel source, IOCondition condition)
+    {
+        char data[1024];
+
+        ssize_t n_read;
+        try
+        {
+            n_read = socket.receive ((string) data, data.length);
+        }
+        catch (Error e)
+        {
+            warning ("Error reading from FICS server: %s", e.message);
+            return false;
+        }
+
+        debug ("read %zi", n_read);
+
+#if 0
+        buffer += data;
+
+        callbacks = [];
+        while (true)
+        {
+            index = buffer.find("\n\r");
+            if (index < 0)
+                break;
+
+            line = buffer[:index];
+            buffer = buffer[index+2:];
+
+            /* Strip pesky prompt off the front */
+            if (line.has_prefix (PROMPT))
+            {
+                line = line[len(PROMPT):];
+                callbacks.append((onPrompt, ()));
+                if (len(line) == 0)
+                    continue;
+            }
+
+            (callback, data) = parseLine(line);
+            if (callback is not None)
+                callbacks.append((callback, data));
+        }
+
+        (callback, data) = parsePrompt(buffer);
+        if (callback is not None)
+            callbacks.append((callback, data));
+
+        for ((callback, data) in callbacks)
+            callback(*data);
+#endif
+
+        return false;
+    }
+
+    private bool parse_line (string line)
+    {
+#if 0
+        /* Join continuing chat messages */
+        if (longChat != None)
+        {
+            /* Remove leading space ("\   text") */
+            while (line.has_prefix ("\\"))
+                line = line[1:];
+            while (line.has_prefix (" "))
+                line = line[1:];
+            longChat += line;
+
+            /* Continues on the next line too */
+            if (line[-1] == " ")
+                return (None, None);
+
+            text = longChat;
+            longChat = None;
+            return (onChat, (longChatOptions[0], longChatOptions[1], text));
+        }
+#endif
+
+        if (parse_line_game (line) ||
+            parse_line_example_game (line) ||
+            parse_line_name_assign (line) ||
+            parse_line_seek (line) ||
+            parse_line_end_seek (line) ||
+            parse_line_announce (line) ||
+            parse_line_challenge (line) ||
+            parse_line_game_result (line) ||
+            parse_line_chat (line) ||
+            parse_line_tell (line) ||
+            parse_line_say (line) ||
+            parse_line_game_move (line) ||
+            parse_line_seek_add (line) ||
+            parse_line_seek_remove (line) ||
+            parse_line_seek_clear (line) ||
+            parse_prompt (line))
+            return true;
+
+        return false;
+    }
+
+    private bool parse_line_game (string line)
+    {
+        MatchInfo info;
+        if (!game_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        /* Game in progress */
+        white = Player();
+        black = Player();
+        game = Game();
+        (game.number, white.rating, white.name, black.rating, black.name,
+         game.options, game.a, game.b, whiteMin, whiteSec,
+         blackMin, blackSec,
+         white.strength, black.strength,
+         game.colour, game.moveNumber) = result[0];
+        game.isExample = False;
+        white.time = int(whiteMin) * 60 + int(whiteSec);
+        black.time = int(blackMin) * 60 + int(blackSec);
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_example_game (string line)
+    {
+        MatchInfo info;
+        if (!example_game_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        white = Player();
+                    black = Player();
+                    game = Game();
+                    (game.number, white.rating, white.name, black.rating, black.name,
+                     game.options, game.a, game.b,
+                     game.colour, game.moveNumber) = result[0];
+                    game.isExample = True;
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_name_assign (string line)
+    {
+        MatchInfo info;
+        if (!name_assign_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        name = result;
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_seek (string line)
+    {
+        MatchInfo info;
+        if (!seek_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        /* Requested seek */
+        player = Player();
+        game = Game();
+        (number,
+        player.rating, player.name,
+        game.a, game.b, game.rating, game.type, game.colour, game.minRating, game.maxRating, game.options) = result[0];
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_end_seek (string line)
+    {
+        MatchInfo info;
+        if (!end_seek_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        //(nSeeks, ) = result;
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_announce (string line)
+    {
+        MatchInfo info;
+        if (!announce_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        /* Dynamic seek */
+        player = Player();
+        game = Game();
+        //(player.name, player.rating, game.a, game.b, game.rating, game.type, game.options, number) = result[0];
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_challenge (string line)
+    {
+        MatchInfo info;
+        if (!challenge_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        /* Explicit challenge */
+        player = Player();
+        game = Game();
+        //(player.name, player.rating, game.rating, game.type, game.a, game.b) = result[0];
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_game_result (string line)
+    {
+        MatchInfo info;
+        if (!game_result_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        /* Game result */
+        white = Player();
+        black = Player();
+        game = Game();
+        //(game.number, white.name, black.name, text, game.result) = result[0];
+        if (game.result == "")
+            game.result = "*";
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_chat (string line)
+    {
+        MatchInfo info;
+        if (!chat_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        //(playerName, channel, text) = result[0];
+        if (text[-1] == " ")
+        {
+            longChat = text;
+            longChatOptions = (channel, playerName);
+        }
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_tell (string line)
+    {
+        MatchInfo info;
+        if (!tell_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        //(playerName, rating, text) = result[0];
+        if (text[-1] == " ")
+        {
+            longChat = text;
+            longChatOptions = ("", playerName);
+        }
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_say (string line)
+    {
+        MatchInfo info;
+        if (!say_pattern.match_all (line, 0, out info))
+            return false;
+
+#if 0
+        //(playerName, rating, game, text) = result[0];
+        if (text[-1] == " ")
+        {
+            longChat = text;
+            longChatOptions = ("", playerName);
+        }
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_game_move (string line)
+    {
+        /* Game move */
+        if (!line.has_prefix ("<12> "))
+            return false;
+
+#if 0
+        try
+        {
+            move = style12.decode(line);
+        }
+        catch (Error e)
+        {
+            debug ("Invalid move: %s (%s)", line, e.message);
+            return false;
+        }
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_seek_add (string line)
+    {
+        if (!line.has_prefix ("<s> "))
+            return false;
+
+#if 0
+        var words = line.split();
+        //player = Player();
+        //game = Game();
+        try
+        {
+            number = int(words[1]);
+        }
+        catch (Error e)
+        {
+            return false;
+        }
+
+        foreach (var word in words[2:])
+        {
+            try
+            {
+                (name, value) = word.split("=", 1);
+            }
+            catch (Error e)
+            {
+                return false;
+            }
+
+            /* FIXME: Accept errors */
+            if (name == "w")
+                player.name = value;
+            else if (name == "ti")
+                ;
+            else if (name == "rt")
+            {
+                while (!value[-1].isdigit())
+                    value = value[:-1];
+                player.rating = int(value);
+            }
+            else if (name == "t")
+                game.time = int(value);
+            else if (name == "i")
+                game.inc = int(value);
+            else if (name == "r")
+                game.isRated = value != "0";
+            else if (name == "tp")
+                game.type = value;
+            else if (name == "c")
+                game.colour = value;
+            else if (name == "rr")
+            {
+                (minRating, maxRating) = value.split("-", 1);
+                game.minRating = int(minRating);
+                game.maxRating = int(maxRating);
+            }
+            else if (name == "a")
+                game.isAutomatic = value != "0";
+            else if (name == "f")
+                game.formulaCheked = value != "0";
+        }
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_seek_remove (string line)
+    {
+        if (!line.has_prefix ("<sr> "))
+            return false;
+
+#if 0
+        adverts = [];
+        foreach (var word in line.split()[1:])
+        {
+            try
+            {
+                adverts.append(int(word));
+            }
+            catch (Error e)
+            {
+                return false;
+            }
+        }
+#endif
+
+        return true;
+    }
+
+    private bool parse_line_seek_clear (string line)
+    {
+        if (!line.has_prefix ("<sc>"))
+            return false;
+
+        return true;
+    }
+
+    private bool parse_prompt (string line)
+    {
+        const string PROMPT = "fics% ";
+        const string PROMPT_LOGIN = "login: ";
+
+        if (line == PROMPT_LOGIN)
+            return true;
+        else if (line == PROMPT)
+            return true;
+
+        return false;
+    }
+}



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