Index: iagno/gnothello.h
===================================================================
--- iagno/gnothello.h	(リビジョン 7688)
+++ iagno/gnothello.h	(作業コピー)
@@ -1,6 +1,7 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
 /*
  * gnothello.h - Header for gnothello.c
- * written by Ian Peters <itp@gnu.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -14,74 +15,181 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
  *
  * For more details see the file COPYING.
  */
 
-#ifndef _GNOTHELLO_H_
-#define _GNOTHELLO_H_
 
-#define BLACK_TURN 1
-#define WHITE_TURN 31
-#define PIXMAP_FLIP_DELAY 20
-#define PIXMAP_STAGGER_DELAY 3
-#define COMPUTER_MOVE_DELAY 1000
+#define APP_NAME                "iagno"
+#define APP_NAME_LONG           N_("Iagno")
 
-#define OTHER_PLAYER(w) (((w) == WHITE_TURN) ? BLACK_TURN : WHITE_TURN)
+#define DEFAULT_TILESET         "sun_and_star.svg"
+#define DEFAULT_BGCOLOR         "#000066660000"
 
-#define TILEWIDTH   80
-#define TILEHEIGHT  80
-#define GRIDWIDTH   1
-#define BOARDWIDTH  ((TILEWIDTH+GRIDWIDTH)  * 8)
-#define BOARDHEIGHT ((TILEHEIGHT+GRIDWIDTH) * 8)
+#define DEFAULT_WINDOW_W        336
+#define DEFAULT_WINDOW_H        340
+#define BOARD_MIN               263
+#define GRID_WIDTH              1
 
-#define MAIN_PAGE           	0
-#define NETWORK_PAGE           	1
+#define PIXMAP_FLIP_DELAY       16
 
-gboolean ggz_network_mode;
-int player_id;
-int seat;
-int seats[2];
-char names[2][17];
+#define MAIN_PAGE               0
+#define NETWORK_PAGE            1
 
-extern GtkWidget *notebook;
-extern GtkWidget *window;
+// Takes a seat and transform into a player code
+#define SEAT2PLAYER(seat)       ((seat == 0)? BLACK: WHITE)
 
-void new_game_cb (GtkWidget * widget, gpointer data);
-void new_network_game_cb (GtkWidget * widget, gpointer data);
-void on_network_leave (GObject * object, gpointer data);
-void on_player_list (void);
-void on_chat_window (void);
-void quit_game_cb (GtkWidget * widget, gpointer data);
-void undo_move_cb (GtkWidget * widget, gpointer data);
-void redo_move_cb (GtkWidget * widget, gpointer data);
-void about_cb (GtkWidget * widget, gpointer data);
-void comp_black_cb (GtkWidget * widget, gpointer data);
-void comp_white_cb (GtkWidget * widget, gpointer data);
-void quick_moves_cb (GtkWidget * widget, gpointer data);
-void anim_cb (GtkWidget * widget, gpointer data);
-void anim_stagger_cb (GtkWidget * widget, gpointer data);
-void load_tiles_cb (GtkWidget * widget, gpointer data);
-void set_selection (GtkWidget * widget, void *data);
-void free_str (GtkWidget * widget, void *data);
-void load_tiles_callback (GtkWidget * widget, void *data);
-void cancel (GtkWidget * widget, void *data);
-gint expose_event (GtkWidget * widget, GdkEventExpose * event);
-gint configure_event (GtkWidget * widget, GdkEventConfigure * event);
-gint button_press_event (GtkWidget * widget, GdkEventButton * event);
-void gui_draw_pixmap (gint which, gint x, gint y);
-void gui_draw_pixmap_buffer (gint which, gint x, gint y);
-gint flip_pixmaps (gpointer data);
-void init_new_game (void);
-void clear_board (void);
-void create_window (void);
-void gui_status (void);
-void gui_message (gchar * message);
-guint check_computer_players (void);
-void load_pixmaps (void);
-void properties_cb (GtkWidget * widget, gpointer data);
+// Takes a player code and transform into a seat index
+#define PLAYER2SEAT(player)     ((player == BLACK)? 0: 1)
+
+
+// GtkWidget
+#define WINDOW          0
+#define MENUBAR         1
+#define STATUSBAR       2
+#define COUNTER         3
+#define BLACK_SCORE     4
+#define WHITE_SCORE     5
+#define BLACK_TIME      6
+#define WHITE_TIME      7
+#define NOTEBOOK        8
+#define VPANED          9
+#define BOARD           10
+#define TOOLBAR         11
+#define TIMER           12
+#define KEYBOARD        13
+#define PROPERTIES      14
+#define FILE_DIALOG     15
+
+#ifdef GGZ_CLIENT
+#define GGZBOX          16
+#define HPANED          17
+#define PLAYERLIST      18
+#define CHAT            19
+#define MAX_WIDGET      20
+#else
+#define MAX_WIDGET      16
+#endif
+
+// Actions;
+#define NEWGAME         0
+#define HEAD            1
+#define BACK            2
+#define FORWARD         3
+#define LAST            4
+#define FULLSCREEN      5
+#define UNFULLSCREEN    6
+#define SAVE            7
+#define OPEN            8
+#define HINT            9
+
+#ifdef GGZ_CLIENT
+#define NETWORK         10
+#define LEAVE           11
+#define MAX_ACTIONS     12
+#else
+#define MAX_ACTIONS     10
+#endif
+
+// Game options
+#define MAX_OPTIONS 9
+
+typedef enum {
+  Fast_Moves             = 1 << 0,
+  Sound                  = 1 << 1,
+  Final_Results          = 1 << 2,
+  Valid_Squares          = 1 << 3,
+  Last_Move_Mark         = 1 << 4,
+  ToolBar                = 1 << 5,
+  Timer                  = 1 << 6,
+  Keyboard               = 1 << 7,
+  FullScreen             = 1 << 8
+} GameOptions;
+
+// Game state
+typedef enum {
+  GAME_PROGRESS          = 0,
+  GAME_W_INPUT           = 1,
+  GAME_W_CONECT          = 1 << 1,
+  GAME_BACK              = 1 << 2,
+  GAME_DONE              = 1 << 3,
+  GAME_STOP              = 1 << 4,
+} GameState;
+
+// Game flags
+typedef enum {
+  CHECK_SOUNDS           = 1,
+  GAMEOVER_SOUND         = 1 << 1,
+  FLIP_PIXMAPS           = 1 << 2,
+  FLIP_FINAL_RESULTS     = 1 << 3,
+  CHECK_COMPUTER_PLAYERS = 1 << 4,
+  COMPUTER_MOVE          = 1 << 5,
+  CHECK_HINT             = 1 << 6,
+  GUI_HINT               = 1 << 7
+} GameFlags;
+
+// Game Kifu
+typedef struct {
+  gint8 who;
+  gint8 yx;
+} GameKifu;
+
+// Game window
+typedef struct {
+  gint  width;
+  gint  height;
+  gint  xpos;
+  gint  ypos;
+} GameWindow;
+
+// Game board
+typedef struct {
+  gint8 array[8][8];
+  gint  width;
+  gint  height;
+} GameBoard;
+
+// Game tile
+typedef struct {
+  GdkPixmap *pixmap;
+  gchar     *name;
+  gint      width;
+  gint      height;
+} GameTile;
+
+// Game pixmap
+typedef struct {
+  GdkPixmap *buffer;
+  gint8     array[8][8];
+} GamePixmap;
+
+
 void set_bg_color (void);
+
+void load_tiles (void);
+
 void gui_draw_grid (void);
 
-#endif
+void gui_message (gchar *message);
+
+void copy_board (void);
+
+void gui_redraw_board (void);
+
+gboolean check_flags (gpointer data);
+
+void check_game_over (void);
+
+gboolean check_valid_move (gint yx);
+
+void game_move (gint yx);
+
+void game_stop (void);
+
+void game_init (void);
+
+void game_start (void);
+
+void network_gui_update (void);
Index: iagno/properties.h
===================================================================
--- iagno/properties.h	(リビジョン 7688)
+++ iagno/properties.h	(作業コピー)
@@ -1,7 +1,41 @@
-#ifndef _PROPERTIES_H_
-#define _PROPERTIES_H_
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
 
-void load_properties (void);
-void show_properties_dialog (void);
+/*
+ * properties.h - Header for properties.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
+ *
+ * For more details see the file COPYING.
+ */
 
-#endif
+
+void properties_load (void);
+
+void properties_save (void);
+
+void properties_reset (void);
+
+void properties_apply_changes (void);
+
+void on_properties_cancel_clicked (GtkButton *button, gpointer user_data);
+
+void on_properties_activate (GtkMenuItem *menuitem, gpointer user_data);
+
+/**** File open & file save ****/
+
+void on_save_activate (GtkMenuItem *menuitem, gpointer user_data);
+
+void on_open_activate (GtkMenuItem *menuitem, gpointer user_data);
Index: iagno/server.c
===================================================================
--- iagno/server.c	(リビジョン 7688)
+++ 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
@@ -20,618 +22,480 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
+ *
+ * For more details see the file COPYING.
  */
 
-#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 <config.h>
 
 #include "server.h"
+#include "othello.h"
 
+
+#define COMPUTER_LEVEL          5
+
+
 // Global game variables
-struct rvr_game_t rvr_game;
+static GGZdMod *ggz;
+static int     state;
+static struct Kifu {
+  gint8 who;
+  gint8 yx;
+}              kifu[MAX_MOVE_COUNT + 1];
 
+extern Othello othello;
 
-// 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));
-}
 
-// 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 int
+game_make_move (int player, int yx);
 
-  // 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 (new_state == GGZDMOD_STATE_PLAYING) {
-    // Game already going on?
-    if (rvr_game.turn == EMPTY)
-      rvr_game.turn = BLACK;
+static void
+log_error (GGZdMod *ggzdmod, int err)
+{
+ 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 */
+  };
 
-    // No! Let's start the game!
-    game_start ();
-    game_play ();
-  }
+  if (err < RVR_ERROR_OPCODE)
+    err = RVR_ERROR_OPCODE;
+  ggzdmod_log (ggzdmod, strs[-err - 1]);
+}
 
-  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");
-  }
+// Initializes everything
+static void
+game_init (GGZdMod *ggzdmod)
+{
+  othello_init ();
+// othello.count = 4; othello.black = othello.white = 2; othello.turn = BLACK;
+  ggz         = ggzdmod;
+  kifu[4].who = 0;
+  state       = RVR_STATE_INIT;
 }
 
-
 static int
-seats_full (void)
+game_check_bot (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;
-}
+  int seat = PLAYER2SEAT (othello.turn);
 
+  // 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;
 
+  // Yes! Wait for a second.
+  sleep (1);
+  return game_make_move ((int) othello.turn,
+                         (int) computer_move (COMPUTER_LEVEL));
+}
+
 static int
-seats_empty (void)
+game_skip_move (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;
-}
+  int seat, fd;
 
+  // Send a RVR_ERROR_CANTMOVE 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_MOVE) < 0
+                   || ggz_write_int (fd, RVR_ERROR_CANTMOVE) < 0))
+      return RVR_ERROR_CANTWRITE;
+  }
 
-void
-game_handle_ggz_seat (GGZdMod * ggz, GGZdModEvent event, const void *data)
+  return game_check_bot ();
+}
+
+static int
+game_check_over (void)
 {
-  const GGZSeat *old_seat = data;
-  GGZSeat new_seat = ggzdmod_get_seat (ggz, old_seat->num);
-  GGZdModState new_state;
+  int seat, fd, winner;
+  GGZGameResult results[2];
 
-  /* 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;
+  // Continue?
+  if (entry_valid_squares (0))
+    return game_check_bot ();
+  // Skip move?
+  othello.turn = OTHER_PLAYER (othello.turn);
+  if (entry_valid_squares (0))
+    return game_skip_move ();
+  // The game is over.
+  if (othello.black > othello.white) {
+    results[PLAYER2SEAT (BLACK)] = GGZ_GAME_WIN;
+    results[PLAYER2SEAT (WHITE)] = GGZ_GAME_LOSS;
+    winner = BLACK;
+  } else if (othello.white > othello.black) {
+    results[PLAYER2SEAT (WHITE)] = GGZ_GAME_WIN;
+    results[PLAYER2SEAT (BLACK)] = GGZ_GAME_LOSS;
+    winner = WHITE;
+  } else {
+    winner = 0;
+    results[0] = results[1] = GGZ_GAME_TIE;
+  }
 
-  // That's great!! Do stuff
+  // Report game to GGZ.
+  ggzdmod_report_game (ggz, NULL, results, NULL);
 
-  if (new_seat.type == GGZ_SEAT_PLAYER)
-    game_send_seat (new_seat.num);
-  game_send_players ();
+  // Send a RVR_MSG_GAMEOVER 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;;
+  }
 
-  if (new_state == GGZDMOD_STATE_PLAYING && rvr_game.turn != EMPTY)
-    game_send_sync (new_seat.num);
+  // Ends everything.
+  game_init (ggz);
+  state = RVR_STATE_DONE;
+  othello.turn = 0;
+  // Puts human players score = 0 and bots score = 1.
+  othello.black = othello.white = 0;
+  if (ggzdmod_get_seat (ggz, PLAYER2SEAT (BLACK)).type == GGZ_SEAT_BOT)
+    othello.black = 1;
+  if (ggzdmod_get_seat (ggz, PLAYER2SEAT (WHITE)).type == GGZ_SEAT_BOT)
+    othello.white = 1;
+  ggzdmod_log (ggz, "Game is over. Waiting to see if we should play again\n");
 
-  ggzdmod_set_state (ggz, new_state);
+  return SERVER_OK;
 }
 
-
-int
-game_send_seat (int seat)
+static int
+game_start (void)
 {
-  int fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd;
+  int seat, fd;
 
-  ggzdmod_log (rvr_game.ggz, "Sending player %d's his seat number\n", seat);
+  // Start game.
+  state = RVR_STATE_PLAYING;
 
-  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;
+  for (seat = 0; seat < ggzdmod_get_num_seats (ggz); seat++) {
+    fd = ggzdmod_get_seat (ggz, seat).fd;
+    // Send a RVR_MSG_START message.
+    if (fd != -1 && ggz_write_int (fd, RVR_MSG_START) < 0)
+      return RVR_ERROR_CANTWRITE;
   }
 
-  return 0;
+  ggzdmod_log (ggz, "Game has started!\n");
+  return game_check_over ();
 }
 
-int
-game_send_players (void)
+static int
+game_check_move (int player, int yx)
 {
-  int i, j, fd;
+  // Check if it's right time.
+  if (state != RVR_STATE_PLAYING)
+    return RVR_ERROR_NOTPLAYING;
+  // Check if it's his turn.
+  if (player != (int) othello.turn)
+    return RVR_ERROR_WRONGTURN;
+  // Check if out of bounds.
+  if (yx < 11 || yx > 88)
+    return RVR_ERROR_INVALIDMOVE;
+  // Check if duplicated.
+  if (othello.board[yx] != EMPTY)
+    return RVR_ERROR_INVALIDMOVE;
+  // Check if valid yx.
+  if (!othello_check_valid ((gint) player, (gint) yx)) 
+    return RVR_ERROR_INVALIDMOVE;
 
-  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);
+  return yx;
+}
 
-    if (ggz_write_int (fd, RVR_MSG_PLAYERS) < 0) {
-      ggzdmod_log (rvr_game.ggz, "Can't send player list!\n");
-      return -1;
-    }
+static int
+game_make_move (int player, int yx)
+{
+  int seat, fd;
 
-    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;
-      }
-    }
+  kifu[othello.count].who = (gint8) player;
+  kifu[othello.count].yx  = (gint8) yx;
+  othello_move ((gint) yx);
+  kifu[othello.count].who = 0;
+
+  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;
   }
 
-  return 0;
+  // Check if the game is over.
+  return game_check_over ();
 }
 
-int
+static int
 game_send_sync (int seat)
 {
-  int i, fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd;
+  int fd = ggzdmod_get_seat (ggz, seat).fd;
+  int i = 4;
 
-  ggzdmod_log (rvr_game.ggz, "Handling sync for player %d", seat);
+  ggzdmod_log (ggz, "Handling sync for player %d", seat);
 
-  // Send SYNC message and current turn
+  // Send a RVR_MSG_SYNC message.
+  if (ggz_write_int (fd, RVR_MSG_SYNC) < 0)
+    return RVR_ERROR_CANTWRITE;
+  // Send kifu.
+  while (kifu[i].who) {
+    if (ggz_write_int (fd, (int) kifu[i].who) < 0
+       || ggz_write_int (fd, (int) kifu[i++].yx) < 0)
+      return RVR_ERROR_CANTWRITE;
+  }
+  // Send a end mark and current turn.
+  // For the compatibility with the old protocol,
+  // the old client is waiting for the seat, so send a dummy seat.
+  if (ggz_write_int (fd, 0) < 0 || ggz_write_int (fd, (int) othello.turn) < 0)
+    return RVR_ERROR_CANTWRITE;
 
-  if (ggz_write_int (fd, RVR_MSG_SYNC) < 0
-      || ggz_write_char (fd, rvr_game.turn) < 0)
-    return -1;
+  // That's fine.
+  return SERVER_OK;
+}
 
-  // Send current board state
+static int
+game_handle_move (int seat)
+{
+  int yx, fd = ggzdmod_get_seat (ggz, seat).fd;
 
-  for (i = 0; i < 64; i++) {
-    if (ggz_write_char (fd, rvr_game.board[i]) < 0)
-      return -1;
-  }
+  // Get the yx from the message.
+  if (ggz_read_int (fd, &yx) < 0)
+    return RVR_ERROR_CANTREAD;
 
-  // That's fine
+  ggzdmod_log (ggz, "Handling move %d, for player %d\n", yx, seat);
 
-  return 0;
+  // Check if it's valid.
+  yx = game_check_move (SEAT2PLAYER (seat), OLD2NEW (yx));
+  if (yx > 0)
+    // Make move if it's valid (also sends it to everyone).
+    return game_make_move (SEAT2PLAYER (seat), yx);
 
+  // If invalid yx, sends sync and error status to the player.
+  if (game_send_sync (seat) < 0)
+    return RVR_ERROR_CANTWRITE;
+  if (ggz_write_int (fd, RVR_MSG_MOVE) < 0 || ggz_write_int (fd, yx) < 0)
+    return RVR_ERROR_CANTWRITE;
+
+  return SERVER_OK;
 }
 
-int
-game_start (void)
+// Puts human players score = 0,
+// When they send a RVR_REQ_AGAIN message, put it = 1,
+// When everyone score = 1, then starts it all again.
+static int
+game_play_again (int seat, int fd)
 {
+  ggzdmod_log (ggz, "%d wants to play again!\n", seat);
 
-  int i, fd;
+  // Check if the game was over.
+  if (othello.turn) {
+    // Send a RVR_ERROR_PLAYAGAIN message.
+    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;
+  }
 
-  // Start game variables
-  rvr_game.state = RVR_STATE_PLAYING;
+  // Send a RVR_MSG_INIT message.
+  if (fd != -1 && ggz_write_int (fd, RVR_MSG_INIT) < 0)
+    return RVR_ERROR_CANTWRITE;
 
-  // 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;
+  if (SEAT2PLAYER (seat) == WHITE)
+    othello.white = 1;
+  else if (SEAT2PLAYER (seat) == BLACK)
+    othello.black = 1;
+
+  if (!(othello.black * othello.white)) {
+    state = RVR_STATE_WAITING;
+    return SERVER_OK;
   }
 
-  ggzdmod_log (rvr_game.ggz, "Game has started!\n");
-
-  return 0;
+  // Starts again.
+  othello.black = othello.white = 2;
+  othello.turn = BLACK;
+  return game_start ();
 }
 
-/* return -1 on error, 1 on gameover */
-void
-game_handle_player (GGZdMod * ggz, GGZdModEvent event, const void *data)
+static void
+game_handle_player (GGZdMod *ggzdmod, GGZdModEvent event, const void *data)
 {
   const int *seat_ptr = data;
   const int seat = *seat_ptr;
-  int op, move;
-  int fd = ggzdmod_get_seat (ggz, seat).fd;
+  int op, err;
+  int fd = ggzdmod_get_seat (ggzdmod, seat).fd;
 
   if (ggz_read_int (fd, &op) < 0)
     return;
 
   switch (op) {
-
-  case RVR_REQ_MOVE:
-    game_handle_move (seat, &move);
+  case RVR_REQ_MOVE:                    /* 4 */
+    err = game_handle_move (seat);
     break;
-
-  case RVR_REQ_SYNC:
-    game_send_sync (seat);
+  case RVR_REQ_AGAIN:                   /* 8 */
+    err = game_play_again (seat, fd);
     break;
-
-  case RVR_REQ_AGAIN:
-    game_play_again (seat);
-    break;
-
   default:
-    ggzdmod_log (rvr_game.ggz, "ERROR: unknown player opcode %d.", op);
+    err = RVR_ERROR_OPCODE;
     break;
   }
-}
 
-int
-game_handle_move (int seat, int *move)
-{
-  int fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd, status;
-
-  // Get the move from the message
-  if (ggz_read_int (fd, move) < 0)
-    return -1;
-
-  ggzdmod_log (rvr_game.ggz, "Handling move %d,%dfor player %d\n", X (*move),
-	       Y (*move), seat);
-
-  // Check if it's his turn
-  if (SEAT2PLAYER (seat) != rvr_game.turn) {
-    status = RVR_ERROR_WRONGTURN;
-  } else {
-    // Check if it's valid (status return a negative value if error, the move on sucess)
-    status = game_check_move (SEAT2PLAYER (seat), *move);
-  }
-
-  // Make move if it's valid (also sends it to everyone);
-  game_make_move (SEAT2PLAYER (seat), status);
-
-  return status;
-
+  if (err < 0)
+    log_error (ggzdmod, err);
 }
 
-void
-game_play (void)
+static int
+seats_full (void)
 {
-  int move;
-  int seat = PLAYER2SEAT (rvr_game.turn);
-
-  // 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);
-  }
-  // It's not! Wait until the player sends the message...
-
-  return;
+  /* 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);
 }
 
-int
-game_bot_move (int player)
+static int
+seats_empty (void)
 {
-  int i;
-
-  // 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);
+  /* This calculation is a bit inefficient, but that's OK. */
+  return !ggzdmod_count_seats (ggz, GGZ_SEAT_PLAYER)
+    && !ggzdmod_count_spectators (ggz);
 }
 
