Index: iagno/gnothello.h
===================================================================
--- iagno/gnothello.h	(リビジョン 6478)
+++ iagno/gnothello.h	(作業コピー)
@@ -40,10 +40,6 @@
 #define NETWORK_PAGE           	1
 
 gboolean ggz_network_mode;
-int player_id;
-int seat;
-int seats[2];
-char names[2][17];
 
 extern GtkWidget *notebook;
 extern GtkWidget *window;
@@ -83,5 +79,5 @@
 void properties_cb (GtkWidget * widget, gpointer data);
 void set_bg_color (void);
 void gui_draw_grid (void);
-
+void redraw_board (void);
 #endif
Index: iagno/server.c
===================================================================
--- iagno/server.c	(リビジョン 6478)
+++ iagno/server.c	(作業コピー)
@@ -1,5 +1,7 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
 /*
- * File: main.c
+ * File: server.c
  * Author: Ismael Orenstein
  * Project: GGZ Reversi game module
  * Date: 09/17/2000
@@ -26,612 +28,610 @@
 #include "config.h"
 #include <gnome.h>
 #include <ggzdmod.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
+#include <assert.h>
 
 #include "server.h"
 
-// Global game variables
-struct rvr_game_t rvr_game;
+#define BLACK           49
+#define WHITE           79
+#define BLANK           1
+#define OUTSIDE           (BLACK + WHITE - 1)
+#define OTHER_PLAYER(who) (OUTSIDE - who + 1)
 
+#define UL     -11
+#define UU     -10
+#define UR     -9
+#define LL     -1
+#define RR     +1
+#define DL     +9
+#define DD     +10
+#define DR     +11
+#define NDIRS  8
 
-// Initializes everything
-void
-game_init (GGZdMod * ggzdmod)
-{
-  int i;
-  rvr_game.ggz = ggzdmod;
-  rvr_game.black = 2;
-  rvr_game.white = 2;
-  rvr_game.state = RVR_STATE_INIT;
-  rvr_game.turn = EMPTY;
-  for (i = 0; i < 64; i++) {
-    rvr_game.board[i] = EMPTY;
-  }
-  // Initial positions
-  rvr_game.board[CART (4, 4)] = WHITE;
-  rvr_game.board[CART (5, 5)] = WHITE;
-  rvr_game.board[CART (5, 4)] = BLACK;
-  rvr_game.board[CART (4, 5)] = BLACK;
-  // Inits random number generator
-  srand (time (0));
-}
+static const gint dirs[] = { UL, UU, UR, LL, RR, DL, DD, DR };
 
-// Handle server messages
-void
-game_handle_ggz_state (GGZdMod * ggz, GGZdModEvent event, const void *data)
-{
-  GGZdModState new_state = ggzdmod_get_state (ggz);
-  const GGZdModState *old_state_ptr = data;
-  const GGZdModState old_state = *old_state_ptr;
+static const gchar *strs[] = {
+  "Invalid move\n",              /* -1 */
+  "Wrong turn\n",                /* -2 */
+  "Skip move\n",                 /* -3 */
+  "Can't read message\n",        /* -4 */
+  "Can't send message\n",        /* -5 */
+  "Not playing error\n",         /* -6 */
+  "Play again error\n",          /* -7 */
+  "Unknown opcode\n"             /* -8 */
+};
 
-  // Check if it's the right time to launch the game and if ggz could do taht
-  if (old_state == GGZDMOD_STATE_CREATED) {
-    /*assert(rvr_game.state == RVR_STATE_INIT); */
-    return;
-  }
+// Global game variables
+static guint8 squares[] = {
+  44, 45, 54, 55, 23, 26, 73, 76,
+  32, 62, 37, 67, 13, 16, 31, 61,
+  38, 68, 83, 86, 14, 15, 41, 51,
+  48, 58, 84, 85, 24, 25, 42, 52,
+  74, 75, 47, 57, 36, 63, 33, 35,
+  53, 66, 46, 64, 34, 43, 56, 65,
+  12, 17, 21, 71, 28, 78, 82, 87,
+  22, 27, 72, 77, 11, 18, 81, 88
+};
 
-  if (new_state == GGZDMOD_STATE_PLAYING) {
-    // Game already going on?
-    if (rvr_game.turn == EMPTY)
-      rvr_game.turn = BLACK;
+static gint8   board0[100];
+static gint    vsquares[40];
+static guint   move_count;
+static guint   whose_turn;
+static guint   bcount;
+static guint   wcount;
+static guint   count;
+static int     kifu[61][2];
+static GGZdMod *ggz;
+static int     state;
 
-    // No! Let's start the game!
-    game_start ();
-    game_play ();
-  }
 
-  if (new_state == GGZDMOD_STATE_WAITING) {
-    // That's great! Update the state
-    // Now waiting for people to join
-    rvr_game.state = RVR_STATE_WAIT;
-    ggzdmod_log (rvr_game.ggz, "Waiting for players");
-  }
-}
+static int game_make_move (int player, int yx);
 
+/**** Othello AI program ****/
 
-static int
-seats_full (void)
+/* Initialization of data */
+static void
+init (void)
 {
-  /* This calculation is a bit inefficient, but that's OK */
-  return ggzdmod_count_seats (rvr_game.ggz, GGZ_SEAT_OPEN) == 0
-    && ggzdmod_count_seats (rvr_game.ggz, GGZ_SEAT_RESERVED) == 0
-    && ggzdmod_count_seats (rvr_game.ggz, GGZ_SEAT_ABANDONED) == 0;
-}
+  guint i, j, ij = 0;
 
+  for (i = 0; i < 10; i++)
+    for (j = 0; j < 10; j++) {
+      if (i == 0 || i == 9 || j == 0 || j == 9)
+        board0[ij++] = OUTSIDE;
+      else
+        board0[ij++] = BLANK;
+    }
+  board0[44] = WHITE;
+  board0[45] = BLACK;
+  board0[54] = BLACK;
+  board0[55] = WHITE;
 
-static int
-seats_empty (void)
-{
-  /* This calculation is a bit inefficient, but that's OK */
-  return ggzdmod_count_seats (rvr_game.ggz, GGZ_SEAT_PLAYER) == 0
-    && ggzdmod_count_spectators (rvr_game.ggz) == 0;
+  move_count = 0;
+  bcount     = 2;
+  wcount     = 2;
+  whose_turn = BLACK;
 }
 
-
-void
-game_handle_ggz_seat (GGZdMod * ggz, GGZdModEvent event, const void *data)
+static gboolean
+is_valid0 (guint who, guint yx, gint dir)
 {
-  const GGZSeat *old_seat = data;
-  GGZSeat new_seat = ggzdmod_get_seat (ggz, old_seat->num);
-  GGZdModState new_state;
+  guint tmp = yx + dir;
+  gint8 not_me = (gint8) OTHER_PLAYER (who);
 
-  /* Check the state. */
-  if (seats_full ())
-    new_state = GGZDMOD_STATE_PLAYING;
-  else if (seats_empty ())
-    new_state = GGZDMOD_STATE_DONE;
-  else
-    new_state = GGZDMOD_STATE_WAITING;
+  if (board0[tmp] != not_me)
+    return FALSE;
 
-  // That's great!! Do stuff
+  do {
+    tmp += dir;
+  } while (board0[tmp] == not_me);
 
-  if (new_seat.type == GGZ_SEAT_PLAYER)
-    game_send_seat (new_seat.num);
-  game_send_players ();
-
-  if (new_state == GGZDMOD_STATE_PLAYING && rvr_game.turn != EMPTY)
-    game_send_sync (new_seat.num);
-
-  ggzdmod_set_state (ggz, new_state);
+  return board0[tmp] == (gint8) who;
 }
 
-
-int
-game_send_seat (int seat)
+/* Check if a given (empty) square can provide a valid move */
+static gboolean
+is_valid (guint who, guint yx)
 {
-  int fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd;
+  guint i;
 
-  ggzdmod_log (rvr_game.ggz, "Sending player %d's his seat number\n", seat);
+  for (i = 0; i < NDIRS; i++)
+    if (is_valid0 (who, yx, dirs[i]))
+      return TRUE;
 
-  if (ggz_write_int (fd, RVR_MSG_SEAT) < 0 || ggz_write_int (fd, seat) < 0) {
-    ggzdmod_log (rvr_game.ggz, "Couldn't send seat!\n");
-    return -1;
-  }
-
-  return 0;
+  return FALSE;
 }
 
