Hi!

Here's a first shot at letting a gtp client decide on which groups are
dead before letting the user score. 

Open issues:
 - No visual feed-back to the user that the engine is scoring. Opening a
small dialog box would be nice, as it may take some seconds.
 - If Quarry is used to have two gtp clients play against each other,
only black is asked to score.
 - The score the gtp client calculates should be queried and compared to
what Quarry determines. Yell if they disagree.
 - Seki?

The missing feed-back while scoring might be a show-stopper, but before
starting on that, I wanted to ask if the approach in general is ok.


        * src/utils/string-list.c, src/utils/utils.h (string_list_count): 
        New function.

        * src/gtp/gtp-client.c (gtp_client_final_status_list)
        (parse_final_status_list): New functions.
        * src/gtp/gtp-client.h (GtpStoneStatus)
        (GtpClientFinalStatusListCallback): New types.
        * src/gtp/gtp-client.h (parse_final_status_list): New prototype.
        * src/gui-gtk/gtk-goban-window.c (engine_has_scored)
        (enter_scoring_mode): New functions.
        * src/gui-gtk/gtk-goban-window.c (move_has_been_played): Invoke
        gtp_client_final_status_list of first gtp client player (if there is
        one) before user may score.
        

Index: src/gtp/gtp-client.c
===================================================================
RCS file: /cvs/quarry/quarry/src/gtp/gtp-client.c,v
retrieving revision 1.5
diff -u -r1.5 gtp-client.c
--- src/gtp/gtp-client.c        19 Jun 2004 20:38:23 -0000      1.5
+++ src/gtp/gtp-client.c        18 Jul 2004 15:38:57 -0000
@@ -82,6 +82,9 @@
                   GtpClientUserCallbackData *callback_data);
 static int     parse_generated_move(GtpClient *client, int successful,
                                     GtpClientUserCallbackData *callback_data);
+static int     parse_final_status_list
+                 (GtpClient *client, int successful,
+                  GtpClientUserCallbackData *callback_data);
 
 
 /* Create a new client for an engine that can be sent commands to by
@@ -621,6 +624,37 @@
               COLOR_STRING(color));
 }
 
+void
+gtp_client_final_status_list(GtpClient *client,
+                            GtpClientFinalStatusListCallback response_callback,
+                            void *user_data, GtpStoneStatus status)
+{
+  const char *status_string = NULL;
+
+  assert(client);
+
+  switch (status) {
+    case GTP_ALIVE:
+      status_string = "alive";
+      break;
+
+    case GTP_DEAD:
+      status_string = "dead";
+      break;
+
+    case GTP_SEKI:
+      status_string = "seki";
+      break;
+  }
+
+  assert(status_string);
+
+  send_command(client, (GtpClientResponseCallback) parse_final_status_list,
+              store_user_callback_data(((GtpClientResponseCallback)
+                                        response_callback),
+                                       user_data, status, NULL),
+              "final_status_list %s", status_string);
+}
 
 static void
 send_command(GtpClient *client,
@@ -908,6 +942,37 @@
   utils_free(callback_data);
 
   return !successful || move_parsed;
+}
+
+
+static int
+parse_final_status_list(GtpClient *client, int successful,
+                       GtpClientUserCallbackData *callback_data)
+{
+  StringListItem *this_item;
+  int idx = 0;
+
+  GtpClientFinalStatusListCallback final_status_list_callback
+    = (GtpClientFinalStatusListCallback) callback_data->response_callback;
+
+  BoardPositionList *stones 
+    = board_position_list_new_empty(string_list_count(&client->response));
+
+  for (this_item = client->response.first; 
+       this_item; 
+       this_item = this_item->next) {
+    int x, y;
+    game_parse_point(GAME_GO, client->board_size, client->board_size, 
+                    this_item->text, &x, &y); 
+    stones->positions[idx++] = POSITION(x, y);
+  }
+
+  final_status_list_callback(client, stones != NULL,
+                            callback_data->user_data, 
+                            callback_data->integer_data, stones);
+  utils_free(callback_data);
+
+  return !successful || stones != NULL;
 }
 
 
Index: src/gtp/gtp-client.h
===================================================================
RCS file: /cvs/quarry/quarry/src/gtp/gtp-client.h,v
retrieving revision 1.4
diff -u -r1.4 gtp-client.h
--- src/gtp/gtp-client.h        11 Jun 2004 21:39:47 -0000      1.4
+++ src/gtp/gtp-client.h        18 Jul 2004 15:38:57 -0000
@@ -55,6 +55,11 @@
   GTP_SUCCESS
 } GtpError;
 
+typedef enum {
+  GTP_ALIVE,
+  GTP_DEAD,
+  GTP_SEKI
+} GtpStoneStatus;
 
 typedef struct _GtpClient      GtpClient;
 
@@ -158,6 +163,10 @@
                                        int color, int x, int y,
                                        BoardAbstractMoveData *move_data);
 
+typedef void (* GtpClientFinalStatusListCallback)
+  (GtpClient *client, int successful, void *user_data,
+   GtpStoneStatus status, BoardPositionList *stones);
+
 
 GtpClient *    gtp_client_new
                  (GtpClientSendToEngine send_to_engine,
@@ -234,6 +243,11 @@
                  (GtpClient *client,
                   GtpClientMoveCallback response_callback,
                   void *user_data, int color);
+
+void           gtp_client_final_status_list
+                 (GtpClient *client,
+                  GtpClientFinalStatusListCallback response_callback,
+                  void *user_data, GtpStoneStatus status);
 
 
 #endif /* QUARRY_GTP_CLIENT_H */