-int
-game_check_move (int player, int move)
+static int
+game_send_seat (int seat)
 {
+  int fd = ggzdmod_get_seat (ggz, seat).fd;
 
-  int x = X (move), y = Y (move), status = 0;
+  ggzdmod_log (ggz, "Sending player %d's his seat number\n", seat);
 
-  // Check if it's right time
-  if (rvr_game.state != RVR_STATE_PLAYING)
-    return RVR_ERROR_WRONGTURN;
+  if (ggz_write_int (fd, RVR_MSG_SEAT) < 0 || ggz_write_int (fd, seat) < 0)
+    return RVR_ERROR_CANTWRITE;
 
-  // Check if out of bounds
-  if (move < 0 || move > 63)
-    return RVR_ERROR_INVALIDMOVE;
-
-  // Check if duplicated
-  if (rvr_game.board[move] != EMPTY)
-    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
-    return RVR_ERROR_INVALIDMOVE;
-
+  return SERVER_OK;
 }
 
-int
-game_check_direction (int player, int vx, int vy, int x, int y)
+static int
+game_send_players (void)
 {
-  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 seat, i, fd;
 
-int
-game_make_move (int player, int move)
-{
-  int x = X (move), y = Y (move);
-  int status = 0;
-  int a, fd;
-
-  // 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)
+  for (seat = 0; seat < ggzdmod_get_num_seats (ggz); seat++) {
+    fd = ggzdmod_get_seat (ggz, seat).fd;
+    if (fd == -1) {
+      ggzdmod_log (ggz, "Bot seat\n");
       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;
-  }
 
-  // Check if game is over
-  if (status >= 0 && !game_check_over ()) {
+    ggzdmod_log (ggz, "Sending player list to player %d", seat);
+    if (ggz_write_int (fd, RVR_MSG_PLAYERS) < 0)
+      return RVR_ERROR_CANTWRITE;
 
-    // AI play
-    game_play ();
-
-  }
-  // If couldn`t make the move, sends sync to the player
-  if (status < 0)
-    game_send_sync (PLAYER2SEAT (player));
-
-  return status;
-
-}
-
-int
-game_check_over (void)
-{
-  int i, status = 0;
-
-  // Check if the current player can play
-  for (i = 0; i < 64; i++) {
-    if (game_check_move (rvr_game.turn, i) > 0) {
-      status++;
-      break;
+    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;
     }
   }
 
-  // If he can play, the game is not over
-  if (status > 0)
-    return 0;
-
-  // 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;
-    }
-  }
-
-  // If he can, then skip the players move.
-  // If he can't, end the game
-
-  if (status > 0)
-    game_skip_move ();
-  else {
-    game_gameover ();
-    return 1;
-  }
-
-  return 0;
+  return SERVER_OK;
 }
 
 
-
-
-
-int
-game_mark_board (int player, int vx, int vy, int x, int y)
+static void
+game_handle_ggz_seat (GGZdMod *ggzdmod, GGZdModEvent event, const void *data)
 {
-  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;
-}
+  const GGZSeat *old_seat = data;
+  GGZSeat new_seat = ggzdmod_get_seat (ggzdmod, old_seat->num);
+  GGZdModState new_state;
+  int err = 0;
 
-void
-game_skip_move (void)
-{
-  int seat;
+  // 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;
 
-  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");
-    }
-  }
+  // That's great! Do stuff.
+  // For the compatibility with the old protocol,
+  // game_send_sync should be before game_send_seat.
+  // New sync make for the old client to mistake get_seat.
+  if (new_state == GGZDMOD_STATE_PLAYING && othello.turn)
+    err = game_send_sync (new_seat.num);
 
-  rvr_game.turn *= -1;
+  if (!err && new_seat.type == GGZ_SEAT_PLAYER)
+    err = game_send_seat (new_seat.num);
+  if (!err)
+    err = game_send_players ();
+  if (err < 0)
+    return log_error (ggzdmod, err);
 
-  return;
-
+  ggzdmod_set_state (ggzdmod, new_state);
 }
 
-void
-game_gameover (void)
+// Handle server messages
+static void
+game_handle_ggz_state (GGZdMod *ggzdmod, GGZdModEvent event,
+                     const void *data)
 {
-  int seat, fd, winner;
-  GGZGameResult results[2];
+  GGZdModState new_state = ggzdmod_get_state (ggzdmod);
+  const GGZdModState *old_state_ptr = data;
+  const GGZdModState old_state = *old_state_ptr;
 
-  // Ends everything
-  rvr_game.turn = EMPTY;
-  rvr_game.state = RVR_STATE_DONE;
+  // 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.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;
+  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");
+    return;
   }
 