-int
-game_send_players (void)
+static void
+move_board0 (guint yx, gint dir)
 {
-  int i, j, fd;
+  guint tmp = yx + dir;
+  gint8 not_me = (gint8) OTHER_PLAYER (whose_turn);
 
-  for (j = 0; j < ggzdmod_get_num_seats (rvr_game.ggz); j++) {
-    if ((fd = ggzdmod_get_seat (rvr_game.ggz, j).fd) == -1) {
-      ggzdmod_log (rvr_game.ggz, "Bot seat\n");
-      continue;
-    }
-    ggzdmod_log (rvr_game.ggz, "Sending player list to player %d", j);
+  if (board0[tmp] != not_me)
+    return;
 
-    if (ggz_write_int (fd, RVR_MSG_PLAYERS) < 0) {
-      ggzdmod_log (rvr_game.ggz, "Can't send player list!\n");
-      return -1;
-    }
+  do {
+    tmp += dir;
+  } while (board0[tmp] == not_me);
 
-    for (i = 0; i < ggzdmod_get_num_seats (rvr_game.ggz); i++) {
-      if (ggz_write_int (fd, ggzdmod_get_seat (rvr_game.ggz, i).type) < 0)
-	return -1;
-      if (ggzdmod_get_seat (rvr_game.ggz, i).type != GGZ_SEAT_OPEN &&
-	  ggz_write_string (fd,
-			    ggzdmod_get_seat (rvr_game.ggz, i).name) < 0) {
-	ggzdmod_log (rvr_game.ggz, "Can't send player name!\n");
-	return -1;
-      }
-    }
+  if (board0[tmp] != (gint8) whose_turn)
+    return;
+
+  tmp -= dir;
+  while (tmp != yx) {
+    board0[tmp] = (gint8) whose_turn;
+    count++;
+    tmp -= dir;
   }
-
-  return 0;
 }
 
-int
-game_send_sync (int seat)
+/* reverse some pieces */
+static void
+move_board (guint yx)
 {
-  int i, fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd;
+  guint i, tmp;
 
-  ggzdmod_log (rvr_game.ggz, "Handling sync for player %d", seat);
+  count = 0;
+  for (i = 0; i < NDIRS; i++)
+    move_board0 (yx, dirs[i]);
 
-  // Send SYNC message and current turn
+  board0[yx] = (gint8) whose_turn;
 
-  if (ggz_write_int (fd, RVR_MSG_SYNC) < 0
-      || ggz_write_char (fd, rvr_game.turn) < 0)
-    return -1;
+  i = move_count++ + 4;
+  tmp = (guint) squares[i];
+  squares[i] = (guint8) yx;
+  if (tmp != yx) {
+    while (squares[++i] != (guint8) yx);
+    squares[i] = (guint8) tmp;
+  }
 
-  // Send current board state
-
-  for (i = 0; i < 64; i++) {
-    if (ggz_write_char (fd, rvr_game.board[i]) < 0)
-      return -1;
+  if (whose_turn == WHITE) {
+    wcount += count + 1;
+    bcount -= count;
+  } else {
+    bcount += count + 1;
+    wcount -= count;
   }
 
-  // That's fine
-
-  return 0;
-
+  whose_turn = OTHER_PLAYER (whose_turn);
 }
 
-int
-game_start (void)
+static guint
+entry_valid_move (void)
 {
+  guint yx, i, j = 0;
 
-  int i, fd;
+  for (i = move_count + 4; i < 64; i++) {
+    yx = (guint) squares[i];
+    if (is_valid (whose_turn, yx)) {
+      vsquares[j++] = (gint) yx;
+    }
+  }
 
-  // Start game variables
-  rvr_game.state = RVR_STATE_PLAYING;
+  return j;
+}
 
-  // Sends out start message
-  for (i = 0; i < ggzdmod_get_num_seats (rvr_game.ggz); i++) {
-    fd = ggzdmod_get_seat (rvr_game.ggz, i).fd;
-    // Don't send anything if the player is a computer!
-    if (fd == -1)
-      continue;
-    if (ggz_write_int (fd, RVR_MSG_START) < 0)
-      return -1;
-  }
+/**** Server program ****/
 
-  ggzdmod_log (rvr_game.ggz, "Game has started!\n");
-
-  return 0;
+// Initializes everything
+static void
+game_init (GGZdMod *ggzdmod)
+{
+  init ();
+  /* move_count = 0; bcount = wcount = 2; whose_turn = BLACK; */
+  ggz        = ggzdmod;
+  kifu[0][0] = 0;
+  state      = RVR_STATE_INIT;
 }
 
-/* return -1 on error, 1 on gameover */
-void
-game_handle_player (GGZdMod * ggz, GGZdModEvent event, const void *data)
+static int
+game_check_bot (void)
 {
-  const int *seat_ptr = data;
-  const int seat = *seat_ptr;
-  int op, move;
-  int fd = ggzdmod_get_seat (ggz, seat).fd;
+  int seat = PLAYER2SEAT (whose_turn);
 
-  if (ggz_read_int (fd, &op) < 0)
-    return;
+  // Is the AI?
+  if (ggzdmod_get_seat (ggz, seat).type != GGZ_SEAT_BOT)
+    // It's not! Wait until the player sends the message...
+    return SERVER_OK;
 
-  switch (op) {
+  // Yes! Wait for a second
+  sleep (1);
+  return game_make_move ((int) whose_turn, (int) vsquares[0]);
+}
 
-  case RVR_REQ_MOVE:
-    game_handle_move (seat, &move);
-    break;
+static int
+game_skip_move (void)
+{
+  int seat, fd;
 
-  case RVR_REQ_SYNC:
-    game_send_sync (seat);
-    break;
+  for (seat = 0; seat < ggzdmod_get_num_seats (ggz); seat++) {
+    fd = ggzdmod_get_seat (ggz, seat).fd;
+    if (fd != -1 && (ggz_write_int (fd, RVR_MSG_MOVE) < 0
+                     || ggz_write_int (fd, RVR_ERROR_CANTMOVE) < 0))
+      return RVR_ERROR_CANTWRITE;
+  }
 
-  case RVR_REQ_AGAIN:
-    game_play_again (seat);
-    break;
-
-  default:
-    ggzdmod_log (rvr_game.ggz, "ERROR: unknown player opcode %d.", op);
-    break;
-  }
+  return game_check_bot ();
 }
 
-int
-game_handle_move (int seat, int *move)
+static int
+game_check_over (void)
 {
-  int fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd, status;
+  int seat, fd, winner;
+  GGZGameResult results[2];
 
-  // Get the move from the message
-  if (ggz_read_int (fd, move) < 0)
-    return -1;
+  if (entry_valid_move ())
+    return game_check_bot ();
 
-  ggzdmod_log (rvr_game.ggz, "Handling move %d,%dfor player %d\n", X (*move),
-	       Y (*move), seat);
+  whose_turn = OTHER_PLAYER (whose_turn);
+  if (entry_valid_move ())
+    return game_skip_move ();
 
-  // Check if it's his turn
-  if (SEAT2PLAYER (seat) != rvr_game.turn) {
-    status = RVR_ERROR_WRONGTURN;
+  if (bcount > wcount) {
+    results[PLAYER2SEAT (BLACK)] = GGZ_GAME_WIN;
+    results[PLAYER2SEAT (WHITE)] = GGZ_GAME_LOSS;
+    winner = BLACK;
+  } else if (wcount > bcount) {
+    results[PLAYER2SEAT (WHITE)] = GGZ_GAME_WIN;
+    results[PLAYER2SEAT (BLACK)] = GGZ_GAME_LOSS;
+    winner = WHITE;
   } else {
-    // Check if it's valid (status return a negative value if error, the move on sucess)
-    status = game_check_move (SEAT2PLAYER (seat), *move);
+    winner = 0;
+    results[0] = results[1] = GGZ_GAME_TIE;
   }
 
-  // Make move if it's valid (also sends it to everyone);
-  game_make_move (SEAT2PLAYER (seat), status);
+  // Report game to GGZ 
+  ggzdmod_report_game (ggz, NULL, results, NULL);
 
-  return status;
+  // Send message 
+  for (seat = 0; seat < ggzdmod_get_num_seats (ggz); seat++) {
+    fd = ggzdmod_get_seat (ggz, seat).fd;
+    if (fd != -1 && (ggz_write_int (fd, RVR_MSG_GAMEOVER) < 0
+                     || ggz_write_int (fd, winner) < 0))
+      return RVR_ERROR_CANTWRITE;;
+  }
 
+  // Ends everything
+  game_init (ggz);
+  state = RVR_STATE_DONE;
+  whose_turn = 0;
+  bcount = wcount = 0;
+  if (ggzdmod_get_seat (ggz,
+          PLAYER2SEAT (BLACK)).type == GGZ_SEAT_BOT)
+    bcount = 1;
+  if (ggzdmod_get_seat (ggz,
+          PLAYER2SEAT (WHITE)).type == GGZ_SEAT_BOT)
+    wcount = 1;
+  ggzdmod_log (ggz,
+  "Game is over. Waiting to see if we should play again\n");
+
+  return SERVER_OK;
 }
 
-void
-game_play (void)
+static int
+game_start (void)
 {
-  int move;
-  int seat = PLAYER2SEAT (rvr_game.turn);
+  int fd, seat;
 
-  // Is the AI?
-  if (ggzdmod_get_seat (rvr_game.ggz, seat).type == GGZ_SEAT_BOT) {
-    // Yes! Wait for a second
-    sleep (1);
-    move = game_bot_move (rvr_game.turn);
-    game_make_move (rvr_game.turn, move);
+  // Start game variables
+  state = RVR_STATE_PLAYING;
+
+  for (seat = 0; seat < ggzdmod_get_num_seats (ggz); seat++) {
+    fd = ggzdmod_get_seat (ggz, seat).fd;
+    // Don't send anything if the player is a computer!
+    if (fd != -1 && ggz_write_int (fd, RVR_MSG_START) < 0)
+      return RVR_ERROR_CANTWRITE;
   }
-  // It's not! Wait until the player sends the message...
 
-  return;
+  ggzdmod_log (ggz, "Game has started!\n");
+  return game_check_over ();
 }
 
-int
-game_bot_move (int player)
+// Puts human players score = 0
+// When they send a REQ_AGAIN message, put it = 1
+// When everyone equal = 1, then starts it all again
+static int
+game_play_again (int seat, int fd)
 {
-  int i;
+  ggzdmod_log (ggz, "%d wants to play again!\n", seat);
 
-  // Returns a random move between 0 and 63
-  i = (int) (64.0 * rand () / (RAND_MAX + 1.0));
-  if (game_check_move (player, i) >= 0)
-    return i;
-  else
-    return game_bot_move (player);
+  // Check game is finished or not. 
+  if (whose_turn) {
+    if (ggz_write_int (fd, RVR_MSG_MOVE) < 0
+        || ggz_write_int (fd, RVR_ERROR_PLAYAGAIN) < 0)
+      return RVR_ERROR_CANTWRITE;
+    return RVR_ERROR_PLAYAGAIN;
+  }
+
+  if (fd != -1 && ggz_write_int (fd, RVR_MSG_INIT) < 0)
+      return RVR_ERROR_CANTWRITE;
+
+  if (SEAT2PLAYER (seat) == WHITE) 
+    wcount = 1;
+  else if (SEAT2PLAYER (seat) == BLACK)
+    bcount = 1;
+
+  if (!bcount || !wcount) {
+    state = RVR_STATE_WAITING;
+    return SERVER_OK;
+  }
+
+  // Starts again
+  bcount = wcount = 2;
+  whose_turn = BLACK;
+ return game_start ();
 }
 
-int
-game_check_move (int player, int move)
+static int
+game_check_move (int player, int yx)
 {
-
-  int x = X (move), y = Y (move), status = 0;
-
   // Check if it's right time
-  if (rvr_game.state != RVR_STATE_PLAYING)
+  if (state != RVR_STATE_PLAYING)
+    return RVR_ERROR_NOTPLAYING;
+  // Check if it's his turn
+  if (player != whose_turn)
     return RVR_ERROR_WRONGTURN;
-
   // Check if out of bounds
-  if (move < 0 || move > 63)
+  if (yx < 0 || yx > 99)
     return RVR_ERROR_INVALIDMOVE;
-
   // Check if duplicated
-  if (rvr_game.board[move] != EMPTY)
+  if (board0[yx] != BLANK)
     return RVR_ERROR_INVALIDMOVE;
-
-  /* CHECK IF THE MOVE IS VALID */
-
-  // Check if it's valid up
-  status += game_check_direction (player, 0, -1, x, y);
-  status += game_check_direction (player, 1, -1, x, y);
-  status += game_check_direction (player, 1, 0, x, y);
-  status += game_check_direction (player, 1, 1, x, y);
-  status += game_check_direction (player, 0, 1, x, y);
-  status += game_check_direction (player, -1, 1, x, y);
-  status += game_check_direction (player, -1, 0, x, y);
-  status += game_check_direction (player, -1, -1, x, y);
-
-  if (status > 0)
-    return move;
-  else
+  // Check if valid yx
+  if (!is_valid (player, yx))
     return RVR_ERROR_INVALIDMOVE;
 
+  return SERVER_OK;
 }
 
-int
-game_check_direction (int player, int vx, int vy, int x, int y)
+static int
+game_make_move (int player, int yx)
 {
-  int i, j;
-  for (i = x + vx, j = y + vy; GET (i, j) == -player; i += vx, j += vy) {
-    if (GET (i + vx, j + vy) == player)
-      return 1;
-  }
-  return 0;
-}
+  int fd, seat;
 
-int
-game_make_move (int player, int move)
-{
-  int x = X (move), y = Y (move);
-  int status = 0;
-  int a, fd;
+  kifu[move_count][0]     = player;
+  kifu[move_count][1]     = yx;
+  kifu[move_count + 1][0] = 0;
+  move_board ((guint) yx);
 
-  // Make the move
-  if (move >= 0) {
-    rvr_game.board[move] = player;
-
-    // Now goes through all directions, marking the board
-
-    status += game_mark_board (player, 0, -1, x, y);
-    status += game_mark_board (player, 1, -1, x, y);
-    status += game_mark_board (player, 1, 0, x, y);
-    status += game_mark_board (player, 1, 1, x, y);
-    status += game_mark_board (player, 0, 1, x, y);
-    status += game_mark_board (player, -1, 1, x, y);
-    status += game_mark_board (player, -1, 0, x, y);
-    status += game_mark_board (player, -1, -1, x, y);
-
-
-    // Change turn
-    rvr_game.turn *= -1;
-
-    game_update_scores ();
-
-  } else
-    status = -1;
-
-  for (a = 0; a < ggzdmod_get_num_seats (rvr_game.ggz); a++) {
-    fd = ggzdmod_get_seat (rvr_game.ggz, a).fd;
-    if (fd == -1)
-      continue;
-    if (status > 0) {
-      if (ggz_write_int (fd, RVR_MSG_MOVE) < 0
-	  || ggz_write_int (fd, move) < 0)
-	ggzdmod_log (rvr_game.ggz, "Couldn't send message to player\n");
-    } else {
-      if (ggz_write_int (fd, RVR_MSG_MOVE) < 0
-	  || ggz_write_int (fd, RVR_ERROR_INVALIDMOVE) < 0)
-	ggzdmod_log (rvr_game.ggz, "Couldn't send error message to player\n");
-    }
-    player *= -1;
+  for (seat = 0; seat < ggzdmod_get_num_seats (ggz); seat++) {
+    fd = ggzdmod_get_seat (ggz, seat).fd;
+    if (fd != -1 && (ggz_write_int (fd, RVR_MSG_MOVE) < 0
+                     || ggz_write_int (fd, NEW2OLD (yx))) < 0)
+      return RVR_ERROR_CANTWRITE;
   }
 
   // Check if game is over
-  if (status >= 0 && !game_check_over ()) {
+  return game_check_over ();
+}
 
-    // AI play
-    game_play ();
+static int
+game_send_sync (int seat)
+{
+  int fd = ggzdmod_get_seat (ggz, seat).fd;
+  int i = 0;
 
+  ggzdmod_log (ggz, "Handling sync for player %d", seat);
+
+  // Send SYNC message
+  if (ggz_write_int (fd, RVR_MSG_SYNC) < 0)
+    return RVR_ERROR_CANTWRITE;
+  // Send kifu
+  while (kifu[i][0]) {
+    if (ggz_write_int (fd, kifu[i][0]) < 0
+        || ggz_write_int (fd, kifu[i++][1]) < 0)
+      return RVR_ERROR_CANTWRITE;
   }
-  // If couldn`t make the move, sends sync to the player
-  if (status < 0)
-    game_send_sync (PLAYER2SEAT (player));
+  // Send end mark and current turn.
+  // For the compatibility with the old protocol.
+  // Old client are waiting for the seat, therefor send dummy seat.
+  if (ggz_write_int (fd, 0) < 0 || ggz_write_int (fd, whose_turn) < 0)
+    return RVR_ERROR_CANTWRITE;
 
-  return status;
-
+  // That's fine
+  return SERVER_OK;
 }
 
-int
-game_check_over (void)
+static int
+game_handle_move (int seat, int *move)
 {
-  int i, status = 0;
+  int yx, status, fd = ggzdmod_get_seat (ggz, seat).fd;
 
-  // Check if the current player can play
-  for (i = 0; i < 64; i++) {
-    if (game_check_move (rvr_game.turn, i) > 0) {
-      status++;
-      break;
-    }
-  }
+  // Get the yx from the message
+  if (ggz_read_int (fd, move) < 0)
+    return RVR_ERROR_CANTREAD;
 
-  // If he can play, the game is not over
-  if (status > 0)
-    return 0;
+  yx = OLD2NEW (*move);
+  ggzdmod_log (ggz, "Handling move %d, for player %d\n", yx, seat);
 
-  // He can't! Check if the opponent can
-  status = 0;
-
-  for (i = 0; i < 64; i++) {
-    if (game_check_move (-rvr_game.turn, i) > 0) {
-      status++;
-      break;
-    }
+  // Check if it's valid
+  status = game_check_move (SEAT2PLAYER (seat), yx);
+  if (status < 0) {
+    // If invalid yx, sends sync and status to the player.
+    game_send_sync (seat);
+    if (ggz_write_int (fd, RVR_MSG_MOVE) < 0
+        || ggz_write_int (fd, status) < 0)
+      return RVR_ERROR_CANTWRITE;
+    return SERVER_OK;
   }
+  // Make move if it's valid (also sends it to everyone);
+  return game_make_move (SEAT2PLAYER (seat), yx);
+}
 
-  // If he can, then skip the players move.
-  // If he can't, end the game
+static int
+seats_full (void)
+{
+  /* This calculation is a bit inefficient, but that's OK */
+  return !ggzdmod_count_seats (ggz, GGZ_SEAT_OPEN)
+    && !ggzdmod_count_seats (ggz, GGZ_SEAT_RESERVED)
+    && !ggzdmod_count_seats (ggz, GGZ_SEAT_ABANDONED);
+}
 
-  if (status > 0)
-    game_skip_move ();
-  else {
-    game_gameover ();
-    return 1;
-  }
-
-  return 0;
+static int
+seats_empty (void)
+{
+  /* This calculation is a bit inefficient, but that's OK */
+  return !ggzdmod_count_seats (ggz, GGZ_SEAT_PLAYER)
+    && !ggzdmod_count_spectators (ggz);
 }
 
+static int
+game_send_seat (int seat)
+{
+  int fd = ggzdmod_get_seat (ggz, seat).fd;
 
+  ggzdmod_log (ggz, "Sending player %d's his seat number\n", seat);
 
+  if (ggz_write_int (fd, RVR_MSG_SEAT) < 0
+      || ggz_write_int (fd, seat) < 0)
+    return RVR_ERROR_CANTWRITE;
 
-
-int
-game_mark_board (int player, int vx, int vy, int x, int y)
-{
-  int i, j;
-  if (!game_check_direction (player, vx, vy, x, y))
-    return 0;
-  for (i = x + vx, j = y + vy; GET (i, j) == -player; i += vx, j += vy) {
-    rvr_game.board[CART (i, j)] *= -1;
-  }
-  return 1;
+  return SERVER_OK;
 }
 
-void
-game_skip_move (void)
+static int
+game_send_players (void)
 {
-  int seat;
+  int i, j, fd;
 
-  for (seat = 0; seat < ggzdmod_get_num_seats (rvr_game.ggz); seat++) {
-    int fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd;
-    if (fd != -1) {
-      if (ggz_write_int (fd, RVR_MSG_MOVE) < 0 ||
-	  ggz_write_int (fd, RVR_ERROR_CANTMOVE) < 0)
-	ggzdmod_log (rvr_game.ggz, "Can't skip move");
+  for (j = 0; j < ggzdmod_get_num_seats (ggz); j++) {
+    fd = ggzdmod_get_seat (ggz, j).fd;
+    if (fd == -1) {
+      ggzdmod_log (ggz, "Bot seat\n");
+      continue;
     }
-  }
 
-  rvr_game.turn *= -1;
+    ggzdmod_log (ggz, "Sending player list to player %d", j);
+    if (ggz_write_int (fd, RVR_MSG_PLAYERS) < 0)
+      return RVR_ERROR_CANTWRITE;
 
-  return;
+    for (i = 0; i < ggzdmod_get_num_seats (ggz); i++) {
+      if (ggz_write_int (fd, ggzdmod_get_seat (ggz, i).type) < 0)
+        return RVR_ERROR_CANTWRITE;
+      if (ggzdmod_get_seat (ggz, i).type != GGZ_SEAT_OPEN &&
+          ggz_write_string (fd, ggzdmod_get_seat (ggz, i).name) < 0)
+        return RVR_ERROR_CANTWRITE;
+    }
+  }
 
+  return SERVER_OK;
 }
 
-void
-game_gameover (void)
+static void
+game_handle_player (GGZdMod *ggzdmod, GGZdModEvent event,
+                    const void *data)
 {
-  int seat, fd, winner;
-  GGZGameResult results[2];
+  const int *seat_ptr = data;
+  const int seat = *seat_ptr;
+  int op, yx, err;
+  int fd = ggzdmod_get_seat (ggzdmod, seat).fd;
 
-  // Ends everything
-  rvr_game.turn = EMPTY;
-  rvr_game.state = RVR_STATE_DONE;
+  if (ggz_read_int (fd, &op) < 0)
+    return;
 
-  if (rvr_game.black > rvr_game.white) {
-    results[PLAYER2SEAT (BLACK)] = GGZ_GAME_WIN;
-    results[PLAYER2SEAT (WHITE)] = GGZ_GAME_LOSS;
-    winner = BLACK;
-  } else if (rvr_game.white > rvr_game.black) {
-    results[PLAYER2SEAT (WHITE)] = GGZ_GAME_WIN;
-    results[PLAYER2SEAT (BLACK)] = GGZ_GAME_LOSS;
-    winner = WHITE;
-  } else {
-    winner = EMPTY;
-    results[0] = results[1] = GGZ_GAME_TIE;
+  switch (op) {
+  case RVR_REQ_MOVE:                        /* 4 */
+    err = game_handle_move (seat, &yx);
+    break;
+  case RVR_REQ_AGAIN:                       /* 8 */
+    err = game_play_again (seat, fd);
+    break;
+  default:
+    err = RVR_ERROR_OPCODE;
+    break;
   }
 
-  /* Report game to GGZ */
-  ggzdmod_report_game (rvr_game.ggz, NULL, results, NULL);
+  if (err < RVR_ERROR_OPCODE)
+    err = RVR_ERROR_OPCODE;
+  if (err < 0)
+    ggzdmod_log (ggzdmod, strs[-err - 1]);
+}
 
-  // Send message 
-  for (seat = 0; seat < ggzdmod_get_num_seats (rvr_game.ggz); seat++) {
-    fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd;
-    if (fd == -1)
-      continue;
-    if (ggz_write_int (fd, RVR_MSG_GAMEOVER) < 0
-	|| ggz_write_int (fd, winner) < 0)
-      ggzdmod_log (rvr_game.ggz, "Can't send gameover message");
-  }
+static void
+game_handle_ggz_seat (GGZdMod *ggzdmod, GGZdModEvent event,
+                      const void *data)
+{
+  const GGZSeat *old_seat = data;
+  GGZSeat new_seat = ggzdmod_get_seat (ggzdmod, old_seat->num);
+  GGZdModState new_state;
 
-  // What to do now?
-  // Puts human players score = 0
-  // When they send a REQ_AGAIN message, put it = 1
-  // When everyone equal = 1, then starts it all again
-  ggzdmod_log (rvr_game.ggz,
-	       "Game is over. Waiting to see if we should play again\n");
-  rvr_game.white =
-    (ggzdmod_get_seat (rvr_game.ggz, PLAYER2SEAT (WHITE)).type ==
-     GGZ_SEAT_BOT);
-  rvr_game.black =
-    (ggzdmod_get_seat (rvr_game.ggz, PLAYER2SEAT (BLACK)).type ==
-     GGZ_SEAT_BOT);
+  // Check the state.
+  if (seats_full ())
+    new_state = GGZDMOD_STATE_PLAYING;
+  else if (seats_empty ())
+    new_state = GGZDMOD_STATE_DONE;
+  else
+    new_state = GGZDMOD_STATE_WAITING;
 
-  return;
+  // For the compatibility with the old protocol,
+  // game_send_sync should be before game_send_seat.
+  // New sync make for the old client to mitake get_seat.
+  if (new_state == GGZDMOD_STATE_PLAYING && whose_turn != 0)
+    game_send_sync (new_seat.num);
 
+  // That's great!! Do stuff
+  if (new_seat.type == GGZ_SEAT_PLAYER)
+    game_send_seat (new_seat.num);
+  game_send_players ();
+
+  ggzdmod_set_state (ggzdmod, new_state);
 }
 
-int
-game_play_again (int seat)
+// Handle server messages
+static void
+game_handle_ggz_state (GGZdMod *ggzdmod, GGZdModEvent event,
+                       const void *data)
 {
-  ggzdmod_log (rvr_game.ggz, "%d wants to play again! He is a good fellow.\n",
-	       seat);
-  // If game is not finished, forget about it
-  if (rvr_game.state != RVR_STATE_DONE) {
-    ggzdmod_log (rvr_game.ggz, "The game wasn`t over yet! Are you crazy?\n");
-    return RVR_SERVER_ERROR;
-  }
+  GGZdModState new_state = ggzdmod_get_state (ggzdmod);
+  const GGZdModState *old_state_ptr = data;
+  const GGZdModState old_state = *old_state_ptr;
 
-  if (SEAT2PLAYER (seat) == WHITE)
-    rvr_game.white = 1;
-  else if (SEAT2PLAYER (seat) == BLACK)
-    rvr_game.black = 1;
+  // Check if it's the right time to launch the game and
+  // if ggz could do taht
+  if (old_state == GGZDMOD_STATE_CREATED)
+    /*assert(rvr_game.state == RVR_STATE_INIT); */
+    return;
 
-  if (rvr_game.white && rvr_game.black) {
-    // Starts is again
-    game_init (rvr_game.ggz);
+  if (new_state == GGZDMOD_STATE_WAITING) {
+    // That's great! Update the state
+    // Now waiting for people to join
+    state = RVR_STATE_WAITING;
+    ggzdmod_log (ggzdmod, "Waiting for players");
+  } else if (new_state == GGZDMOD_STATE_PLAYING) {
+    // Let's start the game!
     game_start ();
-    rvr_game.turn = BLACK;
-    game_play ();
   }
-
-
-  return RVR_SERVER_OK;
-
 }
 
-void
-game_update_scores (void)
-{
-  int i;
-  rvr_game.white = 0;
-  rvr_game.black = 0;
-  for (i = 0; i < 64; i++) {
-    if (rvr_game.board[i] == WHITE)
-      rvr_game.white++;
-    if (rvr_game.board[i] == BLACK)
-      rvr_game.black++;
-  }
-}
-
-
 int
 main (void)
 {
-  GGZdMod *ggz = ggzdmod_new (GGZDMOD_GAME);
+  GGZdMod *ggzdmod = ggzdmod_new (GGZDMOD_GAME);
 
-  /* game_init is called at the start of _each_ game, so we must do
-   * ggz stuff here. */
-  ggzdmod_set_handler (ggz, GGZDMOD_EVENT_STATE, &game_handle_ggz_state);
-  ggzdmod_set_handler (ggz, GGZDMOD_EVENT_JOIN, &game_handle_ggz_seat);
-  ggzdmod_set_handler (ggz, GGZDMOD_EVENT_LEAVE, &game_handle_ggz_seat);
-  ggzdmod_set_handler (ggz, GGZDMOD_EVENT_SEAT, &game_handle_ggz_seat);
-  ggzdmod_set_handler (ggz, GGZDMOD_EVENT_PLAYER_DATA, &game_handle_player);
+  // game_init is called at the start of each game, so we must do
+  // ggz stuff here.
+  ggzdmod_set_handler (ggzdmod, GGZDMOD_EVENT_STATE,
+                       (GGZdModHandler) game_handle_ggz_state);
+  ggzdmod_set_handler (ggzdmod, GGZDMOD_EVENT_JOIN,
+                       (GGZdModHandler) game_handle_ggz_seat);
+  ggzdmod_set_handler (ggzdmod, GGZDMOD_EVENT_LEAVE,
+                       (GGZdModHandler) game_handle_ggz_seat);
+  ggzdmod_set_handler (ggzdmod, GGZDMOD_EVENT_SEAT,
+                       (GGZdModHandler) game_handle_ggz_seat);
+  ggzdmod_set_handler (ggzdmod, GGZDMOD_EVENT_PLAYER_DATA,
+                       (GGZdModHandler) game_handle_player);
 
-  game_init (ggz);
+  game_init (ggzdmod);
 
-  /* Connect to GGZ server; main loop */
-  if (ggzdmod_connect (ggz) < 0)
+  // Connect to GGZ server; main loop
+  if (ggzdmod_connect (ggzdmod) < 0)
     return -1;
-  (void) ggzdmod_loop (ggz);
-  (void) ggzdmod_disconnect (ggz);
-  ggzdmod_free (ggz);
 
+  ggzdmod_loop (ggzdmod);
+  ggzdmod_disconnect (ggzdmod);
+  ggzdmod_free (ggzdmod);
+
   return 0;
 }
+
Index: iagno/server.h
===================================================================
--- iagno/server.h	(リビジョン 6478)
+++ iagno/server.h	(作業コピー)
@@ -1,5 +1,5 @@
 /*
- * File: game.h
+ * File: server.h
  * Author: Ismael Orenstein
  * Project: GGZ Reversi game module
  * Date: 09/17/2000
@@ -23,211 +23,42 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
-#define BLACK -1
-#define WHITE +1
-#define EMPTY  0
+/* PROTOCOL VERSION 2 */
 
-/* REVERSI PROTOCOL VERSION 0.0.5
- *
- * The server handles everything, from the AI to the validity of moves
- *
- * RVR_STATE_INIT:
- *
- * First, it fetchs from the ggz_server how much seats there are, and how much are open/closed
- *
- * RVR_STATE_JOIN:
- *
- * Then, it waits until some player join . When he does, it sends:
- *
- * To Joining player:
- * 	RVR_MSG_SEAT (int)SEAT_NUM
- * To All Human players:
- * 	RVR_MSG_PLAYERS PLAYER_IDENTIFER[BLACK] PLAYER_IDENTIFIER[WHITE]
- *  where PLAYER_IDENTIFIER is:
- *  	(int)PLAYER_TYPE
- *  	if PLAYER_TYPE == GGZ_SEAT_OPEN
- *  		(str)PLAYER_NAME
- *
- * If the game was already happening, send the current game state to the new player
- *
- * 	RVR_MSG_SYNC (char)TURN BOARD_STATE
- * 	where TURN is the current turn, and:
- * 		BOARD_STATE = (char)POSITION * 64
- *
- * When all the open seats are filled, it enters playing state (state = RVR_STATE_PLAYING) and sends:
- *
- * To All Human players:
- * 	RVR_MSG_START
- *
- * RVR_STATE_PLAYING:
- *
- * If current player is AI:
- *
- * 	doMove(AI_MOVE());
- *
- * If it isn't AI, then it waits until client sends a RVR_REQ_MOVE
- *
- * When client sends a RVR_REQ_MOVE, the server must check if he is the current player and
- * if the move is valid. (The client should do it too, must the server must recheck to avoid cheating)
- * Then the server executes the move, and sends:
- * 
- * To All Human players:
- *
- *	RVR_MSG_MOVE (int)MOVE
- * 	where MOVE can be a array index (0-63) or one of the following error values:
- * 		RVR_ERROR_WRONGTURN
- * 			The player tried to move when it wasn't his turn
- * 		RVR_ERROR_INVALIDMOVE
- * 			The player tried a invalid move (Cheating sign!)
- * 		RVR_ERROR_CANTMOVE
- * 			The player can't move (no possible move)
- *
- * Then the server checks if the game is over (No more valid moves) and who has won. If the game is over,
- * it sends to All Human players:
- *
- * 	RVR_MSG_GAMEOVER (int)WINNER
- * 		where WINNER can be: BLACK, WHITE, EMPTY(draw)
- *
- * If some player left while the game was happening, it sends to all Human players:
- *
- * 	RVR_MSG_PLAYERS
- *
- * And it will wait until someone returns
- *
- * Any time, the server can receive a RVR_REQ_SYNC message from the client.
- *  If this is the case, it sents a RVR_MSG_SYNC to this player.
- *
- * The client (more information should be avaiable on the client's game.h file):
- * 
- * The client waits until a RVR_MSG_SEAT is sent to him, indicating what is his seat.
- * Then it waits until a RVR_MSG_PLAYERS, with the type/name of all the players
- * Then it waits until a RVR_MSG_START is sent.
- *
- * If a RVR_MSG_SYNC message is sent to him, it replaces the current game state with the one sent.
- * 
- * Then he enters playing mode.
- *
- * If it is his turn, The user selects a valid square and the client sends:
- * 	RVR_REQ_MOVE (int)MOVE
- * Then it waits until the server sends:
- * 	RVR_MSG_MOVE (int)MOVE
- * If move >= 0, do the move. Else, tell the player what was the error.
- * 
- * If it isn't his turn, it waits until the server sents a
- * 	RVR_MSG_MOVE (int)MOVE
- * If move >= 0, do the move. Else, tell (if necessary) what was the error.
- * 
- * After the move is done, change to the other turn.	
- *
- * If anyone has left the table, it will receive a RVR_MSG_PLAYERS from the server. Then it enters waiting mode again.
- *
- * When the game is over, it sends a RVR_MSG_GAMEOVER (int)winner to the players, and enters DONE state. If it receives enough RVR_REQ_AGAIN msgs, it sends a RVR_MSG_START to the players.
- *
- * Luckily that's all, this protocol is perfect and it shouldn't be modified anymore. Or so I hope. :) */
+#define RVR_MSG_SEAT        0
+#define RVR_MSG_PLAYERS     1
+#define RVR_MSG_MOVE        2
+#define RVR_MSG_GAMEOVER    3
+#define RVR_REQ_MOVE        4
+#define RVR_MSG_START       5
+#define RVR_MSG_SYNC        6
+#define RVR_MSG_INIT        7
+#define RVR_REQ_AGAIN       8
 
-#include "ggzdmod.h"
-
-// Reversi protocol
-// The numbers aren't on order, because I used the same constants from TicTacToe - simplify testing
-#define RVR_MSG_SEAT 0
-#define RVR_MSG_PLAYERS 1
-#define RVR_MSG_SYNC 6
-#define RVR_REQ_SYNC 7
-#define RVR_REQ_AGAIN 8
-#define RVR_MSG_START 5
-#define RVR_MSG_MOVE 2
-#define RVR_MSG_GAMEOVER 3
-#define RVR_REQ_MOVE 4
-
 // States
-#define RVR_STATE_INIT 0
-#define RVR_STATE_WAIT 1
-#define RVR_STATE_PLAYING 2
-#define RVR_STATE_DONE 3
+#define RVR_STATE_INIT      0
+#define RVR_STATE_WAITING   1
+#define RVR_STATE_PLAYING   2
+#define RVR_STATE_DONE      3
 
-// Responses from server
-#define RVR_SERVER_ERROR -1
-#define RVR_SERVER_OK 0
-#define RVR_SERVER_JOIN 1
-#define RVR_SERVER_LEFT 2
-#define RVR_SERVER_QUIT 3
-
 // Errors
+#define SERVER_OK              0
 #define RVR_ERROR_INVALIDMOVE -1
-#define RVR_ERROR_WRONGTURN -2
-#define RVR_ERROR_CANTMOVE -3
+#define RVR_ERROR_WRONGTURN   -2
+#define RVR_ERROR_CANTMOVE    -3
+#define RVR_ERROR_CANTREAD    -4
+#define RVR_ERROR_CANTWRITE   -5
+#define RVR_ERROR_NOTPLAYING  -6
+#define RVR_ERROR_PLAYAGAIN   -7
+#define RVR_ERROR_OPCODE      -8
 
-// Takes cartesian coordinates and transform them into a array index
-#define CART(X,Y) ( (Y-1)*8+(X-1) )
-
-// Takes a index and transform it in cartesians coordinates
-#define X(I) ( (I%8)+1 )
-#define Y(I) ( (I/8)+1 )
-
-// See what's the value at that place (like a 10x10 board)
-#define GET(X,Y) ( (X==0 || Y==0 || X>8 || Y>8) ? EMPTY : rvr_game.board[CART(X,Y)] )
-
 // Takes a seat and transform into a player code
-#define SEAT2PLAYER(seat) ( (seat==0)?BLACK:WHITE )
+#define SEAT2PLAYER(seat)   ((seat == 0)? BLACK: WHITE)
 
 // Takes a player code and transform into a seat index
-#define PLAYER2SEAT(player) ( (player==BLACK)?0:1 )
+#define PLAYER2SEAT(player) ((player == BLACK)? 0: 1)
 
+// For the compatibility with the old protocol.
+#define OLD2NEW(yx)  (yx / 8 + 1) * 10 + (yx % 8) + 1
+#define NEW2OLD(yx)  (yx / 10 - 1) * 8 + (yx % 10 - 1)
 
-struct rvr_game_t {
-  /* GGZ data */
-  GGZdMod *ggz;
-  // Board
-  char board[64];
-  // Score
-  int black;
-  int white;
-  // State
-  char state;
-  // Turn
-  char turn;
-};
-
-// Intializes game variables
-void game_init (GGZdMod * ggzdmod);
-// Handle server messages
-void game_handle_ggz_state (GGZdMod * ggz,
-			    GGZdModEvent event, const void *data);
-void game_handle_ggz_seat (GGZdMod * ggz,
-			   GGZdModEvent event, const void *data);
-// Handle player messages
-void game_handle_player (GGZdMod * ggz, GGZdModEvent event, const void *data);
-// Handle player move
-int game_handle_move (int, int *);
-
-// Send to the player what is his seat
-int game_send_seat (int);
-// Send to everyone who is playing
-int game_send_players (void);
-// Send game state to player
-int game_send_sync (int);
-// Sends the start message and start the game
-int game_start (void);
-
-// Play the game (if it is the AI)
-void game_play (void);
-// AI move
-int game_bot_move (int);
-// Check if move is valid (return a error code or the move)
-int game_check_move (int, int);
-// Check if a move is valid in this direction (return true or false)
-int game_check_direction (int, int, int, int, int);
-// Make the move, mark the board, increases the score and sends out the msg
-int game_make_move (int, int);
-// Mark the board at this direction (and increases the score)
-int game_mark_board (int, int, int, int, int);
-// Check if game is over
-int game_check_over (void);
-// Skip current player move
-void game_skip_move (void);
-// Game is over! Send gameover message and stop everything
-void game_gameover (void);
-// Play again?
-int game_play_again (int);
-// Update scores
-void game_update_scores (void);
Index: iagno/ggz-network.c
===================================================================
--- iagno/ggz-network.c	(リビジョン 6478)
+++ iagno/ggz-network.c	(作業コピー)
@@ -1,3 +1,5 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
 /* ggz-network.c
  *
  * Copyright (C) 2006 -  Andreas Røsdal <andrearo@pvv.ntnu.no>
@@ -26,182 +28,221 @@
 #include <ggz-embed.h>
 #include <ggz-gtk.h>
 
-#include "games-dlg-chat.h"
-#include "games-dlg-players.h"
+#include <games-dlg-chat.h>
+#include <games-dlg-players.h>
 
+#include "properties.h"
+#include "othello.h"
 #include "gnothello.h"
 #include "ggz-network.h"
-#include "othello.h"
 
-guint whose_turn = BLACK_TURN;
+#define BLACK           49
 
-static gboolean
-game_handle_io (GGZMod * mod)
-{
-  int op = -1;
+static const gchar *strs[] = {
+  N_("Invalid move!"),                /* 1 */
+  N_("Not your turn!"),               /* 2 */
+  N_("Skip move!"),                   /* 3 */
+  N_("Can't read message!"),          /* 4 */
+  N_("Can't send message!"),          /* 5 */
+  N_("Waiting for an opponent to join the game."), /* -6 */
+  N_("Not game over yet!"),           /* -7 */
+  N_("Incorrect opcode!")             /* -8 */
+};
 
-  fd = ggzmod_get_server_fd (mod);
+static GtkWidget *ggzbox;
+static GGZMod    *ggzmod;
+static int fd;
+static int seats[2];
 
-  // Read the fd
-  if (ggz_read_int (fd, &op) < 0) {
-    ggz_error_msg ("Couldn't read the game fd");
-    return FALSE;
-  }
+int    seat;
+guint player_id;
+char names[2][17];
 
-  switch (op) {
-  case RVR_MSG_SEAT:
-    get_seat ();
-    break;
-  case RVR_MSG_PLAYERS:
-    get_players ();
-    /*game.state = RVR_STATE_WAIT; */
-    break;
-  case RVR_MSG_SYNC:
-    get_sync ();
-    init_new_game ();
-    break;
-  case RVR_MSG_START:
-    /*state = RVR_STATE_PLAYING; */
-    ggz_debug ("main", "Game has started");
-    init_new_game ();
-    break;
-  case RVR_MSG_MOVE:
-    get_move ();
-    break;
-  case RVR_MSG_GAMEOVER:
-    get_gameover ();
-    /*game.state = RVR_STATE_DONE; */
-    break;
-  default:
-    ggz_error_msg ("Incorrect opcode\n");
-    break;
-  }
+extern GtkWidget *window;
+extern GtkWidget *notebook;
+extern gboolean  game_in_progress;
+extern gboolean  ggz_network_mode;
+extern gint8 pixmaps[8][8];
+extern gint8 board[8][8];
 
-  return TRUE;
+extern guint whose_turn;
+extern gint8 move_count;
+extern gint bcount;
+extern gint wcount;
+
+static void
+gui_error (int err)
+{
+  if (err > RVR_ERROR_OPCODE)
+    gui_message ((gchar *) strs[-err - 1]);
 }
 
-
-
-
-int
+static int
 get_seat (void)
 {
-
   if (ggz_read_int (fd, &seat) < 0)
-    return -1;
+    return RVR_ERROR_CANTREAD;
 
-  if (seat == 0) {
-    gui_message (_("Waiting for an opponent to join the game."));
-  }
-
   player_id = SEAT2PLAYER (seat);
 
-  return 0;
+  return SERVER_OK;
 }
 
-int
+static int
 get_players (void)
 {
   int i;
 
   for (i = 0; i < 2; i++) {
     if (ggz_read_int (fd, &seats[i]) < 0)
-      return -1;
+      return RVR_ERROR_CANTREAD;
 
     if (seats[i] != GGZ_SEAT_OPEN) {
       if (ggz_read_string (fd, (char *) &names[i], 17) < 0)
-	return -1;
+        return RVR_ERROR_CANTREAD;
+     } else {
+      gui_message ((gchar *) strs[-RVR_ERROR_NOTPLAYING - 1]);
     }
   }
-
-  return 0;
-
+  return SERVER_OK;
 }
 
-int
-get_gameover ()
+static int
+get_gameover (void)
 {
   int winner;
 
   if (ggz_read_int (fd, &winner) < 0)
-    return -1;
+    return RVR_ERROR_CANTREAD;
 
-  return 1;
-
+  return SERVER_OK;
 }
 
-// Get the move from the server and makes it (don't check for validity!!)
-int
+static int
 get_move (void)
 {
-  int move;
+  int yx;
 
-  if (ggz_read_int (fd, &move) < 0)
-    return -1;
+  if (ggz_read_int (fd, &yx) < 0)
+    return RVR_ERROR_CANTREAD;
+  if (yx == RVR_ERROR_CANTMOVE)
+    return SERVER_OK;
+  if (yx == RVR_ERROR_NOTPLAYING)
+    game_in_progress = FALSE;
+  if (yx < 0)
+    return yx;
 
-  if (move == RVR_ERROR_CANTMOVE) {
-    return 1;
-  }
+  if (!is_valid_move (yx % 8, yx / 8, whose_turn))
+    return RVR_ERROR_INVALIDMOVE;
 
-  if (move < 0) {
-    return -1;
-  }
-  game_make_move (move);
+  move (yx % 8, yx / 8, whose_turn);
 
-  return 0;
-
+  return SERVER_OK;
 }
 
-// make the move
-void
-game_make_move (int pos)
+static int
+get_sync (void)
 {
-  int x = X (pos) - 1, y = Y (pos) - 1;
+  int who, yx, i = 0;
+  guint kifu[61][2];
 
-  // iagno move
-  move (x, y, whose_turn);
+  // Get kifu
+  do {
+    if (ggz_read_int (fd, &who) < 0 || ggz_read_int (fd, &yx) < 0)
+      return RVR_ERROR_CANTREAD;
+    kifu[i][0] = who;
+    kifu[i++][1] = yx;
+  }  while (who) ;
 
-  return;
+  // Auto recovery
+  init ();
+  move_count = 4;
+  bcount = wcount = 2;
+   
+  i = 0;
+  while (kifu[i][0]) {
+    whose_turn = ((kifu[i][0] == BLACK)? BLACK_TURN: WHITE_TURN);
+    move_board (kifu[i++][1]);
+  }
+  whose_turn = ((kifu[i][1] == BLACK)? BLACK_TURN: WHITE_TURN);
 
+  board_copy ();
+  memcpy (pixmaps, board, sizeof (gint8) * 8 * 8);
+  redraw_board ();
+  return SERVER_OK;
 }
 
-
-
-void
-send_my_move (int move, guint turn)
+static int
+get_start (void)
 {
-  if (ggz_write_int (fd, RVR_REQ_MOVE) < 0 || ggz_write_int (fd, move) < 0) {
-    gui_message ("Can't send move!");
-    return;
-  }
-
-  ggz_debug ("main", "Sent move: %d", move);
+  game_in_progress = TRUE;
+  gui_status ();
+  check_valid_moves ();
+  return SERVER_OK;
 }
 
-int
-request_sync (void)
+static int
+get_init (void)
 {
-  if (ggz_write_int (fd, RVR_REQ_SYNC) < 0) {
-    // Not that someone would check this return value, but...
-    return -1;
-  } else {
-    gui_message ("Requesting sync from the server");
-  }
-  return 0;
+  init ();
+  move_count = 4;
+  bcount = wcount = 2;
+  whose_turn = BLACK_TURN;
+  board_copy ();
+  memcpy (pixmaps, board, sizeof (gint8) * 8 * 8);
+  redraw_board ();
+  gui_status ();
+  game_in_progress = FALSE;
+  return SERVER_OK;
 }
 
-int
-get_sync (void)
+
+static int
+game_handle_io (GGZMod *mod)
 {
-/* FIXME: Not supported yet. */
-  return 0;
-}
+  int err, op = -1;
 
+  fd = ggzmod_get_server_fd (mod);
 
+  // Read the fd
+  if (ggz_read_int (fd, &op) < 0) {
+    gui_error (RVR_ERROR_CANTREAD);
+    return FALSE;
+  }
 
+  switch (op) {
+  case RVR_MSG_SEAT:                        /* 0 */
+    err = get_seat ();
+    break;
+  case RVR_MSG_PLAYERS:                     /* 1 */
+    err = get_players ();
+    break;
+  case RVR_MSG_MOVE:                        /* 2 */
+    err = get_move ();
+    break;
+  case RVR_MSG_GAMEOVER:                    /* 3 */
+    err = get_gameover ();
+    break;
+  case RVR_MSG_START:                       /* 5 */
+    err = get_start ();
+    break;
+  case RVR_MSG_SYNC:                        /* 6 */
+    err = get_sync ();
+    break;
+  case RVR_MSG_INIT:                        /* 7 */
+    err = get_init ();
+  default:
+    err = RVR_ERROR_OPCODE;
+    break;
+  }
+  if (err < 0)
+    gui_error (err);
 
+  return TRUE;
+}
+
 static gboolean
-handle_ggzmod (GIOChannel * channel, GIOCondition cond, gpointer data)
+handle_ggzmod (GIOChannel *channel, GIOCondition cond, gpointer data)
 {
   GGZMod *mod = data;
 
@@ -209,7 +250,8 @@
 }
 
 static gboolean
-handle_game_server (GIOChannel * channel, GIOCondition cond, gpointer data)
+handle_game_server (GIOChannel *channel, GIOCondition cond,
+                    gpointer data)
 {
   GGZMod *mod = data;
 
@@ -217,7 +259,7 @@
 }
 
 static void
-handle_ggzmod_server (GGZMod * mod, GGZModEvent e, const void *data)
+handle_ggzmod_server (GGZMod *mod, GGZModEvent e, const void *data)
 {
   const int *fd = data;
   GIOChannel *channel;
@@ -227,13 +269,34 @@
   g_io_add_watch (channel, G_IO_IN, handle_game_server, mod);
 }
 
+void
+network_init (void)
+{
+  GIOChannel *channel;
+
+  if (!ggzmod_is_ggz_mode ())
+    return;
+
+  ggzmod = ggzmod_new (GGZMOD_GAME);
+  ggzmod_set_handler (ggzmod, GGZMOD_EVENT_SERVER,
+                      handle_ggzmod_server);
+  if (ggzmod_connect (ggzmod) != 0)
+    return;
+
+  channel = g_io_channel_unix_new (ggzmod_get_fd (ggzmod));
+  g_io_add_watch (channel, G_IO_IN, handle_ggzmod, ggzmod);
+
+  init_player_list (ggzmod);
+  init_chat (ggzmod);
+}
+
 /****************************************************************************
   Callback function that's called by the library when a connection is
   established (or lost) to the GGZ server.  The server parameter gives
   the server (or NULL).
 ****************************************************************************/
 static void
-ggz_connected (GGZServer * server)
+ggz_connected (GGZServer *server)
 {
   /* Nothing useful to do... */
 }
@@ -247,8 +310,9 @@
 ggz_game_launched (void)
 {
   network_init ();
+
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
   init_new_game ();
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
 }
 
 /****************************************************************************
@@ -257,66 +321,60 @@
 static void
 ggz_closed (void)
 {
+  ggzmod_disconnect (ggzmod);
+  ggzmod_free (ggzmod);
+
+  gtk_widget_destroy (ggzbox);
   gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
+
   ggz_network_mode = FALSE;
-  init_new_game ();
+  init_new_game();
 }
 
 void
-network_init (void)
+on_network_game (void)
 {
-  GGZMod *mod;
-  GIOChannel *channel;
-  int ret, ggzmodfd;
+  struct passwd *pwent;  
 
-  if (!ggzmod_is_ggz_mode ())
+  if (ggz_network_mode)
     return;
+  
+  init_new_game();
   ggz_network_mode = TRUE;
 
-  mod = ggzmod_new (GGZMOD_GAME);
-  ggzmod_set_handler (mod, GGZMOD_EVENT_SERVER, handle_ggzmod_server);
+  ggz_gtk_initialize (FALSE,
+                      ggz_connected, ggz_game_launched, ggz_closed,
+                      NETWORK_ENGINE, NETWORK_VERSION, "iagno.xml",
+                      "GGZ Gaming Zone");
 
-  ret = ggzmod_connect (mod);
-  if (ret != 0) {
-    /* Error: GGZ core client error (e.g. faked GGZMODE env variable) */
-    return;
-  }
+  pwent = getpwuid(getuid());
+  ggz_embed_ensure_server ("GGZ Gaming Zone", "games.gnome.org",
+                           5688, pwent->pw_name);
 
-  ggzmodfd = ggzmod_get_fd (mod);
-  channel = g_io_channel_unix_new (ggzmodfd);
-  g_io_add_watch (channel, G_IO_IN, handle_ggzmod, mod);
+  ggzbox = ggz_gtk_create_main_area (window);
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), ggzbox, NULL);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook),
+                                 NETWORK_PAGE);
+  gtk_widget_show (ggzbox);
+}
 
-  init_player_list (mod);
-  init_chat (mod);
-
+void
+on_again_activate (void)
+{
+  if (ggz_write_int (fd, RVR_REQ_AGAIN) < 0)
+    return gui_error (RVR_ERROR_CANTWRITE);
 }
 
 void
-on_network_game (void)
+send_my_move (guint move, guint turn)
 {
-  GtkWidget *ggzbox;
-  struct passwd *pwent;  
+  if (turn != player_id)
+    return gui_error (RVR_ERROR_WRONGTURN);
+  if (ggz_write_int (fd, RVR_REQ_MOVE) < 0
+      || ggz_write_int (fd, move) < 0)
+    return gui_error (RVR_ERROR_CANTWRITE);
 
+  ggz_debug ("main", "Sent move: %d", move);
+}
 
-  if (ggz_network_mode) {
-    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
-    return;
-  }
 
-  init_new_game ();
-  ggz_network_mode = TRUE;
-
-  ggz_gtk_initialize (FALSE,
-		      ggz_connected, ggz_game_launched, ggz_closed,
-		      NETWORK_ENGINE, NETWORK_VERSION, "iagno.xml",
-		      "GGZ Gaming Zone");
-
-  pwent = getpwuid(getuid());
-
-  ggz_embed_ensure_server ("GGZ Gaming Zone", "gnome.ggzgamingzone.org",
-			   5688, pwent->pw_name);
-
-  ggzbox = ggz_gtk_create_main_area (window);
-  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), ggzbox, NULL);
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
-}
Index: iagno/ggz-network.h
===================================================================
--- iagno/ggz-network.h	(リビジョン 6478)
+++ iagno/ggz-network.h	(作業コピー)
@@ -16,185 +16,57 @@
  * USA
  */
 