Index: src/gui-gtk/gtk-goban-window.c
===================================================================
RCS file: /cvs/quarry/quarry/src/gui-gtk/gtk-goban-window.c,v
retrieving revision 1.16
diff -u -r1.16 gtk-goban-window.c
--- src/gui-gtk/gtk-goban-window.c      16 Jul 2004 19:56:45 -0000      1.16
+++ src/gui-gtk/gtk-goban-window.c      18 Jul 2004 15:39:01 -0000
@@ -105,8 +105,14 @@
                                    SpecialModeButtonClicked cancel_callback);
 static void     leave_special_mode(GtkGobanWindow *goban_window);
 
-static void     free_handicap_mode_done(GtkGobanWindow *goban_window);
+static void     engine_has_scored(GtpClient *client, int successful,
+                                  GtkGobanWindow *goban_window,
+                                  GtpStoneStatus status, 
+                                  BoardPositionList *dead_stones);
+static void     enter_scoring_mode(GtkGobanWindow *goban_window);
 static void     go_scoring_mode_done(GtkGobanWindow *goban_window);
+static void     free_handicap_mode_done(GtkGobanWindow *goban_window);
+
 
 static void     play_pass_move(GtkGobanWindow *goban_window);
 
@@ -1733,19 +1739,69 @@
   }
   else {
     if (goban_window->board->game == GAME_GO) {
+      int player;
+      int engine_is_scoring = FALSE;
+
       goban_window->dead_stones = g_malloc(BOARD_GRID_SIZE * sizeof(char));
       board_fill_grid(goban_window->board, goban_window->dead_stones, 0);
 
-      enter_special_mode(goban_window,
-                        "Please select dead stones\nto score the game",
-                        go_scoring_mode_done, NULL); 
-      set_goban_signal_handlers(goban_window,
-                               G_CALLBACK(go_scoring_mode_pointer_moved),
-                               G_CALLBACK(go_scoring_mode_goban_clicked));
+      for (player = 0; player < NUM_COLORS; player++)
+       if (goban_window->players[player]) {
+         gtp_client_final_status_list(goban_window->players[player],
+                                      (GtpClientFinalStatusListCallback) 
+                                        engine_has_scored, 
+                                      goban_window, 
+                                      GTP_DEAD);
+         engine_is_scoring = TRUE;
+         break;
+       }
 
-      update_territory_markup(goban_window);
+      if(!engine_is_scoring) {
+       enter_scoring_mode(goban_window);
+      }
+    }
+  }
+}
+
+
+static void 
+engine_has_scored(GtpClient *client, int successful,
+                 GtkGobanWindow *goban_window,
+                 GtpStoneStatus status, BoardPositionList *dead_strings)
+{
+  UNUSED(client);
+
+  if (successful) {
+    BoardPositionList *dead_stones;
+    int idx;
+
+    assert(status == GTP_DEAD);
+
+    for(idx = 0; idx < dead_strings->num_positions; idx++) {
+      dead_stones 
+       = go_get_string_stones(goban_window->board, 
+                              POSITION_X(dead_strings->positions[idx]), 
+                              POSITION_Y(dead_strings->positions[idx]));
+      board_position_list_mark_on_grid(dead_stones, 
+                                      goban_window->dead_stones, 1);
     }
   }
+
+  enter_scoring_mode(goban_window);
+}
+
+
+static void
+enter_scoring_mode(GtkGobanWindow *goban_window)
+{
+  enter_special_mode(goban_window,
+                    "Please select dead stones\nto score the game",
+                    go_scoring_mode_done, NULL); 
+  set_goban_signal_handlers(goban_window,
+                           G_CALLBACK(go_scoring_mode_pointer_moved),
+                           G_CALLBACK(go_scoring_mode_goban_clicked));
+
+  update_territory_markup(goban_window);
 }
 
 
Index: src/utils/string-list.c
===================================================================
RCS file: /cvs/quarry/quarry/src/utils/string-list.c,v
retrieving revision 1.4
diff -u -r1.4 string-list.c
--- src/utils/string-list.c     27 May 2004 20:40:24 -0000      1.4
+++ src/utils/string-list.c     18 Jul 2004 15:39:02 -0000
@@ -147,6 +147,23 @@
 }
 
 
+int
+string_list_count(void *abstract_list)
+{
+  StringList *list = (StringList *) abstract_list;
+  StringListItem *this_item;
+
+  int count = 0;
+
+  assert(list);
+
+  for (this_item = list->first; this_item; this_item = this_item->next)
+    count++;
+
+  return count;
+}
+
+
 void
 string_list_fill_from_string(void *abstract_list, const char *super_string)
 {
Index: src/utils/utils.h
===================================================================
RCS file: /cvs/quarry/quarry/src/utils/utils.h,v
retrieving revision 1.7
diff -u -r1.7 utils.h
--- src/utils/utils.h   16 Jul 2004 19:55:07 -0000      1.7
+++ src/utils/utils.h   18 Jul 2004 15:39:03 -0000
@@ -294,6 +294,7 @@
   ((abstract_list)->first != NULL                                      \
    && (abstract_list)->first == (abstract_list)->last)
 
+int              string_list_count(void *abstract_list);
 
 void             string_list_fill_from_string(void *abstract_list,
                                               const char *super_string);



Reply via email to