-  /* Report game to GGZ */
-  ggzdmod_report_game (rvr_game.ggz, NULL, results, NULL);
-
-  // 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");
-  }
-
-  // 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);
-
-  return;
-
-}
-
-int
-game_play_again (int seat)
-{
-  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;
-  }
-
-  if (SEAT2PLAYER (seat) == WHITE)
-    rvr_game.white = 1;
-  else if (SEAT2PLAYER (seat) == BLACK)
-    rvr_game.black = 1;
-
-  if (rvr_game.white && rvr_game.black) {
-    // Starts is again
-    game_init (rvr_game.ggz);
+  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/othello.c
===================================================================
--- iagno/othello.c	(リビジョン 7688)
+++ iagno/othello.c	(作業コピー)
@@ -1,8 +1,7 @@
-/* -*- mode:C; indent-tabs-mode:t; tab-width:4; c-basic-offset:8; -*- */
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
 
 /*
- * othello.c - Othello support routines for iagno
- * written by Ian Peters <itp@gnu.org>
+ * othello.c - AI routines for iagno
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,708 +15,482 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
  *
  * For more details see the file COPYING.
  */
 
-#include <config.h>
 #include <gnome.h>
-#include <string.h>
-#include <games-clock.h>
-#include <games-sound.h>
 
 #include "othello.h"
-#include "gnothello.h"
 
-#define PERFECT   17
-#define VICTORY   19
-#define BEST      56
-#define MAX_DEPTH  7
+#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
 
-#define BLANK 0
-#define OUTSIDE 128
-#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
+static const gint heuristic[] = {
+  0,   0,   0, 0, 0, 0, 0,   0,   0, 0,
+  0, 173, -33, 1, 0, 0, 1, -33, 173, 0,
+  0, -33, -83, 0, 0, 0, 0, -83, -33, 0,
+  0,   1,   0, 0, 0, 0, 0,   0,   1, 0,
+  0,   0,   0, 0, 0, 0, 0,   0,   0, 0,
+  0,   0,   0, 0, 0, 0, 0,   0,   0, 0,
+  0,   1,   0, 0, 0, 0, 0,   0,   1, 0,
+  0, -33, -83, 0, 0, 0, 0, -83, -33, 0,
+  0, 173, -33, 1, 0, 0, 1, -33, 173, 0,
+  0,   0,   0, 0, 0, 0, 0,   0,   0, 0
+};
 
-gint8 squares[64] = { 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,
+static const gint8 squares0[] = {
+  44, 45, 54, 55, 34, 43, 56, 65,
+  35, 46, 53, 64, 33, 36, 63, 66,
+  24, 25, 42, 52, 47, 57, 74, 75, 
+  23, 26, 32, 62, 37, 67, 73, 76,
+  14, 15, 41, 51, 48, 58, 84, 85,
+  13, 16, 31, 61, 38, 68, 83, 86, 
   12, 17, 21, 71, 28, 78, 82, 87,
   22, 27, 72, 77, 11, 18, 81, 88
 };
 
-static const gint heuristic[100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 65, -3, 6, 4, 4, 6, -3, 65, 0,
-  0, -3, -29, 3, 1, 1, 3, -29, -3, 0,
-  0, 6, 3, 5, 3, 3, 5, 3, 6, 0,
-  0, 4, 1, 3, 1, 1, 3, 1, 4, 0,
-  0, 4, 1, 3, 1, 1, 3, 1, 4, 0,
-  0, 6, 3, 5, 3, 3, 5, 3, 6, 0,
-  0, -3, -29, 3, 1, 1, 3, -29, -3, 0,
-  0, 65, -3, 6, 4, 4, 6, -3, 65, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
+static const gint8 dirs[] = { UL, UU, UR, LL, RR, DL, DD, DR };
+static gint8 squares[MAX_MOVE_COUNT];
+// This array can probably be a lot smaller (< 300).
+static gint8 history[MAX_MOVE_COUNT * 12];
+static gint8 *history_pointer;
+static GRand *rgen;
 
-static const gint dirs[] = { UL, UU, UR, LL, RR, DL, DD, DR };
+Othello      othello;
+ValidSquare  valid_squares[(VICTORY + 3) * (VICTORY + 4) / 2];
+gint         sort_of_search;
 
-guint flip_final_id = 0;
-gint flip_final;
-
-gint8 board0[100];
-/* This array can probably be a lot smaller (< 600). However, I am absolutely
- * certain that it cannot be more than 1200. So 1200 is what we use. */
-gint8 history[1200];
-gint hpointer;
-gint vsquares[280][2];
-gint vpointer;
-gint s_kind;
-GRand *rgen;
-
-extern guint black_computer_level;
-extern guint white_computer_level;
-
-extern gint animate;
-extern gint animate_stagger;
-extern guint game_in_progress;
-extern gint8 pixmaps[8][8];
-extern gint8 board[8][8];
-extern gint8 move_count;
-extern guint whose_turn;
-extern gint bcount;
-extern gint wcount;
-
-extern guint tiles_to_flip;
-
-/* Initialization of data */
+// Initialization of data.
 void
-init (void)
+othello_init (void)
 {
-  gint i, j;
-  gint x;
+  guint i, j, ij = 0;
 
   rgen = g_rand_new ();
 
-  x = 0;
-  for (j = 0; j < 10; j++)
-    for (i = 0; i < 10; i++) {
-      if (j == 0 || j == 9)
-	board0[x] = OUTSIDE;
-      else if (i == 0 || i == 9)
-	board0[x] = OUTSIDE;
+  for (i = 0; i < MAX_MOVE_COUNT; i++)
+    squares[i] = squares0[i];
+
+  for (i = 0; i < 10; i++)
+    for (j = 0; j < 10; j++) {
+      if (i == 0 || i == 9 || j == 0 || j == 9)
+        othello.board[ij++] = OUTSIDE;
       else
-	board0[x] = BLANK;
-      x++;
+        othello.board[ij++] = EMPTY;
     }
+  othello.board[44] = WHITE;
+  othello.board[45] = BLACK;
+  othello.board[54] = BLACK;
+  othello.board[55] = WHITE;
 
-  board0[44] = WHITE_TURN;
-  board0[45] = BLACK_TURN;
-  board0[54] = BLACK_TURN;
-  board0[55] = WHITE_TURN;
-
-  hpointer = 0;
-  vpointer = 0;
+  othello.count     = 4;
+  othello.turn      = BLACK;
+  othello.black     = 2;
+  othello.white     = 2;
+  history_pointer   = &history[0];
 }
 
-/* Copy data from board0 to board */
-void
-board_copy (void)
+// Check the validity of the move in a given direction.
+static gboolean
+othello_check_valid0 (gint8 who, gint8 yx, gint8 dir)
 {
-  gint i, j;
+  gint8 tmp    = yx + dir;
+  gint8 not_me = OTHER_PLAYER (who);
 
-  for (j = 0; j < 8; j++)
-    for (i = 0; i < 8; i++)
-      board[i][j] = board0[(j + 1) * 10 + i + 1];
-}
-
-/* Check the validity of the move in a given direction. */
-static
-  gint
-is_valid0 (gint xy, gint dir, gint who)
-{
-  gint tmp;
-  gint8 not_me;
-
-  not_me = OTHER_PLAYER (who);
-
-  /* To be valid, the next counter should not be the current player ... */
-  tmp = xy + dir;
-  if (board0[tmp] != not_me)
+  // To be valid, the next counter should be another player ..
+  if (othello.board[tmp] != not_me)
     return FALSE;
-
-  /* ... but eventually we must find a counter that is. */
+  // ... but eventually we must find a counter that is.
   do {
     tmp += dir;
-  } while (board0[tmp] == not_me);
+  } while (othello.board[tmp] == not_me);
 
-  return board0[tmp] == who;
+  return othello.board[tmp] == who;
 }
 
-/* Check if a given (empty) square can provide a valid move */
-static
-  gint
-is_valid (gint xy, gint who)
+// Check if a given (empty) square can provide a valid move.
+gboolean
+othello_check_valid (gint who, gint yx)
 {
-  int i;
+  gint8 i;
 
   for (i = 0; i < NDIRS; i++)
-    if (is_valid0 (xy, dirs[i], who))
-      return (TRUE);
+    if (othello_check_valid0 ((gint8) who, (gint8) yx, dirs[i]))
+      return TRUE;
 
   return FALSE;
 }
 
-/* Check whether the supplied move is a valid one. */
-gint
-is_valid_move (guint x, guint y, guint who)
+static void
+othello_move0 (gint8 yx, gint8 dir)
 {
-  gint xy;
+  gint8 tmp    = yx + dir;
+  gint8 not_me = OTHER_PLAYER (othello.turn);
 
-  xy = (y + 1) * 10 + x + 1;
-  if (board0[xy] != BLANK)
-    return FALSE;
-
-  return is_valid (xy, who);
-}
-
-static
-  void
-move_board0 (gint xy, gint dir)
-{
-  gint8 tmp;
-  guint not_me;
-
-  not_me = OTHER_PLAYER (whose_turn);
-  tmp = xy + dir;
-  if (board0[tmp] != not_me)
+  if (othello.board[tmp] != not_me)
     return;
-  /* Find the extent of the move in direction dir. */
+  // Find the extent of the move in direction dir.
   do {
     tmp += dir;
-  } while (board0[tmp] == not_me);
-  if (board0[tmp] != whose_turn)
-    return;
+  } while (othello.board[tmp] == not_me);
 
-  /* Now walk back to where we started flipping pieces over. */
+  if (othello.board[tmp] != othello.turn)
+    return;
+  // Now walk back to where we started flipping pieces over.
   tmp -= dir;
-  while (tmp != xy) {
-    board0[tmp] = whose_turn;	/* Flip pieces */
-    history[hpointer++] = tmp;	/* Record history */
-    tmp -= dir;
+  while (tmp != yx) {
+    othello.board[tmp] = othello.turn;  // Reverse this piece.
+    *history_pointer++ = tmp;           // Record this square.
+    tmp               -= dir;
   }
 }
 
-/* reverse some pieces */
+// Reverse some pieces.
 void
-move_board (gint xy)
+othello_move (gint yx)
 {
-  gint tmp, count;
-  int i;
+  gint8 i, count, tmp, *p_tmp;
 
-  count = hpointer;
+  p_tmp = history_pointer;
+  for (i = 0; i < NDIRS; i++)           // Reverse some pieces.
+    othello_move0 ((gint8) yx, dirs[i]);
 
-  for (i = 0; i < NDIRS; i++)
-    move_board0 (xy, dirs[i]);
+  count              = (gint8) (history_pointer - p_tmp) / sizeof (gint8);
+  *history_pointer++ = count;           // history[f1,f2,,,fn,n,who]
+  *history_pointer++ = othello.turn;
+  othello.board[yx]  = othello.turn;    // Set new piece.
 
-  board0[xy] = whose_turn;
-  count = hpointer - count;
-  history[hpointer++] = count;	/* make history */
-  history[hpointer++] = whose_turn;
-
-  if (whose_turn == WHITE_TURN) {
-    wcount += count + 1;
-    bcount -= count;
+  if (othello.turn == WHITE) {          // Set new scores.
+    othello.white += count + 1;
+    othello.black -= count;
   } else {
-    bcount += count + 1;
-    wcount -= count;
+    othello.black += count + 1;
+    othello.white -= count;
   }
-  tmp = squares[move_count];
-  squares[move_count++] = xy;
-  if (tmp != xy) {
-    count = move_count;
-    while (squares[count] != xy)
-      count++;
-    squares[count] = tmp;
-  }
-  whose_turn = OTHER_PLAYER (whose_turn);
-}
 
+  othello.turn = OTHER_PLAYER (othello.turn); // Set new turn.
 
-gint
-move (guint x, guint y, guint me)
-{
-  gint tmp;
-
-  tmp = (gint) ((y + 1) * 10 + x + 1);
-  if (board0[tmp] != BLANK)
-    return FALSE;
-  if (!is_valid (tmp, whose_turn))
-    return FALSE;
-  move_board (tmp);
-  board_copy ();
-
-  pixmaps[x][y] = (gint8) me;
-  gui_draw_pixmap (me, x, y);
-
-  gui_status ();
-
-  tiles_to_flip = 1;
-  check_valid_moves ();
-  check_computer_players ();
-
-  games_sound_play ("flip-piece");
-
-  return FALSE;
+  i = othello.count++;                  // Increase othello.count.
+  tmp = squares[i];                     // squares[0,1,2,,,,othello.count,,,62,63]
+  squares[i] = (gint8) yx;              //   [<-already filled->|<-yet empty->]
+  if (tmp != (gint8) yx) {              // Sort squares.
+    while (squares[++i] != (gint8) yx)
+      ;
+    squares[i] = tmp;
+  }
 }
 
-/* Back to before board0 */
+// Back to the one previous othello.board.
 void
-undo (void)
+othello_back (void)
 {
   gint8 not_me, count;
 
-  whose_turn = history[--hpointer];	/* history[t1,t2,,,tn, n,who] */
-  count = history[--hpointer];
+  othello.turn = *--history_pointer;      // Set new turn.
+  count        = *--history_pointer;      // history[f1,f2,,,fn,n,who]
 
-  if (whose_turn == WHITE_TURN) {
-    wcount -= count + 1;
-    bcount += count;
+  if (othello.turn == WHITE) {            // Set new scores
+    othello.white -= count + 1;
+    othello.black += count;
   } else {
-    bcount -= count + 1;
-    wcount += count;
+    othello.black -= count + 1;
+    othello.white += count;
   }
+                                                   // Decrease othello.count
+  othello.board[squares[--othello.count]] = EMPTY; // and remove the last piece.
 
-  board0[squares[--move_count]] = BLANK;	/* decrease move_count    */
-
-  not_me = OTHER_PLAYER (whose_turn);
-  while (count > 0) {
-    board0[history[--hpointer]] = not_me;
-    count--;
-  }
+  not_me = OTHER_PLAYER (othello.turn);
+  while (count-- > 0)
+    othello.board[*--history_pointer] = not_me; // Reverse some pieces.
 }
 
-/* Sort vsquares by small order */
-static
-  void
-sort (gint l, gint r)
+static gint
+mobility (gint who)
 {
-  gint i, j, v, w, x;
-
-  i = l;
-  j = r;
-  x = vsquares[(l + r) / 2][1];
-  do {
-    while (vsquares[i][1] < x)
-      i++;
-    while (x < vsquares[j][1])
-      j--;
-    if (i < j) {
-      v = vsquares[i][0];
-      w = vsquares[i][1];
-      vsquares[i][0] = vsquares[j][0];
-      vsquares[i][1] = vsquares[j][1];
-      vsquares[j][0] = v;
-      vsquares[j][1] = w;
-    }
-    if (i <= j) {
-      i++;
-      j--;
-    }
-  } while (i <= j);
-
-  if (l < j)
-    sort (l, j);
-  if (i < r)
-    sort (i, r);
-}
-
-static
-  gint
-eval_heuristic (void)
-{
-  gint8 i, xy;
+  gint8 i;
   gint count = 0;
 
-  for (i = 0; i < move_count; i++) {
-    xy = squares[i];
-    count = (board0[xy] == whose_turn) ?
-      count + heuristic[xy] : count - heuristic[xy];
+  for (i = othello.count; i < MAX_MOVE_COUNT; i++) {
+    if (othello_check_valid (who, (gint) squares[i]))
+      count++;
   }
 
   return count;
 }
 
-static
-  gint
-mobility (void)
+static gint
+around0 (gint8 yx)
 {
-  gint8 i, xy;
+  gint8 i;
   gint count = 0;
 
-  for (i = move_count; i < 64; i++) {
-    xy = squares[i];
-    if (is_valid (xy, whose_turn))
-      count++;
-  }
+  for (i = 0; i < NDIRS; i++)
+    if (othello.board[yx + dirs[i]] == EMPTY)
+      count--;
 
   return count;
 }
 
-static
-  gint
-around0 (gint xy)
+static gint
+around (void)
 {
+  gint8 i, yx;
   gint count = 0;
-  int i;
 
-  for (i = 0; i < NDIRS; i++)
-    if (board0[xy + dirs[i]] == BLANK)
-      count--;
+  for (i = 0; i < othello.count; i++) {
+    yx = squares[i];
+    if (othello.board[yx] == othello.turn)
+      count += around0 (yx);
+    else
+      count -= around0 (yx);
+  }
 
-  if (!count)
-    count = 2;
-
   return count;
 }
 
-static
-  gint
-around (void)
+static gint
+evaluate_heuristic (void)
 {
-  gint8 i, xy;
+  gint8 i, yx;
   gint count = 0;
 
-  for (i = 0; i < move_count; i++) {
-    xy = squares[i];
-    count = (board0[xy] == whose_turn) ?
-      count + around0 ((gint) xy) : count - around0 ((gint) xy);
+  for (i = 0; i < othello.count; i++) {
+    yx = squares[i];
+    if (othello.board[yx] == othello.turn)
+      count += heuristic[yx];
+    else
+      count -= heuristic[yx];
   }
 
   return count;
 }
 
-/* Evaluate the board   */
-static
-  gint
-b_evaluation (void)
+static gint
+best_evaluation (void)
 {
-  gint score1, score2, score3;
+  gint score1, score2, score3, score4;
 
-  score1 = mobility ();
-  whose_turn = OTHER_PLAYER (whose_turn);
-  score1 -= mobility ();
-  whose_turn = OTHER_PLAYER (whose_turn);
-
+  score1 = mobility ((gint) othello.turn)
+           - mobility ((gint) OTHER_PLAYER (othello.turn));
   score2 = around ();
-  score3 = eval_heuristic ();
+  score3 = (othello.turn == BLACK) ? (gint) (othello.white - othello.black) :
+            (gint) (othello.black - othello.white);
+  score4 = evaluate_heuristic ();
 
-  return score1 + score2 + score3;
+  return score1 * 8 + score2 + score3 / 2 + score4 / 2;
 }
 
-/* Victory evaluation */
-static
-  gint
-v_evaluation (void)
+// For the best search.
+static gint
+win_evaluation (void)
 {
   gint aa;
 
-  aa = wcount - bcount;
-  if (whose_turn == BLACK_TURN)
+  aa = (gint) (othello.black - othello.white);
+  if (othello.turn == WHITE)
     aa = -aa;
 
+  if (!othello.black || !othello.white) {
+    if (aa > 0)
+      return aa + 10000;
+    return aa - 10000;
+  }
+
   if (aa > 0)
-    return 1;			/* win  */
+    return aa + 1000;
   if (aa < 0)
-    return -1;			/* lose */
-  return 0;			/* draw */
-}
+    return aa - 1000;
 
-static
-  gint
-p_evaluation (void)
-{
-
-  if (whose_turn == WHITE_TURN)
-    return wcount - bcount;
-
-  return bcount - wcount;
+  return 0;
 }
 
-static
-  gint
-w_evaluation (void)
+static gint
+victory_evaluation (void)
 {
-  gint aa;
+  gint8 aa;
 
-  if (!bcount || !wcount) {
-    if (whose_turn == WHITE_TURN && !bcount)
-      return 10000;
-    if (whose_turn == BLACK_TURN && !wcount)
-      return 10000;
-    return -10000;
-  }
-
-  aa = wcount - bcount;
-  if (whose_turn == BLACK_TURN)
+  aa = othello.black - othello.white;
+  if (othello.turn == WHITE)
     aa = -aa;
 
   if (aa > 0)
-    return aa + 100;
+    return 1;                   // Win
   if (aa < 0)
-    return aa - 100;
-  return (0);
+    return -1;                  // Lose
+
+  return 0;                     // Draw
 }
 
-/* alpha-beta search */
-static
-  gint
-search (gint n, gint a, gint b)
+static gint
+perfect_evaluation (void)
 {
-  gint aa, bb, xy, i, j;
+  if (othello.turn == BLACK)
+    return (gint) (othello.black - othello.white);
 
-  if (!n) {
-    switch (s_kind) {
-    case PERFECT:
-      return (p_evaluation ());
-    case VICTORY:
-      return (v_evaluation ());
-    default:
-      return (b_evaluation ());
-    }
+  return (gint) (othello.white - othello.black);
+}
+
+gint
+entry_valid_squares (gint pointer)
+{
+  gint j = pointer;
+  gint8 i, yx;
+
+  for (i = othello.count; i < MAX_MOVE_COUNT; i++) {
+    yx = squares[i];
+    if (othello_check_valid ((gint) othello.turn, (gint) yx))
+      valid_squares[++j].square = yx;
   }
 
-  aa = a;
+  return j;
+}
 
-  j = vpointer;
-  for (i = (gint) move_count; i < 64; i++) {	/* entry valid squares */
-    xy = (gint) squares[i];
-    if (is_valid (xy, whose_turn)) {
-      vsquares[++j][0] = xy;
-      move_board (xy);
-      vsquares[j][1] = mobility ();
-      undo ();
+// Sort valid_squares by small order.
+static void
+sort (gint l, gint r)
+{
+  gint i, j, v, x;
+  gint8 w;
+
+  i = l;
+  j = r;
+  x = valid_squares[(l + r) / 2].evaluation;
+
+  do {
+    while (valid_squares[i].evaluation < x)
+      i++;
+    while (x < valid_squares[j].evaluation)
+      j--;
+    if (i < j) {
+      v = valid_squares[i].evaluation;
+      w = valid_squares[i].square;
+      valid_squares[i].evaluation = valid_squares[j].evaluation;
+      valid_squares[i].square     = valid_squares[j].square;
+      valid_squares[j].evaluation = v;
+      valid_squares[j].square     = w;
     }
+    if (i <= j) {
+      i++;
+      j--;
+    }
   }
+  while (i <= j);
 
-  if (j == vpointer) {		/* pass ?  */
-    whose_turn = (whose_turn == WHITE_TURN) ? BLACK_TURN : WHITE_TURN;
-    if (!mobility ()) {
-      whose_turn = OTHER_PLAYER (whose_turn);
+  if (l < j)
+    sort (l, j);
+  if (i < r)
+    sort (i, r);
+}
 
-      switch (s_kind) {
+// Alpha-beta search
+static gint
+search (gint n, gint a, gint b, gint pointer)
+{
+  gint i, j, aa, bb;
+
+  if (!n) {                                     // Did we reach a search end?
+    switch (sort_of_search) {
       case PERFECT:
-	return (p_evaluation ());
+        return perfect_evaluation ();
       case VICTORY:
-	return (v_evaluation ());
+        return victory_evaluation ();
       default:
-	return (w_evaluation ());
+        return best_evaluation ();
+    }
+  }
+
+  j = entry_valid_squares (pointer);
+  if (j == pointer) {                           // Is the game over?
+    othello.turn = OTHER_PLAYER (othello.turn);
+    if (!mobility ((gint) othello.turn)) {
+      othello.turn = OTHER_PLAYER (othello.turn);
+      switch (sort_of_search) {
+        case PERFECT:
+          return perfect_evaluation ();
+        case VICTORY:
+          return victory_evaluation ();
+        default:
+          return win_evaluation ();
       }
     }
-    aa = -search (n, -b, -aa);
-    whose_turn = OTHER_PLAYER (whose_turn);
-    vsquares[j][0] = 0;		/* mark pass              */
+
+    aa = -search (n, -b, -a, pointer);          // Skip move.
+    othello.turn = OTHER_PLAYER (othello.turn);
+    valid_squares[pointer].square = 0;          // Mark pass.
     return aa;
   }
 
-  sort (vpointer + 1, j);
+  for (i = j; i > pointer; i--) {               // Continue search.
+    othello_move ((gint) valid_squares[i].square); // Simple evaluation
+    valid_squares[i].evaluation = mobility ((gint) othello.turn);
+    othello_back ();
+  }                                             // i = pointer;
+  sort (i + 1, j);                              // Sort valid_squares.
 
-  i = vpointer;			/* save old vpointer      */
-  vpointer = j + 1;		/* new vpointer           */
-
-  j = i + 1;
-  while (aa < b && j < vpointer) {
-    xy = vsquares[j][0];
-    move_board (xy);
-    bb = -search (n - 1, -b, -aa);	/* evaluate this square  */
-    undo ();
-    if (aa < bb) {
+  aa = a;
+  j++;                                          // New pointer
+  while (aa < b && ++i < j) {                   // Evaluate squares.
+    othello_move ((gint) valid_squares[i].square);
+    bb = -search (n - 1, -b, -aa, j);
+    othello_back ();
+    if (bb > aa) {                              // Save this square.
       aa = bb;
-      vsquares[i][0] = xy;	/* save this square       */
+      valid_squares[pointer].square = valid_squares[i].square;
     }
-    j++;
   }
-  vpointer = i;			/* pop vpointer           */
+
   return aa;
 }
 
-static
-  void
+// For the first several turns.
+static gint
 random_select (void)
 {
-  gint xy, i, j;
+  gint j = entry_valid_squares (0);
+  gint i = g_rand_int_range (rgen, 1, j + 1);
 
-  vsquares[0][0] = 0;
-  j = 0;
-  for (i = move_count; i < 64; i++) {
-    xy = squares[i];
-    if (is_valid (xy, whose_turn))
-      vsquares[j++][0] = xy;
-  }
-  if (j) {
-    i = g_rand_int_range (rgen, 0, j);
-    vsquares[0][0] = vsquares[i][0];
-  }
-}
+  if (heuristic[valid_squares[i].square] < 0)   // If the square is critical,
+    i = g_rand_int_range (rgen, 1, j + 1);      // then select once more. 
 
-static
-  gint
-computer_move (gint level)
-{
-  gint nn, aa, kind, best_xy;
-
-  vsquares[0][0] = -1;
-  nn = 64 - move_count;
-  if (nn > BEST)
-    random_select ();
-  else {
-    if (nn <= PERFECT - level) {
-      kind = PERFECT;
-      aa = 127;
-    }
-    if (PERFECT - level < nn && nn <= VICTORY - level) {
-      kind = VICTORY;
-      aa = 2;
-    }
-    if (VICTORY - level < nn && nn <= BEST) {
-      kind = BEST;
-      aa = 32767;
-      nn = MAX_DEPTH - level;
-    }
-    s_kind = kind;
-    vsquares[0][1] = search (nn, -aa, aa);
-  }
-
-  best_xy = vsquares[0][0];
-
-  if (best_xy == -1) {		/* If I can't win, then search the best again. */
-    s_kind = BEST;
-    vsquares[0][1] = search (MAX_DEPTH - level, -32767, 32767);
-    best_xy = vsquares[0][0];
-  }
-
-  if (best_xy)
-    move (best_xy % 10 - 1, best_xy / 10 - 1, whose_turn);
-
-  return FALSE;
+  valid_squares[0].square = valid_squares[i].square;
+  return 0;
 }
 
 gint
-computer_move_1 (guint me)
+computer_move (gint level)
 {
-  return computer_move (6);
-}
+  gint nn = (gint) (MAX_MOVE_COUNT - othello.count);
 
-gint
-computer_move_2 (guint me)
-{
-  return computer_move (4);
-}
-
-gint
-computer_move_3 (guint me)
-{
-  return computer_move (2);
-}
-
-gint
-computer_move_4 (guint me)
-{
-  return computer_move (0);
-}
-
-gboolean
-flip_final_results (gpointer data)
-{
-  guint i;
-  guint white_pieces;
-  guint black_pieces;
-  guint adder = 0;
-
-  white_pieces = wcount;
-  black_pieces = bcount;
-
-  i = 0;
-  for (; i < black_pieces; i++) {
-    board[i % 8][i / 8] = BLACK_TURN;
-    if (pixmaps[i % 8][i / 8] < 1)
-      pixmaps[i % 8][i / 8] = WHITE_TURN;
-    if (pixmaps[i % 8][i / 8] == WHITE_TURN) {
-      pixmaps[i % 8][i / 8] += adder;
-      if (animate_stagger)
-	adder++;
+  if (nn <= PERFECT - MAX_DEPTH + level) {
+    sort_of_search = PERFECT;
+    valid_squares[0].evaluation = search (nn, -127, 127, 0);
+  } else if (nn <= VICTORY - MAX_DEPTH + level) {
+    sort_of_search = VICTORY;
+    valid_squares[0].evaluation = search (nn, -1, 1, 0);
+    if (valid_squares[0].evaluation == -1) {    // If the computer can't win,
+      sort_of_search = BEST;                    // then search the best again.
+      valid_squares[0].evaluation = search (level + 2, -32767, 32767, 0);
     }
+  } else if (nn <= BEST2 - MAX_DEPTH + level) {
+    sort_of_search = BEST;
+    valid_squares[0].evaluation = search (level + 2, -32767, 32767, 0);
+  } else if (nn <= BEST - (MAX_DEPTH - 2 - level) / 2) {
+    sort_of_search = BEST;
+    valid_squares[0].evaluation = search (level, -32767, 32767, 0);
+  } else {
+    sort_of_search = RANDOM;
+    valid_squares[0].evaluation = random_select ();
   }
-  for (; i < 64 - white_pieces; i++) {
-    board[i % 8][i / 8] = 0;
-    pixmaps[i % 8][i / 8] = 100;
-  }
-  for (; i < 64; i++) {
-    board[i % 8][i / 8] = WHITE_TURN;
-    if (pixmaps[i % 8][i / 8] == 0)
-      pixmaps[i % 8][i / 8] = BLACK_TURN;
-    if (pixmaps[i % 8][i / 8] == BLACK_TURN) {
-      pixmaps[i % 8][i / 8] -= adder;
-      if (animate_stagger)
-	adder++;
-    }
-  }
 
-  tiles_to_flip = 1;
-
-  return FALSE;
+  return (gint) valid_squares[0].square;
 }
-
-gint
-check_valid_moves (void)
-{
-  guint white_moves = 0;
-  guint black_moves = 0;
-
-  if (!game_in_progress)
-    return TRUE;
-  if (mobility ())
-    return TRUE;
-
-  whose_turn = OTHER_PLAYER (whose_turn);
-
-  if (!mobility ()) {
-    white_moves = wcount;
-    black_moves = bcount;
-    if (white_moves > black_moves)
-      gui_message (_("Light player wins!"));
-    if (black_moves > white_moves)
-      gui_message (_("Dark player wins!"));
-    if (white_moves == black_moves)
-      gui_message (_("The game was a draw."));
-    whose_turn = 0;
-    game_in_progress = 0;
-    if (flip_final)
-      flip_final_id = g_timeout_add (100, flip_final_results, NULL);
-
-    games_sound_play ("gameover");
-
-    return TRUE;
-  }
-
-  if (whose_turn == BLACK_TURN) {
-    gui_message (_("Light must pass, Dark's move"));
-    return TRUE;
-  }
-
-  if (whose_turn == WHITE_TURN) {
-    gui_message (_("Dark must pass, Light's move"));
-    return TRUE;
-  }
-
-  return TRUE;
-}
Index: iagno/server.h
===================================================================
--- iagno/server.h	(リビジョン 7688)
+++ iagno/server.h	(作業コピー)
@@ -1,5 +1,7 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
 /*
- * File: game.h
+ * File: server.h
  * Author: Ismael Orenstein
  * Project: GGZ Reversi game module
  * Date: 09/17/2000
@@ -20,214 +22,48 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
+ *
+ * For more details see the file COPYING.
  */
 
-#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 RVR_ERROR_INVALIDMOVE -1
-#define RVR_ERROR_WRONGTURN -2
-#define RVR_ERROR_CANTMOVE -3
+#define SERVER_OK               0
+#define RVR_ERROR_INVALIDMOVE   -1
+#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/othello.h
===================================================================
--- iagno/othello.h	(リビジョン 7688)
+++ iagno/othello.h	(作業コピー)
@@ -1,6 +1,7 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
 /*
  * othello.h - Header for othello.c
- * written by Ian Peters <itp@gnu.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -14,25 +15,52 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
  *
  * For more details see the file COPYING.
  */
 
-#ifndef _OTHELLO_H_
-#define _OTHELLO_H_
+#define BLACK                   49
+#define WHITE                   79
+#define EMPTY                   1
+#define OUTSIDE                 127
 
-gint is_valid_move (guint, guint, guint);
-gint move (guint, guint, guint);
-void move_board (gint);
-gboolean flip_final_results (gpointer data);
-gint check_valid_moves (void);
-gint computer_move_1 (guint);
-gint computer_move_2 (guint);
-gint computer_move_3 (guint);
-gint computer_move_4 (guint);
-void init (void);
-void board_copy (void);
-void undo (void);
+#define OTHER_PLAYER(who)       (128 - who)
 
-#endif
+#define PERFECT                 20
+#define VICTORY                 23
+#define BEST2                   32
+#define BEST                    56
+#define RANDOM                  60
+#define MAX_DEPTH               10
+#define MAX_MOVE_COUNT          64
+
+// Othello
+typedef struct {
+  gint8 board[100];
+  gint8 count;
+  gint8 turn;
+  gint8 black;
+  gint8 white;
+} Othello;
+
+// Valid square
+typedef struct {
+  gint8 square;
+  gint  evaluation;
+} ValidSquare;
+
+
+void othello_init (void);
+
+gboolean othello_check_valid (gint who, gint yx);
+
+void othello_move (gint yx);
+
+void othello_back (void);
+
+gint entry_valid_squares (gint pointer);
+
+gint computer_move (gint level);
+
Index: iagno/ggz-network.c
===================================================================
--- iagno/ggz-network.c	(リビジョン 7688)
+++ iagno/ggz-network.c	(作業コピー)
@@ -1,11 +1,14 @@
-/* ggz-network.c
+/* -*- 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>
+ * Copyright (C) 2006 - 2007 -  Andreas Røsdal <andrearo@pvv.ntnu.no>
  *
- * This game is free software; you can redistribute it and/or modify
+ * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,11 +17,12 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
  * USA
+ *
+ * For more details see the file COPYING.
  */
 
-#include "config.h"
 #include <gnome.h>
 #include <pwd.h>
 
@@ -26,182 +30,237 @@
 #include <ggz-embed.h>
 #include <ggz-gtk.h>
 
-#include "games-dlg-chat.h"
-#include "games-dlg-players.h"
+#include <config.h>
+#include <games-dlg-chat.h>
+#include <games-dlg-players.h>
 
+#include "othello.h"
 #include "gnothello.h"
 #include "ggz-network.h"
-#include "othello.h"
 
-guint whose_turn = BLACK_TURN;
 
-static gboolean
-game_handle_io (GGZMod * mod)
-{
-  int op = -1;
+static GGZMod     *ggzmod;
+static int        fd;
+static int        seats[2];
+static int        seat;
+static char       names[2][17];
+static gboolean   old = FALSE;
 
-  fd = ggzmod_get_server_fd (mod);
+extern GList      *focusable_widgets;
+extern GtkWidget  *widget[];
+extern GameKifu   kifu[];
+extern GameState  state;
+extern gboolean   ggz_network_mode;
+extern gint8      player_id;
 
-  // Read the fd
-  if (ggz_read_int (fd, &op) < 0) {
-    ggz_error_msg ("Couldn't read the game fd");
-    return FALSE;
-  }
+extern Othello    othello;
 
-  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;
-  }
 
-  return TRUE;
+static void
+gui_error (int err)
+{
+const gchar *strs[] = {
+  _("Invalid move."),                   /* -1 */
+  _("Not your turn!"),                  /* -2 */
+  _("Skip move!"),                      /* -3 */
+  _("Can't read message!"),             /* -4 */
+  _("Can't send message!"),             /* -5 */
+  _("Waiting for an opponent to join the game."), /* -6 */
+  _("The game wasn`t over yet!"),       /* -7 */
+  _("Incorrect opcode!")                /* -8 */
+};
+
+  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;
+  player_id = (gint8) SEAT2PLAYER (seat);
+  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;
-    }
+    if (seats[i] != GGZ_SEAT_OPEN
+        && ggz_read_string (fd, (char *) &names[i], 17) < 0)
+      return RVR_ERROR_CANTREAD;
   }
-
-  return 0;
-
+  return SERVER_OK;
 }
 
-int
-get_gameover ()
+static int
+gui_turn (void)
 {
-  int winner;
-
-  if (ggz_read_int (fd, &winner) < 0)
-    return -1;
-
-  return 1;
-
+  if (othello.turn == OTHER_PLAYER(player_id)) {
+    gui_message (g_strdup_printf (_("Waiting for %s to move"),
+                                  names[1 - seat]));
+    state = GAME_W_INPUT;
+  } else if (othello.turn == BLACK) {
+    gui_message (_("It is your turn to place a dark piece"));
+    state = GAME_PROGRESS;
+  } else if (othello.turn == WHITE) {
+    gui_message (_("It is your turn to place a light piece"));
+    state = GAME_PROGRESS;
+  }
+  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 (move == RVR_ERROR_CANTMOVE) {
-    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_stop();
+    state |= GAME_W_CONECT;
   }
+  if (yx == RVR_ERROR_INVALIDMOVE)
+    check_game_over ();
+  if (yx < 0)
+    return yx;
 
-  if (move < 0) {
-    return -1;
-  }
-  game_make_move (move);
+  yx = OLD2NEW (yx);
+  if (!check_valid_move ((gint) yx))
+    return RVR_ERROR_INVALIDMOVE;
 
-  return 0;
-
+  game_move((gint) yx);
+  return gui_turn ();
 }
 
-// make the move
-void
-game_make_move (int pos)
+static int
+get_gameover (void)
 {
-  int x = X (pos) - 1, y = Y (pos) - 1;
+  int winner;
 
-  // iagno move
-  move (x, y, whose_turn);
+  if (ggz_read_int (fd, &winner) < 0)
+    return RVR_ERROR_CANTREAD;
+  // For the compatibility with the old protocol.
+  if (winner == -1 || winner == 1) {
+    old = TRUE;
+    winner = ((winner == -1) ? BLACK : WHITE);
+  }
 
-  return;
+  if (winner)
+    gui_message (g_strdup_printf
+                 (_("%s wins!"), names[PLAYER2SEAT (winner)]));
+  else
+    gui_message (_("The game was a draw."));
 
+  state = GAME_STOP | GAME_DONE;
+  return SERVER_OK;
 }
 
+static int
+get_start (void)
+{
+  // For the compatibility with the old protocol. 
+  if (old)
+    game_init();
+  ggz_debug ("main", "Game has started");
+  game_start();
+  return gui_turn ();
+}
 
+static int
+get_sync (void)
+{
+  int who, yx, i = 4;
 
-void
-send_my_move (int move, guint turn)
-{
-  if (ggz_write_int (fd, RVR_REQ_MOVE) < 0 || ggz_write_int (fd, move) < 0) {
-    gui_message ("Can't send move!");
-    return;
+  game_stop();
+  othello_init();
+  // Get kifu
+  do {
+    if (ggz_read_int (fd, &who) < 0 || ggz_read_int (fd, &yx) < 0)
+      return RVR_ERROR_CANTREAD;
+    kifu[i].who  = (gint8) who;
+    kifu[i++].yx = (gint8) yx;
+  } while (who);
+
+  // Auto recovery
+  while (kifu[othello.count].who) {
+    othello.turn = kifu[othello.count].who;
+    othello_move((gint) kifu[othello.count].yx);
   }
+  othello.turn = kifu[othello.count].yx;
 
-  ggz_debug ("main", "Sent move: %d", move);
+  copy_board ();
+  gui_redraw_board();
+  game_start();
+  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;
+  game_init();
+  gui_error (RVR_ERROR_NOTPLAYING);
+  state = GAME_STOP | GAME_W_CONECT;
+  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 ();
+      break;
+    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 +268,7 @@
 }
 
 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 +276,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 +286,33 @@
   g_io_add_watch (channel, G_IO_IN, handle_game_server, mod);
 }
 
+static 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 +326,32 @@
 ggz_game_launched (void)
 {
   network_init ();
-  init_new_game ();
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
+
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (widget[NOTEBOOK]), MAIN_PAGE);
+  gtk_widget_hide (widget[GGZBOX]);
+
+  // Create hpaned, playerlist and chat
+  if (!widget[HPANED]) {
+    widget[HPANED] = gtk_hpaned_new ();
+    gtk_paned_pack2 (GTK_PANED (widget[VPANED]), widget[HPANED], TRUE, TRUE);
+    gtk_widget_show (widget[HPANED]);
+    widget[PLAYERLIST] = create_playerlist_widget ();
+    gtk_paned_pack1 (GTK_PANED (widget[HPANED]), widget[PLAYERLIST], TRUE, TRUE);
+    gtk_widget_show (widget[PLAYERLIST]);
+    widget[CHAT] = create_chat_widget ();
+    gtk_paned_pack2 (GTK_PANED (widget[HPANED]), widget[CHAT], TRUE, TRUE);
+    gtk_widget_show (widget[CHAT]);
+    // Remove playerlist from focus chain
+    gtk_container_set_focus_chain ((GtkContainer *) widget[HPANED], focusable_widgets);
+    gtk_container_set_focus_chain ((GtkContainer *) widget[CHAT], focusable_widgets);
+//    gtk_container_set_focus_child ((GtkContainer *) widget[HPANED], widget[CHAT]);
+  }
+  else
+    gtk_widget_show (widget[HPANED]);
+
+  ggz_network_mode = TRUE;
+  network_gui_update ();
+  get_init ();
 }
 
 /****************************************************************************
@@ -257,69 +360,90 @@
 static void
 ggz_closed (void)
 {
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
+  ggzmod_disconnect (ggzmod);
+  ggzmod_free (ggzmod);
+
+  // Destroy ggzbox and hide hpaned
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (widget[NOTEBOOK]), MAIN_PAGE);
+  gtk_widget_destroy (widget[GGZBOX]);
+  gtk_notebook_remove_page (GTK_NOTEBOOK (widget[NOTEBOOK]), NETWORK_PAGE);
+  if (widget[HPANED])
+    gtk_widget_hide (widget[HPANED]);
+
   ggz_network_mode = FALSE;
-  init_new_game ();
+  network_gui_update ();
+  game_stop();
+  game_init();
+  game_start();
 }
 
+/****************************************************************************
+  Window menu callback functions.
+****************************************************************************/
 void
-network_init (void)
+on_again_activate (GtkMenuItem *menuitem, gpointer user_data)
 {
-  GGZMod *mod;
-  GIOChannel *channel;
-  int ret, ggzmodfd;
+  if (old)
+    get_init ();
+  if (ggz_write_int (fd, RVR_REQ_AGAIN) < 0)
+    return gui_error (RVR_ERROR_CANTWRITE);
+}
 
-  if (!ggzmod_is_ggz_mode ())
-    return;
-  ggz_network_mode = TRUE;
+void
+on_network_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  struct passwd *pwent;
 
-  mod = ggzmod_new (GGZMOD_GAME);
-  ggzmod_set_handler (mod, GGZMOD_EVENT_SERVER, handle_ggzmod_server);
+  game_stop();
 
-  ret = ggzmod_connect (mod);
-  if (ret != 0) {
-    /* Error: GGZ core client error (e.g. faked GGZMODE env variable) */
-    return;
-  }
+  ggz_gtk_initialize (FALSE,
+                      ggz_connected, ggz_game_launched, ggz_closed,
+                      NETWORK_ENGINE, NETWORK_VERSION, "iagno.xml",
+                      "GGZ Gaming Zone");
 
-  ggzmodfd = ggzmod_get_fd (mod);
-  channel = g_io_channel_unix_new (ggzmodfd);
-  g_io_add_watch (channel, G_IO_IN, handle_ggzmod, mod);
+  pwent = getpwuid (getuid ());
+  ggz_embed_ensure_server ("GGZ Gaming Zone", "gnome.ggzgamingzone.org",
+                           5688, pwent->pw_name);
 
-  init_player_list (mod);
-  init_chat (mod);
+  // Create ggzbox
+  widget[GGZBOX] = ggz_gtk_create_main_area (widget[WINDOW]);
+  gtk_notebook_append_page (GTK_NOTEBOOK (widget[NOTEBOOK]), widget[GGZBOX], NULL);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (widget[NOTEBOOK]), NETWORK_PAGE);
+  gtk_widget_show (widget[GGZBOX]);
+}
 
+void
+on_leave_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  ggz_embed_leave_table ();
+  gtk_widget_show (widget[GGZBOX]);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (widget[NOTEBOOK]), NETWORK_PAGE);
 }
 
 void
-on_network_game (void)
+send_my_move (gint move)
 {
-  GtkWidget *ggzbox;
-  struct passwd *pwent;  
-  static gboolean ggz_initialized = FALSE;
+  int yx = (int) NEW2OLD (move);
 
+  if (state & GAME_STOP) {
+    if (state & GAME_W_CONECT)
+      return;
+    if (state & GAME_BACK) {
+      gui_message (_("You can't change any moves on network mode!"));
+      return; 
+    } 
+    game_start();
+   }
+  // For the compatibility with the old protocol,
+  // if the new client send a invalid move to the old server, 
+  // the new client hang up at sync.
+  if (state & GAME_W_INPUT)
+    return gui_error (RVR_ERROR_WRONGTURN);
+  if (!check_valid_move (move))
+    return gui_error (RVR_ERROR_INVALIDMOVE);
 
-  if (ggz_network_mode) {
-    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
-    return;
-  }
+  if (ggz_write_int (fd, RVR_REQ_MOVE) < 0 || ggz_write_int (fd, yx) < 0)
+    return gui_error (RVR_ERROR_CANTWRITE);
 
-  init_new_game ();
-  ggz_network_mode = TRUE;
-
-  if (ggz_initialized == FALSE) {
-    ggz_initialized = TRUE;
-    ggz_gtk_initialize (FALSE,
-		      ggz_connected, ggz_game_launched, ggz_closed,
-		      NETWORK_ENGINE, NETWORK_VERSION, "iagno.xml",
-		      "GGZ Gaming Zone");
-
-    ggzbox = ggz_gtk_create_main_area (window);
-    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), ggzbox, NULL);
-  }
-  pwent = getpwuid(getuid());
-  ggz_embed_ensure_server ("GGZ Gaming Zone", "gnome.ggzgamingzone.org",
-			   5688, pwent->pw_name);
-
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
+  ggz_debug ("main", "Sent move: %d", yx);
 }
Index: iagno/ggz-network.h
===================================================================
--- iagno/ggz-network.h	(リビジョン 7688)
+++ iagno/ggz-network.h	(作業コピー)
@@ -1,9 +1,12 @@
-/* ggz-network.h
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
+/*
+ * ggz-network.h
  *
- * This game is free software; you can redistribute it and/or modify
+ * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,189 +15,49 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
  * USA
+ *
+ * For more details see the file COPYING.
  */
 
-#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
-
-// 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 RVR_ERROR_INVALIDMOVE -1
-#define RVR_ERROR_WRONGTURN -2
-#define RVR_ERROR_CANTMOVE -3
+#define SERVER_OK               0
+#define RVR_ERROR_INVALIDMOVE   -1
+#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) )
+// 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))
 
-// 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)] )
+#define NETWORK_ENGINE          "Iagno"
+#define NETWORK_VERSION         "1"
 
-// Takes a seat and transform into a player code
-#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 )
+void on_again_activate (GtkMenuItem *menuitem, gpointer user_data);
 
-#define NETWORK_ENGINE "Iagno"
-#define NETWORK_VERSION "1"
+void on_network_activate (GtkMenuItem *menuitem, gpointer user_data);
 
-void network_init (void);
-void on_network_game (void);
+void on_leave_activate (GtkMenuItem *menuitem, gpointer user_data);
 
-int fd;
+void send_my_move (gint move);
 
-// Setup functions
-void game_init (void);
-
-// 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/Makefile.am
===================================================================
--- iagno/Makefile.am	(リビジョン 7688)
+++ iagno/Makefile.am	(作業コピー)
@@ -20,7 +20,9 @@
 if GGZ_SERVER
 ggzexecmod_PROGRAMS += iagnod
 iagnod_SOURCES = server.h   \
-		 server.c   
+                 othello.h  \
+                 othello.c  \
+                 server.c   
 
 iagnod_LDADD = \
 	$(GNOME_GAMES_LIBS)     \
@@ -51,8 +53,9 @@
 	$(LIB_GGZ_GTK)
 
 pixmap_DATA = \
-	classic.png \
-	woodtrim.png
+        disk.svg \
+        marble.svg \
+        sun_and_star.svg
 
 Games_in_files = iagno.desktop.in.in
 Games_DATA = $(Games_in_files:.desktop.in.in=.desktop)
Index: iagno/gnothello.c
===================================================================
--- iagno/gnothello.c	(リビジョン 7688)
+++ iagno/gnothello.c	(作業コピー)
@@ -2,7 +2,6 @@
 
 /*
  * gnothello.c - Main GUI part of iagno
- * written by Ian Peters <itp@gnu.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,861 +15,1254 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
  *
  * For more details see the file COPYING.
  */
 
-#include <config.h>
+
 #include <gnome.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <stdio.h>
 
-#include <string.h>
+#include <config.h>
 #include <games-stock.h>
 #include <games-sound.h>
+#include <games-preimage.h>
+#include <games-files.h>
 #include <games-conf.h>
 
+#include "othello.h"
+#include "gnothello.h"
+#include "properties.h"
+
 #ifdef GGZ_CLIENT
-#include <games-dlg-chat.h>
-#include <games-dlg-players.h>
 #include "ggz-network.h"
-#include <ggz-embed.h>
+gboolean           ggz_network_mode = FALSE;
+gint8              player_id;
 #endif
 
-#include "gnothello.h"
-#include "othello.h"
-#include "properties.h"
+static GdkGC       *gridGC[2] = { 0 };
+static GTimer      *timer[2];
+static GtkUIManager   *manager;
+static GtkActionGroup *action_group;
+static GtkAction      *actions[MAX_ACTIONS];
+static GameBoard   board;
+static GamePixmap  pixmap;
+static guint       context_id = 0;
+static guint       timer_id = 0;
 
-#define APP_NAME "iagno"
-#define APP_NAME_LONG N_("Iagno")
+GList              *focusable_widgets = NULL;
+GtkWidget          *widget[MAX_WIDGET];
+GdkColor           bg_color[3] = {
+                     {0, 0, 0, 0},                         // background color
+                     {0xffffffff, 0xffff, 0xffff, 0xffff}, // grid color
+                     {0, 0, 0, 0}                          // tmp color
+                      };
+GameOptions        options;
+GameState          state = GAME_STOP;
+GameFlags          flags = 0;
+GameKifu           kifu[MAX_MOVE_COUNT + 1];
+GameWindow         window;
+GameTile           tile;
+gchar              *bg_color_name;
+gint               computer_level[2];
+guint              check_flags_id = 0;
 
-GnomeAppBar *appbar;
-GtkWidget *window;
-GtkWidget *notebook;
-GtkWidget *drawing_area;
-GtkWidget *tile_dialog;
-GtkWidget *black_score;
-GtkWidget *white_score;
+extern Othello     othello;
+extern ValidSquare valid_squares[];
+extern gint        sort_of_search;
 
-GdkPixmap *buffer_pixmap = NULL;
-GdkPixmap *tiles_pixmap = NULL;
-GdkPixmap *tiles_mask = NULL;
 
-gint flip_pixmaps_id = 0;
-gint statusbar_id;
-guint black_computer_level;
-guint white_computer_level;
-guint black_computer_id = 0;
-guint white_computer_id = 0;
-guint computer_speed = COMPUTER_MOVE_DELAY;
-gint animate;
-gint animate_stagger;
-gint grid = 0;
-guint tiles_to_flip = 0;
+/**** Basic routines ****/
 
-gint64 milliseconds_total = 0;
-gint64 milliseconds_current_start = 0;
+static void
+set_board_size (void)
+{
+  gint depth = -1;
 
-guint game_in_progress;
+  tile.width   = (board.width  - GRID_WIDTH * 7) / 8;
+  tile.height  = (board.height - GRID_WIDTH * 7) / 8;
+  board.width  = (tile.width  + GRID_WIDTH) * 8 - GRID_WIDTH;
+  board.height = (tile.height + GRID_WIDTH) * 8 - GRID_WIDTH;
 
-gint8 pixmaps[8][8] = { {0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-};
+  if (pixmap.buffer) {
+    g_object_unref (pixmap.buffer);
+    depth = gdk_drawable_get_depth ((GdkDrawable *) widget[BOARD]->window);
+  }
+  pixmap.buffer = gdk_pixmap_new (widget[BOARD]->window,
+                                  board.width, board.height, depth);
 
-gint8 board[8][8] = { {0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-,
-{0, 0, 0, 0, 0, 0, 0, 0}
-};
-guint whose_turn;
-gint8 move_count;
-gint bcount;
-gint wcount;
+  return set_bg_color ();
+}
 
-extern guint flip_final_id;
-extern gint8 squares[64];
+void
+set_bg_color (void)
+{
+  gint i;
 
-int session_flag = 0;
-int session_xpos = -1;
-int session_ypos = -1;
-int session_position = 0;
+  gdk_color_parse (bg_color_name, &bg_color[0]);
+  gdk_colormap_alloc_color (gtk_widget_get_colormap (widget[BOARD]),
+                            &bg_color[0], FALSE, TRUE);
 
-gchar *tile_set = NULL;
-gchar *tile_set_tmp = NULL;
+  for (i = 0; i < 2; i++) {
+    if (gridGC[i])
+      g_object_unref (gridGC[i]);
+    gridGC[i] = gdk_gc_new (widget[BOARD]->window);
+    gdk_gc_copy (gridGC[i], widget[BOARD]->style->bg_gc[0]);
+    gdk_gc_set_background (gridGC[i], &bg_color[i]);
+    gdk_gc_set_foreground (gridGC[i], &bg_color[i]);
+  }
+  gdk_draw_rectangle (pixmap.buffer, gridGC[0], TRUE, 0, 0,
+                      board.width, board.height);
 
-GdkGC *gridGC[2] = { 0 };
+  return gui_draw_grid ();
+}
 
-static const GOptionEntry options[] = {
-  {"x", 'x', 0, G_OPTION_ARG_INT, &session_xpos, N_("X location of window"),
-   N_("X")},
-  {"y", 'y', 0, G_OPTION_ARG_INT, &session_ypos, N_("Y location of window"),
-   N_("Y")},
-  {NULL}
-};
+void
+gui_draw_grid (void)
+{
+  gint i;
 
-GnomeUIInfo game_menu[] = {
-  GNOMEUIINFO_MENU_NEW_GAME_ITEM (new_game_cb, NULL),
+  gdk_gc_set_line_attributes (gridGC[1], GRID_WIDTH, GDK_LINE_ON_OFF_DASH,
+                              GDK_CAP_BUTT, GDK_JOIN_MITER);
 
-  GNOMEUIINFO_ITEM (N_("Net_work Game"), NULL, new_network_game_cb, NULL),
+  for (i = tile.height; i < board.height; i += tile.height + GRID_WIDTH)
+    gdk_draw_line (pixmap.buffer, gridGC[1], 0, i, board.width, i);
+  for (i = tile.width;  i < board.width;  i += tile.width  + GRID_WIDTH)
+    gdk_draw_line (pixmap.buffer, gridGC[1], i, 0, i, board.height);
 
-  GNOMEUIINFO_SEPARATOR,
+  return load_tiles ();
+}
 
-  GNOMEUIINFO_MENU_UNDO_MOVE_ITEM (undo_move_cb, NULL),
+static GamesPreimage *
+load_image (gchar *tileset)
+{
+  GError *error = NULL;
+  gchar *fname;
+  gchar *pathname;
+  GamesPreimage *preimage;
 
-  GNOMEUIINFO_ITEM (N_("_Player list"), NULL, on_player_list, NULL),
+  fname    = g_build_filename (APP_NAME, tileset, NULL);
+  pathname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP,
+                                        fname, TRUE, NULL);
+  preimage = games_preimage_new_from_file (pathname, &error);
 
-  GNOMEUIINFO_ITEM (N_("_Chat Window"), NULL, on_chat_window, NULL),
+  g_free (fname);
+  g_free (pathname);
+  return preimage;
+}
 
-  GNOMEUIINFO_SEPARATOR,
+void
+load_tiles (void)
+{
+  GamesPreimage *t_image;
+  GdkPixbuf *image;
+  gint depth = -1;
+  GdkGC *gc;
 
-  GNOMEUIINFO_ITEM (N_("_Leave Game"), NULL, on_network_leave, NULL),
+  t_image = load_image (tile.name);
+  if (!t_image) {
+    g_free (tile.name);
+    tile.name = g_strdup (DEFAULT_TILESET);
+    t_image = load_image (tile.name);
+    if (!t_image) {
+      g_print (_("Could not find \'%s\' pixmap file\n"), DEFAULT_TILESET);
+      exit (1);
+    }
+    properties_reset ();
+  }
 
-  GNOMEUIINFO_MENU_QUIT_ITEM (quit_game_cb, NULL),
+  image = games_preimage_render (t_image, tile.width * 8, tile.height * 4);
 
-  GNOMEUIINFO_END
-};
+  if (tile.pixmap) {
+    g_object_unref (tile.pixmap);
+    depth = gdk_drawable_get_depth ((GdkDrawable *) widget[BOARD]->window);
+  }
+  tile.pixmap = gdk_pixmap_new (widget[BOARD]->window,
+                                 tile.width * 8, tile.height * 4, depth);
 
-GnomeUIInfo settings_menu[] = {
-  GNOMEUIINFO_MENU_PREFERENCES_ITEM (properties_cb, NULL),
-  GNOMEUIINFO_END
-};
+  gc = gdk_gc_new (tile.pixmap);
+  gdk_gc_set_foreground (gc, &bg_color[0]);
+  gdk_gc_set_background (gc, &bg_color[0]);
 
-GnomeUIInfo help_menu[] = {
-  GNOMEUIINFO_HELP ("iagno"),
-  GNOMEUIINFO_MENU_ABOUT_ITEM (about_cb, NULL),
-  GNOMEUIINFO_END
-};
+  gdk_draw_rectangle (tile.pixmap, gc, TRUE, 0, 0,
+                      tile.width * 8, tile.height * 4);
+  gdk_draw_pixbuf (tile.pixmap, gc, image, 0, 0, 0, 0,
+                   tile.width * 8, tile.height * 4,
+                   GDK_RGB_DITHER_NONE, 0, 0);
 
-GnomeUIInfo mainmenu[] = {
-  GNOMEUIINFO_MENU_GAME_TREE (game_menu),
-  GNOMEUIINFO_MENU_SETTINGS_TREE (settings_menu),
-  GNOMEUIINFO_MENU_HELP_TREE (help_menu),
-  GNOMEUIINFO_END
-};
+  g_object_unref (t_image);
+  g_object_unref (image);
+  return gui_redraw_board ();
+}
 
 static void
-undo_set_sensitive (gboolean state)
+gui_draw_pixmap_buffer (gint which, gint x, gint y)
 {
-  gtk_widget_set_sensitive (game_menu[3].widget, state);
+  gdk_draw_drawable (pixmap.buffer, gridGC[0], tile.pixmap,
+                     tile.width * (which % 8), tile.height * (which / 8),
+                     (tile.width  + GRID_WIDTH) * x,
+                     (tile.height + GRID_WIDTH) * y,
+                     tile.width, tile.height);
 }
 
-void
-quit_game_cb (GtkWidget * widget, gpointer data)
+static void
+gui_draw_board (gint which, gint x, gint y)
 {
-  gtk_main_quit ();
+  gdk_draw_drawable (widget[BOARD]->window, gridGC[0], tile.pixmap,
+                     tile.width * (which % 8), tile.height * (which / 8),
+                     (tile.width  + GRID_WIDTH) * x,
+                     (tile.height + GRID_WIDTH) * y,
+                     tile.width, tile.height);
+  return gui_draw_pixmap_buffer (which, x, y);
 }
 
-void
-new_game_cb (GtkWidget * widget, gpointer data)
+static void
+gui_draw_arc_buffer (gint x, gint y)
 {
-  init_new_game ();
+  gdk_draw_arc ((GdkDrawable *) pixmap.buffer, gridGC[1], TRUE,
+                (tile.width  + GRID_WIDTH) * x + tile.width  * 13 / 16,
+                (tile.height + GRID_WIDTH) * y + tile.height * 13 / 16,
+                tile.width / 8, tile.height / 8, 0, 64 * 360);
 }
 
-void
-on_player_list (void)
+static void
+gui_draw_arc (gint x, gint y)
 {
-#ifdef GGZ_CLIENT
-  create_or_raise_dlg_players (GTK_WINDOW (window));
-#endif
+  gdk_draw_arc ((GdkDrawable *) widget[BOARD]->window, gridGC[1], TRUE,
+                (tile.width  + GRID_WIDTH) * x + tile.width  * 13 / 16,
+                (tile.height + GRID_WIDTH) * y + tile.height * 13 / 16,
+                tile.width / 8, tile.height / 8, 0, 64 * 360);
+  return gui_draw_arc_buffer (x, y);
 }
 
-void
-on_chat_window (void)
+static void
+gui_scores (void)
 {
-#ifdef GGZ_CLIENT
-  create_or_raise_dlg_chat (GTK_WINDOW (window));
-#endif
+  gchar message[5];
+
+  sprintf (message, "%.2d", (int) othello.count - 4);
+  gtk_label_set_text (GTK_LABEL (widget[COUNTER]),     message);
+  sprintf (message, "%.2d", (int) othello.black);
+  gtk_label_set_text (GTK_LABEL (widget[BLACK_SCORE]), message);
+  sprintf (message, "%.2d", (int) othello.white);
+  gtk_label_set_text (GTK_LABEL (widget[WHITE_SCORE]), message);
 }
 
 void
-new_network_game_cb (GtkWidget * widget, gpointer data)
+gui_message (gchar *message)
 {
-#ifdef GGZ_CLIENT
-  on_network_game ();
-  gtk_widget_hide (mainmenu[0].widget);
-  gtk_widget_hide (mainmenu[1].widget);
-#endif
+  if (context_id)
+    gtk_statusbar_pop (GTK_STATUSBAR (widget[STATUSBAR]), context_id);
+
+  context_id =
+    gtk_statusbar_get_context_id (GTK_STATUSBAR (widget[STATUSBAR]), message);
+  gtk_statusbar_push (GTK_STATUSBAR (widget[STATUSBAR]), context_id, message);
 }
 
 void
-on_network_leave (GObject * object, gpointer data)
+copy_board (void)
 {
-#ifdef GGZ_CLIENT
-  ggz_embed_leave_table ();
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
-#endif
+  gint i, j;
+
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 8; j++)
+      board.array[i][j] = othello.board[(i + 1) * 10 + j + 1];
+
+  return gui_scores ();
 }
 
 void
-undo_move_cb (GtkWidget * widget, gpointer data)
+gui_redraw_board (void)
 {
-  gint8 which_computer, xy;
+  gint i, j;
 
-  if ((black_computer_level && white_computer_level) || move_count == 4)
-    return;
-   
-  /* Cancel any pending AI operations */
-  if (black_computer_id) {
-    g_source_remove (black_computer_id);
-    black_computer_id = 0;
-  }
-  if (white_computer_id) {
-    g_source_remove (white_computer_id);
-    white_computer_id = 0;
-  }
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 8; j++)
+      pixmap.array[i][j] = 0;
 
-  if (flip_final_id) {
-    g_source_remove (flip_final_id);
-    flip_final_id = 0;
-  }
+  flags |= FLIP_PIXMAPS;
+}
 
-  game_in_progress = 1;
+/** Timer **/
 
-  which_computer = OTHER_PLAYER (whose_turn);
-  undo ();
-  board_copy ();
-  xy = squares[move_count];
-  pixmaps[xy % 10 - 1][xy / 10 - 1] = 100;
-  if ((((whose_turn == WHITE_TURN) && white_computer_level) ||
-       ((whose_turn == BLACK_TURN) && black_computer_level))
-      && (move_count > 4)) {
-    undo ();
-    board_copy ();
-    xy = squares[move_count];
-    pixmaps[xy % 10 - 1][xy / 10 - 1] = 100;
-  }
+static void
+sprint_time (gchar *message, GTimer *timer)
+{
+  int mm, ss;
 
-  gui_status ();
-  tiles_to_flip = 1;
-  check_computer_players ();
+  ss = (int) g_timer_elapsed (timer, NULL);
+  mm = ss / 60;
+  ss -= mm * 60;
+  sprintf (message, "%.2d:%.2d", mm, ss);
 }
 
-void
-about_cb (GtkWidget * widget, gpointer data)
+static gboolean
+gui_timer (gpointer data)
 {
-  const gchar *authors[] = { "Ian Peters", NULL };
+  gchar message[9];
+  gint i;
 
-  const gchar *documenters[] = { "Eric Baudais", NULL };
+  for (i = 0; i < 2; i++) {
+    sprint_time (message, timer[i]);
+    gtk_label_set_text (GTK_LABEL (widget[BLACK_TIME + i]), message);
+  }
+  return TRUE;
+}
 
-  gchar *license = games_get_license (_(APP_NAME_LONG));
+static void
+timer_start (void)
+{
+  gui_timer (NULL);
 
-  gtk_show_about_dialog (GTK_WINDOW (window),
-			 "name", _(APP_NAME_LONG),
-			 "version", VERSION,
-			 "copyright",
-			 "Copyright \xc2\xa9 1998-2008 Ian Peters",
-                         "license", license,
-                         "comments", _("A disk flipping game derived from Reversi.\n\nIagno is a part of GNOME Games."),
-			 "authors", authors,
-                         "documenters", documenters,
-			 "translator-credits", _("translator-credits"),
-			 "logo-icon-name", "gnome-iagno",
-			 "website-label", _("GNOME Games web site"),
-                         "website", "http://www.gnome.org/projects/gnome-games/",
-			 "wrap-license", TRUE,
-                         NULL);
-  g_free (license);
+  if (timer_id)
+    g_source_remove (timer_id);
+  timer_id = g_timeout_add (500, (GSourceFunc) gui_timer, NULL);
 }
 
-void
-properties_cb (GtkWidget * widget, gpointer data)
+static void
+timer_continue (void)
 {
-  show_properties_dialog ();
+  g_timer_continue (timer[PLAYER2SEAT (othello.turn)]);
 }
 
-gint
-expose_event (GtkWidget * widget, GdkEventExpose * event)
+static void
+timer_stop (void)
 {
-  gdk_draw_drawable (widget->window,
-		     widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-		     buffer_pixmap,
-		     event->area.x, event->area.y,
-		     event->area.x, event->area.y,
-		     event->area.width, event->area.height);
-
-  return (FALSE);
+  g_timer_stop (timer[PLAYER2SEAT (othello.turn)]);
 }
 
-gboolean
-configure_event (GtkWidget * widget, GdkEventConfigure * event)
+static void
+timer_reset (void)
 {
-  static int old_width = 0, old_height = 0;
-  guint i, j;
+  gint i;
 
-  if (old_width == event->width && old_height == event->height) {
-    return TRUE;
-  } else {
-    old_width = event->width;
-    old_height = event->height;
+  if (timer_id)
+    g_source_remove (timer_id);
+  timer_id = 0;
+  for (i = 0; i < 2; i++) {
+    g_timer_start (timer[i]);
+    g_timer_stop  (timer[i]);
   }
 
-  if (gridGC[0] != 0) {
-    gdk_draw_rectangle (buffer_pixmap, gridGC[0], 1,
-			0, 0, BOARDWIDTH, BOARDHEIGHT);
-    for (i = 0; i < 8; i++)
-      for (j = 0; j < 8; j++)
-	gui_draw_pixmap_buffer (pixmaps[i][j], i, j);
-    gui_draw_grid ();
-  }
-
-  return TRUE;
+  gui_timer (NULL);
 }
 
-gint
-button_press_event (GtkWidget * widget, GdkEventButton * event)
+/****************/
+
+static gboolean
+gui_hint (void)
 {
-  guint x, y;
+  GString *string;
+  gchar message[] = { 0, 0, 0x20, 0 };
+  gint yx;
 
-  if (game_in_progress == 0)
-    return TRUE;
+  flags ^= GUI_HINT;
 
-  if (!ggz_network_mode && (whose_turn == WHITE_TURN) && white_computer_level)
-    return TRUE;
+  yx = computer_move (MAX_DEPTH - 2);
+  message[0] = (gchar) (yx % 10 + 0x40);
+  message[1] = (gchar) (yx / 10 + 0x30);
 
-  if (!ggz_network_mode && (whose_turn == BLACK_TURN) && black_computer_level)
-    return TRUE;
-
-  if (event->button == 1) {
-    x = event->x / (TILEWIDTH + GRIDWIDTH);
-    y = event->y / (TILEHEIGHT + GRIDWIDTH);
-    if (ggz_network_mode && player_id == whose_turn
-	&& is_valid_move (x, y, whose_turn)) {
-#ifdef GGZ_CLIENT
-      send_my_move (CART (x + 1, y + 1), whose_turn);
-#endif
-    } else if (!ggz_network_mode && is_valid_move (x, y, whose_turn)) {
-      move (x, y, whose_turn);
-    } else {
-      gui_message (_("Invalid move."));
-    }
-
+  string = g_string_new (message);
+  g_string_append_printf (string, "%d", valid_squares[0].evaluation);
+  if (sort_of_search == PERFECT || sort_of_search == VICTORY) {
+    if (valid_squares[0].evaluation > 0)
+      g_string_append_printf (string, "%s", _(" You shall win the game."));
+    else if (valid_squares[0].evaluation < 0)
+      g_string_append_printf (string, "%s", _(" You shall lose the game."));
+    else
+      g_string_append_printf (string, "%s", _(" The game shall be a draw."));
+  } else {
+    if (valid_squares[0].evaluation > 12)
+      g_string_append_printf (string, "%s", _(" The game is superiority for you."));
+    else if (valid_squares[0].evaluation < -12)
+      g_string_append_printf (string, "%s", _(" The game is inferiority for you."));
+    else
+      g_string_append_printf (string, "%s", _(" The game is a good match."));
   }
+  gui_message (string->str);
 
+  g_string_free (string, TRUE);
   return TRUE;
 }
 
-void
-gui_draw_pixmap (gint which, gint x, gint y)
+static gboolean
+check_hint (void)
 {
-  gdk_draw_drawable (drawing_area->window, gridGC[0], tiles_pixmap,
-		     (which % 8) * TILEWIDTH, (which / 8) * TILEHEIGHT,
-		     x * (TILEWIDTH + GRIDWIDTH),
-		     y * (TILEHEIGHT + GRIDWIDTH), TILEWIDTH, TILEHEIGHT);
-  gdk_draw_drawable (buffer_pixmap, gridGC[0], tiles_pixmap,
-		     (which % 8) * TILEWIDTH, (which / 8) * TILEHEIGHT,
-		     x * (TILEWIDTH + GRIDWIDTH),
-		     y * (TILEHEIGHT + GRIDWIDTH), TILEWIDTH, TILEHEIGHT);
+  flags ^= CHECK_HINT;
+
+  gui_message (_("Now thinking."));
+  flags |= GUI_HINT;
+  return TRUE;
 }
 
-void
-gui_draw_pixmap_buffer (gint which, gint x, gint y)
+static gboolean
+t_computer_move (void)
 {
-  gdk_draw_drawable (buffer_pixmap, gridGC[0], tiles_pixmap,
-		     (which % 8) * TILEWIDTH, (which / 8) * TILEHEIGHT,
-		     x * (TILEWIDTH + GRIDWIDTH),
-		     y * (TILEHEIGHT + GRIDWIDTH), TILEWIDTH, TILEHEIGHT);
+  flags ^= COMPUTER_MOVE;
+  if (flags & CHECK_HINT)
+    flags ^= CHECK_HINT;
+
+  game_move (computer_move (computer_level[PLAYER2SEAT (othello.turn)] * 2 - 1));
+
+  return TRUE;
 }
 
-void
-gui_draw_grid (void)
+static gboolean
+check_computer_players  (void)
 {
-  int i;
+  flags ^= CHECK_COMPUTER_PLAYERS;
 
-  for (i = 1; i < 8; i++) {
-    gdk_draw_line (buffer_pixmap, gridGC[grid],
-		   i * BOARDWIDTH / 8 - 1, 0,
-		   i * BOARDWIDTH / 8 - 1, BOARDHEIGHT);
-    gdk_draw_line (buffer_pixmap, gridGC[grid],
-		   0, i * BOARDHEIGHT / 8 - 1,
-		   BOARDWIDTH, i * BOARDHEIGHT / 8 - 1);
-  }
+#ifdef GGZ_CLIENT
+  if (ggz_network_mode)
+    return TRUE;
+#endif
+ 
+  if ((state & GAME_STOP) || !computer_level[PLAYER2SEAT (othello.turn)])
+    return TRUE;
 
-  gdk_draw_drawable (drawing_area->window, gridGC[0], buffer_pixmap,
-		     0, 0, 0, 0, BOARDWIDTH, BOARDHEIGHT);
+  gui_message (_("Now thinking."));
+  flags |= COMPUTER_MOVE;
+  return TRUE;
 }
 
-void
-load_pixmaps (void)
+static gboolean
+flip_final_results (void)
 {
-  GdkPixbuf *image;
-  GError *error = NULL;
-  gchar *tmp;
-  gchar *fname;
+  gint8 i = 0, adder = 0;
 
-  g_return_if_fail (tile_set != NULL && tile_set[0] != '0');
+  flags ^= FLIP_FINAL_RESULTS;
 
-  tmp = g_build_filename ("iagno", tile_set, NULL);
-  fname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP,
-				     tmp, FALSE, NULL);
-  g_free (tmp);
-
-  if (!g_file_test (fname, G_FILE_TEST_EXISTS)) {
-    g_free (fname);
-    fname = gnome_program_locate_file (NULL,
-				       GNOME_FILE_DOMAIN_APP_PIXMAP,
-				       "iagno/classic.png", FALSE, NULL);
+  for (; i < othello.black; i++) {
+    board.array[i / 8][i % 8] = BLACK;
+    if (pixmap.array[i / 8][i % 8] == EMPTY)
+      pixmap.array[i / 8][i % 8] = WHITE;
+    if (pixmap.array[i / 8][i % 8] == WHITE) {
+      pixmap.array[i / 8][i % 8] += adder;
+      adder++;
+    }
   }
 
-  if (!g_file_test (fname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
-    g_print (_("Could not find \'%s\' pixmap file\n"), fname);
-    exit (1);
-  }
+  for (; i < 64 - othello.white; i++)
+    board.array[i / 8][i % 8] = EMPTY;
 
-  image = gdk_pixbuf_new_from_file (fname, &error);
-  if (error) {
-    g_warning (G_STRLOC ": gdk-pixbuf error %s\n", error->message);
-    g_error_free (error);
-    error = NULL;
+  for (; i < 64; i++) {
+    board.array[i / 8][i % 8] = WHITE;
+    if (pixmap.array[i / 8][i % 8] == EMPTY)
+      pixmap.array[i / 8][i % 8] = BLACK;
+    if (pixmap.array[i / 8][i % 8] == BLACK) {
+      pixmap.array[i / 8][i % 8] -= adder;
+      adder++;
+    }
   }
 
-  gdk_pixbuf_render_pixmap_and_mask_for_colormap (image,
-						  gdk_colormap_get_system (),
-						  &tiles_pixmap,
-						  &tiles_mask, 127);
-
-  gdk_pixbuf_unref (image);
-  g_free (fname);
+  flags |= FLIP_PIXMAPS;
+  return TRUE;
 }
 
-gint
-flip_pixmaps (gpointer data)
+static gboolean
+flip_pixmaps (void)
 {
-  guint i, j;
-  guint flipped_tiles = 0;
+  gint i, j, state, which;
 
-  if (!tiles_to_flip)
-    return TRUE;
+  flags ^= FLIP_PIXMAPS;
 
   for (i = 0; i < 8; i++)
     for (j = 0; j < 8; j++) {
-      /* This first case only happens when undoing the "final flip". */
-      if ((pixmaps[i][j] == 101) && (board[i][j] != 0)) {
-	pixmaps[i][j] = board[i][j];
-	gui_draw_pixmap (pixmaps[i][j], i, j);
-	flipped_tiles = 1;
-      } else if ((pixmaps[i][j] == 100)
-		 || ((pixmaps[i][j] != 101) && (board[i][j] == 0))) {
-	pixmaps[i][j] = 101;
-	gui_draw_pixmap (0, i, j);
-	flipped_tiles = 1;
-      } else if (pixmaps[i][j] < board[i][j]) {
-	if (animate == 0) {
-	  if (pixmaps[i][j] == BLACK_TURN)
-	    pixmaps[i][j] = board[i][j];
-	  else
-	    pixmaps[i][j]++;
-	} else if (animate == 1) {
-	  if (pixmaps[i][j] < 1)
-	    pixmaps[i][j] += 2;
-	  else if (pixmaps[i][j] >= 1 && pixmaps[i][j] < 8)
-	    pixmaps[i][j] = 8;
-	  else if (pixmaps[i][j] >= 8 && pixmaps[i][j] < 16)
-	    pixmaps[i][j] = 16;
-	  else if (pixmaps[i][j] >= 16 && pixmaps[i][j] < 23)
-	    pixmaps[i][j] = 23;
-	  else if (pixmaps[i][j] >= 23 && pixmaps[i][j] < 31)
-	    pixmaps[i][j] = 31;
-	  else if (pixmaps[i][j] > 31)
-	    pixmaps[i][j] = 31;
-	} else if (animate == 2)
-	  pixmaps[i][j]++;
-	if (pixmaps[i][j] > 0)
-	  gui_draw_pixmap (pixmaps[i][j], i, j);
-	flipped_tiles = 1;
-      } else if (pixmaps[i][j] > board[i][j] && pixmaps[i][j] != 101) {
-	if (animate == 0) {
-	  if (pixmaps[i][j] == WHITE_TURN)
-	    pixmaps[i][j] = board[i][j];
-	  else
-	    pixmaps[i][j]--;
-	} else if (animate == 1) {
-	  if (pixmaps[i][j] > 31)
-	    pixmaps[i][j] -= 2;
-	  else if (pixmaps[i][j] <= 31 && pixmaps[i][j] > 23)
-	    pixmaps[i][j] = 23;
-	  else if (pixmaps[i][j] <= 23 && pixmaps[i][j] > 16)
-	    pixmaps[i][j] = 16;
-	  else if (pixmaps[i][j] <= 16 && pixmaps[i][j] > 8)
-	    pixmaps[i][j] = 8;
-	  else if (pixmaps[i][j] <= 8 && pixmaps[i][j] > 1)
-	    pixmaps[i][j] = 1;
-	  else if (pixmaps[i][j] < 1)
-	    pixmaps[i][j] = 1;
-	} else if (animate == 2)
-	  pixmaps[i][j]--;
-	if (pixmaps[i][j] < 32)
-	  gui_draw_pixmap (pixmaps[i][j], i, j);
-	flipped_tiles = 1;
+      if (pixmap.array[i][j] == board.array[i][j])
+        continue;
+
+      if (pixmap.array[i][j] < -EMPTY && board.array[i][j] > EMPTY)
+        pixmap.array[i][j] *= -1;
+      if (pixmap.array[i][j] < board.array[i][j] && pixmap.array[i][j] > EMPTY)
+        pixmap.array[i][j]++;
+      else if (pixmap.array[i][j] > board.array[i][j] && board.array[i][j] > EMPTY)
+        pixmap.array[i][j]--;
+      else
+        pixmap.array[i][j] = board.array[i][j];
+
+      state = 0;
+      which = pixmap.array[i][j];
+      if (which < 0) {
+        state = -1;
+        which *= -1;
       }
+      if (which == EMPTY)
+        which = 0;
+      else
+        which = CLAMP (which, BLACK, WHITE) - BLACK + 1;
+      gui_draw_board (which, j, i);
+      if (state)
+        gui_draw_arc (j, i);
+      flags |= FLIP_PIXMAPS;
     }
 
-  if (!flipped_tiles)
-    tiles_to_flip = 0;
-
   return TRUE;
 }
 
-static void
-redraw_board (void)
+static gboolean
+check_sounds (void)
 {
-  guint i, j;
+  flags ^= CHECK_SOUNDS;
 
-  gui_status ();
+  if (flags & GAMEOVER_SOUND) {
+    flags ^= GAMEOVER_SOUND;
+    games_sound_play ("gameover");
+  } else
+    games_sound_play ("flip-piece");
 
-  for (i = 0; i < 8; i++)
-    for (j = 0; j < 8; j++)
-      gui_draw_pixmap_buffer (pixmaps[i][j], i, j);
-
-  gui_draw_grid ();
+  return TRUE;
 }
 
-void
-clear_board (void)
+static void
+set_last_move_mark (void)
 {
-  guint i, j;
+  gint8 yx;
 
-  if (flip_final_id) {
-    g_source_remove (flip_final_id);
-    flip_final_id = 0;
-  }
+  if (!(options & Last_Move_Mark))
+    return;
+  if (othello.count < 5)
+    return;
+  // set a last move mark
+  yx = kifu[othello.count - 1].yx;
+  board.array[yx / 10 - 1][yx % 10 - 1] = - kifu[othello.count - 1].who;
+}
 
-  if (black_computer_id) {
-    g_source_remove (black_computer_id);
-    black_computer_id = 0;
+static void
+set_valid_square_marks (gint i)
+{
+  gint8 yx;
+  // clear all marks
+  for (yx = 0; yx < 64; yx++)
+    if (board.array[yx / 8][yx % 8] < 0)
+      board.array[yx / 8][yx % 8] *= -1;
+  if (!(options & Valid_Squares))
+    return set_last_move_mark ();
+  // set valid square marks
+  while (i > 0) {
+    yx = valid_squares[i--].square;
+    board.array[yx / 10 - 1][yx % 10 - 1] = -EMPTY;
   }
+  return set_last_move_mark ();
+};
 
-  if (white_computer_id) {
-    g_source_remove (white_computer_id);
-    white_computer_id = 0;
-  }
+static void
+set_sensitive (void)
+{
+  gint i;
 
-  game_in_progress = 0;
-  move_count = 0;
-  for (i = 0; i < 8; i++)
-    for (j = 0; j < 8; j++)
-      board[i][j] = 0;
+  // NEWGAME
+#ifdef GGZ_CLIENT
+  gtk_action_set_sensitive (actions[NEWGAME],
+                            !(ggz_network_mode && !(state & GAME_DONE)));
+#endif
+  // HINT
+  gtk_action_set_sensitive (actions[HINT],
+#ifdef GGZ_CLIENT
+                            !ggz_network_mode && 
+#endif
+                            (!(state & GAME_DONE) || (state & GAME_BACK)));
+  // HEAD, BACK
+  for (i = HEAD; i <= BACK; i++)
+    gtk_action_set_sensitive (actions[i],
+#ifdef GGZ_CLIENT
+                              !(ggz_network_mode && !(state & GAME_STOP)
+                                && !(state & GAME_W_INPUT)) &&
+#endif
+                                othello.count > 4);
+  // FORWARD, LAST
+  for (i = FORWARD; i <= LAST; i++)
+    gtk_action_set_sensitive (actions[i], state & GAME_BACK);
+  // SAVE
+  gtk_action_set_sensitive (actions[SAVE], kifu[4].who);
+}
 
-  memcpy (pixmaps, board, sizeof (gint8) * 8 * 8);
 
-  bcount = 0;
-  wcount = 0;
+/**** For game ****/
 
-  redraw_board ();
+gboolean
+check_flags (gpointer data)
+{
+  if (flags & CHECK_SOUNDS)
+    return check_sounds ();
+  if (flags & FLIP_PIXMAPS)
+    return flip_pixmaps ();
+  if (flags & FLIP_FINAL_RESULTS)
+    return flip_final_results ();
+  if (flags & CHECK_COMPUTER_PLAYERS)
+    return check_computer_players ();
+  if (flags & COMPUTER_MOVE)
+    return t_computer_move ();
+  if (flags & CHECK_HINT)
+    return check_hint ();
+  if (flags & GUI_HINT)
+    return gui_hint ();
+
+  return TRUE;
 }
 
 void
-init_new_game (void)
+check_game_over (void)
 {
-  clear_board ();
-  game_in_progress = 1;
-  move_count = 4;
+  gint i;
 
-  undo_set_sensitive (FALSE);
+  flags |= FLIP_PIXMAPS | CHECK_SOUNDS;
+  // Continue?
+  i = entry_valid_squares (0);
+  if (i) {
+    set_valid_square_marks (i);
+    if (othello.turn == BLACK)
+      gui_message (_("Dark's move"));
+    else
+      gui_message (_("Light's move"));
+    return set_sensitive ();
+  }
+  // Pass?
+  othello.turn = OTHER_PLAYER (othello.turn);
+  i = entry_valid_squares (0);
+  if (i) {
+    set_valid_square_marks (i);
+    if (othello.turn == BLACK)
+      gui_message (_("Light must pass, Dark's move"));
+    else
+      gui_message (_("Dark must pass, Light's move"));
+    return set_sensitive ();
+  }
+  // The game is over.
+  if (othello.black > othello.white)
+    gui_message (_("Dark player wins!"));
+  else if (othello.white > othello.black)
+    gui_message (_("Light player wins!"));
+  else
+    gui_message (_("The game was a draw."));
 
-  board[3][3] = WHITE_TURN;
-  board[3][4] = BLACK_TURN;
-  board[4][3] = BLACK_TURN;
-  board[4][4] = WHITE_TURN;
+  othello.turn  = 0;
+  state = GAME_STOP | GAME_DONE;
+  flags |= GAMEOVER_SOUND;
 
-  bcount = 2;
-  wcount = 2;
-  init ();
+  if (options & Final_Results)
+    flags |= FLIP_FINAL_RESULTS;
+  else {
+    copy_board ();
+    set_last_move_mark ();
+  }
 
-  memcpy (pixmaps, board, sizeof (gint8) * 8 * 8);
+  return set_sensitive ();
+}
 
-  redraw_board ();
+gboolean
+check_valid_move (gint yx)
+{
+  if (yx < 11 || yx > 88)
+    return FALSE;
+  if (othello.board[yx] != EMPTY)
+    return FALSE;        
+  if (!othello_check_valid ((gint) othello.turn, yx))
+    return FALSE;
 
-  whose_turn = BLACK_TURN;
-  gui_status ();
-  gtk_widget_show (mainmenu[0].widget);
-  gtk_widget_show (mainmenu[1].widget);
-
-  check_computer_players ();
+  return TRUE;
 }
 
 void
-create_window (void)
+game_move (gint yx)
 {
-  GtkWidget *table;
+  if (!(state & GAME_STOP)) {
+    timer_stop ();
+    kifu[othello.count].who     = othello.turn;
+    kifu[othello.count].yx      = (gint8) yx;
+    kifu[othello.count + 1].who = 0;
+  }
 
-  window = gnome_app_new ("iagno", _(APP_NAME_LONG));
+  othello_move (yx);
+  copy_board ();
+  check_game_over ();
+  if (state & GAME_STOP)
+    return;
 
-  games_conf_add_window (GTK_WINDOW (window), NULL);
+  timer_continue ();
+  flags |= CHECK_COMPUTER_PLAYERS;
+}
 
-  notebook = gtk_notebook_new ();
-  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
+void
+game_stop (void)
+{
+  flags = 0;
+  if (state & GAME_STOP)
+    return;
 
-  gtk_widget_realize (window);
-  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
-  g_signal_connect (G_OBJECT (window), "delete_event",
-		    G_CALLBACK (quit_game_cb), NULL);
+  state = GAME_STOP;
+  timer_stop ();
+}
 
-  gnome_app_create_menus (GNOME_APP (window), mainmenu);
+void
+game_init (void)
+{
+  othello_init ();
+  copy_board ();
+  kifu[othello.count].who = 0;
 
-  drawing_area = gtk_drawing_area_new ();
+  state = GAME_STOP;
+  timer_reset ();
+  set_valid_square_marks (entry_valid_squares (0));
+  gui_redraw_board ();
+  set_sensitive ();
+}
 
-  gtk_widget_pop_colormap ();
+void
+game_start (void)
+{
+  if (!(state & GAME_STOP))
+    return;
 
-  gnome_app_set_contents (GNOME_APP (window), notebook);
-  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), drawing_area, NULL);
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
+  state = GAME_PROGRESS;
+  kifu[othello.count].who = 0;
+  check_game_over ();
+  if (state & GAME_DONE)
+    return;
 
-  gtk_widget_set_size_request (GTK_WIDGET (drawing_area),
-			       BOARDWIDTH, BOARDHEIGHT);
-  g_signal_connect (G_OBJECT (drawing_area), "expose_event",
-		    G_CALLBACK (expose_event), NULL);
-  g_signal_connect (G_OBJECT (window), "configure_event",
-		    G_CALLBACK (configure_event), NULL);
-  g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
-		    G_CALLBACK (button_press_event), NULL);
-  gtk_widget_set_events (drawing_area,
-			 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
-  /* We do our own double-buffering. */
-  gtk_widget_set_double_buffered (drawing_area, FALSE);
+  timer_start ();
+  timer_continue ();
+  flags |= CHECK_COMPUTER_PLAYERS;
+}
 
-  gtk_widget_show (drawing_area);
+/****  Callbacks  ****/
 
-  appbar = GNOME_APPBAR (gnome_appbar_new (FALSE, TRUE, FALSE));
-  gnome_app_set_statusbar (GNOME_APP (window), GTK_WIDGET (appbar));
-  gnome_app_install_menu_hints (GNOME_APP (window), mainmenu);
+static void
+on_newgame_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+#ifdef GGZ_CLIENT
+  if (ggz_network_mode)
+    return on_again_activate (menuitem, user_data);
+#endif
 
-  table = gtk_table_new (1, 8, FALSE);
+  game_stop ();
+  game_init ();
+  game_start ();
+}
 
-  black_score = gtk_label_new (_("Dark:"));
-  gtk_widget_show (black_score);
+static void
+on_hint_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  flags |= CHECK_HINT;
+}
 
-  gtk_table_attach (GTK_TABLE (table), black_score, 1, 2, 0, 1, 0, 0, 3, 1);
+static void
+back (void)
+{
+  copy_board ();
+  state |= GAME_BACK;
+  return check_game_over ();
+}
 
-  black_score = gtk_label_new ("00");
-  gtk_widget_show (black_score);
+static void
+on_head_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  game_stop ();
+  othello_init ();
+  return back ();
+}
 
-  gtk_table_attach (GTK_TABLE (table), black_score, 2, 3, 0, 1, 0, 0, 3, 1);
+static void
+on_back_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  game_stop ();
+  othello_back ();
+  return back ();
+}
 
-  white_score = gtk_label_new (_("Light:"));
-  gtk_widget_show (white_score);
+static void
+forward (void)
+{
+  copy_board ();
+  if (!kifu[othello.count].who)
+    state ^= GAME_BACK;
+  return check_game_over ();
+}
 
-  gtk_table_attach (GTK_TABLE (table), white_score, 4, 5, 0, 1, 0, 0, 3, 1);
+static void
+on_forward_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  othello_move ((gint) kifu[othello.count].yx);
+  return forward ();
+}
 
-  white_score = gtk_label_new ("00");
-  gtk_widget_show (white_score);
+static void
+on_last_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  while (kifu[othello.count].who) {
+    othello.turn = kifu[othello.count].who;
+    othello_move ((gint) kifu[othello.count].yx);
+  }
+  return forward ();
+}
 
-  gtk_table_attach (GTK_TABLE (table), white_score, 5, 6, 0, 1, 0, 0, 3, 1);
-  undo_set_sensitive (FALSE);
+static void
+on_quit_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  // For flip_pixmaps dosn't draw widget[BOARD] after destroy window.
+  g_source_remove (check_flags_id);
+  if (timer_id)
+    g_source_remove (timer_id);
+  // When the player quit the game at once after unfullscreen,
+  // games_conf dosn't save window size.
+  if (!(options & FullScreen)) {
+    gtk_window_get_size (GTK_WINDOW (widget[WINDOW]), &window.width, &window.height);
+    gtk_window_get_position (GTK_WINDOW (widget[WINDOW]), &window.xpos, &window.ypos);
+  }
+  properties_save ();
+  gtk_main_quit ();
+}
 
-  gtk_widget_show (table);
+static void
+on_fullscreen_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  options ^= FullScreen;
+  if (options & FullScreen)
+    gtk_window_fullscreen (GTK_WINDOW (widget[WINDOW]));
+  else 
+    gtk_window_unfullscreen (GTK_WINDOW (widget[WINDOW]));
+  gtk_action_set_visible   (actions[FULLSCREEN],   !(options & FullScreen));
+  gtk_action_set_visible   (actions[UNFULLSCREEN],  options & FullScreen);
+}
 
-  gtk_box_pack_start (GTK_BOX (appbar), table, FALSE, TRUE, 0);
+static void
+on_help_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  gnome_help_display ("iagno.xml", NULL, NULL);
+}
 
-  gnome_appbar_set_status (GNOME_APPBAR (appbar), _("Welcome to Iagno!"));
+static void
+on_about_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  const gchar *authors[] = { "Ian Peters", NULL };
+  const gchar *documenters[] = { "Eric Baudais", NULL };
+  gchar *license = games_get_license (_(APP_NAME_LONG));
+
+  gtk_show_about_dialog (GTK_WINDOW (widget[WINDOW]),
+                         "name", _(APP_NAME_LONG),
+                         "version", VERSION,
+                         "copyright",
+                         "Copyright \xc2\xa9 1998-2007 Ian Peters",
+                         "license", license,
+                         "comments",
+                         _("A disk flipping game derived from Reversi."),
+                         "authors", authors, "documenters", documenters,
+                         "translator-credits", _("translator-credits"),
+                         "logo-icon-name", "gnome-iagno", "website",
+                         "http://www.gnome.org/projects/gnome-games/",
+                         "wrap-license", TRUE, NULL);
+  g_free (license);
 }
 
-void
-gui_status (void)
+static gboolean
+check_event_move (gint x, gint y)
 {
-  gchar message[3];
+  gint yx = y * 10 + x;
 
-  sprintf (message, _("%.2d"), bcount);
-  gtk_label_set_text (GTK_LABEL (black_score), message);
-  sprintf (message, _("%.2d"), wcount);
-  gtk_label_set_text (GTK_LABEL (white_score), message);
-  undo_set_sensitive (move_count > 0);
-
+#ifdef GGZ_CLIENT
   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);
-    gtk_widget_show (game_menu[4].widget);
-    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);
-    gtk_widget_hide (game_menu[4].widget);
-    gtk_widget_hide (game_menu[5].widget);
-    gtk_widget_hide (game_menu[7].widget);
+    send_my_move (yx);
+    return FALSE;
   }