-#define EMPTY  0
+/* PROTOCOL VERSION 2 */
 
-/* REVERSI PROTOCOL VERSION 0.0.5
- *
- * The server handles everything, from the AI to the validity of moves
- *
- * RVR_STATE_INIT:
- *
- * First, it fetchs from the ggz_server how much seats there are, and how much are open/closed
- *
- * RVR_STATE_JOIN:
- *
- * Then, it waits until some player join . When he does, it sends:
- *
- * To Joining player:
- * 	RVR_MSG_SEAT (int)SEAT_NUM
- * To All Human players:
- * 	RVR_MSG_PLAYERS PLAYER_IDENTIFER[BLACK] PLAYER_IDENTIFIER[WHITE]
- *  where PLAYER_IDENTIFIER is:
- *  	(int)PLAYER_TYPE
- *  	if PLAYER_TYPE == GGZ_SEAT_OPEN
- *  		(str)PLAYER_NAME
- *
- * If the game was already happening, send the current game state to the new player
- *
- * 	RVR_MSG_SYNC (char)TURN BOARD_STATE
- * 	where TURN is the current turn, and:
- * 		BOARD_STATE = (char)POSITION * 64
- *
- * When all the open seats are filled, it enters playing state (state = RVR_STATE_PLAYING) and sends:
- *
- * To All Human players:
- * 	RVR_MSG_START
- *
- * RVR_STATE_PLAYING:
- *
- * If current player is AI:
- *
- * 	doMove(AI_MOVE());
- *
- * If it isn't AI, then it waits until client sends a RVR_REQ_MOVE
- *
- * When client sends a RVR_REQ_MOVE, the server must check if he is the current player and
- * if the move is valid. (The client should do it too, must the server must recheck to avoid cheating)
- * Then the server executes the move, and sends:
- * 
- * To All Human players:
- *
- *	RVR_MSG_MOVE (int)MOVE
- * 	where MOVE can be a array index (0-63) or one of the following error values:
- * 		RVR_ERROR_WRONGTURN
- * 			The player tried to move when it wasn't his turn
- * 		RVR_ERROR_INVALIDMOVE
- * 			The player tried a invalid move (Cheating sign!)
- *
- * Then the server checks if the game is over (No more valid moves) and who has won. If the game is over,
- * it sends to All Human players:
- *
- * 	RVR_MSG_GAMEOVER (int)WINNER
- * 		where WINNER can be: BLACK, WHITE, EMPTY(draw)
- *
- * If some player left while the game was happening, it sends to all Human players:
- *
- * 	RVR_MSG_PLAYERS
- *
- * And it will wait until someone returns
- *
- * The client:
- *
- * game_init():
- * - Init variables and set the turn to BLACK (first turn) and the state to init
- *
- * RVR_MSG_SEAT
- * - Store his seat on a safe variable
- *
- * RVR_MSG_PLAYERS
- * - Store (and display) the name of the players
- * - Set the state to wait
- *
- * RVR_MSG_START
- * - Set the state to playing
- *
- * RVR_MSG_SYNC
- * - Believes what the server says and updates everything
- *
- * RVR_MSG_MOVE
- * - Do the move
- *
- * RVR_MSG_GAMEOVER
- * - Display ending message
- * 
- * And sends to the server:
- *
- * RVR_REQ_MOVE
- * - Ask to move
- *
- * RVR_REQ_SYNC
- * - Ask for sync
- *
- * RVR_REQ_AGAIN
- * - Ask for playing again
- *
- * Luckily that's all, this protocol is perfect and it shouldn't be modified anymore. Or so I hope. :) */
+#define RVR_MSG_SEAT       0
+#define RVR_MSG_PLAYERS    1
+#define RVR_MSG_MOVE       2
+#define RVR_MSG_GAMEOVER   3
+#define RVR_REQ_MOVE       4
+#define RVR_MSG_START      5
+#define RVR_MSG_SYNC       6
+#define RVR_MSG_INIT       7
+#define RVR_REQ_AGAIN      8
 
-// Reversi protocol
-// The numbers aren't on order, because I used the same constants from TicTacToe - simplify testing
-
-#include "gnothello.h"
-
-#define RVR_MSG_SEAT 0
-#define RVR_MSG_PLAYERS 1
-#define RVR_MSG_SYNC 6
-#define RVR_REQ_SYNC 7
-#define RVR_REQ_AGAIN 8
-#define RVR_MSG_START 5
-#define RVR_MSG_MOVE 2
-#define RVR_MSG_GAMEOVER 3
-#define RVR_REQ_MOVE 4
-
 // States
-#define RVR_STATE_INIT 0
-#define RVR_STATE_WAIT 1
-#define RVR_STATE_PLAYING 2
-#define RVR_STATE_DONE 3
+#define RVR_STATE_INIT     0
+#define RVR_STATE_WAITING  1
+#define RVR_STATE_PLAYING  2
+#define RVR_STATE_DONE     3
 
-// Responses from server
-#define RVR_SERVER_ERROR -1
-#define RVR_SERVER_OK 0
-#define RVR_SERVER_JOIN 1
-#define RVR_SERVER_LEFT 2
-#define RVR_SERVER_QUIT 3
-
 // Errors
+#define GAME_OVER              1
+#define SERVER_OK              0
 #define RVR_ERROR_INVALIDMOVE -1