+#endif
 
-  gtk_widget_set_sensitive (settings_menu[0].widget, !ggz_network_mode);
+  if (!check_valid_move (yx)) {
+    gui_message (_("Invalid move."));
+    return FALSE;
+  }
 
-#ifndef GGZ_CLIENT
-  gtk_widget_set_sensitive (game_menu[1].widget, FALSE);
-#endif
+  if (state & GAME_STOP)
+    game_start ();
+  game_move (yx);
+  return FALSE;
+}
 
-  if (ggz_network_mode) {
-    if (whose_turn == player_id && whose_turn == BLACK_TURN) {
-      gui_message (_("It is your turn to place a dark piece"));
-    } else if (whose_turn == player_id && whose_turn == WHITE_TURN) {
-      gui_message (_("It is your turn to place a light piece"));
-    } else {
-      gchar *str;
-      str = g_strdup_printf (_("Waiting for %s to move"),
-			     names[(seat + 1) % 2]);
-      gui_message (str);
-      g_free (str);
-    }
-  } else {
-    if (whose_turn == BLACK_TURN) {
-      gui_message (_("Dark's move"));
-    } else if (whose_turn == WHITE_TURN) {
-      gui_message (_("Light's move"));
-    }
+/**** Keyboard ****/
+static gboolean
+on_entry_key_press_event (GtkWidget *widget, GdkEventKey *event,
+                          gpointer user_data)
+{
+  gchar *ch;
+  gint x, y;
 
-  }
+  if (gtk_editable_get_position ((GtkEditable *) widget) < 2)
+    return FALSE;
+  ch = gtk_editable_get_chars ((GtkEditable *) widget, 0, 1);
+  x = (gint) ((*ch & 0xdf) - 0x40);
+  ch = gtk_editable_get_chars ((GtkEditable *) widget, 1, 2);
+  y = (gint) (*ch - 0x30);
 
+  gtk_editable_delete_text ((GtkEditable *) widget, 0, -1);
+  return check_event_move (x, y);
+}
 