-#define RVR_ERROR_WRONGTURN -2
-#define RVR_ERROR_CANTMOVE -3
+#define RVR_ERROR_WRONGTURN   -2
+#define RVR_ERROR_CANTMOVE    -3
+#define RVR_ERROR_CANTREAD    -4
+#define RVR_ERROR_CANTWRITE   -5
+#define RVR_ERROR_NOTPLAYING  -6
+#define RVR_ERROR_PLAYAGAIN   -7
+#define RVR_ERROR_OPCODE      -8
 
+#define NETWORK_ENGINE 	 "Iagno"
+#define NETWORK_VERSION 	 "1"
+
 // Takes cartesian coordinates and transform them into a array index
 #define CART(X,Y) ( (Y-1)*8+(X-1) )
 
-// Takes a index and transform it in cartesians coordinates
-#define X(I) ( (I%8)+1 )
-#define Y(I) ( (I/8)+1 )
-
-// See what's the value at that place (like a 10x10 board)
-#define GET(X,Y) ( (X==0 || Y==0 || X>8 || Y>8) ? EMPTY : game.board[CART(X,Y)] )
-
 // Takes a seat and transform into a player code
-#define SEAT2PLAYER(seat) ( (seat==0)?BLACK_TURN:WHITE_TURN )
+#define SEAT2PLAYER(seat)  ((seat == 0)? BLACK_TURN: WHITE_TURN)
 
 // Takes a player code and transform into a seat index
-#define PLAYER2SEAT(player) ( (player==BLACK_TURN)?0:1 )
+#define PLAYER2SEAT(player)  ((player == BLACK_TURN)? 0: 1)
 
-#define NETWORK_ENGINE "Iagno"
-#define NETWORK_VERSION "1"
+// For the compatibility with the old protocol.
+#define OLD2NEW(yx)  (yx / 8 + 1) * 10 + (yx % 8) + 1
+#define NEW2OLD(yx)  (yx / 10 - 1) * 8 + (yx % 10 - 1)
 
 void network_init (void);
+
 void on_network_game (void);
 
-int fd;
+void on_again_activate (void);
 
-// Setup functions
-void game_init (void);
+void send_my_move (guint move, guint turn);
 
-// Get stuff from server
-int get_seat (void);
-int get_players (void);
-int get_gameover (void);
-int get_sync (void);
-int get_move (void);
-int get_gameover (void);
-
-// Send stuff to server
-void send_my_move (int move, guint turn);
-int request_sync (void);
-
-// Game functions
-void game_make_move (int);
-void game_mark_board (int, int, int, int, int);
-int game_check_direction (int, int, int, int, int);
-int game_check_move (int, int);
-void game_update_scores (void);
Index: iagno/gnothello.c
===================================================================
--- iagno/gnothello.c	(リビジョン 6478)
+++ iagno/gnothello.c	(作業コピー)
@@ -34,8 +34,11 @@
 #ifdef GGZ_CLIENT
 #include <games-dlg-chat.h>
 #include <games-dlg-players.h>