+/******************/
+
+static gboolean
+on_drawing_area_button_press_event (GtkWidget *widget, GdkEventButton *event,
+                                    gpointer user_data)
+{
+  if (event->button != 1)       // The left mouse button was pressed.
+    return FALSE;
+
+  return check_event_move (event->x / (tile.width  + GRID_WIDTH) + 1,
+                           event->y / (tile.height + GRID_WIDTH) + 1);
 }
 
-void
-gui_message (gchar * message)
+static gboolean
+on_drawing_area_expose_event (GtkWidget *widget, GdkEventExpose *event,
+                              gpointer user_data)
 {
-  gnome_appbar_pop (GNOME_APPBAR (appbar));
-  gnome_appbar_push (GNOME_APPBAR (appbar), message);
+  gdk_draw_drawable (widget->window, gridGC[0], pixmap.buffer,
+                     event->area.x, event->area.y,
+                     event->area.x, event->area.y,
+                     event->area.width, event->area.height);
+  return FALSE;
 }
 
-guint
-check_computer_players (void)
+static gboolean
+on_drawing_area_configure_event (GtkWidget *widget, GdkEventConfigure *event,
+                                 gpointer user_data)
 {
+  board.width  = event->width;
+  board.height = event->height;
 
-  if (ggz_network_mode) {
-    black_computer_id = 0;
-    white_computer_id = 0;
-    return TRUE;
-  }
-  if (black_computer_level && whose_turn == BLACK_TURN)
-    switch (black_computer_level) {
-    case 1:
-      black_computer_id =
-	g_timeout_add (computer_speed, (GSourceFunc) computer_move_1,
-		       (gpointer) BLACK_TURN);
-      break;
-    case 2:
-      black_computer_id =
-	g_timeout_add (computer_speed, (GSourceFunc) computer_move_2,
-		       (gpointer) BLACK_TURN);
-      break;
-    case 3:
-      black_computer_id =
-	g_timeout_add (computer_speed, (GSourceFunc) computer_move_3,
-		       (gpointer) BLACK_TURN);
-      break;
-    }
+  // configure board
+  set_board_size ();
+  return FALSE;
+}
 
-  if (white_computer_level && whose_turn == WHITE_TURN)
-    switch (white_computer_level) {
-    case 1:
-      white_computer_id =
-	g_timeout_add (computer_speed, (GSourceFunc) computer_move_1,
-		       (gpointer) WHITE_TURN);
-      break;
-    case 2:
-      white_computer_id =
-	g_timeout_add (computer_speed, (GSourceFunc) computer_move_2,
-		       (gpointer) WHITE_TURN);
-      break;
-    case 3:
-      white_computer_id =
-	g_timeout_add (computer_speed, (GSourceFunc) computer_move_3,
-		       (gpointer) WHITE_TURN);
-      break;
-    }
+/**** Main window ****/
 
-  return TRUE;
-}
-
 void
-set_bg_color (void)
+network_gui_update (void)
 {
-  GdkImage *tmpimage;
-  GdkColor bgcolor;
+  gint i;
 
-  tmpimage = gdk_drawable_get_image (tiles_pixmap, 0, 0, 1, 1);
-  bgcolor.pixel = gdk_image_get_pixel (tmpimage, 0, 0);
-  gdk_window_set_background (drawing_area->window, &bgcolor);
+#ifdef GGZ_CLIENT
+// OPEN, HINT, NETWORK and LEAVE
+  for (i = OPEN; i <= NETWORK; i++) {
+    gtk_action_set_visible (actions[i],     !ggz_network_mode);
+    gtk_action_set_sensitive (actions[i],   !ggz_network_mode);
+  }
+  gtk_action_set_sensitive (actions[LEAVE],  ggz_network_mode);
+  gtk_action_set_visible   (actions[LEAVE],  ggz_network_mode);
+#endif
+// Fullscreen
+  gtk_action_set_visible (actions[FULLSCREEN], !(options & FullScreen));
+  gtk_action_set_visible (actions[UNFULLSCREEN], options & FullScreen);
+// Properties dialog
+  if (widget[PROPERTIES])
+    on_properties_cancel_clicked (NULL, NULL);
+}
 
-  if (gridGC[0])
-    g_object_unref (gridGC[0]);
-  gridGC[0] = gdk_gc_new (drawing_area->window);
-  if (gridGC[1])
-    g_object_unref (gridGC[1]);
-  gridGC[1] = gdk_gc_new (drawing_area->window);
+static void
+set_actions (void)
+{
+  const gchar *action_names[] = {
+    "newgame",
+    "head",
+    "back",
+    "forward",
+    "last",
+    "fullscreen",
+    "unfullscreen",
+    "save",
+    "open",
+    "hint",
+#ifdef GGZ_CLIENT
+    "network",
+    "leave"
+#endif
+  };
+  gint i;
 
-  gdk_gc_copy (gridGC[0], drawing_area->style->bg_gc[0]);
-  gdk_gc_copy (gridGC[1], drawing_area->style->bg_gc[0]);
+  for ( i = 0; i < MAX_ACTIONS; i++)
+    actions[i] = gtk_action_group_get_action (action_group, action_names[i]);
+}
 
-  gdk_gc_set_background (gridGC[0], &bgcolor);
-  gdk_gc_set_foreground (gridGC[0], &bgcolor);
+static const gchar manager_definition[] = {
+    "<ui>"
+    "  <menubar name='MenuBar'>"
+    "    <menu name='GameMenu' action='game_menu'>"
+    "      <menuitem action='newgame'/>"
+    "      <menuitem action='hint'/>"
+#ifdef GGZ_CLIENT
+    "      <menuitem action='network'/>"
+    "      <menuitem action='leave'/>"
+#endif
+    "      <separator/>"
+    "      <menuitem action='head'/>"
+    "      <menuitem action='back'/>"
+    "      <menuitem action='forward'/>"
+    "      <menuitem action='last'/>"
+/**** File open & file save ****/
+    "      <separator/>"
+    "      <menuitem action='open'/>"
+    "      <menuitem action='save'/>"
+/******************/
+    "      <separator/>"
+    "      <menuitem action='quit'/>"
+    "    </menu>"
+    "    <menu name='ViewMenu' action='view_menu'>"
+    "      <menuitem action='fullscreen'/>"
+    "      <menuitem action='unfullscreen'/>"
+    "    </menu>"
+    "    <menu name='SettingsMenu' action='settings_menu'>"
+    "      <menuitem action='preferences'/>"
+    "    </menu>"
+    "    <menu name='HelpMenu' action='help_menu'>"
+    "      <menuitem action='help'/>"
+    "      <menuitem action='about'/>"
+    "    </menu>"
+    "  </menubar>"
+    "  <toolbar  name='ToolBar'>"
+    "      <toolitem action='newgame'/>"
+    "      <toolitem action='hint'/>"
+#ifdef GGZ_CLIENT
+    "      <toolitem action='network'/>"
+    "      <toolitem action='leave'/>"
+#endif
+    "      <toolitem action='quit'/>"
+    "      <separator/>"
+    "      <toolitem action='head'/>"
+    "      <toolitem action='back'/>"
+    "      <toolitem action='forward'/>"
+    "      <toolitem action='last'/>"
+    "  </toolbar>"
+    "</ui>"
+};
 
-  /* Create a complementary color to use for the ON state */
-  bgcolor.pixel = 0xFFFFFF - bgcolor.pixel;
-  gdk_gc_set_background (gridGC[1], &bgcolor);
-  gdk_gc_set_foreground (gridGC[1], &bgcolor);
+static GtkActionEntry action_entries[] = {
+  {"game_menu", NULL, N_("_Game")},
+  {"newgame", GAMES_STOCK_NEW_GAME, NULL, NULL,
+   N_("Start a new game"),
+   G_CALLBACK (on_newgame_activate)},
+  {"hint", GAMES_STOCK_HINT, NULL, NULL,
+   N_("Get a hint for your next move"),
+   G_CALLBACK (on_hint_activate)},
+#ifdef GGZ_CLIENT
+  {"network", GAMES_STOCK_NETWORK_GAME, NULL, NULL,
+   N_("Start a new multiplayer network game"),
+   G_CALLBACK (on_network_activate)},
+  {"leave", GAMES_STOCK_NETWORK_LEAVE, NULL, NULL,
+   N_("End the current network game and return to network server"),
+   G_CALLBACK (on_leave_activate)},
+#endif
+  {"head", GTK_STOCK_GOTO_FIRST, NULL, "<ALT>T",
+   N_("Back to the first step"),
+   G_CALLBACK (on_head_activate)},
+  {"back", GTK_STOCK_GO_BACK, NULL, "<ALT>B",
+   N_("Back to the one previous step"),
+   G_CALLBACK (on_back_activate)},
+  {"forward", GTK_STOCK_GO_FORWARD, NULL, "<ALT>F",
+   N_("Forward to the next step"),
+   G_CALLBACK (on_forward_activate)},
+  {"last", GTK_STOCK_GOTO_LAST, NULL, "<ALT>L",
+   N_("Forward to the last step"),
+   G_CALLBACK (on_last_activate)},
+/**** File open & file save ****/
+  {"open", GTK_STOCK_OPEN, NULL, NULL,
+   NULL,
+   G_CALLBACK (on_open_activate)},
+  {"save", GTK_STOCK_SAVE, NULL, NULL,
+   NULL,
+   G_CALLBACK (on_save_activate)},
+/******************/
+  {"quit", GTK_STOCK_QUIT, NULL, NULL,
+   N_("Quit this game"),
+   G_CALLBACK (on_quit_activate)},
+  {"view_menu", NULL, N_("_View")},
+  {"fullscreen", GAMES_STOCK_FULLSCREEN, NULL, NULL,
+   NULL,
+   G_CALLBACK (on_fullscreen_activate)},
+  {"unfullscreen", GAMES_STOCK_LEAVE_FULLSCREEN, NULL, NULL,
+   NULL,
+   G_CALLBACK (on_fullscreen_activate)},
+  {"settings_menu", NULL, N_("_Settings")},
+  {"preferences", GTK_STOCK_PREFERENCES, NULL, NULL,
+   NULL,
+   G_CALLBACK (on_properties_activate)},
+  {"help_menu", NULL, N_("_Help")},
+  {"help", GAMES_STOCK_CONTENTS, NULL, NULL,
+   NULL,
+   G_CALLBACK (on_help_activate)},
+  {"about", GTK_STOCK_ABOUT, NULL, NULL,
+   NULL,
+   G_CALLBACK (on_about_activate)}
+};
 
-  gdk_gc_set_line_attributes (gridGC[1], 0,
-			      GDK_LINE_ON_OFF_DASH,
-			      GDK_CAP_BUTT, GDK_JOIN_MITER);
+/******************/
 
-  g_object_unref (tmpimage);
-}
-
-static int
-save_state (GnomeClient * client, gint phase, GnomeRestartStyle save_style,
-	    gint shutdown, GnomeInteractStyle interact_style,
-	    gint fast, gpointer client_data)
+static GtkWidget *
+create_window (void)
 {
-  char *argv[20];
-  int i;
-  gint xpos, ypos;
+  const gchar *strs[] = {
+    _("Dark:"),         /* 0 */
+    _("Light:"),        /* 1 */
+    _("00"),                /* 2 */
+    _("00:00"),             /* 3 */
+  };
 
-  gdk_window_get_origin (window->window, &xpos, &ypos);
+  GtkWidget *_window;
+  GtkWidget *vbox;
+  GtkWidget *table;
+  GtkWidget *label;
+  GError    *error = NULL;
+  gchar     name[2] = { 0, 0 };
+  gchar     *markup;
+  gint      i;
 
-  i = 0;
-  argv[i++] = (char *) client_data;
-  argv[i++] = "-x";
-  argv[i++] = g_strdup_printf ("%d", xpos);
-  argv[i++] = "-y";
-  argv[i++] = g_strdup_printf ("%d", ypos);
+/**** Main window ****/
+  _window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (_window), APP_NAME_LONG);
+  gtk_window_set_default_size (GTK_WINDOW (_window),
+                               window.width, window.height);
+  games_conf_add_window (GTK_WINDOW (_window), NULL);
+  g_signal_connect (G_OBJECT (_window), "delete_event",
+                    G_CALLBACK (on_quit_activate), NULL);
+/**** UI manager ****/
+  manager = gtk_ui_manager_new ();
+  gtk_ui_manager_add_ui_from_string (manager, manager_definition, -1, &error);
+  action_group = gtk_action_group_new ("ActionGroup");
+  gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
+  gtk_action_group_add_actions (action_group, action_entries,
+                                G_N_ELEMENTS (action_entries), _window);
+  gtk_ui_manager_insert_action_group (manager, action_group, 0);
+  gtk_window_add_accel_group (GTK_WINDOW (_window),
+                              gtk_ui_manager_get_accel_group (manager));
+  set_actions ();
+/**** Notebook ****/
+  widget[NOTEBOOK] = gtk_notebook_new ();
+  gtk_container_add (GTK_CONTAINER (_window), widget[NOTEBOOK]);
+  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget[NOTEBOOK]), FALSE);
 