+#include <ggz-embed.h>
 #include "ggz-network.h"
-#include <ggz-embed.h>
+extern int     seat;
+extern guint  player_id;
+extern char  names[2][17];
 #endif
 
 #include "gnothello.h"
@@ -188,6 +191,10 @@
 void
 new_game_cb (GtkWidget * widget, gpointer data)
 {
+#ifdef GGZ_CLIENT
+  if (ggz_network_mode)
+    return on_again_activate ();
+#endif
   init_new_game ();
 }
 
@@ -534,7 +541,7 @@
   return TRUE;
 }
 
-static void
+void
 redraw_board (void)
 {
   guint i, j;
@@ -700,7 +707,6 @@
   undo_set_sensitive (move_count > 0);
 
   if (ggz_network_mode) {
-    gtk_widget_hide (game_menu[0].widget);
     gtk_widget_hide (game_menu[1].widget);
     gtk_widget_hide (game_menu[2].widget);
     gtk_widget_hide (game_menu[3].widget);
@@ -708,7 +714,6 @@
     gtk_widget_show (game_menu[5].widget);
     gtk_widget_show (game_menu[7].widget);
   } else {
-    gtk_widget_show (game_menu[0].widget);
     gtk_widget_show (game_menu[1].widget);
     gtk_widget_show (game_menu[2].widget);
     gtk_widget_show (game_menu[3].widget);