-  gnome_client_set_restart_command (client, i, argv);
-  gnome_client_set_clone_command (client, 0, NULL);
+  widget[VPANED] = gtk_vpaned_new ();
+  gtk_notebook_append_page (GTK_NOTEBOOK (widget[NOTEBOOK]), widget[VPANED], NULL);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (widget[NOTEBOOK]), MAIN_PAGE);
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_paned_pack1 (GTK_PANED (widget[VPANED]), vbox, TRUE, TRUE);
+/**** Menubar ****/
+  widget[MENUBAR] = gtk_ui_manager_get_widget (manager, "/MenuBar");
+  gtk_box_pack_start (GTK_BOX (vbox), widget[MENUBAR], FALSE, FALSE, 0);
+/**** Toolbar ****/
+  widget[TOOLBAR] = gtk_ui_manager_get_widget (manager, "/ToolBar");
+  gtk_box_pack_start (GTK_BOX (vbox), widget[TOOLBAR], FALSE, FALSE, 0);
+  gtk_toolbar_set_style (GTK_TOOLBAR (widget[TOOLBAR]), GTK_TOOLBAR_BOTH);
+  for (i = 0; i < MAX_ACTIONS - 2; i++) {
+    gtk_tool_item_set_expand (gtk_toolbar_get_nth_item
+                              ((GtkToolbar *) widget[TOOLBAR], i), TRUE);
+    gtk_tool_item_set_homogeneous (gtk_toolbar_get_nth_item
+                                   ((GtkToolbar *) widget[TOOLBAR], i), FALSE);
+  }
 
-  g_free (argv[2]);
-  g_free (argv[4]);
+  table = gtk_table_new (9, 9, FALSE);
+  gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
+/**** Label. A,B,C.. ****/
+  for (i = 1; i < 9; i++) {
+    name[0] = (gchar) (0x40 + i);
+    label = gtk_label_new (name);
+    gtk_table_attach (GTK_TABLE (table), label, i, i + 1, 0, 1,
+                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0, 0);
+    gtk_widget_set_size_request (label, -1, 19);
+    markup =
+      g_markup_printf_escaped ("<span foreground=\"red\">%s</span>", name);
+    gtk_label_set_markup_with_mnemonic ((GtkLabel *) label, markup);
+    g_free (markup);
+  }
+/**** Label. 1,2,3.. ****/
+  for (i = 1; i < 9; i++) {
+    name[0] = (gchar) (0x30 + i);
+    label = gtk_label_new (name);
+    gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i + 1,
+                      0, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+    gtk_widget_set_size_request (label, 19, -1);
+    markup =
+      g_markup_printf_escaped ("<span foreground=\"red\">%s</span>", name);
+    gtk_label_set_markup_with_mnemonic ((GtkLabel *) label, markup);
+    g_free (markup);
+  }
+/**** Drawing area ****/
+  widget[BOARD] = gtk_drawing_area_new ();
+  gtk_widget_set_double_buffered (widget[BOARD], FALSE);
+  gtk_widget_set_size_request (widget[BOARD], BOARD_MIN, BOARD_MIN);
+  gtk_table_attach (GTK_TABLE (table), widget[BOARD], 1, 9, 1, 9,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+  gtk_widget_set_events (widget[BOARD],
+                         GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
+  g_signal_connect ((gpointer) widget[BOARD], "expose_event",
+                    G_CALLBACK (on_drawing_area_expose_event), NULL);
+  g_signal_connect ((gpointer) widget[BOARD], "button_press_event",
+                    G_CALLBACK (on_drawing_area_button_press_event), NULL);
+  g_signal_connect ((gpointer) widget[BOARD], "configure_event",
+                    G_CALLBACK (on_drawing_area_configure_event), NULL);
+/**** Keyboard ****/
+  widget[KEYBOARD] = gtk_entry_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), widget[KEYBOARD], FALSE, FALSE, 0);
+  gtk_widget_set_events (widget[KEYBOARD], GDK_KEY_PRESS_MASK);
+  g_signal_connect ((gpointer) widget[KEYBOARD], "key_press_event",
+                    G_CALLBACK (on_entry_key_press_event), NULL);
+  gtk_editable_set_editable ((GtkEditable *) widget[KEYBOARD], TRUE);
+  gtk_container_get_focus_chain ((GtkContainer *) vbox, &focusable_widgets);
+  gtk_container_set_focus_child ((GtkContainer *) vbox, widget[KEYBOARD]);
+/**** Statusbar ****/
+  widget[STATUSBAR] = gtk_statusbar_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), widget[STATUSBAR], FALSE, FALSE, 0);
+  gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (widget[STATUSBAR]), FALSE);
 
-  return TRUE;
+  table = gtk_table_new (1, 5, FALSE);
+  gtk_box_pack_start (GTK_BOX (widget[STATUSBAR]), table, FALSE, TRUE, 0);
+/**** Counter ****/
+  widget[COUNTER] = gtk_label_new (strs[2]);
+  gtk_table_attach (GTK_TABLE (table), widget[COUNTER], 0, 1, 0, 1,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (GTK_FILL), 2, 0);
+/**** Scores ****/
+  for (i = 0; i < 2; i++) {
+    label = gtk_label_new (strs[i]);
+    gtk_table_attach (GTK_TABLE (table), label, i * 2 + 1, i * 2 + 2, 0, 1,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 3, 0);
+    markup =
+     g_markup_printf_escaped ("<span foreground=\"blue\">%s</span>", strs[i]);
+    gtk_label_set_markup_with_mnemonic ((GtkLabel *) label, markup);
+    g_free (markup);
+    widget[BLACK_SCORE + i] = gtk_label_new (strs[1]);
+    gtk_table_attach (GTK_TABLE (table), widget[BLACK_SCORE + i], i * 2 + 2, i * 2 + 3, 0, 1,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 3, 0);
+  }
+/**** Timers ****/
+  widget[TIMER] = gtk_table_new (1, 4, FALSE);
+  gtk_box_pack_start (GTK_BOX (widget[STATUSBAR]), widget[TIMER], FALSE, FALSE, 0);
+  for (i = 0; i < 2; i++) {
+    timer[i] = g_timer_new ();
+    label = gtk_label_new (strs[i]);
+    gtk_table_attach (GTK_TABLE (widget[TIMER]), label, i * 2, i * 2 + 1, 0, 1,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 3, 0);
+    markup =
+     g_markup_printf_escaped ("<span foreground=\"blue\">%s</span>", strs[i]);
+    gtk_label_set_markup_with_mnemonic ((GtkLabel *) label, markup);
+    g_free (markup);
+    widget[BLACK_TIME + i] = gtk_label_new (strs[2]);
+    gtk_table_attach (GTK_TABLE (widget[TIMER]), widget[BLACK_TIME + i], i * 2 + 1,
+                      i * 2 + 2, 0, 1,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 3, 0);
+  }
+/****************/
+
+  gtk_widget_show_all (_window);
+  return _window;
 }
 
+/**** Main ****/
 int
 main (int argc, char **argv)
 {
-  GnomeClient *client;
   GnomeProgram *program;
   GOptionContext *context;
 
@@ -881,54 +1273,43 @@
   g_thread_init (NULL);
 
   context = g_option_context_new (NULL);
-  g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
   games_sound_add_option_group (context);
 
-  program = gnome_program_init ("iagno", VERSION,
-				LIBGNOMEUI_MODULE,
-				argc, argv,
-				GNOME_PARAM_GOPTION_CONTEXT, context,
-				GNOME_PARAM_APP_DATADIR, DATADIR, NULL);
+  program = gnome_program_init (APP_NAME, VERSION,
+                                LIBGNOMEUI_MODULE,
+                                argc, argv,
+                                GNOME_PARAM_GOPTION_CONTEXT, context,
+                                GNOME_PARAM_APP_DATADIR, DATADIR, NULL);
 
+  games_stock_init ();
   gtk_window_set_default_icon_name ("gnome-iagno");
-
   games_conf_initialise (APP_NAME);
 
-  client = gnome_master_client ();
-
-  g_signal_connect (G_OBJECT (client), "save_yourself",
-		    G_CALLBACK (save_state), argv[0]);
-  g_signal_connect (G_OBJECT (client), "die",
-		    G_CALLBACK (quit_game_cb), argv[0]);
-
-  create_window ();
-
-  load_properties ();
-
-  load_pixmaps ();
-
-  gtk_widget_show (window);
-
+  // Initialization of data.
+  tile.pixmap = NULL;
+  pixmap.buffer = NULL;
+  widget[PROPERTIES] = NULL;
 #ifdef GGZ_CLIENT
-  network_init ();
+  widget[HPANED] = NULL;
 #endif
 
-  if (session_xpos >= 0 && session_ypos >= 0) {
-    gdk_window_move (window->window, session_xpos, session_ypos);
-  }
+  // Create main window
+  properties_load ();
+  widget[WINDOW] = create_window ();
+  if (window.xpos > 0 && window.ypos > 0)
+    gtk_window_move (GTK_WINDOW (widget[WINDOW]), window.xpos, window.ypos);
+  network_gui_update ();
+  properties_reset ();
 
-  buffer_pixmap = gdk_pixmap_new (drawing_area->window,
-				  BOARDWIDTH, BOARDHEIGHT, -1);
-
-  set_bg_color ();
-
-  init_new_game ();
-
+  // Start game
+  game_init ();
+  properties_apply_changes ();
+  game_start ();
+  gui_message (_("Welcome to Iagno!"));
   gtk_main ();
 
+  // Quit game
   games_conf_shutdown ();
-
   g_object_unref (program);
-
   return 0;
 }
Index: iagno/properties.c
===================================================================
--- iagno/properties.c	(リビジョン 7688)
+++ iagno/properties.c	(作業コピー)
@@ -15,607 +15,535 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307,
+ * USA
  *
  * For more details see the file COPYING.
  */
 
-#include <config.h>
 #include <gnome.h>
-#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <config.h>
 #include <games-conf.h>
-#include <games-frame.h>
-#include <games-files.h>
 #include <games-sound.h>
+#include <games-files.h>
+#include <games-frame.h>
 
-#include "properties.h"
-#include "gnothello.h"
 #include "othello.h"
+#include "gnothello.h"
+#include "properties.h"
 
-#define KEY_TILESET             "tileset"
-#define KEY_BLACK_LEVEL         "black_level"
-#define KEY_WHITE_LEVEL         "white_level"
-#define KEY_QUICK_MOVES         "quick_moves"
-#define KEY_ANIMATE             "animate"
-#define KEY_ANIMATE_STAGGER     "animate_stagger"
-#define KEY_SHOW_GRID           "show_grid"
-#define KEY_FLIP_FINAL_RESULTS "flip_final_results"
-#define KEY_SOUND               "sound"
+// GConf keys
+static const gchar *keys[] = {
+  "tileset",                    /* 0 */
+  "bg_color_name",              /* 1 */
+  "width",                      /* 2 */
+  "height",                     /* 3 */
+  "x_position",                 /* 4 */
+  "y_position",                 /* 5 */
+  "black_level",                /* 6 */
+  "white_level",                /* 7 */
+  "quick_moves",                /* 8 */
+  "sound",                      /* 9 */
+  "flip_final_results",         /* 10 */
+  "valid_squares",              /* 11 */
+  "last_move_mark",             /* 12 */
+  "toolbar",                    /* 13 */
+  "timer",                      /* 14 */
+  "keyboard",                   /* 15 */
+  "fullscreen"                  /* 16 */
+};
 
-#define DEFAULT_TILESET "classic.png"
+static const gchar *tiles_name[] = {
+  N_("disk"),
+  N_("marble"),
+  N_("sun and star")
+};
 
+static const gchar *tiles_svg[] = {
+  "disk.svg",
+  "marble.svg",
+  "sun_and_star.svg"
+};
 
-extern GtkWidget *window;
-extern guint black_computer_level;
-extern guint white_computer_level;
-extern guint computer_speed;
-extern guint black_computer_id;
-extern guint white_computer_id;
-extern gchar *tile_set;
-extern gchar *tile_set_tmp;
-extern gint8 pixmaps[8][8];
-extern gint animate;
-extern gint animate_stagger;
-extern gint flip_pixmaps_id;
-extern gint flip_final;
-extern gint grid;
-gint sound;
+static GameOptions t_options;
+static gchar       *t_bg_color_name;
+static gint        t_tile_name = 0;
+static gint        t_computer_level[2];
 
-guint t_black_computer_level;
-guint t_white_computer_level;
-gint t_animate;
-gint t_quick_moves;
-gint t_animate_stagger;
-gint t_flip_final;
-gint t_grid;
+extern GtkWidget   *widget[];
+extern GdkColor    bg_color[];
+extern GameOptions options;
+extern GameState   state;
+extern GameFlags   flags;
+extern GameKifu    kifu[];
+extern GameWindow  window;
+extern GameTile    tile;
+extern gchar       *bg_color_name;
+extern gint        computer_level[];
+extern guint       check_flags_id;
+#ifdef GGZ_CLIENT
+extern gboolean    ggz_network_mode;
+#endif
 
-static GamesFileList *theme_file_list = NULL;
 
-static void apply_changes (void);
 
-/*
- * FIXME:
- *	It doesn't abide by the HIG.
- */
-
-static gint
-clamp_int (gint input, gint low, gint high)
+void
+properties_load (void)
 {
-  if (input < low)
-    input = low;
-  if (input > high)
-    input = high;
+  gint i;
 
-  return input;
+  tile.name     = games_conf_get_string_with_default  (NULL, keys[0],
+                                                       DEFAULT_TILESET);
+  bg_color_name = games_conf_get_string_with_default  (NULL, keys[1],
+                                                       DEFAULT_BGCOLOR);
+  window.width  = games_conf_get_integer_with_default (NULL, keys[2],
+                                                       DEFAULT_WINDOW_W);
+  window.height = games_conf_get_integer_with_default (NULL, keys[3],
+                                                       DEFAULT_WINDOW_H);
+  window.xpos   = games_conf_get_integer_with_default (NULL, keys[4], 0);
+  window.ypos   = games_conf_get_integer_with_default (NULL, keys[5], 0);
+  for (i = 0; i < 2; i++)
+    computer_level[i] = CLAMP (games_conf_get_integer (NULL, keys[6 + i],
+                                                           NULL), 0, 4);
+  options = 0;
+  for (i = 0; i < MAX_OPTIONS; i++) {
+    if (games_conf_get_boolean (NULL, keys[8 + i], NULL))
+      options |= 1 << i;
+  }
 }
 
 void
-load_properties (void)
+properties_save (void)
 {
-  black_computer_level = games_conf_get_integer (NULL, KEY_BLACK_LEVEL, NULL);
-  black_computer_level = clamp_int (black_computer_level, 0, 3);
+  gint i;
 
-  white_computer_level = games_conf_get_integer (NULL, KEY_WHITE_LEVEL, NULL);
-  white_computer_level = clamp_int (white_computer_level, 0, 3);
+  games_conf_set_string  (NULL, keys[0], tile.name);
+  games_conf_set_string  (NULL, keys[1], bg_color_name);
+  games_conf_set_integer (NULL, keys[2], window.width);
+  games_conf_set_integer (NULL, keys[3], window.height);
+  games_conf_set_integer (NULL, keys[4], window.xpos);
+  games_conf_set_integer (NULL, keys[5], window.ypos);
+  for (i = 0; i < 2; i++)
+    games_conf_set_integer (NULL, keys[i + 6], computer_level[i]);
+  for (i = 0; i < MAX_OPTIONS - 1; i++)
+    games_conf_set_boolean (NULL, keys[i + 8], options & (1 << i));
+}
 
-  if (games_conf_get_boolean (NULL, KEY_QUICK_MOVES, NULL))
-    computer_speed = COMPUTER_MOVE_DELAY / 2;
-  else
-    computer_speed = COMPUTER_MOVE_DELAY;
+void
+properties_reset (void)
+{
+  gint i;
 
-  if (tile_set)
-    g_free (tile_set);
+  for (i = 0; i < 2; i++)
+    t_computer_level[i] = computer_level[i];
+  t_bg_color_name = g_strdup (bg_color_name);
+  t_tile_name = 0;
+  while (t_tile_name < 2 && strcmp (tile.name, tiles_svg[t_tile_name]))
+    t_tile_name++;
+  t_options = options;
 
-  tile_set = games_conf_get_string_with_default (NULL, KEY_TILESET, DEFAULT_TILESET);
-
-  animate = games_conf_get_integer (NULL, KEY_ANIMATE, NULL);
-  animate = clamp_int (animate, 0, 2);
-
-  animate_stagger = games_conf_get_boolean (NULL, KEY_ANIMATE_STAGGER, NULL);
-
-  sound = games_conf_get_boolean (NULL, KEY_SOUND, NULL);
-  games_sound_enable (sound);
-
-  grid = games_conf_get_boolean (NULL, KEY_SHOW_GRID, NULL);
-
-  flip_final = games_conf_get_boolean (NULL, KEY_FLIP_FINAL_RESULTS, NULL);
-
-  switch (animate) {
-  case 0:
-    flip_pixmaps_id = g_timeout_add (100, flip_pixmaps, NULL);
-    break;
-  case 1:
-    flip_pixmaps_id =
-      g_timeout_add (PIXMAP_FLIP_DELAY * 8, flip_pixmaps, NULL);
-    break;
-  default:
-  case 2:
-    flip_pixmaps_id = g_timeout_add (PIXMAP_FLIP_DELAY, flip_pixmaps, NULL);
-    break;
-  }
+  gdk_color_parse (bg_color_name, &bg_color[2]);
+  gdk_colormap_alloc_color (gtk_widget_get_colormap (widget[BOARD]),
+                            &bg_color[2], FALSE, TRUE);
 }
 
-static void
-reset_properties (void)
+void
+properties_apply_changes (void)
 {
-  black_computer_level = games_conf_get_integer (NULL, KEY_BLACK_LEVEL, NULL);
-  black_computer_level = clamp_int (black_computer_level, 0, 3);
+  gint i;
 
-  white_computer_level = games_conf_get_integer (NULL, KEY_WHITE_LEVEL, NULL);
-  white_computer_level = clamp_int (white_computer_level, 0, 3);
-      
-  t_black_computer_level = black_computer_level;
-  t_white_computer_level = white_computer_level;
+  flags   = 0;
+  options = t_options;
 
-  t_quick_moves = games_conf_get_boolean (NULL, KEY_QUICK_MOVES, NULL);
+  if (check_flags_id)
+    g_source_remove (check_flags_id);
+  check_flags_id = g_timeout_add (PIXMAP_FLIP_DELAY * (options & Fast_Moves ? 1 : 2),
+                                  (GSourceFunc)check_flags, NULL);
 
-  if (tile_set_tmp)
-    g_free (tile_set_tmp);
+  games_sound_enable (options & Sound);
 
-  tile_set_tmp = games_conf_get_string_with_default (NULL, KEY_TILESET, DEFAULT_TILESET);
-
-  t_animate = animate;
-  t_animate_stagger = animate_stagger;
-  t_grid = grid;
-  t_flip_final = flip_final;
-}
-
-static void
-black_computer_level_select (GtkWidget * widget, gpointer data)
-{
-  if ((GPOINTER_TO_INT (data) != t_black_computer_level)
-      && (GTK_TOGGLE_BUTTON (widget)->active)) {
-    t_black_computer_level = GPOINTER_TO_INT (data);
-    apply_changes ();
+  // toolbar, timer, keyboard
+  for (i = 0; i < 3; i++) {
+    if (options & (1 << (5 + i)))
+      gtk_widget_show (widget[TOOLBAR + i]);
+    else
+      gtk_widget_hide (widget[TOOLBAR + i]);
   }
-}
+   
+  if (strcmp (bg_color_name, t_bg_color_name)) {
+    g_free (bg_color_name);
+    bg_color_name = g_strdup (t_bg_color_name);
+    set_bg_color ();
+  }
 
-static void
-white_computer_level_select (GtkWidget * widget, gpointer data)
-{
-  if ((GPOINTER_TO_INT (data) != t_white_computer_level)
-      && (GTK_TOGGLE_BUTTON (widget)->active)) {
-    t_white_computer_level = GPOINTER_TO_INT (data);
-    apply_changes ();
+  if (strcmp (tile.name, tiles_svg[t_tile_name])) {
+    g_free (tile.name);
+    tile.name = g_strdup (tiles_svg[t_tile_name]);
+    load_tiles ();
   }
-}
 
-static void
-sound_select (GtkWidget * widget, gpointer data)
-{
-  sound = GTK_TOGGLE_BUTTON (widget)->active;
-  apply_changes ();
+  check_game_over ();
+  flags |= CHECK_COMPUTER_PLAYERS;
 }
 
-static void
-quick_moves_select (GtkWidget * widget, gpointer data)
-{
-  if (GTK_TOGGLE_BUTTON (widget)->active)
-    t_quick_moves = 1;
-  else
-    t_quick_moves = 0;
-  apply_changes ();
-}
+/**** Properties dialog callbacks ****/
 
 static void
-flip_final_select (GtkWidget * widget, gpointer data)
+on_computer_level_changed (GtkToggleButton *togglebutton, gpointer user_data)
 {
-  if (GTK_TOGGLE_BUTTON (widget)->active)
-    t_flip_final = 1;
-  else
-    t_flip_final = 0;
-  apply_changes ();
-}
+  gint i;
 
-static void
-animate_stagger_select (GtkWidget * widget, gpointer data)
-{
-  if (GTK_TOGGLE_BUTTON (widget)->active)
-    t_animate_stagger = 1;
-  else
-    t_animate_stagger = 0;
-  apply_changes ();
+  if (togglebutton->active) {
+    t_computer_level[GPOINTER_TO_INT (user_data) / 16] =
+      GPOINTER_TO_INT (user_data) % 16;
+    game_stop ();
+    for (i = 0; i < 2; i++)
+      computer_level[i] = t_computer_level[i];
+    game_start ();
+  }
 }
 
 static void
-grid_select (GtkWidget * widget, gpointer data)
+on_options_toggled (GtkToggleButton *togglebutton, gpointer user_data)
 {
-  if (GTK_TOGGLE_BUTTON (widget)->active)
-    t_grid = 1;
-  else
-    t_grid = 0;
-  apply_changes ();
+  t_options ^= 1 << GPOINTER_TO_INT (user_data);
+  properties_apply_changes ();
 }
 
 static void
-animate_select (GtkWidget * widget, gpointer data)
+on_tile_set_box_changed (GtkComboBox *combobox, gpointer user_data)
 {
-  if (GTK_TOGGLE_BUTTON (widget)->active) {
-    t_animate = GPOINTER_TO_INT (data);
-  }
-  apply_changes ();
+  t_tile_name = gtk_combo_box_get_active (combobox);
+  properties_apply_changes ();
 }
 
 static void
-save_properties (void)
+on_color_button_color_set (GtkColorButton *colorbutton, gpointer user_data)
 {
-  games_conf_set_integer (NULL, KEY_BLACK_LEVEL, black_computer_level);
-  games_conf_set_integer (NULL, KEY_WHITE_LEVEL, white_computer_level);
-
-  games_conf_set_boolean (NULL, KEY_QUICK_MOVES, t_quick_moves);
-
-  games_conf_set_string (NULL, KEY_TILESET, tile_set_tmp);
-
-  games_conf_set_integer (NULL, KEY_ANIMATE, animate);
-
-  games_conf_set_boolean (NULL, KEY_ANIMATE_STAGGER, animate_stagger);
-  games_conf_set_boolean (NULL, KEY_SHOW_GRID, grid);
-  games_conf_set_boolean (NULL, KEY_FLIP_FINAL_RESULTS, flip_final);
-  games_conf_set_boolean (NULL, KEY_SOUND, sound);
+  gtk_color_button_get_color (colorbutton, &bg_color[2]);
+  g_free (t_bg_color_name);
+  t_bg_color_name = g_strdup_printf ("#%04X%04X%04X",
+                                     bg_color[2].red, bg_color[2].green,
+                                     bg_color[2].blue);
+  properties_apply_changes ();
 }
 
-static void
-apply_changes (void)
-{
-  guint i, j;
-
-  black_computer_level = t_black_computer_level;
-  white_computer_level = t_white_computer_level;
-
-  if (black_computer_id) {
-    g_source_remove (black_computer_id);
-    black_computer_id = 0;
-  }
-
-  if (white_computer_id) {
-    g_source_remove (white_computer_id);
-    white_computer_id = 0;
-  }
-
-  if (t_quick_moves)
-    computer_speed = COMPUTER_MOVE_DELAY / 2;
-  else
-    computer_speed = COMPUTER_MOVE_DELAY;
-
-  if (strcmp (tile_set, tile_set_tmp)) {
-    g_free (tile_set);
-    tile_set = g_strdup (tile_set_tmp);
-    load_pixmaps ();
-    set_bg_color ();
-    for (i = 0; i < 8; i++)
-      for (j = 0; j < 8; j++)
-	if (pixmaps[i][j] >= BLACK_TURN && pixmaps[i][j] <= WHITE_TURN)
-	  gui_draw_pixmap_buffer (pixmaps[i][j], i, j);
-	else
-	  gui_draw_pixmap_buffer (0, i, j);
-    gui_draw_grid ();
-  }
-
-  animate = t_animate;
-
-  if (flip_pixmaps_id) {
-    g_source_remove (flip_pixmaps_id);
-    flip_pixmaps_id = 0;
-  }
-
-  switch (animate) {
-  case 0:
-    flip_pixmaps_id = g_timeout_add (100, flip_pixmaps, NULL);
-    break;
-  case 1:
-    flip_pixmaps_id = g_timeout_add (PIXMAP_FLIP_DELAY * 8,
-				     flip_pixmaps, NULL);
-    break;
-  case 2:
-    flip_pixmaps_id = g_timeout_add (PIXMAP_FLIP_DELAY, flip_pixmaps, NULL);
-    break;
-  }
-
-  animate_stagger = t_animate_stagger;
-
-  flip_final = t_flip_final;
-
-  if (grid != t_grid) {
-    grid = t_grid;
-    gui_draw_grid ();
-  }
-
-  games_sound_enable (sound);
-
-  check_computer_players ();
-
-  save_properties ();
-}
-
-static gboolean
-close_cb (GtkWidget * widget)
-{
-  gtk_widget_hide (widget);
-
-  return TRUE;
-}
-
 void
-set_selection (GtkWidget * widget, gpointer data)
+on_properties_cancel_clicked (GtkButton *button, gpointer user_data)
 {
-  gchar *filename;
-
-  if (tile_set_tmp)
-    g_free (tile_set_tmp);
-
-  filename = games_file_list_get_nth (theme_file_list,
-				      gtk_combo_box_get_active (GTK_COMBO_BOX
-								(widget)));
-
-  tile_set_tmp = g_strdup (filename);
-
-  apply_changes ();
+  gtk_widget_destroy (widget[PROPERTIES]);
+  widget[PROPERTIES] = NULL;
 }
 
-void
-free_str (GtkWidget * widget, void *data)
-{
-  g_free (data);
-}
+/**** Properties dialog *****/
 
-static GtkWidget *
-fill_menu (void)
-{
-  gchar *dname = NULL;
-
-  /* FIXME: we need to check that both dname is valid and that
-   * games_file_list_new_images returns something. */
-
-  dname = gnome_program_locate_file (NULL,
-				     GNOME_FILE_DOMAIN_APP_PIXMAP,
-				     "iagno", FALSE, NULL);
-
-  if (theme_file_list)
-    g_object_unref (theme_file_list);
-
-  theme_file_list = games_file_list_new_images (dname, NULL);
-  g_free (dname);
-
-  games_file_list_transform_basename (theme_file_list);
-
-  return games_file_list_create_widget (theme_file_list, tile_set,
-					GAMES_FILE_LIST_REMOVE_EXTENSION |
-					GAMES_FILE_LIST_REPLACE_UNDERSCORES);
-}
-
 void
-show_properties_dialog (void)
+on_properties_activate (GtkMenuItem *menuitem, gpointer user_data)
 {
+  const gchar *strs[] = {
+    _("Dark"),                  /* 0 */
+    _("Light"),                 /* 1 */
+    _("Human"),                 /* 2 */
+    _("Level one"),             /* 3 */
+    _("Level two"),             /* 4 */
+    _("Level three"),           /* 5 */
+    _("Level four"),            /* 6 */
+    _("_Use fast moves"),       /* 7 */
+    _("E_nable sounds"),        /* 8 */
+    _("_Flip final results"),   /* 9 */
+    _("Show _valid squares"),   /* 10 */
+    _("Show _last move mark"),  /* 11 */
+    _("_Show toolbar"),         /* 12 */
+    _("Show ti_mer"),           /* 13 */
+    _("Enable _keyboard"),      /* 14 */
+  };
+
   GtkWidget *notebook;
-  GtkWidget *hbox;
+  GtkWidget *vbox, *vbox1;
   GtkWidget *label;
-  GtkWidget *label2;
   GtkWidget *table;
   GtkWidget *button;
   GtkWidget *frame;
-  GtkWidget *vbox, *vbox2;
-  GtkWidget *propbox = NULL;
-  GtkWidget *option_menu;
+  GtkWidget *hbox;
+  GtkWidget *tile_set_box;
+  GtkWidget *color_button;
+  GSList    *human_group[2] = { NULL, NULL };
+  gint      f, v;
 
-  if (propbox) {
-    gtk_window_present (GTK_WINDOW (propbox));
+  if (widget[PROPERTIES]) {
+    gtk_window_present (GTK_WINDOW (widget[PROPERTIES]));
     return;
   }
 
-  reset_properties ();
-
-  propbox = gtk_dialog_new_with_buttons (_("Iagno Preferences"),
-					 GTK_WINDOW (window),
-					 0,
-					 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
-					 NULL);
-
-  gtk_dialog_set_has_separator (GTK_DIALOG (propbox), FALSE);
-  gtk_container_set_border_width (GTK_CONTAINER (propbox), 5);
-  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (propbox)->vbox), 2);
-  gtk_window_set_resizable (GTK_WINDOW (propbox), FALSE);
+  widget[PROPERTIES] = gtk_dialog_new_with_buttons (_("Iagno Preferences"),
+                                                   GTK_WINDOW (widget[WINDOW]), 0,
+                                                   GTK_STOCK_CLOSE,
+                                                   GTK_RESPONSE_CLOSE, NULL);
+  gtk_dialog_set_has_separator (GTK_DIALOG (widget[PROPERTIES]), FALSE);
+  gtk_container_set_border_width (GTK_CONTAINER (widget[PROPERTIES]), 5);
+  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (widget[PROPERTIES])->vbox), 2);
+  gtk_window_set_resizable (GTK_WINDOW (widget[PROPERTIES]), FALSE);
+/*** Notebook ***/
   notebook = gtk_notebook_new ();
   gtk_container_set_border_width (GTK_CONTAINER (notebook), 5);
-  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (propbox)->vbox), notebook);
-
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (widget[PROPERTIES])->vbox),
+                     notebook);
+/*** Game page ***/
   label = gtk_label_new (_("Game"));
-
   vbox = gtk_vbox_new (FALSE, 18);
   gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label);
-
   table = gtk_table_new (1, 2, FALSE);
   gtk_table_set_col_spacings (GTK_TABLE (table), 18);
   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
-
-  vbox2 = gtk_vbox_new (FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
-
-  button = gtk_check_button_new_with_mnemonic (_("_Use quick moves"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
-				(computer_speed == COMPUTER_MOVE_DELAY / 2));
-  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK
-		    (quick_moves_select), NULL);
-
-  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
-
-  button = gtk_check_button_new_with_mnemonic (_("E_nable sounds"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), sound);
-  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK
-		    (sound_select), NULL);
-
-  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
-
-  frame = games_frame_new (_("Dark"));
-  gtk_table_attach_defaults (GTK_TABLE (table), frame, 0, 1, 0, 1);
-
-  vbox = gtk_vbox_new (FALSE, 6);
-
-  button = gtk_radio_button_new_with_label (NULL, _("Human"));
-  if (black_computer_level == 0)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (black_computer_level_select), (gpointer) 0);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Level one"));
-  if (black_computer_level == 1)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (black_computer_level_select), (gpointer) 1);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Level two"));
-  if (black_computer_level == 2)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (black_computer_level_select), (gpointer) 2);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Level three"));
-  if (black_computer_level == 3)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (black_computer_level_select), (gpointer) 3);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
-
-  frame = games_frame_new (_("Light"));
-  gtk_table_attach_defaults (GTK_TABLE (table), frame, 1, 2, 0, 1);
-
-  vbox = gtk_vbox_new (FALSE, 6);
-
-  button = gtk_radio_button_new_with_label (NULL, _("Human"));
-  if (white_computer_level == 0)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (white_computer_level_select), (gpointer) 0);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Level one"));
-  if (white_computer_level == 1)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (white_computer_level_select), (gpointer) 1);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Level two"));
-  if (white_computer_level == 2)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (white_computer_level_select), (gpointer) 2);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Level three"));
-  if (white_computer_level == 3)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (white_computer_level_select), (gpointer) 3);
-
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
-
-
+/*** Dark and Light frame ***/
+  for (f = 0; f < 2; f++) {
+    frame = games_frame_new (strs[f]);
+    gtk_table_attach_defaults (GTK_TABLE (table), frame, f, f + 1, 0, 1);
+    vbox1 = gtk_vbox_new (FALSE, 6);
+    gtk_container_add (GTK_CONTAINER (frame), vbox1);
+/*** Human and Level one ... ***/
+    for (v = 0; v < 5; v++) {
+      button = gtk_radio_button_new_with_mnemonic (NULL, strs[v + 2]);
+      gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 0);
+      gtk_radio_button_set_group (GTK_RADIO_BUTTON (button), human_group[f]);
+      human_group[f] = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+                                    (t_computer_level[f] == v));
+      g_signal_connect ((gpointer) button, "toggled",
+                        G_CALLBACK (on_computer_level_changed),
+                        GINT_TO_POINTER (f * 16 + v));
+#ifdef GGZ_CLIENT
+      gtk_widget_set_sensitive (button, !ggz_network_mode);
+#endif
+    }
+  }
+/**** Use fast moves and Enable sounds ****/
+  vbox1 = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), vbox1, FALSE, FALSE, 0);
+  for (v = 0; v < 2; v++) {
+    button = gtk_check_button_new_with_mnemonic (strs[v + 7]);
+    gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+                                  t_options & (1 << v));
+    g_signal_connect ((gpointer) button, "toggled",
+                      G_CALLBACK (on_options_toggled), GINT_TO_POINTER (v));
+  }
+/***  Appearance page ***/
   label = gtk_label_new (_("Appearance"));
-
   table = gtk_table_new (1, 2, FALSE);
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label);
   gtk_table_set_col_spacings (GTK_TABLE (table), 18);
   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
+/*** Options frame ***/
+  frame = games_frame_new (_("Options"));
+  gtk_table_attach_defaults (GTK_TABLE (table), frame, 1, 2, 0, 1);
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_container_add (GTK_CONTAINER (frame), vbox);
+/*** Options ***/
+  for (v = 2; v < MAX_OPTIONS - 1; v++) {
+    button = gtk_check_button_new_with_mnemonic (strs[v + 7]);
+    gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), t_options & (1 << v));
+    g_signal_connect ((gpointer) button, "toggled",
+                      G_CALLBACK (on_options_toggled), GINT_TO_POINTER (v));
+  }
+/*** Tile set ***/
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  label = gtk_label_new_with_mnemonic (_("_Tile set:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  tile_set_box = gtk_combo_box_new_text ();
+  gtk_box_pack_start (GTK_BOX (hbox), tile_set_box, TRUE, TRUE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), tile_set_box);
+  for (f = 0; f < 3; f++) {
+    gtk_combo_box_append_text (GTK_COMBO_BOX (tile_set_box), tiles_name[f]);
+  }
+  gtk_combo_box_set_active (GTK_COMBO_BOX (tile_set_box), t_tile_name);
+  g_signal_connect (G_OBJECT (tile_set_box), "changed",
+                    G_CALLBACK (on_tile_set_box_changed), NULL);
+/*** Background color ***/
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  label = gtk_label_new_with_mnemonic (_("_Background color:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  color_button = gtk_color_button_new ();
+  gtk_box_pack_start (GTK_BOX (hbox), color_button, TRUE, TRUE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), color_button);
+  gtk_color_button_set_color ((GtkColorButton *) color_button, &bg_color[2]);
+  g_signal_connect ((gpointer) color_button, "color_set",
+                    G_CALLBACK (on_color_button_color_set), NULL);
+/******************/
+  g_signal_connect (G_OBJECT (widget[PROPERTIES]), "response",
+                    G_CALLBACK (on_properties_cancel_clicked), NULL);
+  g_signal_connect (G_OBJECT (widget[PROPERTIES]), "delete_event",
+                    G_CALLBACK (on_properties_cancel_clicked), NULL);
+  gtk_widget_show_all (widget[PROPERTIES]);
+}
 
-  frame = games_frame_new (_("Animation"));
+/**** File open & file save ****/
 
-  vbox = gtk_vbox_new (FALSE, 6);
+/**** Write and read kifu ****/
+static void
+write_kifu (int fd)
+{
+  gchar buf[9] = { 0, 0, 0x20, 0, 0x20, 0, 0, 0x0A, 0 };
+  gint8 i = 3;
+  ssize_t count;
 
-  button = gtk_radio_button_new_with_label (NULL, _("None"));
-  if (animate == 0)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (animate_select), (gpointer) 0);
+  count = write (fd, _("iagno\n"), 6);
+  while (kifu[++i].who && count > 0) {
+    buf[0] = (gchar) ((i - 3) / 10 + 0x30);
+    buf[1] = (gchar) ((i - 3) % 10 + 0x30);
+    buf[3] = (kifu[i].who == BLACK) ? 0x42 : 0x57;
+    buf[5] = (gchar) (kifu[i].yx % 10 + 0x40);
+    buf[6] = (gchar) (kifu[i].yx / 10 + 0x30);
+    count = write (fd, buf, 8);
+  }
+}
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Partial"));
-  if (animate == 1)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (animate_select), (gpointer) 1);
+static void
+read_kifu (int fd)
+{
+  gchar buf[9];
+  guint i = 4;
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-  button = gtk_radio_button_new_with_label (gtk_radio_button_get_group
-					    (GTK_RADIO_BUTTON (button)),
-					    _("Complete"));
-  if (animate == 2)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (animate_select), (gpointer) 2);
+  read (fd, buf, 6);
+  buf[6] = 0;
+  if (!g_str_equal (buf, _("iagno\n"))) {
+    gui_message (N_("This isn't a file of iagno!"));
+    return;
+  }
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  while (read (fd, buf, 8) > 0) {
+    kifu[i].who = (buf[3] == 0x42) ? BLACK : WHITE;
+    kifu[i++].yx = (gint8) ((buf[6] - 0x30) * 10 + buf[5] - 0x40);
+  }
+  kifu[i].who = 0;
+}
 
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
-  gtk_table_attach_defaults (GTK_TABLE (table), frame, 0, 1, 0, 1);
+/**** File dialog callbacks ****/
+static void
+on_file_cancel_clicked (GtkButton *button, gpointer user_data)
+{
+  gtk_widget_destroy (widget[FILE_DIALOG]);
+}
 
-  frame = games_frame_new (_("Options"));
-  vbox = gtk_vbox_new (FALSE, 6);
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
-  button = gtk_check_button_new_with_mnemonic (_("_Stagger flips"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
-				t_animate_stagger);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (animate_stagger_select), NULL);
+static void
+on_save_clicked (GtkButton *button, gpointer user_data)
+{
+  int fd;
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  fd =
+    creat (gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget[FILE_DIALOG])),
+           0644);
+  if (fd > 0) {
+    write_kifu (fd);
+    close (fd);
+  }
+  return on_file_cancel_clicked (NULL, NULL);
+}
 
-  button = gtk_check_button_new_with_mnemonic (_("S_how grid"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), t_grid);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (grid_select), NULL);
+static void
+on_open_clicked (GtkButton *button, gpointer user_data)
+{
+  int fd;
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  fd =
+    open (gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget[FILE_DIALOG])),
+          0, 0644);
+  if (fd > 0) {
+    game_init ();
+    gui_message (_("Dark's move"));
+    read_kifu (fd);
+    close (fd);
+  }
 
-  button = gtk_check_button_new_with_mnemonic (_("_Flip final results"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), t_flip_final);
-  g_signal_connect (G_OBJECT (button), "toggled",
-		    G_CALLBACK (flip_final_select), NULL);
+  state = GAME_STOP | GAME_BACK;
+  check_game_over ();
+  return on_file_cancel_clicked (NULL, NULL);
+}
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+/**** Create file dialog ****/
+static void
+create_file_dialog (gint user_data)
+{
+  GtkWidget *dialog_vbox;
+  GtkWidget *dialog_action_area;
+  GtkWidget *file_cancel;
+  GtkWidget *file_ok;
 
-  hbox = gtk_hbox_new (FALSE, 12);
+  if (user_data)
+    widget[FILE_DIALOG] =
+      gtk_file_chooser_dialog_new ("", (GtkWindow *) widget[WINDOW],
+                                   GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
+  else
+    widget[FILE_DIALOG] =
+      gtk_file_chooser_dialog_new ("", (GtkWindow *) widget[WINDOW],
+                                   GTK_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
+  gtk_window_set_type_hint (GTK_WINDOW (widget[FILE_DIALOG]),
+                            GDK_WINDOW_TYPE_HINT_DIALOG);
 
-  label2 = gtk_label_new_with_mnemonic (_("_Tile set:"));
+  game_stop ();
 
-  gtk_box_pack_start (GTK_BOX (hbox), label2, FALSE, FALSE, 0);
+  dialog_vbox = GTK_DIALOG (widget[FILE_DIALOG])->vbox;
+  dialog_action_area = GTK_DIALOG (widget[FILE_DIALOG])->action_area;
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area),
+                             GTK_BUTTONBOX_END);
 
-  option_menu = fill_menu ();
-  gtk_label_set_mnemonic_widget (GTK_LABEL (label2), option_menu);
-  g_signal_connect (G_OBJECT (option_menu), "changed",
-		    G_CALLBACK (set_selection), NULL);
-  gtk_box_pack_start (GTK_BOX (hbox), option_menu, TRUE, TRUE, 0);
+  file_cancel = gtk_button_new_from_stock ("gtk-cancel");
+  gtk_dialog_add_action_widget (GTK_DIALOG (widget[FILE_DIALOG]), file_cancel,
+                                GTK_RESPONSE_CANCEL);
+  GTK_WIDGET_SET_FLAGS (file_cancel, GTK_CAN_DEFAULT);
+  if (user_data)
+    file_ok = gtk_button_new_from_stock ("gtk-open");
+  else
+    file_ok = gtk_button_new_from_stock ("gtk-save");
 
-  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_dialog_add_action_widget (GTK_DIALOG (widget[FILE_DIALOG]), file_ok,
+                                GTK_RESPONSE_OK);
+  GTK_WIDGET_SET_FLAGS (file_ok, GTK_CAN_DEFAULT);
 
-  gtk_table_attach_defaults (GTK_TABLE (table), frame, 1, 2, 0, 1);
+  g_signal_connect ((gpointer) file_cancel, "clicked",
+                    G_CALLBACK (on_file_cancel_clicked), NULL);
+  if (user_data)
+    g_signal_connect ((gpointer) file_ok, "clicked",
+                      G_CALLBACK (on_open_clicked), NULL);   
+  else
+    g_signal_connect ((gpointer) file_ok, "clicked",
+                      G_CALLBACK (on_save_clicked), NULL);
+  g_signal_connect ((gpointer) widget[FILE_DIALOG], "delete_event",
+                    G_CALLBACK (on_file_cancel_clicked), NULL);
 
-  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label);
+  gtk_widget_show_all (widget[FILE_DIALOG]);
+  gtk_widget_grab_default (file_ok);
+  gtk_window_set_modal ((GtkWindow *)widget[FILE_DIALOG], TRUE);
+}
 
-  g_signal_connect (G_OBJECT (propbox), "response", G_CALLBACK
-		    (close_cb), NULL);
-  g_signal_connect (G_OBJECT (propbox), "delete_event", G_CALLBACK
-		    (close_cb), NULL);
+/**** Main menu callbacks ****/
+void
+on_save_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  gchar     filename[28];
+  time_t    t;
+  struct tm *tmp;
 
-  gtk_widget_show_all (propbox);
+  create_file_dialog (0);
+  t = time (NULL);
+  tmp = localtime (&t);
+  strftime (filename, sizeof(filename), "%y%m%d%H%M%S", tmp);
+  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (widget[FILE_DIALOG]),
+                                       filename);
 }
+
+void
+on_open_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  create_file_dialog (1);
+}
