Index: iagno/gnothello.h
===================================================================
--- iagno/gnothello.h	(リビジョン 6541)
+++ 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
@@ -19,69 +20,68 @@
  * 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 PIXMAP_FLIP_DELAY		16
 
-#define MAIN_PAGE           	0
-#define NETWORK_PAGE           	1
+#define WINDOW_W_DEFAULT		468
+#define WINDOW_H_DEFAULT		565
+#define BOARD_MIN			279
+#define GRID_WIDTH			1
 
-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;
+#define FLIP_TILES			1
+#define FLIP_FINAL			1 << 1
+#define CHECK_COMPUTER_PLAYERS	1 << 2
+#define COMPUTER_FLAG		1 << 3
+#define HINT_FLAG			1 << 4
+#define GUI_HINT_FLAG		1 << 5
+#define FLIP_SOUND			1 << 6
+#define GAMEOVER_SOUND		1 << 7
 
-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);
+
+gint clamp_int (gint input, gint low, gint high);
+
+void copy_board (void);
+
+void set_bg_color (void);
+
 void load_pixmaps (void);
-void properties_cb (GtkWidget * widget, gpointer data);
-void set_bg_color (void);
+
 void gui_draw_grid (void);
 
-#endif
+void redraw_board (void);
+
+void gui_status (void);
+
+void gui_message (gchar *message);
+
+void reset_timer (void);
+
+gboolean flip_pixmaps (gpointer data);
+
+void set_sensitive (void);
+
+void check_game_over (void);
+
+gboolean check_valid_move (gint yx, gint who);
+
+void move (gint yx);
+
+void stop_game (void);
+
+void init_game (void);
+
+void start_game (void);
+
+void on_head_activate (GtkMenuItem *menuitem, gpointer user_data);
+
+void network_gui_update (void);
+
Index: iagno/properties.h
===================================================================
--- iagno/properties.h	(リビジョン 6541)
+++ iagno/properties.h	(作業コピー)
@@ -1,7 +1,43 @@
-#ifndef _PROPERTIES_H_
-#define _PROPERTIES_H_
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
 
+/*
+ * 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.
+ */
+
+
 void load_properties (void);
-void show_properties_dialog (void);
 
-#endif
+void save_properties (void);
+
+void reset_properties (void);
+
+void apply_changes (void);
+
+void on_ok_clicked (GtkButton *button, gpointer user_data);
+
+void on_preferences_activate (GtkMenuItem *menuitem, gpointer user_data);
+
+void on_save_cancel_clicked (GtkButton *button, gpointer user_data);
+
+void on_save_activate (GtkMenuItem *menuitem, gpointer user_data);
+
+void on_open_cancel_clicked (GtkButton *button, gpointer user_data);
+
+void on_open_activate (GtkMenuItem *menuitem, gpointer user_data);
+
Index: iagno/othello.c
===================================================================
--- iagno/othello.c	(リビジョン 6541)
+++ iagno/othello.c	(作業コピー)
@@ -2,7 +2,6 @@
 
 /*
  * othello.c - Othello support routines for 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
@@ -21,33 +20,22 @@
  * 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
-
-gint8 squares[64] = { 44, 45, 54, 55, 23, 26, 73, 76,
+static const  gint8 squares0[] = {
+  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,
@@ -57,667 +45,450 @@
   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 gint heuristic[] = {
+  0,   0,   0, 0, 0, 0, 0,   0,   0, 0,
+  0, 153, -33, 6, 4, 4, 6, -33, 153, 0,
+  0, -33, -73, 3, 2, 2, 3, -73, -33, 0,
+  0,   6,   3, 5, 3, 3, 5,   3,   6, 0,
+  0,   4,   2, 3, 1, 1, 3,   2,   4, 0,
+  0,   4,   2, 3, 1, 1, 3,   2,   4, 0,
+  0,   6,   3, 5, 3, 3, 5,   3,   6, 0,
+  0, -33, -73, 3, 2, 2, 3, -73, -33, 0,
+  0, 153, -33, 6, 4, 4, 6, -33, 153, 0,
+  0,   0,   0, 0, 0, 0, 0,   0,   0, 0
 };
 
 static const gint dirs[] = { UL, UU, UR, LL, RR, DL, DD, DR };
+static gint8 squares[64];
+/* This array can probably be a lot smaller (< 300). */
+static gint8 history[MAX_MOVE_COUNT * 12];
+static gint8 *history_pointer;
+static GRand *rgen;
 
-guint flip_final_id = 0;
-gint flip_final;
+gint8        board0[100];
+gint         valid_squares[(VICTORY + 2) * (VICTORY + 3) / 2][2];
+gint         s_kind;
+gint8        whose_turn;
+gint8        black_score;
+gint8        white_score;
+gint8        move_count;
 
-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)
 {
-  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 < 64; 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)
+        board0[ij++] = OUTSIDE;
       else
-	board0[x] = BLANK;
-      x++;
+        board0[ij++] = BLANK;
     }
+  board0[44] = WHITE;
+  board0[45] = BLACK;
+  board0[54] = BLACK;
+  board0[55] = WHITE;
 
-  board0[44] = WHITE_TURN;
-  board0[45] = BLACK_TURN;
-  board0[54] = BLACK_TURN;
-  board0[55] = WHITE_TURN;
-
-  hpointer = 0;
-  vpointer = 0;
+  move_count      = 4;
+  black_score     = 2;
+  white_score     = 2;
+  whose_turn      = BLACK;
+  history_pointer = &history[0];
 }
 
-/* Copy data from board0 to board */
-void
-board_copy (void)
-{
-  gint i, j;
-
-  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)
+static gboolean
+check_valid0 (gint yx, gint dir, gint who)
 {
-  gint tmp;
-  gint8 not_me;
-
-  not_me = OTHER_PLAYER (who);
-
+  gint tmp = yx + dir;
+  gint8 not_me = (gint8) OTHER_PLAYER (who);
   /* To be valid, the next counter should not be the current player ... */
-  tmp = xy + dir;
   if (board0[tmp] != not_me)
     return FALSE;
-
   /* ... but eventually we must find a counter that is. */
   do {
     tmp += dir;
   } while (board0[tmp] == not_me);
 
-  return board0[tmp] == who;
+  return board0[tmp] == (gint8) 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
+check_valid (gint yx, gint who)
 {
-  int i;
+  gint i;
 
   for (i = 0; i < NDIRS; i++)
-    if (is_valid0 (xy, dirs[i], who))
-      return (TRUE);
+    if (check_valid0 (yx, dirs[i], who))
+      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
+move_board0 (gint yx, gint dir)
 {
-  gint xy;
+  gint tmp = yx + dir;
+  gint8 not_me = OTHER_PLAYER (whose_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)
     return;
   /* Find the extent of the move in direction dir. */
   do {
     tmp += dir;
   } while (board0[tmp] == not_me);
+
   if (board0[tmp] != whose_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 */
+  while (tmp != yx) {
+    board0[tmp] = whose_turn;			/* Flip pieces.    */
+    *history_pointer++ = (gint8) tmp;	/* Record history. */
     tmp -= dir;
   }
 }
 
-/* reverse some pieces */
+/* Reverse some pieces. */
 void
-move_board (gint xy)
+move_board (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++)
-    move_board0 (xy, dirs[i]);
+    move_board0 (yx, dirs[i]);
 
-  board0[xy] = whose_turn;
-  count = hpointer - count;
-  history[hpointer++] = count;	/* make history */
-  history[hpointer++] = whose_turn;
+  count              = (gint8) (history_pointer - p_tmp) / sizeof (gint8);
+  *history_pointer++ = count; 		/* history[f1,f2,,,fn,n,who] */
+  *history_pointer++ = whose_turn;
+  board0[yx]         = whose_turn;
 
-  if (whose_turn == WHITE_TURN) {
-    wcount += count + 1;
-    bcount -= count;
+  i = move_count++;					/* move_count = move_count + 1;         */
+  tmp = squares[i];					/* squares[0,1,2,,,,move_count,,,62,63] */
+  squares[i] = (gint8) yx;			/*        [-already puted-|-yet blank-] */
+  if (tmp != (gint8) yx) {			/* Sort squares. */
+    while (squares[++i] != (gint8) yx)
+      ;
+    squares[i] = tmp;
+  }
+
+  if (whose_turn == WHITE) {
+    white_score += count + 1;
+    black_score -= count;
   } else {
-    bcount += count + 1;
-    wcount -= count;
+    black_score += count + 1;
+    white_score -= 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);
 }
 
-
-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;
-}
-
-/* Back to before board0 */
+/* Back to the one previous board0. */
 void
-undo (void)
+back (void)
 {
   gint8 not_me, count;
 
-  whose_turn = history[--hpointer];	/* history[t1,t2,,,tn, n,who] */
-  count = history[--hpointer];
+  whose_turn = *--history_pointer;	/* history[f1,f2,,,fn,n,who] */
+  count      = *--history_pointer;
 
-  if (whose_turn == WHITE_TURN) {
-    wcount -= count + 1;
-    bcount += count;
+  if (whose_turn == WHITE) {
+    white_score -= count + 1;
+    black_score += count;
   } else {
-    bcount -= count + 1;
-    wcount += count;
+    black_score -= count + 1;
+    white_score += count;
   }
 
-  board0[squares[--move_count]] = BLANK;	/* decrease move_count    */
+  board0[squares[--move_count]] = BLANK; /* move_count = move_count - 1; */
 
   not_me = OTHER_PLAYER (whose_turn);
-  while (count > 0) {
-    board0[history[--hpointer]] = not_me;
-    count--;
-  }
+  while (count-- > 0)
+    board0[*--history_pointer] = not_me;
 }
 
-/* Sort vsquares by small order */
-static
-  void
-sort (gint l, gint r)
+static gint
+evaluate_heuristic (void)
 {
-  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, yx;
   gint count = 0;
 
   for (i = 0; i < move_count; i++) {
-    xy = squares[i];
-    count = (board0[xy] == whose_turn) ?
-      count + heuristic[xy] : count - heuristic[xy];
+    yx = squares[i];
+    if (board0[yx] == whose_turn)
+      count += heuristic[yx];
+    else
+      count -= heuristic[yx];
   }
 
   return count;
 }
 
-static
-  gint
-mobility (void)
+static gint
+mobility (gint who)
 {
-  gint8 i, xy;
+  gint8 i;
   gint count = 0;
 
   for (i = move_count; i < 64; i++) {
-    xy = squares[i];
-    if (is_valid (xy, whose_turn))
+    if (check_valid ((gint) squares[i], who))
       count++;
   }
 
   return count;
 }
 
-static
-  gint
-around0 (gint xy)
+static gint
+around0 (gint yx)
 {
+  gint8 i;
   gint count = 0;
-  int i;
 
   for (i = 0; i < NDIRS; i++)
-    if (board0[xy + dirs[i]] == BLANK)
+    if (board0[yx + dirs[i]] == BLANK)
       count--;
 
-  if (!count)
-    count = 2;
-
   return count;
 }
 
-static
-  gint
+static gint
 around (void)
 {
-  gint8 i, xy;
-  gint count = 0;
+  gint8 i;
+  gint yx, 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);
+    yx = (gint) squares[i];
+    if (board0[yx] == whose_turn)
+      count += around0 (yx);
+    else
+      count -= around0 (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) whose_turn)
+			 - mobility ((gint) OTHER_PLAYER (whose_turn));
+  score2 =  around ();
+  score3 =  evaluate_heuristic ();
+  score4 =  (whose_turn == BLACK)? (gint) (white_score - black_score):
+                                   (gint) (black_score - white_score);
 
-  score2 = around ();
-  score3 = eval_heuristic ();
+  return score1 * 8 + score2 + score3 / 2 + score4 / 2;
+}
 
-  return score1 + score2 + score3;
+static gint
+perfect_evaluation (void)
+{
+  if (whose_turn == BLACK)
+    return (gint) (black_score - white_score);
+
+  return (gint) (white_score - black_score);
 }
 
-/* Victory evaluation */
-static
-  gint
-v_evaluation (void)
+static gint
+victory_evaluation (void)
 {
-  gint aa;
+  gint8 aa;
 
-  aa = wcount - bcount;
-  if (whose_turn == BLACK_TURN)
+  aa = black_score - white_score;
+  if (whose_turn == WHITE)
     aa = -aa;
 
   if (aa > 0)
-    return 1;			/* win  */
+    return 1;				/* Win  */
   if (aa < 0)
-    return -1;			/* lose */
-  return 0;			/* draw */
+    return -1;			/* Lose */
+
+  return 0;				/* Draw */
 }
 
-static
-  gint
-p_evaluation (void)
+/* For the best search. */
+static gint
+win_evaluation (void)
 {
+  gint aa;
 
-  if (whose_turn == WHITE_TURN)
-    return wcount - bcount;
+  aa = (gint) (black_score - white_score);
+  if (whose_turn == WHITE)
+    aa = -aa;
 
-  return bcount - wcount;
+  if (!black_score || !white_score) {
+    if (aa > 0)
+      return aa + 10000;
+    return aa - 10000;
+  }
+
+  if (aa > 0)
+    return aa + 1000;
+  if (aa < 0)
+    return aa - 1000;
+
+  return 0;
 }
 
-static
-  gint
-w_evaluation (void)
+gint
+entry_valid_squares (gint pointer)
 {
-  gint aa;
-
-  if (!bcount || !wcount) {
-    if (whose_turn == WHITE_TURN && !bcount)
-      return 10000;
-    if (whose_turn == BLACK_TURN && !wcount)
-      return 10000;
-    return -10000;
+  gint yx, j = pointer;
+  gint8 i;
+  
+  for (i = move_count; i < 64; i++) {
+    yx = (gint) squares[i];
+    if (check_valid (yx, (gint) whose_turn))
+      valid_squares[++j][1] = yx;
   }
 
-  aa = wcount - bcount;
-  if (whose_turn == BLACK_TURN)
-    aa = -aa;
+  return j;
+}
 
-  if (aa > 0)
-    return aa + 100;
-  if (aa < 0)
-    return aa - 100;
-  return (0);
+/* Sort valid_squares by small order. */
+static void
+sort (gint l, gint r)
+{
+  gint i, j, v, w, x;
+
+  i = l;
+  j = r;
+  x = valid_squares[(l + r) / 2][0];
+  do {
+    while (valid_squares[i][0] < x)
+      i++;
+    while (x < valid_squares[j][0])
+      j--;
+    if (i < j) {
+      v = valid_squares[i][0];
+      w = valid_squares[i][1];
+      valid_squares[i][0] = valid_squares[j][0];
+      valid_squares[i][1] = valid_squares[j][1];
+      valid_squares[j][0] = v;
+      valid_squares[j][1] = w;
+    }
+    if (i <= j) {
+      i++;
+      j--;
+    }
+  }
+  while (i <= j);
+
+  if (l < j)
+    sort (l, j);
+  if (i < r)
+    sort (i, r);
 }
 
-/* alpha-beta search */
-static
-  gint
-search (gint n, gint a, gint b)
+/* Alpha-beta search */
+static gint
+search (gint n, gint a, gint b, gint pointer)
 {
-  gint aa, bb, xy, i, j;
+  gint i, j, aa, bb;
 
-  if (!n) {
+  if (!n) {										/* Search end?         */
     switch (s_kind) {
     case PERFECT:
-      return (p_evaluation ());
+      return perfect_evaluation ();
     case VICTORY:
-      return (v_evaluation ());
+      return victory_evaluation ();
     default:
-      return (b_evaluation ());
+      return best_evaluation ();
     }
   }
 
-  aa = a;
-
-  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 ();
-    }
-  }
-
-  if (j == vpointer) {		/* pass ?  */
-    whose_turn = (whose_turn == WHITE_TURN) ? BLACK_TURN : WHITE_TURN;
-    if (!mobility ()) {
+  j = entry_valid_squares (pointer);
+  if (j == pointer) {							/* Skip move?          */
+    whose_turn = OTHER_PLAYER (whose_turn);
+    if (!mobility ((gint) whose_turn)) {		/* No, the game is over. */
       whose_turn = OTHER_PLAYER (whose_turn);
-
       switch (s_kind) {
       case PERFECT:
-	return (p_evaluation ());
+        return perfect_evaluation ();
       case VICTORY:
-	return (v_evaluation ());
+        return victory_evaluation ();
       default:
-	return (w_evaluation ());
+        return win_evaluation ();
       }
     }
-    aa = -search (n, -b, -aa);
+
+    aa = -search (n, -b, -a, pointer);			/* Yes, skip move. 	 */
     whose_turn = OTHER_PLAYER (whose_turn);
-    vsquares[j][0] = 0;		/* mark pass              */
+    valid_squares[pointer][1] = 0;				/* Mark pass. 		 */
     return aa;
   }
 
-  sort (vpointer + 1, j);
+  for (i = j; i > pointer; i--) {				/* No, continue search. */
+    move_board (valid_squares[i][1]);			/* Simple evaluation   */
+    valid_squares[i][0] = mobility ((gint) whose_turn);
+    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.   */
+    move_board (valid_squares[i][1]);
+    bb = -search (n - 1, -b, -aa, j);
+    back ();
+    if (bb > aa) {
       aa = bb;
-      vsquares[i][0] = xy;	/* save this square       */
+      valid_squares[pointer][1] = valid_squares[i][1]; /* Save this square. */
     }
-    j++;
   }
-  vpointer = i;			/* pop vpointer           */
+
   return aa;
 }
 
-static
-  void
+/* For first 6 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][1]] < 0)		/* If the square is critical, */
+    i = g_rand_int_range (rgen, 1, j + 1);		/* then select once more.     */
+
+  valid_squares[0][1] = valid_squares[i][1];
+  return 0;
 }
 
-static
-  gint
+gint
 computer_move (gint level)
 {
-  gint nn, aa, kind, best_xy;
+  gint nn = (gint) (64 - move_count);
 
-  vsquares[0][0] = -1;
-  nn = 64 - move_count;
-  if (nn > BEST)
-    random_select ();
-  else {
-    if (nn <= PERFECT - level) {
-      kind = PERFECT;
-      aa = 127;
+  if (nn <= PERFECT - MAX_DEPTH + level) {
+    s_kind = PERFECT;
+    valid_squares[0][0] = search (nn, -127, 127, 0);
+  } else if (nn <= VICTORY - MAX_DEPTH + level) {
+    s_kind = VICTORY;
+    valid_squares[0][0] = search (nn, -1, 1, 0);
+    if (valid_squares[0][0] == -1) {			/* If the computer can't win,  */
+      s_kind = BEST;								/* then search the best again. */
+      valid_squares[0][0] = search (level, -32767, 32767, 0);
     }
-    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. */
+  } else if (nn <= BEST) {
     s_kind = BEST;
-    vsquares[0][1] = search (MAX_DEPTH - level, -32767, 32767);
-    best_xy = vsquares[0][0];
+    valid_squares[0][0] = search (level, -32767, 32767, 0);
+  } else {
+    s_kind = RANDOM;
+    valid_squares[0][0] = random_select ();
   }
-
-  if (best_xy)
-    move (best_xy % 10 - 1, best_xy / 10 - 1, whose_turn);
-
-  return FALSE;
+  
+  return valid_squares[0][1];
 }
 
-gint
-computer_move_1 (guint me)
-{
-  return computer_move (6);
-}
-
-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++;
-    }
-  }
-  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;
-}
-
-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.c
===================================================================
--- iagno/server.c	(リビジョン 6541)
+++ iagno/server.c	(作業コピー)
@@ -1,5 +1,7 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
 /*
- * File: main.c
+ * File: server.c
  * Author: Ismael Orenstein
  * Project: GGZ Reversi game module
  * Date: 09/17/2000
@@ -26,612 +28,459 @@
 #include "config.h"
 #include <gnome.h>
 #include <ggzdmod.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
+#include <assert.h>
 
 #include "server.h"
+#include "othello.h"
 
+#define COMPUTER_LEVEL 5
+
+static const gchar *strs[] = {
+  "Invalid move\n",		/* -1 */
+  "Wrong turn\n",		/* -2 */
+  "Skip move\n",		/* -3 */
+  "Can't read message\n",	/* -4 */
+  "Can't send message\n",	/* -5 */
+  "Not playing error\n",	/* -6 */
+  "Play again error\n",	/* -7 */
+  "Unknown opcode\n"		/* -8 */
+};
+
 // Global game variables
-struct rvr_game_t rvr_game;
+static GGZdMod *ggz;
+static int     kifu[MAX_MOVE_COUNT + 1][2];
+static int     state;
 
+extern gint8   board0[];
+extern gint8   move_count;
+extern gint8   whose_turn;
+extern gint8   black_score;
+extern gint8   white_score;
 
+
+static int game_make_move (int yx, int player);
+
 // Initializes everything
-void
-game_init (GGZdMod * ggzdmod)
+static 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));
+  init (); /* Call othello.c */
+  /* move_count = 4; black_score = white_score = 2; whose_turn = BLACK; */
+  ggz        = ggzdmod;
+  kifu[4][0] = 0;
+  state      = RVR_STATE_INIT;
 }
 
-// Handle server messages
-void
-game_handle_ggz_state (GGZdMod * ggz, GGZdModEvent event, const void *data)
+static int
+game_check_bot (void)
 {
-  GGZdModState new_state = ggzdmod_get_state (ggz);
-  const GGZdModState *old_state_ptr = data;
-  const GGZdModState old_state = *old_state_ptr;
+  int seat = PLAYER2SEAT (whose_turn);
 
-  // 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;
-  }
+  // 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;
 
-  if (new_state == GGZDMOD_STATE_PLAYING) {
-    // Game already going on?
-    if (rvr_game.turn == EMPTY)
-      rvr_game.turn = BLACK;
-
-    // No! Let's start the game!
-    game_start ();
-    game_play ();
-  }
-
-  if (new_state == GGZDMOD_STATE_WAITING) {
-    // That's great! Update the state
-    // Now waiting for people to join
-    rvr_game.state = RVR_STATE_WAIT;
-    ggzdmod_log (rvr_game.ggz, "Waiting for players");
-  }
+  // Yes! Wait for a second.
+  sleep (1); /* Call othello.c */
+  return game_make_move ((int) computer_move (COMPUTER_LEVEL),
+                         (int) whose_turn);
 }
 
-
 static int
-seats_full (void)
+game_skip_move (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, 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;
+  }
 
-static int
-seats_empty (void)
-{
-  /* This calculation is a bit inefficient, but that's OK */
-  return ggzdmod_count_seats (rvr_game.ggz, GGZ_SEAT_PLAYER) == 0
-    && ggzdmod_count_spectators (rvr_game.ggz) == 0;
+  return game_check_bot ();
 }
 
-
-void
-game_handle_ggz_seat (GGZdMod * ggz, GGZdModEvent event, const void *data)
+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? */
+  whose_turn = OTHER_PLAYER (whose_turn);
+  if (entry_valid_squares (0))
+    return game_skip_move ();
+  /* The game is over. */
+  if (black_score > white_score) {
+    results[PLAYER2SEAT (BLACK)] = GGZ_GAME_WIN;
+    results[PLAYER2SEAT (WHITE)] = GGZ_GAME_LOSS;
+    winner = BLACK;
+  } else if (white_score > black_score) {
+    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;
+  whose_turn = 0;
+  // Puts human players score = 0 and bots score = 1.
+  black_score = white_score = 0;
+  if (ggzdmod_get_seat (ggz, PLAYER2SEAT (BLACK)).type
+      == GGZ_SEAT_BOT)
+    black_score = 1;
+  if (ggzdmod_get_seat (ggz, PLAYER2SEAT (WHITE)).type
+      == GGZ_SEAT_BOT)
+    white_score = 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 fd, seat;
 
-  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)
+// Puts human players score = 0,
+// When they send a RVR_REQ_AGAIN message, put it = 1,
+// When everyone equal = 1, then starts it all again.
+static int
+game_play_again (int seat, int fd)
 {
-  int i, j, fd;
+  ggzdmod_log (ggz, "%d wants to play again!\n", seat);
 
-  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);
+  // Check game is finished or not.
+  if (whose_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;
+  }
+  // Send a RVR_MSG_INIT message.
+  if (fd != -1 && ggz_write_int (fd, RVR_MSG_INIT) < 0)
+    return RVR_ERROR_CANTWRITE;
 
-    if (ggz_write_int (fd, RVR_MSG_PLAYERS) < 0) {
-      ggzdmod_log (rvr_game.ggz, "Can't send player list!\n");
-      return -1;
-    }
+  if (SEAT2PLAYER (seat) == WHITE) 
+    white_score = 1;
+  else if (SEAT2PLAYER (seat) == BLACK)
+    black_score = 1;
 
-    for (i = 0; i < ggzdmod_get_num_seats (rvr_game.ggz); i++) {
-      if (ggz_write_int (fd, ggzdmod_get_seat (rvr_game.ggz, i).type) < 0)
-	return -1;
-      if (ggzdmod_get_seat (rvr_game.ggz, i).type != GGZ_SEAT_OPEN &&
-	  ggz_write_string (fd,
-			    ggzdmod_get_seat (rvr_game.ggz, i).name) < 0) {
-	ggzdmod_log (rvr_game.ggz, "Can't send player name!\n");
-	return -1;
-      }
-    }
+  if (!black_score || !white_score) {
+    state = RVR_STATE_WAITING;
+    return SERVER_OK;
   }
 
-  return 0;
+  // Starts again.
+  black_score = white_score = 2;
+  whose_turn = BLACK;
+ return game_start ();
 }
 
-int
-game_send_sync (int seat)
+static int
+game_check_move (int yx, int player)
 {
-  int i, fd = ggzdmod_get_seat (rvr_game.ggz, seat).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) whose_turn)
+    return RVR_ERROR_WRONGTURN;
+  // Check if out of bounds.
+  if (yx < 11 || yx > 88)
+    return RVR_ERROR_INVALIDMOVE;
+  // Check if duplicated.
+  if (board0[yx] != BLANK)
+    return RVR_ERROR_INVALIDMOVE;
+  // Check if valid yx.
+  if (!check_valid ((gint) yx, (gint) player)) /* Call othello.c */
+    return RVR_ERROR_INVALIDMOVE;
 
-  ggzdmod_log (rvr_game.ggz, "Handling sync for player %d", seat);
-
-  // Send SYNC message and current turn
-
-  if (ggz_write_int (fd, RVR_MSG_SYNC) < 0
-      || ggz_write_char (fd, rvr_game.turn) < 0)
-    return -1;
-
-  // Send current board state
-
-  for (i = 0; i < 64; i++) {
-    if (ggz_write_char (fd, rvr_game.board[i]) < 0)
-      return -1;
-  }
-
-  // That's fine
-
-  return 0;
-
+  return yx;
 }
 
-int
-game_start (void)
+static int
+game_make_move (int yx, int player)
 {
+  int fd, seat;
 
-  int i, fd;
+  kifu[move_count][0] = player;
+  kifu[move_count][1] = yx;
+  move_board ((gint) yx);
+  kifu[move_count][0] = 0;
 
-  // Start game variables
-  rvr_game.state = RVR_STATE_PLAYING;
-
-  // 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;
+  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;
   }
 
-  ggzdmod_log (rvr_game.ggz, "Game has started!\n");
-
-  return 0;
+  // Check if the game is over.
+  return game_check_over ();
 }
 
-/* return -1 on error, 1 on gameover */
-void
-game_handle_player (GGZdMod * ggz, GGZdModEvent event, const void *data)
+static int
+game_send_sync (int seat)
 {
-  const int *seat_ptr = data;
-  const int seat = *seat_ptr;
-  int op, move;
   int fd = ggzdmod_get_seat (ggz, seat).fd;
+  int i = 4;
 
-  if (ggz_read_int (fd, &op) < 0)
-    return;
+  ggzdmod_log (ggz, "Handling sync for player %d", seat);
 
-  switch (op) {
-
-  case RVR_REQ_MOVE:
-    game_handle_move (seat, &move);
-    break;
-
-  case RVR_REQ_SYNC:
-    game_send_sync (seat);
-    break;
-
-  case RVR_REQ_AGAIN:
-    game_play_again (seat);
-    break;
-
-  default:
-    ggzdmod_log (rvr_game.ggz, "ERROR: unknown player opcode %d.", op);
-    break;
+  // Send a RVR_MSG_SYNC message.
+  if (ggz_write_int (fd, RVR_MSG_SYNC) < 0)
+    return RVR_ERROR_CANTWRITE;
+  // Send kifu.
+  while (kifu[i][0]) {
+    if (ggz_write_int (fd, kifu[i][0]) < 0
+        || ggz_write_int (fd, kifu[i++][1]) < 0)
+      return RVR_ERROR_CANTWRITE;
   }
+  // Send a end mark and current turn.
+  // For the compatibility with the old protocol,
+  // the old client is waiting for the seat, therefor send a dummy seat.
+  if (ggz_write_int (fd, 0) < 0 || ggz_write_int (fd, (int) whose_turn) < 0)
+    return RVR_ERROR_CANTWRITE;
+
+  // That's fine.
+  return SERVER_OK;
 }
 
-int
-game_handle_move (int seat, int *move)
+static int
+game_handle_move (int seat)
 {
-  int fd = ggzdmod_get_seat (rvr_game.ggz, seat).fd, status;
+  int yx, fd = ggzdmod_get_seat (ggz, seat).fd;
 
-  // Get the move from the message
-  if (ggz_read_int (fd, move) < 0)
-    return -1;
+  // Get the yx from the message.
+  if (ggz_read_int (fd, &yx) < 0)
+    return RVR_ERROR_CANTREAD;
 
-  ggzdmod_log (rvr_game.ggz, "Handling move %d,%dfor player %d\n", X (*move),
-	       Y (*move), seat);
+  ggzdmod_log (ggz, "Handling move %d, for player %d\n", yx, 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);
-  }
+  // Check if it's valid.
+  yx = game_check_move (OLD2NEW (yx), SEAT2PLAYER (seat));
+  if (yx > 0) 
+    // Make move if it's valid (also sends it to everyone).
+    return game_make_move (yx, SEAT2PLAYER (seat));
 
-  // Make move if it's valid (also sends it to everyone);
-  game_make_move (SEAT2PLAYER (seat), status);
+  // 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 status;
-
+  return SERVER_OK;
 }
 
-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 i, j, 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 (j = 0; j < ggzdmod_get_num_seats (ggz); j++) {
+    fd = ggzdmod_get_seat (ggz, j).fd;
+    if (fd == -1) {
+      ggzdmod_log (ggz, "Bot seat\n");
       continue;
-    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", j);
+    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_player (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 int *seat_ptr = data;
+  const int seat = *seat_ptr;
+  int op, err;
+  int fd = ggzdmod_get_seat (ggzdmod, seat).fd;
 
-void
-game_skip_move (void)
-{
-  int seat;
+  if (ggz_read_int (fd, &op) < 0)
+    return;
 
-  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");
-    }
+  switch (op) {
+  case RVR_REQ_MOVE:                        /* 4 */
+    err = game_handle_move (seat);
+    break;
+  case RVR_REQ_AGAIN:                       /* 8 */
+    err = game_play_again (seat, fd);
+    break;
+  default:
+    err = RVR_ERROR_OPCODE;
+    break;
   }
 
-  rvr_game.turn *= -1;
-
-  return;
-
+  if (err < 0)
+    ggzdmod_log (ggzdmod, strs[-err - 1]);
 }
 
-void
-game_gameover (void)
+static void
+game_handle_ggz_seat (GGZdMod *ggzdmod, GGZdModEvent event, const void *data)
 {
-  int seat, fd, winner;
-  GGZGameResult results[2];
+  const GGZSeat *old_seat = data;
+  GGZSeat new_seat = ggzdmod_get_seat (ggzdmod, old_seat->num);
+  GGZdModState new_state;
 
-  // Ends everything
-  rvr_game.turn = EMPTY;
-  rvr_game.state = RVR_STATE_DONE;
+  // Check the state.
+  if (seats_full ())
+    new_state = GGZDMOD_STATE_PLAYING;
+  else if (seats_empty ())
+    new_state = GGZDMOD_STATE_DONE;
+  else
+    new_state = GGZDMOD_STATE_WAITING;
 
-  if (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;
-  }
+  // 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 && whose_turn)
+    game_send_sync (new_seat.num);
 
-  /* Report game to GGZ */
-  ggzdmod_report_game (rvr_game.ggz, NULL, results, NULL);
+  // That's great! Do stuff.
+  if (new_seat.type == GGZ_SEAT_PLAYER)
+    game_send_seat (new_seat.num);
+  game_send_players ();
 
-  // 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;
-
+  ggzdmod_set_state (ggzdmod, new_state);
 }
 
-int
-game_play_again (int seat)
+// Handle server messages
+static void
+game_handle_ggz_state (GGZdMod *ggzdmod, GGZdModEvent event,
+                       const void *data)
 {
-  ggzdmod_log (rvr_game.ggz, "%d wants to play again! He is a good fellow.\n",
-	       seat);
-  // If game is not finished, forget about it
-  if (rvr_game.state != RVR_STATE_DONE) {
-    ggzdmod_log (rvr_game.ggz, "The game wasn`t over yet! Are you crazy?\n");
-    return RVR_SERVER_ERROR;
-  }
+  GGZdModState new_state = ggzdmod_get_state (ggzdmod);
+  const GGZdModState *old_state_ptr = data;
+  const GGZdModState old_state = *old_state_ptr;
 
-  if (SEAT2PLAYER (seat) == WHITE)
-    rvr_game.white = 1;
-  else if (SEAT2PLAYER (seat) == BLACK)
-    rvr_game.black = 1;
+  // Check if it's the right time to launch the game
+  // and if ggz could do taht.
+  if (old_state == GGZDMOD_STATE_CREATED)
+    /* assert(rvr_game.state == RVR_STATE_INIT); */
+    return;
 
-  if (rvr_game.white && rvr_game.black) {
-    // Starts is again
-    game_init (rvr_game.ggz);
-    game_start ();
-    rvr_game.turn = BLACK;
-    game_play ();
+  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;
   }
-
-
-  return RVR_SERVER_OK;
-
+  if (new_state == GGZDMOD_STATE_PLAYING) 
+    // Let's start the game!
+    game_start ();
 }
 
-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.h
===================================================================
--- iagno/othello.h	(リビジョン 6541)
+++ 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
@@ -19,20 +20,30 @@
  * For more details see the file COPYING.
  */
 
-#ifndef _OTHELLO_H_
-#define _OTHELLO_H_
+#define BLACK			49
+#define WHITE			79
+#define BLANK			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);
+#define OTHER_PLAYER(who)	(128 - who)
+
+#define PERFECT		17
+#define VICTORY		21
+#define BEST			54
+#define RANDOM		60
+#define MAX_DEPTH		8
+#define MAX_MOVE_COUNT	64
+
+
 void init (void);
-void board_copy (void);
-void undo (void);
 
-#endif
+gboolean check_valid (gint yx, gint who);
+
+void move_board (gint yx);
+
+void back (void);
+
+gint entry_valid_squares (gint pointer);
+
+gint computer_move (gint level);
+
Index: iagno/server.h
===================================================================
--- iagno/server.h	(リビジョン 6541)
+++ 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
@@ -23,211 +25,43 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
-#define BLACK -1
-#define WHITE +1
-#define EMPTY  0
+/* PROTOCOL VERSION 2 */
 
-/* REVERSI PROTOCOL VERSION 0.0.5
- *
- * The server handles everything, from the AI to the validity of moves
- *
- * RVR_STATE_INIT:
- *
- * First, it fetchs from the ggz_server how much seats there are, and how much are open/closed
- *
- * RVR_STATE_JOIN:
- *
- * Then, it waits until some player join . When he does, it sends:
- *
- * To Joining player:
- * 	RVR_MSG_SEAT (int)SEAT_NUM
- * To All Human players:
- * 	RVR_MSG_PLAYERS PLAYER_IDENTIFER[BLACK] PLAYER_IDENTIFIER[WHITE]
- *  where PLAYER_IDENTIFIER is:
- *  	(int)PLAYER_TYPE
- *  	if PLAYER_TYPE == GGZ_SEAT_OPEN
- *  		(str)PLAYER_NAME
- *
- * If the game was already happening, send the current game state to the new player
- *
- * 	RVR_MSG_SYNC (char)TURN BOARD_STATE
- * 	where TURN is the current turn, and:
- * 		BOARD_STATE = (char)POSITION * 64
- *
- * When all the open seats are filled, it enters playing state (state = RVR_STATE_PLAYING) and sends:
- *
- * To All Human players:
- * 	RVR_MSG_START
- *
- * RVR_STATE_PLAYING:
- *
- * If current player is AI:
- *
- * 	doMove(AI_MOVE());
- *
- * If it isn't AI, then it waits until client sends a RVR_REQ_MOVE
- *
- * When client sends a RVR_REQ_MOVE, the server must check if he is the current player and
- * if the move is valid. (The client should do it too, must the server must recheck to avoid cheating)
- * Then the server executes the move, and sends:
- * 
- * To All Human players:
- *
- *	RVR_MSG_MOVE (int)MOVE
- * 	where MOVE can be a array index (0-63) or one of the following error values:
- * 		RVR_ERROR_WRONGTURN
- * 			The player tried to move when it wasn't his turn
- * 		RVR_ERROR_INVALIDMOVE
- * 			The player tried a invalid move (Cheating sign!)
- * 		RVR_ERROR_CANTMOVE
- * 			The player can't move (no possible move)
- *
- * Then the server checks if the game is over (No more valid moves) and who has won. If the game is over,
- * it sends to All Human players:
- *
- * 	RVR_MSG_GAMEOVER (int)WINNER
- * 		where WINNER can be: BLACK, WHITE, EMPTY(draw)
- *
- * If some player left while the game was happening, it sends to all Human players:
- *
- * 	RVR_MSG_PLAYERS
- *
- * And it will wait until someone returns
- *
- * Any time, the server can receive a RVR_REQ_SYNC message from the client.
- *  If this is the case, it sents a RVR_MSG_SYNC to this player.
- *
- * The client (more information should be avaiable on the client's game.h file):
- * 
- * The client waits until a RVR_MSG_SEAT is sent to him, indicating what is his seat.
- * Then it waits until a RVR_MSG_PLAYERS, with the type/name of all the players
- * Then it waits until a RVR_MSG_START is sent.
- *
- * If a RVR_MSG_SYNC message is sent to him, it replaces the current game state with the one sent.
- * 
- * Then he enters playing mode.
- *
- * If it is his turn, The user selects a valid square and the client sends:
- * 	RVR_REQ_MOVE (int)MOVE
- * Then it waits until the server sends:
- * 	RVR_MSG_MOVE (int)MOVE
- * If move >= 0, do the move. Else, tell the player what was the error.
- * 
- * If it isn't his turn, it waits until the server sents a
- * 	RVR_MSG_MOVE (int)MOVE
- * If move >= 0, do the move. Else, tell (if necessary) what was the error.
- * 
- * After the move is done, change to the other turn.	
- *
- * If anyone has left the table, it will receive a RVR_MSG_PLAYERS from the server. Then it enters waiting mode again.
- *
- * When the game is over, it sends a RVR_MSG_GAMEOVER (int)winner to the players, and enters DONE state. If it receives enough RVR_REQ_AGAIN msgs, it sends a RVR_MSG_START to the players.
- *
- * Luckily that's all, this protocol is perfect and it shouldn't be modified anymore. Or so I hope. :) */
+#define RVR_MSG_SEAT			0
+#define RVR_MSG_PLAYERS        	1
+#define RVR_MSG_MOVE           	2
+#define RVR_MSG_GAMEOVER       	3
+#define RVR_REQ_MOVE           	4
+#define RVR_MSG_START          	5
+#define RVR_MSG_SYNC           	6
+#define RVR_MSG_INIT           	7
+#define RVR_REQ_AGAIN          	8
 
-#include "ggzdmod.h"
-
-// Reversi protocol
-// The numbers aren't on order, because I used the same constants from TicTacToe - simplify testing
-#define RVR_MSG_SEAT 0
-#define RVR_MSG_PLAYERS 1
-#define RVR_MSG_SYNC 6
-#define RVR_REQ_SYNC 7
-#define RVR_REQ_AGAIN 8
-#define RVR_MSG_START 5
-#define RVR_MSG_MOVE 2
-#define RVR_MSG_GAMEOVER 3
-#define RVR_REQ_MOVE 4
-
 // States
-#define RVR_STATE_INIT 0
-#define RVR_STATE_WAIT 1
-#define RVR_STATE_PLAYING 2
-#define RVR_STATE_DONE 3
+#define RVR_STATE_INIT         	0
+#define RVR_STATE_WAITING      	1
+#define RVR_STATE_PLAYING      	2
+#define RVR_STATE_DONE         	3
 
-// Responses from server
-#define RVR_SERVER_ERROR -1
-#define RVR_SERVER_OK 0
-#define RVR_SERVER_JOIN 1
-#define RVR_SERVER_LEFT 2
-#define RVR_SERVER_QUIT 3
-
 // Errors
-#define 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/ggz-network.c
===================================================================
--- iagno/ggz-network.c	(リビジョン 6541)
+++ iagno/ggz-network.c	(作業コピー)
@@ -1,3 +1,5 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
 /* ggz-network.c
  *
  * Copyright (C) 2006 -  Andreas Røsdal <andrearo@pvv.ntnu.no>
@@ -26,182 +28,229 @@
 #include <ggz-embed.h>
 #include <ggz-gtk.h>
 
-#include "games-dlg-chat.h"
-#include "games-dlg-players.h"
+#include <games-dlg-chat.h>
+#include <games-dlg-players.h>
 
+#include "othello.h"
 #include "gnothello.h"
 #include "ggz-network.h"
-#include "othello.h"
 
-guint whose_turn = BLACK_TURN;
+static const gchar *strs[] = {
+  N_("Invalid move!"),			/* -1 */
+  N_("Not your turn!"),			/* -2 */
+  N_("Skip move!"),				/* -3 */
+  N_("Can't read message!"),		/* -4 */
+  N_("Can't send message!"),		/* -5 */
+  N_("Waiting for an opponent to join the game."), /* -6 */
+  N_("The game wasn`t over yet!"),		/* -7 */
+  N_("Incorrect opcode!")			/* -8 */
+};
 
-static gboolean
-game_handle_io (GGZMod * mod)
-{
-  int op = -1;
+static GtkWidget *ggzbox;
+static GGZMod    *ggzmod;
+static int       fd;
+static int       seats[2];
+static int       seat;
+static gint      player_id;
+static char      names[2][17];
+static gboolean  old = FALSE;
 
-  fd = ggzmod_get_server_fd (mod);
+extern GtkWidget *window;
+extern GtkWidget *notebook;
+extern gint      kifu[MAX_MOVE_COUNT + 1][2];
+extern gboolean  game_in_progress;
+extern gboolean  ggz_network_mode;
 
-  // Read the fd
-  if (ggz_read_int (fd, &op) < 0) {
-    ggz_error_msg ("Couldn't read the game fd");
-    return FALSE;
-  }
+extern gint8     whose_turn;
 
-  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)
+{
+  if (err >= RVR_ERROR_OPCODE)
+    gui_message ((gchar *) strs[-err - 1]);
 }
 
-
-
-
-int
+static int
 get_seat (void)
 {
-
   if (ggz_read_int (fd, &seat) < 0)
-    return -1;
+    return RVR_ERROR_CANTREAD;
 
-  if (seat == 0) {
-    gui_message (_("Waiting for an opponent to join the game."));
-  }
-
   player_id = SEAT2PLAYER (seat);
-
-  return 0;
+  return SERVER_OK;
 }
 
-int
+static int
 get_players (void)
 {
   int i;
 
   for (i = 0; i < 2; i++) {
     if (ggz_read_int (fd, &seats[i]) < 0)
-      return -1;
+      return RVR_ERROR_CANTREAD;
 
-    if (seats[i] != GGZ_SEAT_OPEN) {
-      if (ggz_read_string (fd, (char *) &names[i], 17) < 0)
-	return -1;
-    }
+    if (seats[i] != GGZ_SEAT_OPEN
+        && ggz_read_string (fd, (char *) &names[i], 17) < 0)
+      return RVR_ERROR_CANTREAD;
   }
+  return SERVER_OK;
+}
 
-  return 0;
+static int
+gui_turn (void)
+{
+  if (player_id != (gint) whose_turn)
+    gui_message (g_strdup_printf (_("Waiting for %s to move"),
+                             names[1 - seat]));
+  else if (whose_turn == BLACK) 
+    gui_message (_("It is your turn to place a dark piece"));
+  else if (whose_turn == WHITE) 
+    gui_message (_("It is your turn to place a light piece"));
 
+  return SERVER_OK;
 }
 
-int
-get_gameover ()
+static int
+get_move (void)
 {
-  int winner;
+  int yx;
 
-  if (ggz_read_int (fd, &winner) < 0)
-    return -1;
+  if (ggz_read_int (fd, &yx) < 0)
+    return RVR_ERROR_CANTREAD;
+  if (yx == RVR_ERROR_CANTMOVE)
+    return SERVER_OK;
+  if (yx == RVR_ERROR_NOTPLAYING)
+    stop_game ();
+  if (yx == RVR_ERROR_INVALIDMOVE)
+    check_game_over ();
+  if (yx < 0)
+    return yx;
 
-  return 1;
+  yx = OLD2NEW(yx);
+  if (!check_valid_move ((gint) yx, (gint) whose_turn))
+    return SERVER_OK;
 
+  move ((gint) yx);
+  return gui_turn ();
 }
 
-// Get the move from the server and makes it (don't check for validity!!)
-int
-get_move (void)
+static int
+get_gameover (void)
 {
-  int move;
+  int winner;
 
-  if (ggz_read_int (fd, &move) < 0)
-    return -1;
-
-  if (move == RVR_ERROR_CANTMOVE) {
-    return 1;
+  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);
   }
 
-  if (move < 0) {
-    return -1;
-  }
-  game_make_move (move);
+  if (winner)
+    gui_message (g_strdup_printf (_("%s wins!"), names[PLAYER2SEAT(winner)]));
+  else
+    gui_message (_("The game was a draw."));
 
-  return 0;
-
+  return SERVER_OK;
 }
 
-// make the move
-void
-game_make_move (int pos)
+static int
+get_start (void)
 {
-  int x = X (pos) - 1, y = Y (pos) - 1;
-
-  // iagno move
-  move (x, y, whose_turn);
-
-  return;
-
+  /* For the compatibility with the old protocol. */
+  if (old)
+    init_game ();
+  ggz_debug ("main", "Game has started");
+  start_game ();
+  return gui_turn ();
 }
 
+static int
+get_sync (void)
+{
+  int who, yx, i = 0;
 
+  // Get kifu
+  do {
+    if (ggz_read_int (fd, &who) < 0 || ggz_read_int (fd, &yx) < 0)
+      return RVR_ERROR_CANTREAD;
+    kifu[i][0] = (gint) who;
+    kifu[i++][1] = (gint) yx;
+  }  while (who) ;
 
-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;
+  // Auto recovery
+  stop_game ();
+  init ();
+  i = 0;
+  while (kifu[i][0]) {
+    whose_turn = (gint8) kifu[i][0];
+    move_board (kifu[i++][1]);
   }
-
-  ggz_debug ("main", "Sent move: %d", move);
+  whose_turn = (gint8) kifu[i][1];
+  
+  copy_board ();
+  start_game ();
+  redraw_board ();
+  return SERVER_OK;
 }
 
-int
-request_sync (void)
+static int
+get_init (void)
 {
-  if (ggz_write_int (fd, RVR_REQ_SYNC) < 0) {
-    // Not that someone would check this return value, but...
-    return -1;
-  } else {
-    gui_message ("Requesting sync from the server");
-  }
-  return 0;
+  init_game ();
+  gui_error (RVR_ERROR_NOTPLAYING);
+  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 +258,8 @@
 }
 
 static gboolean
-handle_game_server (GIOChannel * channel, GIOCondition cond, gpointer data)
+handle_game_server (GIOChannel *channel, GIOCondition cond,
+                    gpointer data)
 {
   GGZMod *mod = data;
 
@@ -217,7 +267,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 +277,34 @@
   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 +318,13 @@
 ggz_game_launched (void)
 {
   network_init ();
-  init_new_game ();
+
   gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
+  gtk_widget_hide (ggzbox);
+
+  ggz_network_mode = TRUE;
+  network_gui_update ();
+  get_init ();
 }
 
 /****************************************************************************
@@ -257,66 +333,88 @@
 static void
 ggz_closed (void)
 {
+  ggzmod_disconnect (ggzmod);
+  ggzmod_free (ggzmod);
+
   gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
+  gtk_widget_destroy (ggzbox);
+  gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
+
   ggz_network_mode = FALSE;
-  init_new_game ();
+  network_gui_update ();
+  init_game();
+  start_game ();
 }
 
 void
-network_init (void)
+on_network_activate (GtkMenuItem *menuitem, gpointer user_data)
 {
-  GGZMod *mod;
-  GIOChannel *channel;
-  int ret, ggzmodfd;
+  struct passwd *pwent;  
 
-  if (!ggzmod_is_ggz_mode ())
-    return;
-  ggz_network_mode = TRUE;
+  stop_game ();
+  
+  ggz_gtk_initialize (FALSE,
+                      ggz_connected, ggz_game_launched, ggz_closed,
+                      NETWORK_ENGINE, NETWORK_VERSION, "iagno.xml",
+                      "GGZ Gaming Zone");
 
-  mod = ggzmod_new (GGZMOD_GAME);
-  ggzmod_set_handler (mod, GGZMOD_EVENT_SERVER, handle_ggzmod_server);
+  pwent = getpwuid(getuid());
+  ggz_embed_ensure_server ("GGZ Gaming Zone", "games.gnome.org",
+                           5688, pwent->pw_name);
 
-  ret = ggzmod_connect (mod);
-  if (ret != 0) {
-    /* Error: GGZ core client error (e.g. faked GGZMODE env variable) */
-    return;
-  }
+  ggzbox = ggz_gtk_create_main_area (window);
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), ggzbox, NULL);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook),
+                                 NETWORK_PAGE);
+  gtk_widget_show (ggzbox);
+}
 
-  ggzmodfd = ggzmod_get_fd (mod);
-  channel = g_io_channel_unix_new (ggzmodfd);
-  g_io_add_watch (channel, G_IO_IN, handle_ggzmod, mod);
+void
+on_playerlist_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  create_or_raise_dlg_players (GTK_WINDOW (window));
+}
 
-  init_player_list (mod);
-  init_chat (mod);
+void
+on_chat_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  create_or_raise_dlg_chat (GTK_WINDOW (window));
+}
 
+void
+on_leave_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  ggz_embed_leave_table ();
+  gtk_widget_show (ggzbox);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
 }
 
 void
-on_network_game (void)
+on_again_activate (void)
 {
-  GtkWidget *ggzbox;
-  struct passwd *pwent;  
+  if (old)
+    get_init ();
+  if (ggz_write_int (fd, RVR_REQ_AGAIN) < 0)
+    return gui_error (RVR_ERROR_CANTWRITE);
+}
 
+void
+send_my_move (gint move, gint turn)
+{
+  int yx = (int) NEW2OLD(move);
 
-  if (ggz_network_mode) {
-    gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
+  // For the compatibility with the old protocol,
+  // if the new client send a invalid move to the old server, 
+  // the new client hung up at sync.
+  if (!check_valid_move (move, turn))
     return;
-  }
+  if (turn != player_id)
+    return gui_error (RVR_ERROR_WRONGTURN);
 
-  init_new_game ();
-  ggz_network_mode = TRUE;
+  if (ggz_write_int (fd, RVR_REQ_MOVE) < 0
+      || ggz_write_int (fd, yx) < 0)
+    return gui_error (RVR_ERROR_CANTWRITE);
 
-  ggz_gtk_initialize (FALSE,
-		      ggz_connected, ggz_game_launched, ggz_closed,
-		      NETWORK_ENGINE, NETWORK_VERSION, "iagno.xml",
-		      "GGZ Gaming Zone");
+  ggz_debug ("main", "Sent move: %d", yx);
+}
 
-  pwent = getpwuid(getuid());
-
-  ggz_embed_ensure_server ("GGZ Gaming Zone", "gnome.ggzgamingzone.org",
-			   5688, pwent->pw_name);
-
-  ggzbox = ggz_gtk_create_main_area (window);
-  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), ggzbox, NULL);
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
-}
Index: iagno/ggz-network.h
===================================================================
--- iagno/ggz-network.h	(リビジョン 6541)
+++ iagno/ggz-network.h	(作業コピー)
@@ -1,3 +1,5 @@
+/* -*- 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
@@ -16,185 +18,59 @@
  * USA
  */
 
-#define EMPTY  0
+/* PROTOCOL VERSION 2 */
 
-/* REVERSI PROTOCOL VERSION 0.0.5
- *
- * The server handles everything, from the AI to the validity of moves
- *
- * RVR_STATE_INIT:
- *
- * First, it fetchs from the ggz_server how much seats there are, and how much are open/closed
- *
- * RVR_STATE_JOIN:
- *
- * Then, it waits until some player join . When he does, it sends:
- *
- * To Joining player:
- * 	RVR_MSG_SEAT (int)SEAT_NUM
- * To All Human players:
- * 	RVR_MSG_PLAYERS PLAYER_IDENTIFER[BLACK] PLAYER_IDENTIFIER[WHITE]
- *  where PLAYER_IDENTIFIER is:
- *  	(int)PLAYER_TYPE
- *  	if PLAYER_TYPE == GGZ_SEAT_OPEN
- *  		(str)PLAYER_NAME
- *
- * If the game was already happening, send the current game state to the new player
- *
- * 	RVR_MSG_SYNC (char)TURN BOARD_STATE
- * 	where TURN is the current turn, and:
- * 		BOARD_STATE = (char)POSITION * 64
- *
- * When all the open seats are filled, it enters playing state (state = RVR_STATE_PLAYING) and sends:
- *
- * To All Human players:
- * 	RVR_MSG_START
- *
- * RVR_STATE_PLAYING:
- *
- * If current player is AI:
- *
- * 	doMove(AI_MOVE());
- *
- * If it isn't AI, then it waits until client sends a RVR_REQ_MOVE
- *
- * When client sends a RVR_REQ_MOVE, the server must check if he is the current player and
- * if the move is valid. (The client should do it too, must the server must recheck to avoid cheating)
- * Then the server executes the move, and sends:
- * 
- * To All Human players:
- *
- *	RVR_MSG_MOVE (int)MOVE
- * 	where MOVE can be a array index (0-63) or one of the following error values:
- * 		RVR_ERROR_WRONGTURN
- * 			The player tried to move when it wasn't his turn
- * 		RVR_ERROR_INVALIDMOVE
- * 			The player tried a invalid move (Cheating sign!)
- *
- * Then the server checks if the game is over (No more valid moves) and who has won. If the game is over,
- * it sends to All Human players:
- *
- * 	RVR_MSG_GAMEOVER (int)WINNER
- * 		where WINNER can be: BLACK, WHITE, EMPTY(draw)
- *
- * If some player left while the game was happening, it sends to all Human players:
- *
- * 	RVR_MSG_PLAYERS
- *
- * And it will wait until someone returns
- *
- * The client:
- *
- * game_init():
- * - Init variables and set the turn to BLACK (first turn) and the state to init
- *
- * RVR_MSG_SEAT
- * - Store his seat on a safe variable
- *
- * RVR_MSG_PLAYERS
- * - Store (and display) the name of the players
- * - Set the state to wait
- *
- * RVR_MSG_START
- * - Set the state to playing
- *
- * RVR_MSG_SYNC
- * - Believes what the server says and updates everything
- *
- * RVR_MSG_MOVE
- * - Do the move
- *
- * RVR_MSG_GAMEOVER
- * - Display ending message
- * 
- * And sends to the server:
- *
- * RVR_REQ_MOVE
- * - Ask to move
- *
- * RVR_REQ_SYNC
- * - Ask for sync
- *
- * RVR_REQ_AGAIN
- * - Ask for playing again
- *
- * Luckily that's all, this protocol is perfect and it shouldn't be modified anymore. Or so I hope. :) */
+#define RVR_MSG_SEAT			0
+#define RVR_MSG_PLAYERS        	1
+#define RVR_MSG_MOVE           	2
+#define RVR_MSG_GAMEOVER       	3
+#define RVR_REQ_MOVE           	4
+#define RVR_MSG_START          	5
+#define RVR_MSG_SYNC           	6
+#define RVR_MSG_INIT           	7
+#define RVR_REQ_AGAIN          	8
 
-// Reversi protocol
-// The numbers aren't on order, because I used the same constants from TicTacToe - simplify testing
-
-#include "gnothello.h"
-
-#define RVR_MSG_SEAT 0
-#define RVR_MSG_PLAYERS 1
-#define RVR_MSG_SYNC 6
-#define RVR_REQ_SYNC 7
-#define RVR_REQ_AGAIN 8
-#define RVR_MSG_START 5
-#define RVR_MSG_MOVE 2
-#define RVR_MSG_GAMEOVER 3
-#define RVR_REQ_MOVE 4
-
 // States
-#define RVR_STATE_INIT 0
-#define RVR_STATE_WAIT 1
-#define RVR_STATE_PLAYING 2
-#define RVR_STATE_DONE 3
+#define RVR_STATE_INIT         	0
+#define RVR_STATE_WAITING      	1
+#define RVR_STATE_PLAYING      	2
+#define RVR_STATE_DONE         	3
 
-// Responses from server
-#define RVR_SERVER_ERROR -1
-#define RVR_SERVER_OK 0
-#define RVR_SERVER_JOIN 1
-#define RVR_SERVER_LEFT 2
-#define RVR_SERVER_QUIT 3
-
 // Errors
-#define 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 seat and transform into a player code
+#define SEAT2PLAYER(seat)	((seat == 0)? BLACK: WHITE)
 
-// Takes a index and transform it in cartesians coordinates
-#define X(I) ( (I%8)+1 )
-#define Y(I) ( (I/8)+1 )
+// Takes a player code and transform into a seat index
+#define PLAYER2SEAT(player)	((player == BLACK)? 0: 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)] )
+// 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 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 )
+#define NETWORK_ENGINE	"Iagno"
+#define NETWORK_VERSION	"1"
 
-#define NETWORK_ENGINE "Iagno"
-#define NETWORK_VERSION "1"
 
-void network_init (void);
-void on_network_game (void);
+void on_network_activate (GtkMenuItem *menuitem, gpointer user_data);
 
-int fd;
+void on_playerlist_activate (GtkMenuItem *menuitem, gpointer user_data);
 
-// Setup functions
-void game_init (void);
+void on_chat_activate (GtkMenuItem *menuitem, gpointer user_data);
 
-// 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);
+void on_leave_activate (GtkMenuItem *menuitem, gpointer user_data);
 
-// Send stuff to server
-void send_my_move (int move, guint turn);
-int request_sync (void);
+void on_again_activate (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);
+void send_my_move (gint move, gint turn);
+
Index: iagno/Makefile.am
===================================================================
--- iagno/Makefile.am	(リビジョン 6541)
+++ iagno/Makefile.am	(作業コピー)
@@ -13,6 +13,8 @@
 if GGZ_SERVER
 bin_PROGRAMS = iagno iagnod
 iagnod_SOURCES = server.h   \
+	othello.c \
+	othello.h \
 		 server.c   
 
 iagnod_LDFLAGS = @GGZDMOD_LDFLAGS@
@@ -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	(リビジョン 6541)
+++ 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
@@ -21,855 +20,1319 @@
  * For more details see the file COPYING.
  */
 
-#include <config.h>
+#include "config.h"
 #include <gnome.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <stdio.h>
 
-#include <string.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>
+static GtkAction      *network_action;
+static GtkAction      *playerlist_action;
+static GtkAction      *chat_action;
+static GtkAction      *leave_action;
 #endif
 
-#include "gnothello.h"
-#include "othello.h"
-#include "properties.h"
+static GdkPixmap      *buffer_pixmap = NULL;
+static GdkPixmap      *tiles_pixmap = NULL;
+static GdkGC          *gridGC[2] = { 0 };
+static GTimer         *timer[2];
+static GtkWidget      *menubar;
+static GtkWidget      *statusbar;
+static GtkWidget      *score[4];
+static GtkActionGroup *action_group;
+static GtkUIManager   *manager;
+static GtkAction      *newgame_action;
+static GtkAction      *hint_action;
+static GtkAction      *head_action;
+static GtkAction      *back_action;
+static GtkAction      *forward_action;
+static GtkAction      *last_action;
+static GtkAction      *open_action;
+static GtkAction      *save_action;
+static GtkAction      *fullscreen_action;
+static GtkAction      *unfullscreen_action;
+static GtkAction      *keyboard_action;
+static gint8          pixmaps[8][8];
+static gint8          board[8][8];
+static gint           board_width;
+static gint           board_height;
+static gint           tile_width;
+static gint           tile_height;
+static guint          context_id = 0;
+static guint          timer_id = 0;
 
-#define APP_NAME "iagno"
-#define APP_NAME_LONG N_("Iagno")
+GtkWidget             *window;
+GtkWidget             *notebook;
+GtkWidget             *toolbar;
+GtkWidget             *drawing_area;
+GtkWidget             *entry;
+GtkWidget             *timer_table;
+GdkColor              bg_color[3] = {
+                       {0, 0, 0, 0},                   /* background color */
+                       {0xffffffff, 0xffff, 0xffff, 0xffff}, /* grid color */
+                       {0, 0, 0, 0}                          /* tmp color  */
+                         };
+gint                  kifu[MAX_MOVE_COUNT + 1][2];
+guint                 flag = 0;
+gboolean              game_in_progress = FALSE;
+gboolean              ggz_network_mode = FALSE;
 
-GnomeAppBar *appbar;
-GtkWidget *window;
-GtkWidget *notebook;
-GtkWidget *drawing_area;
-GtkWidget *tile_dialog;
-GtkWidget *black_score;
-GtkWidget *white_score;
+extern gint8          board0[];
+extern gint           valid_squares[(VICTORY + 2) * (VICTORY + 3) / 2][2];
+extern gint           s_kind;
+extern gint8          move_count;
+extern gint8          whose_turn;
+extern gint8          black_score;
+extern gint8          white_score;
 
-GdkPixmap *buffer_pixmap = NULL;
-GdkPixmap *tiles_pixmap = NULL;
-GdkPixmap *tiles_mask = NULL;
+extern GtkWidget      *properties_dialog;
+extern GtkWidget      *filesave_dialog;
+extern GtkWidget      *fileopen_dialog;
+extern gboolean       fullscreen;
+extern gint           window_width;
+extern gint           window_height;
+extern gint           computer_level[];
+extern gchar          *tile_set;
+extern gchar          *bg_color_name;
+extern gboolean       hide_valid_squares;
+extern gboolean       hide_last_move;
+extern gboolean       hide_final_results;
+extern guint          flip_pixmaps_id;
+extern guint          flip_delay;
 
-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;
+int session_xpos = -1;
+int session_ypos = -1;
+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}
+};
 
-gint64 milliseconds_total = 0;
-gint64 milliseconds_current_start = 0;
+/**** Basic routines ****/
 
-guint game_in_progress;
+gint
+clamp_int (gint input, gint low, gint high)
+{
+  if (input < low)
+    input = low;
+  if (input > high)
+    input = high;
 
-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}
-};
+  return input;
+}
 
-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;
+void
+copy_board (void)
+{
+  gint i, j;
 
-extern guint flip_final_id;
-extern gint8 squares[64];
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 8; j++)
+      board[i][j] = board0[(i + 1) * 10 + j + 1];
+}
 
-int session_flag = 0;
-int session_xpos = -1;
-int session_ypos = -1;
-int session_position = 0;
+static void
+copy_pixmaps (void)
+{
+  gint i, j;
 
-gchar *tile_set = NULL;
-gchar *tile_set_tmp = NULL;
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 8; j++)
+      pixmaps[i][j] = board[i][j];
+}
 
-GdkGC *gridGC[2] = { 0 };
+static void
+set_board_size (void)
+{
+  gint depth = -1;
 
-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}
-};
+  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;
 
-GnomeUIInfo game_menu[] = {
-  GNOMEUIINFO_MENU_NEW_GAME_ITEM (new_game_cb, NULL),
+  if (buffer_pixmap) {
+    g_object_unref (buffer_pixmap);
+    depth = gdk_drawable_get_depth ((GdkDrawable *) drawing_area->window);
+  }
+  buffer_pixmap = gdk_pixmap_new (drawing_area->window,
+                                  board_width, board_height, depth);
 
-  GNOMEUIINFO_ITEM (N_("Net_work Game"), NULL, new_network_game_cb, NULL),
+  return set_bg_color ();
+}
 
-  GNOMEUIINFO_SEPARATOR,
+void
+set_bg_color (void)
+{
+  gint i;
 
-  GNOMEUIINFO_MENU_UNDO_MOVE_ITEM (undo_move_cb, NULL),
+  gdk_color_parse (bg_color_name, &bg_color[0]);
+  gdk_colormap_alloc_color (gtk_widget_get_colormap (drawing_area),
+                            &bg_color[0], FALSE, TRUE);
 
-  GNOMEUIINFO_ITEM (N_("_Player list"), NULL, on_player_list, NULL),
+  for (i = 0; i < 2; i++) {
+    if (gridGC[i])
+      g_object_unref (gridGC[i]);
+    gridGC[i] = gdk_gc_new (drawing_area->window);
+    gdk_gc_copy (gridGC[i], drawing_area->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 (buffer_pixmap, gridGC[0], TRUE, 0, 0,
+                      board_width, board_height);
 
-  GNOMEUIINFO_ITEM (N_("_Chat Window"), NULL, on_chat_window, NULL),
+  return gui_draw_grid ();
+}
 
-  GNOMEUIINFO_SEPARATOR,
+void
+gui_draw_grid (void)
+{
+  gint i;
 
-  GNOMEUIINFO_ITEM (N_("_Leave Game"), NULL, on_network_leave, NULL),
+  gdk_gc_set_line_attributes (gridGC[1], GRID_WIDTH, GDK_LINE_ON_OFF_DASH,
+                              GDK_CAP_BUTT, GDK_JOIN_MITER);
 
-  GNOMEUIINFO_MENU_QUIT_ITEM (quit_game_cb, NULL),
+  for (i = tile_height; i < board_height; i += tile_height + GRID_WIDTH)
+    gdk_draw_line (buffer_pixmap, gridGC[1], 0, i, board_width, i);
+  for (i = tile_width; i < board_width; i += tile_width + GRID_WIDTH)
+    gdk_draw_line (buffer_pixmap, gridGC[1], i, 0, i, board_height);
 
-  GNOMEUIINFO_END
-};
+  return load_pixmaps ();
+}
 
-GnomeUIInfo settings_menu[] = {
-  GNOMEUIINFO_MENU_PREFERENCES_ITEM (properties_cb, NULL),
-  GNOMEUIINFO_END
-};
+static GamesPreimage *
+load_image (gchar *tileset)
+{
+  GError *error = NULL;
+  gchar *fname;
+  gchar *pathname;
+  GamesPreimage *preimage;
 
-GnomeUIInfo help_menu[] = {
-  GNOMEUIINFO_HELP ("iagno"),
-  GNOMEUIINFO_MENU_ABOUT_ITEM (about_cb, NULL),
-  GNOMEUIINFO_END
-};
+  fname = g_build_filename ("iagno", 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 mainmenu[] = {
-  GNOMEUIINFO_MENU_GAME_TREE (game_menu),
-  GNOMEUIINFO_MENU_SETTINGS_TREE (settings_menu),
-  GNOMEUIINFO_MENU_HELP_TREE (help_menu),
-  GNOMEUIINFO_END
-};
+  g_free (fname);
+  g_free (pathname);
+  return preimage;
+}
 
-static void
-undo_set_sensitive (gboolean state)
+void
+load_pixmaps (void)
 {
-  gtk_widget_set_sensitive (game_menu[3].widget, state);
+  GamesPreimage *t_image;
+  GdkPixbuf *image;
+  gint depth = -1;
+  GdkGC *gc;
+
+  t_image = load_image (tile_set);
+  if (!t_image) {
+    if (tile_set)
+      g_free (tile_set);
+    tile_set = g_strdup (DEFAULT_TILESET);
+    t_image = load_image (tile_set);
+    if (!t_image) {
+      g_print ("Could not find \'%s\' pixmap file\n", DEFAULT_TILESET);
+      exit (1);
+    }
+    reset_properties ();
+  }
+
+  image = games_preimage_render (t_image, tile_width * 8, tile_height * 4);
+
+  if (tiles_pixmap) {
+    g_object_unref (tiles_pixmap);
+    depth = gdk_drawable_get_depth ((GdkDrawable *) drawing_area->window);
+  }
+  tiles_pixmap = gdk_pixmap_new (drawing_area->window,
+                                 tile_width * 8, tile_height * 4, depth);
+
+  gc = gdk_gc_new (tiles_pixmap);
+  gdk_gc_set_foreground (gc, &bg_color[0]);
+  gdk_gc_set_background (gc, &bg_color[0]);
+
+  gdk_draw_rectangle (tiles_pixmap, gc, TRUE, 0, 0,
+                      tile_width * 8, tile_height * 4);
+  gdk_draw_pixbuf (tiles_pixmap, gc, image, 0, 0, 0, 0,
+                   tile_width * 8, tile_height * 4,
+                   GDK_RGB_DITHER_NONE, 0, 0);
+
+  g_object_unref (t_image);
+  g_object_unref (image);
+  return redraw_board ();
 }
 
-void
-quit_game_cb (GtkWidget * widget, gpointer data)
+static void
+gui_draw_pixmap_buffer (gint x, gint y, gint which)
 {
-  gtk_main_quit ();
+  gdk_draw_drawable (buffer_pixmap, gridGC[0], tiles_pixmap,
+                     tile_width * (which % 8), tile_height * (which / 8),
+                     (tile_width + GRID_WIDTH) * x,
+                     (tile_height + GRID_WIDTH) * y,
+                     tile_width, tile_height);
 }
 
-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 *) buffer_pixmap, 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_pixmap (gint x, gint y, gint which)
 {
-#ifdef GGZ_CLIENT
-  create_or_raise_dlg_players (GTK_WINDOW (window));
-#endif
+  gdk_draw_drawable (drawing_area->window, gridGC[0], tiles_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 (x, y, which);
 }
 
-void
-on_chat_window (void)
+static void
+gui_draw_arc (gint x, gint y)
 {
-#ifdef GGZ_CLIENT
-  create_or_raise_dlg_chat (GTK_WINDOW (window));
-#endif
+  gdk_draw_arc ((GdkDrawable *) drawing_area->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
-new_network_game_cb (GtkWidget * widget, gpointer data)
+redraw_board (void)
 {
-#ifdef GGZ_CLIENT
-  on_network_game ();
-  gtk_widget_hide (mainmenu[0].widget);
-  gtk_widget_hide (mainmenu[1].widget);
-#endif
+  gint i, j, state, which;
+
+  copy_pixmaps ();
+
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 8; j++) {
+      state = 0;
+      which = (gint) pixmaps[i][j];
+      if (which < 0) {
+        state = -1;
+        which *= -1;
+      }
+      if (which == BLANK)
+        which = 0;
+      else
+        which = clamp_int (which, BLACK, WHITE) - BLACK + 1;
+      gui_draw_pixmap_buffer (j, i, which);
+      if (state)
+        gui_draw_arc_buffer (j, i);
+    }
+
+  gtk_widget_queue_draw_area (drawing_area, 0, 0, board_width, board_height);
+
+  return gui_status ();
 }
 
 void
-on_network_leave (GObject * object, gpointer data)
+gui_status (void)
 {
-#ifdef GGZ_CLIENT
-  ggz_embed_leave_table ();
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), NETWORK_PAGE);
-#endif
+  gchar message[5];
+
+  sprintf (message, "%.2d", (int) black_score);
+  gtk_label_set_text (GTK_LABEL (score[0]), message);
+  sprintf (message, "%.2d", (int) white_score);
+  gtk_label_set_text (GTK_LABEL (score[1]), message);
 }
 
 void
-undo_move_cb (GtkWidget * widget, gpointer data)
+gui_message (gchar *message)
 {
-  gint8 which_computer, xy;
+  if (context_id)
+    gtk_statusbar_pop (GTK_STATUSBAR (statusbar), context_id);
 
-  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;
-  }
+  context_id =
+    gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), message);
+  gtk_statusbar_push (GTK_STATUSBAR (statusbar), context_id, message);
+}
 
-  if (flip_final_id) {
-    g_source_remove (flip_final_id);
-    flip_final_id = 0;
-  }
+/** Timer **/
 
-  game_in_progress = 1;
+static void
+sprint_time (gchar *message, GTimer *timer)
+{
+  int mm, ss;
 
-  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;
-  }
-
-  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 void
+gui_timer (void)
 {
-  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 (score[i + 2]), message);
+  }
+}
 
-  gchar *license = games_get_license (_(APP_NAME_LONG));
+static void
+start_timer (void)
+{
+  gui_timer ();
 
-  gtk_show_about_dialog (GTK_WINDOW (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);
+  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
+continue_timer (void)
 {
-  show_properties_dialog ();
+  if (game_in_progress)
+    g_timer_continue (timer[PLAYER2SEAT (whose_turn)]);
 }
 
-gint
-expose_event (GtkWidget * widget, GdkEventExpose * event)
+static void
+stop_timer (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);
+  if (game_in_progress)
+    g_timer_stop (timer[PLAYER2SEAT (whose_turn)]);
 }
 
-gboolean
-configure_event (GtkWidget * widget, GdkEventConfigure * event)
+void
+reset_timer (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 ();
 }
 
-gint
-button_press_event (GtkWidget * widget, GdkEventButton * event)
+/****************/
+
+static gboolean
+gui_hint (void)
 {
-  guint x, y;
-
-  if (game_in_progress == 0)
+  GString   *string;
+  gchar message[4] = {0,0,0x20,0};
+  gint yx;
+  
+  if (!(flag & GUI_HINT_FLAG))
     return TRUE;
+  flag ^= GUI_HINT_FLAG;
+ 
+  yx = computer_move (MAX_DEPTH);
+  message[0] = (gchar) (yx % 10 + 0x40);
+  message[1] = (gchar) (yx / 10 + 0x30);
 
-  if (!ggz_network_mode && (whose_turn == WHITE_TURN) && white_computer_level)
-    return TRUE;
-
-  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][0]);
+  if (s_kind == PERFECT || s_kind == VICTORY) {
+    if (valid_squares[0][0] > 0)
+      g_string_append_printf (string, "%s", " You shall win the game.");
+    else if (valid_squares[0][0] < 0)
+      g_string_append_printf (string, "%s", " You shall lose the game.");
+    else if (valid_squares[0][0] == 0)
+      g_string_append_printf (string, "%s", " The game shall be a draw.");
+  } else {
+    if (valid_squares[0][0] > 12)
+      g_string_append_printf (string, "%s", " The game is superiority for you.");
+    else if (valid_squares[0][0] < -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);
-}
+  if (!(flag & HINT_FLAG))
+    return gui_hint ();
+  flag ^= HINT_FLAG;
 
-void
-gui_draw_pixmap_buffer (gint which, gint x, gint y)
-{
-  gdk_draw_drawable (buffer_pixmap, gridGC[0], tiles_pixmap,
-		     (which % 8) * TILEWIDTH, (which / 8) * TILEHEIGHT,
-		     x * (TILEWIDTH + GRIDWIDTH),
-		     y * (TILEHEIGHT + GRIDWIDTH), TILEWIDTH, TILEHEIGHT);
+  gui_message (_("Now thinking."));
+  flag |= GUI_HINT_FLAG;
+  return TRUE;
 }
 
-void
-gui_draw_grid (void)
+static gboolean
+t_computer_move (void)
 {
-  int i;
+  if (!(flag & COMPUTER_FLAG))
+    return check_hint ();
+  flag ^= COMPUTER_FLAG;
+  if (flag & HINT_FLAG)
+   flag ^= HINT_FLAG;
 
-  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);
-  }
+  move (computer_move (computer_level[PLAYER2SEAT (whose_turn)] * 2 - 1));
 
-  gdk_draw_drawable (drawing_area->window, gridGC[0], buffer_pixmap,
-		     0, 0, 0, 0, BOARDWIDTH, BOARDHEIGHT);
+  return TRUE;
 }
 
-void
-load_pixmaps (void)
+static gboolean
+check_computer (void)
 {
-  GdkPixbuf *image;
-  GError *error = NULL;
-  gchar *tmp;
-  gchar *fname;
+  if (!(flag & CHECK_COMPUTER_PLAYERS))
+    return t_computer_move ();
+  flag ^= CHECK_COMPUTER_PLAYERS;
 
-  g_return_if_fail (tile_set != NULL && tile_set[0] != '0');
+  if (!game_in_progress || ggz_network_mode)
+    return TRUE;
+  
+  if (!computer_level[PLAYER2SEAT (whose_turn)])
+    return TRUE;
+    
+  gui_message (_("Now thinking."));
+  flag |= COMPUTER_FLAG;
+  return TRUE;
+}
 
-  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);
+static gboolean
+flip_final_results (void)
+{
+  gint8 i = 0, adder = 0;
 
-  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);
-  }
+  if (!(flag & FLIP_FINAL))
+    return check_computer ();
+  flag ^= FLIP_FINAL;
 
-  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 < black_score; i++) {
+    board[i / 8][i % 8] = BLACK;
+    if (pixmaps[i / 8][i % 8] == BLANK)
+      pixmaps[i / 8][i % 8] = WHITE;
+    if (pixmaps[i / 8][i % 8] == WHITE) {
+      pixmaps[i / 8][i % 8] += adder;
+      adder++;
+    }
   }
 
-  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 - white_score; i++)
+    board[i / 8][i % 8] = BLANK;
+
+  for (; i < 64; i++) {
+    board[i / 8][i % 8] = WHITE;
+    if (pixmaps[i / 8][i % 8] == BLANK)
+      pixmaps[i / 8][i % 8] = BLACK;
+    if (pixmaps[i / 8][i % 8] == BLACK) {
+      pixmaps[i / 8][i % 8] -= adder;
+      adder++;
+    }
   }
 
-  gdk_pixbuf_render_pixmap_and_mask_for_colormap (image,
-						  gdk_colormap_get_system (),
-						  &tiles_pixmap,
-						  &tiles_mask, 127);
+  flag |= FLIP_TILES;
+  return TRUE;
+}
 
-  gdk_pixbuf_unref (image);
-  g_free (fname);
+static gboolean
+check_sound (void)
+{
+  if (flag & FLIP_SOUND) {
+    flag ^= FLIP_SOUND;
+    games_sound_play ("flip-piece");
+  }
+  if (flag & GAMEOVER_SOUND) {
+    flag ^= GAMEOVER_SOUND;
+    games_sound_play ("gameover");
+  }
+  return TRUE;
 }
 
-gint
+gboolean
 flip_pixmaps (gpointer data)
 {
-  guint i, j;
-  guint flipped_tiles = 0;
+  gint i, j, state, which;
 
-  if (!tiles_to_flip)
-    return TRUE;
+  if (!(flag & FLIP_TILES))
+    return flip_final_results ();
+  flag ^= FLIP_TILES;
 
   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 (pixmaps[i][j] == board[i][j])
+          continue;
+
+      if (pixmaps[i][j] < -BLANK && board[i][j] > BLANK)
+        pixmaps[i][j] *= -1;
+      if (pixmaps[i][j] < board[i][j] && pixmaps[i][j] > BLANK)
+        pixmaps[i][j]++;
+      else if (pixmaps[i][j] > board[i][j] && board[i][j] > BLANK)
+        pixmaps[i][j]--;
+      else 
+        pixmaps[i][j] = board[i][j];
+ 
+      state = 0;
+      which = pixmaps[i][j];
+      if (which < 0) {
+        state = -1;
+        which *= -1;
+       }
+      if (which == BLANK)
+        which = 0;
+      else
+        which = clamp_int (which, BLACK, WHITE) - BLACK + 1;
+      gui_draw_pixmap (j, i, which);
+      if (state)
+        gui_draw_arc (j, i);
+      flag |= FLIP_TILES;
     }
 
-  if (!flipped_tiles)
-    tiles_to_flip = 0;
+  return check_sound ();
+}
 
-  return TRUE;
+static void
+set_last_move (void)
+{
+  gint yx;
+
+  if (hide_last_move)
+    return;
+  if (move_count < 5)
+    return;
+
+  yx = kifu[move_count - 1][1];
+  board[yx / 10 - 1][yx % 10 - 1] = (gint8) -kifu[move_count - 1][0];
 }
 
 static void
-redraw_board (void)
+set_valid_squares (gint i)
 {
-  guint i, j;
+  gint yx;
 
-  gui_status ();
+  for (yx = 0; yx < 64; yx++)
+    if (board[yx / 8][yx % 8] < 0)
+      board[yx / 8][yx % 8] *= -1;
+  if (hide_valid_squares)
+    return set_last_move (); 
 
-  for (i = 0; i < 8; i++)
-    for (j = 0; j < 8; j++)
-      gui_draw_pixmap_buffer (pixmaps[i][j], i, j);
+  while (i > 0) {
+    yx = valid_squares[i--][1];
+    board[yx / 10 - 1][yx % 10 - 1] = -BLANK;
+  }
+  return set_last_move (); 
+};
 
-  gui_draw_grid ();
+void
+set_sensitive (void)
+{
+  gtk_action_set_sensitive (newgame_action, !(ggz_network_mode && whose_turn)
+				          && !(filesave_dialog || fileopen_dialog));
+  gtk_action_set_sensitive (hint_action,    !ggz_network_mode && whose_turn);
+  gtk_action_set_sensitive (head_action,    !ggz_network_mode && move_count > 4);
+  gtk_action_set_sensitive (back_action,    !ggz_network_mode && move_count > 4);
+  gtk_action_set_sensitive (forward_action, kifu[move_count][0]);
+  gtk_action_set_sensitive (last_action,    kifu[move_count][0]);
+  gtk_action_set_sensitive (save_action,    kifu[4][0]);
 }
 
+/**** For game ****/
+
 void
-clear_board (void)
+check_game_over (void)
 {
-  guint i, j;
+  gint i;
 
-  if (flip_final_id) {
-    g_source_remove (flip_final_id);
-    flip_final_id = 0;
+  flag |= FLIP_TILES;
+  flag |= FLIP_SOUND;
+ /* Continue? */
+  i = entry_valid_squares (0);
+  if (i) {
+    set_valid_squares (i);
+    if (whose_turn == BLACK)
+      gui_message (_("Dark's move"));
+    else
+      gui_message (_("Light's move"));
+    return  set_sensitive ();
   }
-
-  if (black_computer_id) {
-    g_source_remove (black_computer_id);
-    black_computer_id = 0;
+  /* Pass? */
+  whose_turn = OTHER_PLAYER (whose_turn);
+  i = entry_valid_squares (0);
+  if (i) {
+    set_valid_squares (i);
+    if (whose_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 (white_score > black_score)
+      gui_message (_("Light player wins!"));
+  if (black_score > white_score)
+      gui_message (_("Dark player wins!"));
+  if (white_score == black_score)
+      gui_message (_("The game was a draw."));
 
-  if (white_computer_id) {
-    g_source_remove (white_computer_id);
-    white_computer_id = 0;
-  }
+  whose_turn       = 0;
+  game_in_progress = FALSE;
+  flag |= GAMEOVER_SOUND;
 
-  game_in_progress = 0;
-  move_count = 0;
-  for (i = 0; i < 8; i++)
-    for (j = 0; j < 8; j++)
-      board[i][j] = 0;
+  if (hide_final_results) {
+    copy_board ();
+    set_last_move ();
+  } else 
+    flag |= FLIP_FINAL;
 
-  memcpy (pixmaps, board, sizeof (gint8) * 8 * 8);
+  return set_sensitive ();
+}
 
-  bcount = 0;
-  wcount = 0;
+gboolean
+check_valid_move (gint yx, gint who)
+{
+  if (who == (gint) whose_turn
+      && yx > 10 && yx < 89
+      && board0[yx] == BLANK
+      && check_valid (yx, who))
+    return TRUE;
 
-  redraw_board ();
+  gui_message (_("Invalid move."));
+  return FALSE;
 }
 
 void
-init_new_game (void)
+move (gint yx)
 {
-  clear_board ();
-  game_in_progress = 1;
-  move_count = 4;
+  if (game_in_progress) {
+    stop_timer ();
+    kifu[move_count][0]     = (gint) whose_turn;
+    kifu[move_count][1]     = yx;
+    kifu[move_count + 1][0] = 0;
+  }
 
-  undo_set_sensitive (FALSE);
+  move_board (yx);
+  copy_board ();
+  gui_status ();
+  check_game_over (); 
+  if (!game_in_progress)
+    return;
+    
+  continue_timer ();
+  flag |= CHECK_COMPUTER_PLAYERS;
+}
 
-  board[3][3] = WHITE_TURN;
-  board[3][4] = BLACK_TURN;
-  board[4][3] = BLACK_TURN;
-  board[4][4] = WHITE_TURN;
+void
+stop_game (void)
+{
+  flag = 0;
+  if (!game_in_progress)
+    return;
+    
+  stop_timer ();
+  game_in_progress = FALSE;
+}
 
-  bcount = 2;
-  wcount = 2;
+void
+init_game (void)
+{
+  stop_game ();
+  reset_timer ();
   init ();
-
-  memcpy (pixmaps, board, sizeof (gint8) * 8 * 8);
-
+  copy_board ();
   redraw_board ();
-
-  whose_turn = BLACK_TURN;
-  gui_status ();
-  gtk_widget_show (mainmenu[0].widget);
-  gtk_widget_show (mainmenu[1].widget);
-
-  check_computer_players ();
+  kifu[move_count][0] = 0;
+  set_valid_squares (entry_valid_squares (0));
+  flag |= FLIP_TILES;
+  set_sensitive ();
 }
 
 void
-create_window (void)
+start_game (void)
 {
-  GtkWidget *table;
+  if (game_in_progress)
+    return;
+  check_game_over ();  
+  if (!whose_turn)
+    return;
 
-  window = gnome_app_new ("iagno", _(APP_NAME_LONG));
+  kifu[move_count][0] = 0;
+  game_in_progress = TRUE;
+  start_timer ();
+  continue_timer ();
+  flag |= CHECK_COMPUTER_PLAYERS;
+}
 
-  games_conf_add_window (GTK_WINDOW (window), NULL);
+/****  Callbacks  ****/
 
-  notebook = gtk_notebook_new ();
-  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
+static void
+on_newgame_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+#ifdef GGZ_CLIENT
+  if (ggz_network_mode)
+    return on_again_activate ();
+#endif
 
-  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);
+  init_game ();
+  start_game ();
+}
 
-  gnome_app_create_menus (GNOME_APP (window), mainmenu);
+static void
+on_hint_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  flag |= HINT_FLAG;
+}
 
-  drawing_area = gtk_drawing_area_new ();
+void
+on_head_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  stop_game ();
+  init ();
+  copy_board ();
+  check_game_over (); 
+  redraw_board ();
+}
 
-  gtk_widget_pop_colormap ();
+static void
+on_back_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  stop_game ();
+  back ();
+  copy_board ();
+  gui_status ();
+  check_game_over ();
+}
 
-  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);
+static void
+on_forward_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  move (kifu[move_count][1]);
+}
 
-  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);
+static void
+on_last_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  while (kifu[move_count][0]) {
+    whose_turn = (gint8) kifu[move_count][0];
+    move_board (kifu[move_count][1]);
+  }
 
-  gtk_widget_show (drawing_area);
+  copy_board ();
+  check_game_over ();
+  redraw_board ();
+}
 
-  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_quit_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  // For flip_pixmaps don't draw drawing_area after destroy window.
+  g_source_remove (flip_pixmaps_id);
+  if (timer_id)
+    g_source_remove (timer_id);
+  // When the player quit the game at once after unfullscreen,
+  // games_conf don't save window size.
+  if (!fullscreen)
+    gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
+  gtk_window_get_position (GTK_WINDOW (window), &session_xpos, &session_ypos);
+  save_properties ();
+  gtk_main_quit ();
+}
 
-  table = gtk_table_new (1, 8, FALSE);
+static void
+on_fullscreen_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  fullscreen = !fullscreen;
+  if (fullscreen)
+    gtk_window_fullscreen (GTK_WINDOW (window));
+  else
+    gtk_window_unfullscreen (GTK_WINDOW (window));
 
-  black_score = gtk_label_new (_("Dark:"));
-  gtk_widget_show (black_score);
+  gtk_action_set_visible (fullscreen_action,  !fullscreen);
+  gtk_action_set_visible (unfullscreen_action, fullscreen);
+}
 
-  gtk_table_attach (GTK_TABLE (table), black_score, 1, 2, 0, 1, 0, 0, 3, 1);
+static void
+on_help_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  gnome_help_display ("iagno.xml", NULL, NULL);
+}
 
-  black_score = gtk_label_new ("00");
-  gtk_widget_show (black_score);
+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_table_attach (GTK_TABLE (table), black_score, 2, 3, 0, 1, 0, 0, 3, 1);
-
-  white_score = gtk_label_new (_("Light:"));
-  gtk_widget_show (white_score);
-
-  gtk_table_attach (GTK_TABLE (table), white_score, 4, 5, 0, 1, 0, 0, 3, 1);
-
-  white_score = gtk_label_new ("00");
-  gtk_widget_show (white_score);
-
-  gtk_table_attach (GTK_TABLE (table), white_score, 5, 6, 0, 1, 0, 0, 3, 1);
-  undo_set_sensitive (FALSE);
-
-  gtk_widget_show (table);
-
-  gtk_box_pack_start (GTK_BOX (appbar), table, FALSE, TRUE, 0);
-
-  gnome_appbar_set_status (GNOME_APPBAR (appbar), _("Welcome to Iagno!"));
+  gtk_show_about_dialog (GTK_WINDOW (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);
-
+  if (fileopen_dialog || filesave_dialog)
+    return FALSE;
+    
+#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, (gint) whose_turn);
+    return FALSE;
   }
+#endif
 
-  gtk_widget_set_sensitive (settings_menu[0].widget, !ggz_network_mode);
+  if (!check_valid_move (yx, (gint) whose_turn))
+    return FALSE;
 
-#ifndef GGZ_CLIENT
-  gtk_widget_set_sensitive (game_menu[1].widget, FALSE);
-#endif
+  if (!game_in_progress) 
+    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"));
-    }
+/**** For keyboard ****/
+static void
+on_keyboard_activate (GtkAction *action, gpointer user_data)
+{
+  if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
+    gtk_widget_show (entry);
+  else
+    gtk_widget_hide (entry);
+}
+               
+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 *) entry) < 2)
+    return FALSE;
+  ch = gtk_editable_get_chars ((GtkEditable *) entry, 0, 1);
+  x = (gint) ((*ch & 0xdf) - 0x40);
+  ch = gtk_editable_get_chars ((GtkEditable *) entry, 1, 2);
+  y = (gint) (*ch - 0x30);
 
+  gtk_editable_delete_text ((GtkEditable *) entry, 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 (drawing_area->window, gridGC[0], buffer_pixmap,
+                     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
+network_gui_update (void)
+{
+  gtk_action_set_visible   (hint_action,        !ggz_network_mode);
+#ifdef GGZ_CLIENT
+  gtk_action_set_sensitive (network_action,     !ggz_network_mode);
+  gtk_action_set_visible   (network_action,     !ggz_network_mode);
+  gtk_action_set_sensitive (playerlist_action,   ggz_network_mode);
+  gtk_action_set_visible   (playerlist_action,   ggz_network_mode);
+  gtk_action_set_sensitive (chat_action,         ggz_network_mode);
+  gtk_action_set_visible   (chat_action,         ggz_network_mode);
+  gtk_action_set_sensitive (leave_action,        ggz_network_mode);
+  gtk_action_set_visible   (leave_action,        ggz_network_mode);
+#endif
+  gtk_action_set_visible   (head_action,        !ggz_network_mode);
+  gtk_action_set_visible   (back_action,        !ggz_network_mode);
+  gtk_action_set_visible   (forward_action,     !ggz_network_mode);
+  gtk_action_set_visible   (last_action,        !ggz_network_mode);
+  gtk_action_set_sensitive (open_action,        !ggz_network_mode);
+  gtk_action_set_visible   (fullscreen_action,  !fullscreen);
+  gtk_action_set_visible   (unfullscreen_action, fullscreen);
+  if (properties_dialog)
+    on_ok_clicked (NULL, NULL);
+  if (filesave_dialog)
+    on_save_cancel_clicked (NULL, NULL);
+  if (fileopen_dialog)
+    on_open_cancel_clicked (NULL, NULL);
+// If you don't want file save, file open and keyboard menu,
+// please change the next three lines TRUE to FALSE.
+  gtk_action_set_visible   (open_action,         TRUE);
+  gtk_action_set_visible   (save_action,         TRUE);
+  gtk_action_set_visible   (keyboard_action,     TRUE);
 }
 
-void
-set_bg_color (void)
+static void
+set_actions (void)
 {
-  GdkImage *tmpimage;
-  GdkColor bgcolor;
+  newgame_action    = gtk_action_group_get_action (action_group, "newgame");
+  hint_action       = gtk_action_group_get_action (action_group, "hint");
+#ifdef GGZ_CLIENT
+  network_action    = gtk_action_group_get_action (action_group, "network");
+  playerlist_action = gtk_action_group_get_action (action_group, "playerlist");
+  chat_action       = gtk_action_group_get_action (action_group, "chat");
+  leave_action      = gtk_action_group_get_action (action_group, "leave");
+#endif
+  head_action       = gtk_action_group_get_action (action_group, "head");
+  back_action       = gtk_action_group_get_action (action_group, "back");
+  forward_action    = gtk_action_group_get_action (action_group, "forward");
+  last_action       = gtk_action_group_get_action (action_group, "last");
+  open_action       = gtk_action_group_get_action (action_group, "open");
+  save_action       = gtk_action_group_get_action (action_group, "save");
+  fullscreen_action = gtk_action_group_get_action (action_group, "fullscreen");
+  unfullscreen_action = gtk_action_group_get_action (action_group,
+								   "unfullscreen");
+  keyboard_action   = gtk_action_group_get_action (action_group, "keyboard");
+}
 
-  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);
+static const char 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='playerlist'/>"
+    "      <menuitem action='chat'/>"
+    "      <menuitem action='leave'/>"
+#endif
+    "      <separator/>"
+    "      <menuitem action='head'/>"
+    "      <menuitem action='back'/>"
+    "      <menuitem action='forward'/>"
+    "      <menuitem action='last'/>"
+    "      <separator/>"
+    "      <menuitem action='open'/>"
+    "      <menuitem action='save'/>"
+    "      <separator/>"
+    "      <menuitem action='quit'/>"
+    "    </menu>"
+    "    <menu name='ViewMenu' action='viewmenu'>"
+    "      <menuitem action='fullscreen'/>"
+    "      <menuitem action='unfullscreen'/>"
+    "      <menuitem action='keyboard'/>"
+    "    </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='playerlist'/>"
+    "      <toolitem action='leave'/>"
+#endif
+    "      <toolitem action='quit'/>"
+    "      <separator/>"
+    "      <toolitem action='head'/>"
+    "      <toolitem action='back'/>"
+    "      <toolitem action='forward'/>"
+    "      <toolitem action='last'/>"
+    "  </toolbar>"
+ "</ui>"
+};
 
-  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 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)},
+  {"playerlist",   GAMES_STOCK_PLAYER_LIST,      NULL, NULL,
+    N_("Show a list of players in the network game"),
+    G_CALLBACK (on_playerlist_activate)},
+  {"chat",         NULL,                         N_("_Chat Window"), NULL,
+   NULL,
+    G_CALLBACK (on_chat_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)},
+  {"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)},
+  {"viewmenu",     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_preferences_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_copy (gridGC[0], drawing_area->style->bg_gc[0]);
-  gdk_gc_copy (gridGC[1], drawing_area->style->bg_gc[0]);
+const GtkToggleActionEntry toggle_action_entry[] = {
+  {"keyboard",     NULL,                         N_("_Keyboard"), "<ALT>K",
+    NULL,
+    G_CALLBACK (on_keyboard_activate)},
+};
 
-  gdk_gc_set_background (gridGC[0], &bgcolor);
-  gdk_gc_set_foreground (gridGC[0], &bgcolor);
-
-  /* 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);
-
-  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;
+  GtkAccelGroup *accel_group;
+  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);
+  accel_group = gtk_accel_group_new ();
+/**** 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_action_group_add_toggle_actions (action_group, toggle_action_entry,
+				          G_N_ELEMENTS (toggle_action_entry),
+				          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 ****/
+  notebook = gtk_notebook_new ();
+  gtk_container_add (GTK_CONTAINER (window), notebook);
+  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
 
-  gnome_client_set_restart_command (client, i, argv);
-  gnome_client_set_clone_command (client, 0, NULL);
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, NULL);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), MAIN_PAGE);
+/**** Menubar ****/
+  menubar = gtk_ui_manager_get_widget (manager, "/MenuBar");
+  gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
+/**** Toolbar ****/
+  toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar");
+  gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
+  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH);
+#ifdef GGZ_CLIENT
+  for (i = 0; i < 11; i++) {
+#else
+  for (i = 0; i < 8; i++) {
+#endif
+    gtk_tool_item_set_expand (gtk_toolbar_get_nth_item
+                              ((GtkToolbar *) toolbar, i), TRUE);
+    gtk_tool_item_set_homogeneous (gtk_toolbar_get_nth_item
+                                   ((GtkToolbar *) toolbar, i), FALSE);
+  }
 
-  g_free (argv[2]);
-  g_free (argv[4]);
-
-  return TRUE;
+  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 ****/
+  drawing_area = gtk_drawing_area_new ();
+  gtk_widget_set_double_buffered (drawing_area, FALSE);
+  gtk_widget_set_size_request (drawing_area, BOARD_MIN, BOARD_MIN);
+  gtk_table_attach (GTK_TABLE (table), drawing_area, 1, 9, 1, 9,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+  gtk_widget_set_events (drawing_area,
+			      GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
+  g_signal_connect ((gpointer) drawing_area, "expose_event",
+                    G_CALLBACK (on_drawing_area_expose_event), NULL);
+  g_signal_connect ((gpointer) drawing_area, "button_press_event",
+                    G_CALLBACK (on_drawing_area_button_press_event), NULL);
+  g_signal_connect ((gpointer) drawing_area, "configure_event",
+                    G_CALLBACK (on_drawing_area_configure_event), NULL);
+/**** Keyboard ****/
+  entry = gtk_entry_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+  gtk_widget_set_events (entry, GDK_KEY_PRESS_MASK);
+  g_signal_connect ((gpointer) entry, "key_press_event",
+                    G_CALLBACK (on_entry_key_press_event), NULL);
+  gtk_editable_set_editable ((GtkEditable *) entry, TRUE);
+/**** Statusbar ****/
+  statusbar = gtk_statusbar_new ();
+  gtk_box_pack_start (GTK_BOX (vbox),statusbar , FALSE, FALSE, 0);
+  gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbar), FALSE);
+/**** Scores ****/
+  table = gtk_table_new (1, 4, FALSE);
+  gtk_box_pack_start (GTK_BOX (statusbar), table, FALSE, TRUE, 0);
+  for (i = 0; i < 2; i++) {
+    label = gtk_label_new (strs[i]);
+    gtk_table_attach (GTK_TABLE (table), label, i*2, i*2+1,
+			 0, 1, (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 5, 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);
+    score[i] = gtk_label_new (strs[1]);
+    gtk_table_attach (GTK_TABLE (table), score[i], i*2+1, i*2+2,
+			 0, 1, (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 5, 0);
+   }
+/**** Timers ****/
+  timer_table = gtk_table_new (1, 4, FALSE);
+  gtk_box_pack_start (GTK_BOX (statusbar), timer_table, 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 (timer_table), label, i*2, i*2+1,
+			 0, 1, (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 5, 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);
+    score[i + 2] = gtk_label_new (strs[2]);
+    gtk_table_attach (GTK_TABLE (timer_table), score[i + 2], i*2+1, i*2+2,
+			 0, 1, (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 5, 0);
+   }
+/******************/
+  gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+  gtk_widget_show_all (window);
+  gtk_widget_hide (entry);
+  return window;
 }
 
+/**** Main ****/
+
 int
-main (int argc, char **argv)
+main (int argc, char *argv[])
 {
-  GnomeClient *client;
   GnomeProgram *program;
   GOptionContext *context;
 
@@ -884,50 +1347,32 @@
   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);
+                                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 ();
-
+  init ();
+  copy_board ();
   load_properties ();
+  window = create_window ();
+  if (session_xpos > 0 && session_ypos > 0)
+    gtk_window_move (GTK_WINDOW (window), session_xpos, session_ypos);
+  reset_properties ();
+  apply_changes ();
+  network_gui_update ();
 
-  load_pixmaps ();
-
-  gtk_widget_show (window);
-
-#ifdef GGZ_CLIENT
-  network_init ();
-#endif
-
-  if (session_xpos >= 0 && session_ypos >= 0) {
-    gdk_window_move (window->window, session_xpos, session_ypos);
-  }
-
-  buffer_pixmap = gdk_pixmap_new (drawing_area->window,
-				  BOARDWIDTH, BOARDHEIGHT, -1);
-
-  set_bg_color ();
-
-  init_new_game ();
-
+  init_game ();
+  start_game ();
+  gui_message (_("Welcome to Iagno!"));
   gtk_main ();
 
   games_conf_shutdown ();
-
   g_object_unref (program);
-
   return 0;
 }
+
Index: iagno/properties.c
===================================================================
--- iagno/properties.c	(リビジョン 6541)
+++ iagno/properties.c	(作業コピー)
@@ -20,355 +20,256 @@
  * For more details see the file COPYING.
  */
 
-#include <config.h>
+#include "config.h"
 #include <gnome.h>
-#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.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"
+#define MAX_OPTIONS		7
 
-#define DEFAULT_TILESET "classic.png"
+static const gchar *keys[] = {
+  "fullscreen",		/* 0 */
+  "width",                   /* 1 */
+  "height",                  /* 2 */
+  "x_position",              /* 3 */
+  "y_position",              /* 4 */
+  "black_level",             /* 5 */
+  "white_level",             /* 6 */
+  "tileset",                 /* 7 */
+  "bg_color_name",           /* 8 */
+  "slow_moves",              /* 9 */
+  "disable_sounds",          /* 10 */
+  "hide_final_results",      /* 11 */
+  "hide_valid_squares",	/* 12 */
+  "hide_last_move",          /* 13 */
+  "hide_toolbar",            /* 14 */
+  "hide_timer"               /* 15 */
+};
 
+static gint      t_computer_level[2];
+static gchar     *t_tile_set;
+static gchar     *t_bg_color_name;
+static gboolean  t_options[MAX_OPTIONS];
+static gboolean  use_slow_moves;
+static gboolean  disable_sounds;
+static gboolean  hide_toolbar;
+static gboolean  hide_timer;
 
+GtkWidget        *properties_dialog = NULL;
+GtkWidget        *filesave_dialog = NULL;
+GtkWidget        *fileopen_dialog = NULL;
+gboolean         fullscreen;
+gint             window_width;
+gint             window_height;
+gint             computer_level[2];
+gchar            *tile_set;
+gchar            *bg_color_name;
+gboolean         hide_final_results;
+gboolean         hide_valid_squares;
+gboolean         hide_last_move;
+guint            flip_pixmaps_id = 0;
+guint            flip_delay;
+
 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;
+extern GtkWidget *toolbar;
+extern GtkWidget *drawing_area;
+extern GtkWidget *timer_table;
+extern GdkColor  bg_color[];
+extern gint      kifu[MAX_MOVE_COUNT + 1][2];
+extern guint     flag;
+extern gboolean  ggz_network_mode;
+extern int       session_xpos;
+extern int       session_ypos;
 
-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;
 
-static GamesFileList *theme_file_list = NULL;
+void
+load_properties (void)
+{
+  fullscreen         = games_conf_get_boolean (NULL, keys[0],  NULL);
+  window_width       = games_conf_get_integer (NULL, keys[1],  NULL);
+  window_height      = games_conf_get_integer (NULL, keys[2],  NULL);
+  session_xpos       = games_conf_get_integer (NULL, keys[3],  NULL);
+  session_ypos       = games_conf_get_integer (NULL, keys[4],  NULL);
+  computer_level[0]  = games_conf_get_integer (NULL, keys[5], NULL);
+  computer_level[1]  = games_conf_get_integer (NULL, keys[6], NULL);
+  tile_set           = games_conf_get_string_with_default (NULL, keys[7],
+                        DEFAULT_TILESET);
+  bg_color_name      = games_conf_get_string_with_default (NULL, keys[8],
+                        DEFAULT_BGCOLOR);
+  use_slow_moves     = games_conf_get_boolean (NULL, keys[9],  NULL);
+  disable_sounds     = games_conf_get_boolean (NULL, keys[10], NULL);
+  hide_final_results = games_conf_get_boolean (NULL, keys[11], NULL);
+  hide_valid_squares = games_conf_get_boolean (NULL, keys[12], NULL);
+  hide_last_move     = games_conf_get_boolean (NULL, keys[13], NULL);
+  hide_toolbar       = games_conf_get_boolean (NULL, keys[14], NULL);
+  hide_timer         = games_conf_get_boolean (NULL, keys[15], NULL);
 
-static void apply_changes (void);
+  computer_level[0]  = clamp_int (computer_level[0], 0, 4);
+  computer_level[1]  = clamp_int (computer_level[1], 0, 4);
 
-/*
- * FIXME:
- *	It doesn't abide by the HIG.
- */
+  if (!window_width || !window_height) {
+    window_width  = WINDOW_W_DEFAULT;
+    window_height = WINDOW_H_DEFAULT;
+  }
+}
 
-static gint
-clamp_int (gint input, gint low, gint high)
+void
+save_properties (void)
 {
-  if (input < low)
-    input = low;
-  if (input > high)
-    input = high;
-
-  return input;
+  games_conf_set_boolean (NULL, keys[0],  fullscreen);
+  games_conf_set_integer (NULL, keys[1],  window_width);
+  games_conf_set_integer (NULL, keys[2],  window_height);
+  games_conf_set_integer (NULL, keys[3],  session_xpos);
+  games_conf_set_integer (NULL, keys[4],  session_ypos);
+  games_conf_set_integer (NULL, keys[5],  computer_level[0]);
+  games_conf_set_integer (NULL, keys[6],  computer_level[1]);
+  games_conf_set_string  (NULL, keys[7],  tile_set);
+  games_conf_set_string  (NULL, keys[8],  bg_color_name);
+  games_conf_set_boolean (NULL, keys[9],  use_slow_moves);
+  games_conf_set_boolean (NULL, keys[10], disable_sounds);
+  games_conf_set_boolean (NULL, keys[11], hide_final_results);
+  games_conf_set_boolean (NULL, keys[12], hide_valid_squares);
+  games_conf_set_boolean (NULL, keys[13], hide_last_move);
+  games_conf_set_boolean (NULL, keys[14], hide_toolbar);
+  games_conf_set_boolean (NULL, keys[15], hide_timer);
 }
 
 void
-load_properties (void)
+reset_properties (void)
 {
-  black_computer_level = games_conf_get_integer (NULL, KEY_BLACK_LEVEL, NULL);
-  black_computer_level = clamp_int (black_computer_level, 0, 3);
-
-  white_computer_level = games_conf_get_integer (NULL, KEY_WHITE_LEVEL, NULL);
-  white_computer_level = clamp_int (white_computer_level, 0, 3);
-
-  if (games_conf_get_boolean (NULL, KEY_QUICK_MOVES, NULL))
-    computer_speed = COMPUTER_MOVE_DELAY / 2;
-  else
-    computer_speed = COMPUTER_MOVE_DELAY;
-
-  if (tile_set)
-    g_free (tile_set);
-
-  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;
-  }
+  t_computer_level[0] = computer_level[0];
+  t_computer_level[1] = computer_level[1];
+  t_tile_set          = g_strdup (tile_set);
+  t_bg_color_name     = g_strdup (bg_color_name);
+  t_options[0]        = use_slow_moves;
+  t_options[1]        = disable_sounds;
+  t_options[2]        = hide_final_results;
+  t_options[3]        = hide_valid_squares;
+  t_options[4]        = hide_last_move;
+  t_options[5]        = hide_toolbar;
+  t_options[6]        = hide_timer;
+  gdk_color_parse (bg_color_name, &bg_color[2]);
+  gdk_colormap_alloc_color (gtk_widget_get_colormap (drawing_area),
+                            &bg_color[2], FALSE, TRUE);
 }
 
-static void
-reset_properties (void)
+void
+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);
+  flag = 0;
 
-  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;
+  use_slow_moves     = t_options[0];
+  disable_sounds     = t_options[1];
+  hide_final_results = t_options[2];
+  hide_valid_squares = t_options[3];
+  hide_last_move     = t_options[4];
+  hide_toolbar       = t_options[5];
+  hide_timer         = t_options[6];
 
-  t_quick_moves = games_conf_get_boolean (NULL, KEY_QUICK_MOVES, NULL);
+  flip_delay = PIXMAP_FLIP_DELAY * (use_slow_moves? 2:1);
+  if (flip_pixmaps_id)
+    g_source_remove (flip_pixmaps_id);
+  flip_pixmaps_id = g_timeout_add (flip_delay, flip_pixmaps, NULL);
+ 
+  games_sound_enable (!disable_sounds);
 
-  if (tile_set_tmp)
-    g_free (tile_set_tmp);
+  if (!hide_toolbar) 
+    gtk_widget_show (toolbar);
+  else 
+    gtk_widget_hide (toolbar);
 
-  tile_set_tmp = games_conf_get_string_with_default (NULL, KEY_TILESET, DEFAULT_TILESET);
+  if (!hide_timer)
+    gtk_widget_show (timer_table);
+  else
+    gtk_widget_hide (timer_table);
 
-  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 ();
+  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_set, t_tile_set )) {
+    g_free (tile_set);
+    tile_set = g_strdup (t_tile_set);
+    load_pixmaps ();
   }
-}
 
-static void
-sound_select (GtkWidget * widget, gpointer data)
-{
-  sound = GTK_TOGGLE_BUTTON (widget)->active;
-  apply_changes ();
+  check_game_over ();
+  flag |= 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 dialogs 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 ();
+  if (togglebutton->active) {
+    t_computer_level[GPOINTER_TO_INT (user_data) / 16] =
+                     GPOINTER_TO_INT (user_data) % 16;
+    stop_game ();
+    computer_level[0] = t_computer_level[0];
+    computer_level[1] = t_computer_level[1];
+    start_game ();
+  }
 }
 
 static void
-animate_stagger_select (GtkWidget * widget, gpointer data)
+on_options_toggled (GtkToggleButton *togglebutton, gpointer user_data)
 {
-  if (GTK_TOGGLE_BUTTON (widget)->active)
-    t_animate_stagger = 1;
-  else
-    t_animate_stagger = 0;
+  t_options[GPOINTER_TO_INT (user_data)] = togglebutton->active;
   apply_changes ();
 }
 
 static void
-grid_select (GtkWidget * widget, gpointer data)
+on_tile_set_box_changed (GtkComboBox *combobox, gpointer user_data)
 {
-  if (GTK_TOGGLE_BUTTON (widget)->active)
-    t_grid = 1;
-  else
-    t_grid = 0;
+  g_free (t_tile_set);
+  t_tile_set = gtk_combo_box_get_active_text (combobox);
   apply_changes ();
 }
 
 static void
-animate_select (GtkWidget * widget, gpointer data)
+on_color_button_color_set (GtkColorButton *colorbutton, gpointer user_data)
 {
-  if (GTK_TOGGLE_BUTTON (widget)->active) {
-    t_animate = GPOINTER_TO_INT (data);
-  }
+  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);
   apply_changes ();
 }
 
-static void
-save_properties (void)
-{
-  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);
-}
-
-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_ok_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 (properties_dialog);
+  properties_dialog = NULL;
 }
 
-void
-free_str (GtkWidget * widget, void *data)
-{
-  g_free (data);
-}
+/**** Properties dialog *****/
 
+static GamesFileList *theme_file_list = NULL;
+
 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);
+                                     GNOME_FILE_DOMAIN_APP_PIXMAP,
+                                     "iagno", FALSE, NULL);
 
   if (theme_file_list)
     g_object_unref (theme_file_list);
@@ -377,245 +278,339 @@
   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);
+  return games_file_list_create_widget (theme_file_list, t_tile_set, 0);
 }
 
 void
-show_properties_dialog (void)
+on_preferences_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 slow moves"),          /* 7 */
+     _("Disable _sounds"),          /* 8 */
+     _("Hide _final results"),      /* 9 */
+     _("Hide _valid squares"),      /* 10 */
+     _("Hide _last move mark"),	/* 11 */
+     _("_Hide toolbar"),            /* 12 */
+     _("Hide ti_mer")               /* 13 */
+   };
+
   GtkWidget *notebook;
-  GtkWidget *hbox;
+  GtkWidget *vbox, *vbox1;
   GtkWidget *label;
-  GtkWidget *label2;
   GtkWidget *table;
   GtkWidget *button;
   GtkWidget *frame;
-  GtkWidget *vbox, *vbox2;
-  GtkWidget *propbox = NULL;
+  GtkWidget *hbox;
   GtkWidget *option_menu;
-
-  if (propbox) {
-    gtk_window_present (GTK_WINDOW (propbox));
+  GtkWidget *color_button;
+  GSList    *human_group[2] = {NULL, NULL};
+  gint f, v;
+        
+  if (properties_dialog) {
+    gtk_window_present (GTK_WINDOW (properties_dialog));
     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);
+  properties_dialog = 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 (properties_dialog), FALSE);
+  gtk_container_set_border_width (GTK_CONTAINER (properties_dialog), 5);
+  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (properties_dialog)->vbox), 2);
+  gtk_window_set_resizable (GTK_WINDOW (properties_dialog), 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 (properties_dialog)->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);
-
+/*** 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));
+      gtk_widget_set_sensitive (button, !ggz_network_mode);
+    }
+  }
+/**** Use slow moves and Disable 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[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);
-
-  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);
+/*** Options ***/
+  for (v = 2; v < MAX_OPTIONS; 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[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);
+  option_menu = fill_menu ();
+  gtk_box_pack_start (GTK_BOX (hbox), option_menu, TRUE, TRUE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), option_menu);
+  g_signal_connect (G_OBJECT (option_menu), "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 (properties_dialog), "response",
+                    G_CALLBACK (on_ok_clicked), NULL);
+  g_signal_connect (G_OBJECT (properties_dialog), "delete_event",
+                    G_CALLBACK (on_ok_clicked), NULL);
+  gtk_widget_show_all (properties_dialog);
+}
 
-  frame = games_frame_new (_("Light"));
-  gtk_table_attach_defaults (GTK_TABLE (table), frame, 1, 2, 0, 1);
+/**** Write and read kifu ****/
 
-  vbox = gtk_vbox_new (FALSE, 6);
+static void
+write_kifu (int fd)
+{
+  gchar buf[9] = { 0, 0, 0x20, 0, 0x20, 0, 0, 0x0A, 0 };
+  guint i = 4;
+  ssize_t count;
 
-  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);
+  count = write (fd, _("iagno\n"), 6);
+  while (kifu[i][0] && count > 0) {
+    buf[0] = (gchar) ((i - 3) / 10 + 0x30);
+    buf[1] = (gchar) ((i - 3) % 10 + 0x30);
+    buf[3] = (kifu[i][0] == BLACK) ? 0x42 : 0x57;
+    buf[5] = (gchar) (kifu[i][1] % 10 + 0x40);
+    buf[6] = (gchar) (kifu[i++][1] / 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)),
-					    _("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);
+static gboolean
+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)),
-					    _("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);
+  read (fd, buf, 6);
+  buf[6] = 0;
+  if (!g_str_equal (buf, _("iagno\n"))) {
+    gui_message (N_("This file isn't a iagnos file!"));
+    return FALSE;
+  }
 
-  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);
+  while (read (fd, buf, 8) > 0) {
+    kifu[i][0] = (buf[3] == 0x42) ? BLACK : WHITE;
+    kifu[i++][1] = (gint) ((buf[6] - 0x30) * 10 + buf[5] - 0x40);
+  }
+  kifu[i][0] = 0;
+  return TRUE;
+}
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+/**** File save ****/
 
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
+static void
+on_save_clicked (GtkButton *button, gpointer user_data)
+{
+  int fd;
 
+  fd = creat (gtk_file_chooser_get_filename (
+                           GTK_FILE_CHOOSER (filesave_dialog)), 0644);
+  if (fd > 0) {
+    write_kifu (fd);
+    close (fd);
+  }
 
-  label = gtk_label_new (_("Appearance"));
+  return on_save_cancel_clicked (NULL, NULL);
+}
 
-  table = gtk_table_new (1, 2, FALSE);
-  gtk_table_set_col_spacings (GTK_TABLE (table), 18);
-  gtk_container_set_border_width (GTK_CONTAINER (table), 12);
+void
+on_save_cancel_clicked (GtkButton *button, gpointer user_data)
+{
+  gtk_widget_destroy (filesave_dialog);
+  filesave_dialog = NULL;
+  set_sensitive ();
+}
 
-  frame = games_frame_new (_("Animation"));
+void
+on_save_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  GtkWidget *dialog_vbox;
+  GtkWidget *dialog_action_area;
+  GtkWidget *save_cancel;
+  GtkWidget *save;
+  GDate *date;
+  gchar filename[17];
 
-  vbox = gtk_vbox_new (FALSE, 6);
+  if (filesave_dialog) {
+    gtk_window_present (GTK_WINDOW (filesave_dialog));
+    return;
+  }
 
-  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);
+  filesave_dialog =
+    gtk_file_chooser_dialog_new ("", (GtkWindow *) window,
+                                 GTK_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
+  gtk_window_set_type_hint (GTK_WINDOW (filesave_dialog),
+                            GDK_WINDOW_TYPE_HINT_DIALOG);
 
-  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);
+  stop_game ();
+  set_sensitive ();
 
-  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);
+  dialog_vbox = GTK_DIALOG (filesave_dialog)->vbox;
+  dialog_action_area = GTK_DIALOG (filesave_dialog)->action_area;
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area),
+                             GTK_BUTTONBOX_END);
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  save_cancel = gtk_button_new_from_stock ("gtk-cancel");
+  gtk_dialog_add_action_widget (GTK_DIALOG (filesave_dialog), save_cancel,
+                                GTK_RESPONSE_CANCEL);
+  GTK_WIDGET_SET_FLAGS (save_cancel, GTK_CAN_DEFAULT);
+  save = gtk_button_new_from_stock ("gtk-save");
+  gtk_dialog_add_action_widget (GTK_DIALOG (filesave_dialog), save,
+                                GTK_RESPONSE_OK);
+  GTK_WIDGET_SET_FLAGS (save, GTK_CAN_DEFAULT);
 
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
-  gtk_table_attach_defaults (GTK_TABLE (table), frame, 0, 1, 0, 1);
+  g_signal_connect ((gpointer) save_cancel, "clicked",
+                     G_CALLBACK (on_save_cancel_clicked), NULL);
+  g_signal_connect ((gpointer) save, "clicked",
+                     G_CALLBACK (on_save_clicked), NULL);
+  g_signal_connect ((gpointer) filesave_dialog, "delete_event",
+                     G_CALLBACK (on_save_cancel_clicked), NULL);
 
-  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);
+  gtk_widget_show_all (filesave_dialog);
+  gtk_widget_grab_default (save);
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  date = g_date_new ();
+  g_date_set_time_t (date, time (NULL));
+  g_date_strftime (filename, 17, _("%y%m%d%H"), date);
+  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filesave_dialog),
+					 filename);
+  g_date_free (date);
+}
 
-  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);
+/**** File open *******/
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+static void
+on_open_clicked (GtkButton *button, gpointer user_data)
+{
+  int 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);
+  fd = open (gtk_file_chooser_get_filename (
+                       GTK_FILE_CHOOSER (fileopen_dialog)), 0, 0644);
+  if (fd > 0) {
+    if (read_kifu (fd)) {
+      on_head_activate (NULL, NULL);
+      reset_timer ();
+    }
+    close (fd);
+  }
 
-  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  return on_open_cancel_clicked (NULL, NULL);
+}
 
-  hbox = gtk_hbox_new (FALSE, 12);
+void
+on_open_cancel_clicked (GtkButton *button, gpointer user_data)
+{
+  gtk_widget_destroy (fileopen_dialog);
+  fileopen_dialog = NULL;
+  set_sensitive ();
+}
 
-  label2 = gtk_label_new_with_mnemonic (_("_Tile set:"));
+void
+on_open_activate (GtkMenuItem *menuitem, gpointer user_data)
+{
+  GtkWidget *dialog_vbox;
+  GtkWidget *dialog_action_area;
+  GtkWidget *open_cancel;
+  GtkWidget *open;
 
-  gtk_box_pack_start (GTK_BOX (hbox), label2, FALSE, FALSE, 0);
+  if (fileopen_dialog) {
+    gtk_window_present (GTK_WINDOW (fileopen_dialog));
+    return;
+  }
 
-  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);
+  fileopen_dialog =
+    gtk_file_chooser_dialog_new ("", (GtkWindow *) window,
+                                 GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL);
+  gtk_window_set_type_hint (GTK_WINDOW (fileopen_dialog),
+                            GDK_WINDOW_TYPE_HINT_DIALOG);
 
-  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  stop_game ();
+  set_sensitive ();
 
-  gtk_table_attach_defaults (GTK_TABLE (table), frame, 1, 2, 0, 1);
+  dialog_vbox = GTK_DIALOG (fileopen_dialog)->vbox;
+  dialog_action_area = GTK_DIALOG (fileopen_dialog)->action_area;
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area),
+                             GTK_BUTTONBOX_END);
 
-  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label);
+  open_cancel = gtk_button_new_from_stock ("gtk-cancel");
+  gtk_dialog_add_action_widget (GTK_DIALOG (fileopen_dialog), open_cancel,
+                                GTK_RESPONSE_CANCEL);
+  GTK_WIDGET_SET_FLAGS (open_cancel, GTK_CAN_DEFAULT);
+  open = gtk_button_new_from_stock ("gtk-open");
+  gtk_dialog_add_action_widget (GTK_DIALOG (fileopen_dialog), open,
+                                GTK_RESPONSE_OK);
+  GTK_WIDGET_SET_FLAGS (open, GTK_CAN_DEFAULT);
 
-  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);
+  g_signal_connect ((gpointer) open_cancel, "clicked",
+                     G_CALLBACK (on_open_cancel_clicked), NULL);
+  g_signal_connect ((gpointer) open, "clicked",
+                     G_CALLBACK (on_open_clicked), NULL);
+  g_signal_connect ((gpointer) fileopen_dialog, "delete_event",
+                     G_CALLBACK (on_open_cancel_clicked), NULL);
 
-  gtk_widget_show_all (propbox);
+  gtk_widget_show_all (fileopen_dialog);
+  gtk_widget_grab_default (open);
 }
+
Index: gnobots2/help/es/gnobots2.xml
===================================================================
--- gnobots2/help/es/gnobots2.xml	(リビジョン 6541)
+++ gnobots2/help/es/gnobots2.xml	(作業コピー)
@@ -1,266 +1,406 @@
-<?xml version="1.0"?>
-<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
-  <!ENTITY legal SYSTEM "legal.xml">
-  <!ENTITY appversion "2.6">
-  <!ENTITY manrevision "2.6">
-  <!ENTITY date "Feb 2004">
-  <!ENTITY app "<application>Robots GNOME</application>">
-  <!ENTITY appname "Robots GNOME">
-  <!ENTITY version "2.6">
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY legal SYSTEM "legal.xml">
+<!ENTITY appversion "2.12">
+<!ENTITY manrevision "2.8">
+<!ENTITY date "September 2004">
+<!ENTITY app "<application>GNOME Robots</application>">
+<!ENTITY appname "GNOME Robots">
+<!ENTITY version "2.8.0">
 ]>
+<!-- 
+      (Do not remove this comment block.)
+  Maintained by the GNOME Documentation Project
+  http://developer.gnome.org/projects/gdp
+  Template version: 2.0 beta
+  Template last modified Feb 12, 2002
+-->
+<!-- =============Document Header ============================= -->
+<article id="index" lang="es"> 
+<!-- please do not change the id; for translations, change lang to -->
+<!-- appropriate code -->
+  <articleinfo>
+    <title>Manual de <application>Robots</application> V2.8</title>
+
+    <abstract role="description">
+      <para>Robots es un desarrollo del juego basado en texto robots que se puede encontrar en cierto número de sistemas UNIX.</para>
+    </abstract>
+
+      <copyright>
+        <year>2001</year>
+        <holder>Patanjali Somayaji, Mark Rae</holder>
+      </copyright><copyright><year>2007</year><holder>Jorge González (jorgegonz@svn.gnome.org)</holder></copyright>
+
+    <!-- translators: uncomment this:
+
+    <copyright>
+      <year>2000</year>
+      <holder>ME-THE-TRANSLATOR (Latin translation)</holder>
+    </copyright>
+
+    -->
+
+<!-- An address can be added to the publisher information.  If a role is 
+     not specified, the publisher/author is the same for all versions of the 
+     document.  -->
+    <publisher> 
+      <publishername>Proyecto de documentación de GNOME</publishername> 
+    </publisher> 
+
+     <legalnotice id="legalnotice">
+	<para>Se otorga permiso para copiar, distribuir y/o modificar este documento bajo los términos de la Licencia de Documentación Libre de GNU, Versión 1.1 o cualquier otra versión posterior publicada por la Free Software Foundation; sin Secciones Invariantes ni Textos de Cubierta Delantera ni Textos de Cubierta Trasera. Puede encontrar una copia de la licencia GFDL en este <ulink type="help" url="ghelp:fdl">enlace</ulink> o en el archivo COPYING-DOCS distribuido con este manual.</para>
+         <para>Este manual es parte de una colección de manuales de GNOME distribuido bajo la GFDL. Si quiere distribuir este manual por separado de la colección, puede hacerlo añadiendo una copia de la licencia al manual, tal como se describe en la sección 6 de la licencia.</para>
+
+	<para>Muchos de los nombres utilizados por las empresas para distinguir sus productos y servicios se consideran marcas comerciales. Cuando estos nombres aparezcan en la documentación de GNOME, y siempre que se haya informado a los miembros del Proyecto de documentación de GNOME de dichas marcas comerciales, los nombres aparecerán en mayúsculas o con las iniciales en mayúsculas.</para>
+
+	<para>ESTE DOCUMENTO Y LAS VERSIONES MODIFICADAS DEL MISMO SE PROPORCIONAN SEGÚN LAS CONDICIONES ESTABLECIDAS EN LA LICENCIA DE DOCUMENTACIÓN LIBRE DE GNU (GFDL) Y TENIENDO EN CUENTA QUE: <orderedlist>
+		<listitem>
+		  <para>EL DOCUMENTO SE PROPORCIONA "TAL CUAL", SIN GARANTÍA DE NINGÚN TIPO, NI EXPLÍCITA NI IMPLÍCITA INCLUYENDO, SIN LIMITACIÓN, GARANTÍA DE QUE EL DOCUMENTO O VERSIÓN MODIFICADA DE ÉSTE CAREZCA DE DEFECTOS COMERCIALES, SEA ADECUADO A UN FIN CONCRETO O INCUMPLA ALGUNA NORMATIVA. TODO EL RIESGO RELATIVO A LA CALIDAD, PRECISIÓN Y UTILIDAD DEL DOCUMENTO O SU VERSIÓN MODIFICADA RECAE EN USTED. SI CUALQUIER DOCUMENTO O VERSIÓN MODIFICADA DE AQUÉL RESULTARA DEFECTUOSO EN CUALQUIER ASPECTO, USTED (Y NO EL REDACTOR INICIAL, AUTOR O CONTRIBUYENTE) ASUMIRÁ LOS COSTES DE TODA REPARACIÓN, MANTENIMIENTO O CORRECCIÓN NECESARIOS. ESTA RENUNCIA DE GARANTÍA ES UNA PARTE ESENCIAL DE ESTA LICENCIA. NO SE AUTORIZA EL USO DE NINGÚN DOCUMENTO NI VERSIÓN MODIFICADA DE ÉSTE POR EL PRESENTE, SALVO DENTRO DEL CUMPLIMIENTO DE LA RENUNCIA;Y</para>
+		</listitem>
+		<listitem>
+		  <para>EN NINGUNA CIRCUNSTANCIA NI SEGÚN NINGÚN ARGUMENTO LEGAL, SEA POR MOTIVOS CULPOSOS (INCLUIDA LA NEGLIGENCIA), CONTRACTUALES O DE OTRO TIPO, NI EL AUTOR, NI EL REDACTOR INICIAL, NI CUALQUIER COLABORADOR, NI CUALQUIER DISTRIBUIDOR DEL DOCUMENTO O VERSIÓN MODIFICADA DEL MISMO, NI CUALQUIER PROVEEDOR DE CUALQUIERA DE DICHAS PARTES, SERÁN RESPONSABLES, ANTE NINGÚN TERCERO, DE NINGÚN DAÑO O PERJUICIO DIRECTO, INDIRECTO, ESPECIAL, INCIDENTAL O CONSIGUIENTE DE NINGÚN TIPO, INCLUIDOS, SIN LIMITACIÓN, LOS DAÑOS POR PÉRDIDA DE FONDO DE COMERCIO, INTERRUPCIÓN DEL TRABAJO, FALLO O MAL FUNCIONAMIENTO INFORMÁTICO, NI CUALQUIER OTRO DAÑO O PÉRDIDA DERIVADOS DEL USO DEL DOCUMENTO Y LAS VERSIONES MODIFICADAS DEL MISMO, O RELACIONADO CON ELLO, INCLUSO SI SE HABÍA COMUNICADO A AQUELLA PARTE LA POSIBILIDAD DE TALES DAÑOS.</para>
+		</listitem>
+	  </orderedlist></para>
+  </legalnotice>
+
+
+   <!-- This file  contains link to license for the documentation (GNU FDL), and 
+        other legal stuff such as "NO WARRANTY" statement. Please do not change 
+	any of this. -->
+
+    <authorgroup> 
+      <author role="maintainer"> 
+	<firstname>Patanjali</firstname> 
+	<surname>Somayaji</surname> 
+	<affiliation> 
+	  <address> <email>patanjali@mindless.com</email> </address> 
+	</affiliation> 
+      </author> 
+      <author> 
+	<firstname>Mark</firstname> 
+	<surname>Rae</surname> 
+	<affiliation> 
+	  <address> <email>m.rae@inpharmatica.co.uk</email> </address> 
+	</affiliation> 
+      </author> 
+<!-- This is appropriate place for other contributors: translators,
+      maintainers,  etc. Commented out by default.
+       <othercredit role="translator">
+	<firstname>Latin</firstname> 
+	<surname>Translator 1</surname> 
+	<affiliation> 
+	  <orgname>Latin Translation Team</orgname> 
+	  <address> <email>translator@gnome.org</email> </address> 
+	</affiliation>
+	<contrib>Latin translation</contrib>
+      </othercredit>
+-->
+    </authorgroup>
+
+    <revhistory>
+      <revision> 
+	<revnumber>Manual de Robots V2.8</revnumber> 
+	<date>Septiembre de 2004</date> 
+	<revdescription> 
+	  <para role="author">Patanjali Somayaji <email>patanjali@mindless.com</email></para>
+	  <para role="publisher">Proyecto de documentación de GNOME</para>
+	</revdescription> 
+      </revision> 
+      <revision> 
+	<revnumber>Título completo del manual anterior.</revnumber> 
+	<date>Fecha de lanzamiento del manual anterior.</date> 
+	<revdescription> 
+	  <para role="author">Mark Rae <email>m.rae@inpharmatica.co.uk</email></para>
+	  <para role="publisher">Proyecto de documentación de GNOME</para>
+	</revdescription> 
+      </revision> 
+    </revhistory> 
+
+    <releaseinfo>Este manual describe la versión 2.12 de Robots.</releaseinfo>
+    <!-- The following feedback information only applies to appliactions
+    listed in bugzilla.gnome.org and bugzilla.ximian.com. For other
+    applications, please provide your own feedback info or remove thsi
+    section altogether -->
+    <legalnotice> 
+      <title>Comentarios</title> 
+      <para>Para informar de un fallo, o hacer alguna sugerencia concerniente la aplicación <application>Robots</application> o este manual, siga las indicaciones en la <ulink url="ghelp:gnome-feedback" type="help">Página de comentarios de GNOME</ulink>.</para>
+<!-- Translators may also add here feedback address for translations -->
+    </legalnotice> 
+
+  </articleinfo>
+
+  <indexterm zone="index"> 
+    <primary>GNOME Robots</primary> 
+  </indexterm>
+
+   <!-- ============= Document Body ============================= -->
+
+   <!-- ============= Introduction ============================== -->
+   <sect1 id="intro">
+     <title>Introducción</title>
+
+     <para><application>Robots</application> es un juego donde tine que tratar de evitar una panda de robots merodeadores que, por alguna razón sin explicación, tratan de matarle. Está basado en el juego tipo texto robots que se puede encontrar en cierto número de sistemas UNIX.</para>
+     <para>Esta nueva versión incluye dos tipos de robots, chatarra móvil, múltiples configuraciones para el juego, disposiciones de teclado definibles por el usuario y sonidos, así como todas las características que estaban disponibles en el juego Robots original.</para>
+
+     <para>Para ejecutar <application>Robots</application>, seleccione <menuchoice><guisubmenu>Juegos</guisubmenu><guimenuitem>Robots</guimenuitem></menuchoice> del <guimenu>Menú principal</guimenu>, o escriba <command>gnobots2</command> en la línea de comandos.</para>
+
+     <para><application>Robots</application> está incluido en el paquete gnome-games, que es parte del entorno de escritorio GNOME. Este documento describe la versión 2.8.0 de <application>Robots</application>.</para>
+   </sect1>
  
-<article id="index" lang="es">
+   <sect1 id="objective">
+     <title>Objetivo de Robots</title>
+     <para>El objetivo de Robots es bastanet simple. Está rodeado por un número de robots u otros adversarios hostiles. Conforme se va moviendo ellos tratarán de moverse hacia su posición con cada movimiento que haga. Su objetivo es matarle. Mientras que debe tratar de matar a todos los robots en el tablero tomando ventaja de sus vulnerabilidades.</para>
+   
+     <para>Los robots se destruyen cuando chocan entre ellos o cuando chocan contra basura de una colisión previa. Morirá si un robot acaba posicionandose a su lado.</para>
+
+     <para>En algunas de las configuraciones del juego (puede elegir entre cinco configuraciones distintas de reglas) puede empujar la basura alrededor para montar barricadas para protegerse. Además, si es suficientemente valiente, puede matar (¡Splat!) los robots empujando basura sobre ellos, y así obtener puntos adicionales.</para>
+     <para>También puede salvarse teletransportándose a una ubicación aleatoria. Desafortunadamente, teletransportarse a una ubicación aleatoria significa que puede acabar junto a un robot, así que le matarán cuando les toque mover. Afortunadamente, también existen teletransportes seguros que le transportarán fuera del peligro inmediato, pero sólo dispone de una cantidad limitada. Puede obtener más teletransportes a medida que avanza en el juego (cómo los obtiene depende del juego elegido), pero generalmente obtiene uno por cada robot que se destruye mientras «espera», hasta un máximo de 10. Si no quiere gastar sus teletransportes seguros, puede elegir teletransportarse al azar si cree que es suficientemente seguro.</para>
+   
+     <para>Si pulsa el botón «Esperar» (ver debajo) no podrá moverse hasta que todos los robots (que aún se mueven a su alrededor) se hayan ido, o muera. Hacer esto es peligroso, pero puede que gane teletransportesseguros con ello.</para>
+   
+     <para>Si consigue llegar a un punto en el que la mitad de la pantalla esté ocupada por robots, el número de robots se reiniciará a la cantidad inicial, permitiéndole continuar.</para>
+  </sect1>
+
+
+  <!-- ================ Usage ================================ -->
+  <!-- This section should describe basic usage of the application. -->
+
+  <sect1 id="usage">
+    <title>Usar Robots</title>
+    <para><application>Robots</application> es extremadamente simple de jugar. Puede usar tanto el ratón como el teclado. Esta sección describe el uso báisco de <application>Robots</application>.</para>
+
+    <!-- ========= Basic Usage =========================== -->
+    <sect2 id="mainwin">
+      <title>Uso básico</title>
+      <para>Al iniciar <application>Robots</application> se abrirá la <interface>Ventana principal</interface>, mostrada en <xref linkend="mainwindow-fig"/>. <figure id="mainwindow-fig">
+	  <title>Ventana principal de Robots</title>
+	  <screenshot>
+	  <mediaobject> 
+ 	   <imageobject>
+ 	 <imagedata fileref="figures/gnobots2-main.png" format="PNG" srccredit="Patanjali"/>
+ 	   </imageobject>
+ 	   <textobject> 
+ 	     <phrase>Ventana principal de Robots.</phrase> 
+ 	   </textobject> 
+ 	 </mediaobject>
+	  </screenshot>
+	</figure></para> 
+
+      <para>Para iniciar una nueva partida, pulse <guimenuitem>Nuevo</guimenuitem> en el menú <guimenu>Juego</guimenu>.</para>
+
+      <para>Para moverse, pulse en la dirección a la que quiere desplazarse (el cursor le mostrará en qué dirección se mueve) o pulse la tecla apropiada en el teclado. Pulsando sobre el hombrecillo permanecerá quieto. Para teletransportarse (de forma segura o insegura) y para esperar, use los botones en la barra de herramientas.</para>
+    </sect2>
+  </sect1>
+    
+
   
- <articleinfo>
-   <title>Documentación de GNOME Robots</title>
+  <!-- ========= Menus =========================== --> 
+  
+   <sect1 id="menubar">
+    <title>Menús</title>
+    <para>La barra de menú, ubicada en la parte superior del <interface>tablero de juego</interface>, contiene los siguientes elementos:</para>
+
+
+    <variablelist>
+      <varlistentry>
+        <term><guimenu>Juego</guimenu></term>
+        <listitem>
+        <para>Este menú contiene tres elementos: <itemizedlist>	
+            <listitem>
+	    <para><menuchoice><shortcut><keysym>Ctrl-N</keysym></shortcut><guimenuitem>Nuevo</guimenuitem></menuchoice>: inicia una nueva partida de Robots.</para>
+            </listitem>     
+       
+	    <listitem>
+	    <para><menuchoice><guimenuitem>Puntuación</guimenuitem></menuchoice>: muestra las puntuaciones.</para>
+            </listitem>
+
+       	    <listitem>
+            <para>
+              <menuchoice>
+              <shortcut><keysym>Ctrl-Q</keysym></shortcut>
+              <guimenuitem>Salir</guimenuitem>
+              </menuchoice>
+            </para>
+            </listitem>
+          </itemizedlist></para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><guimenu>Configuración</guimenu></term>
+	<listitem>
+	<para>El menú <guimenu>Ajustes</guimenu> contiene un solo elemento: <itemizedlist>
+	    <listitem>
+	    <para><guimenuitem>Preferencias</guimenuitem> muestra el diálogo de preferencias.</para>
+	    </listitem>
+	  </itemizedlist></para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><guimenu>Ayuda</guimenu></term>
+        <listitem>
+        <para>Este menú contiene: <itemizedlist>
+          <listitem>
+            <para><guimenuitem>Contenido</guimenuitem>: muestra este manual.</para>
+          </listitem>
+          <listitem>
+          <para><guimenuitem>Acerca de</guimenuitem>: muestra información básica acerca de <application>Robots</application>, tal como los nombres de los autores y el número de versión de la aplicación.</para>
+          </listitem>
+        </itemizedlist></para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </sect1>
  
-   <copyright>
-     <year>1999</year>
-     <holder>Mark Rae</holder>
-   </copyright>
+ <!-- =========Using the Keyboard============== -->
  
-   <copyright>
-     <year>1999</year>
-     <holder>Joaquín Cuenca Abela</holder>
-   </copyright>
-   <publisher>
-     <publishername>GNOME Documentation Project </publishername>
-   </publisher>
-   &legal;
-                                                                                
-   <revhistory>
-     <revision>
-       <revnumber>&appname; Manual V&manrevision;</revnumber>
-       <date>&date;</date>
-       <revdescription>
-         <para>Converted from the original HTML by Callum McKenzie, who doesn't speak Spanish.</para>
-       </revdescription>
-     </revision>
-   </revhistory>
-                                                                                
-   <releaseinfo>This manual describes version &appversion; of &appname;.
-   </releaseinfo>
-   <legalnotice>
-      <title>Feedback</title>
-      <para>To report a bug or make a suggestion regarding this game or
-      this manual, follow the directions in the <ulink
-      url="ghelp:gnome-feedback" type="help">GNOME Feedback Page</ulink>.
-      </para>
-    </legalnotice>
-  </articleinfo>
-                                                                                  <indexterm zone="index">
-    <primary>GNOME Robots</primary>
-  </indexterm>
+  
+  <sect1 id="keyboard">
+    <title>Usar el teclado</title>
+    <para>Existen tres juegos de teclas predefinidos para controlar a su jugador. Puede seleccionar cuál quiere usar en la solapa <guimenuitem>Teclado</guimenuitem> del diágolo <guimenuitem>Preferencias</guimenuitem>.</para>
 
-<sect1 id="introduction">
-  <title>Introducción</title>
+      <sect2 id="set3-keys">     
+      <title>El teclado numérico</title>
+      <para>Cuando seleccione este juego, usará el teclado numérico en la parte derecha del teclado (no son las teclas de flechas separadas). <note>
+        <title>Active la tecla BloqNum</title>
+          <para>Puede que necesite activar BloqNum para que esto funcione.</para>
+        </note><orderedlist>
+          <listitem><para>Arriba izquierda: <keycap>7</keycap></para></listitem> 
+          <listitem><para>Arriba: <keycap>8</keycap></para></listitem>
+          <listitem><para>Arriba derecha: <keycap>9</keycap></para></listitem>
+          <listitem><para>Izquierda: <keycap>4</keycap></para></listitem>
+          <listitem><para>Permanecer quieto: <keycap>5</keycap></para></listitem>
+          <listitem><para>Derecha: <keycap>6</keycap></para></listitem>
+          <listitem><para>Abajo izquierda: <keycap>1</keycap></para></listitem>
+          <listitem><para>Abajo: <keycap>2</keycap></para></listitem>
+          <listitem><para>Abajo derecha: <keycap>3</keycap></para></listitem>
+          <listitem><para>Teleportar: <keycap>+</keycap></para></listitem>
+          <listitem><para>Teleportar al azar: <keycap>-</keycap></para></listitem>
+          <listitem><para>Esperar: <keycap>Return</keycap></para></listitem>
+        </orderedlist></para>	  
+    </sect2>
+
+  <sect2 id="set2-keys">	
+      <title>Teclas para la mano izquierda</title>
+      <para>Estas teclas están en la parte izquierda del teclado.</para>
+    <orderedlist>
+          <listitem><para>Arriba izquierda: <keycap>Q</keycap></para></listitem> 
+          <listitem><para>Arriba: <keycap>W</keycap></para></listitem>
+          <listitem><para>Arriba derecha: <keycap>E</keycap></para></listitem>
+          <listitem><para>Izquierda: <keycap>A</keycap></para></listitem>
+          <listitem><para>Permanecer quieto: <keycap>S</keycap></para></listitem>
+          <listitem><para>Derecha: <keycap>D</keycap></para></listitem>
+          <listitem><para>Abajo izquierda: <keycap>Z</keycap></para></listitem>
+          <listitem><para>Abajo: <keycap>X</keycap></para></listitem>
+          <listitem><para>Abajo derecha: <keycap>C</keycap></para></listitem>
+          <listitem><para>Teleportar: <keycap>T</keycap></para></listitem>
+          <listitem><para>Teleportar al azar: <keycap>R</keycap></para></listitem>
+          <listitem><para>Esperar: <keycap>Return</keycap></para></listitem>
+        </orderedlist>
+
+
+
+
+      </sect2>
+
+    <sect2 id="standard-keys">
+
+    <title>Teclas originales</title>
+    
+    <para>Estas teclas son los controles usados en el juego Robots original. Serán familiares a personas que hayan jugado a las versiones antiguas basadas en texto.</para>
+        <orderedlist>
+          <listitem>
+	  <para>Arriba izquierda: <keycap>Y</keycap></para>
+          </listitem> 
+          <listitem><para>Arriba: <keycap>K</keycap></para></listitem>
+          <listitem><para>Arriba derecha: <keycap>U</keycap></para></listitem>
+          <listitem><para>Izquierda: <keycap>H</keycap></para></listitem>
+          <listitem><para>Permanecer quieto: <keycap>.</keycap> o <keycap>espacio</keycap></para></listitem>
+          <listitem><para>Derecha: <keycap>L</keycap></para></listitem>
+          <listitem><para>Abajo izquierda: <keycap>B</keycap></para></listitem>
+          <listitem><para>Abajo: <keycap>J</keycap></para></listitem>
+          <listitem><para>Abajo derecha: <keycap>N</keycap></para></listitem>
+          <listitem><para>Teleportar: <keycap>T</keycap></para></listitem>
+          <listitem><para>Teleportar al azar: <keycap>R</keycap></para></listitem>
+          <listitem><para>Esperar: <keycap>W</keycap></para></listitem>
+        </orderedlist>
+  </sect2>
+      
+  </sect1>
+   
+  <!-- ============= Customization ============================= -->
   
-  <para>
-Gnome Robots es una versión del juego de texto robots que puede encontrar
-en muchos sistemas UNIX, y que viene con el paquete juegos BSD en los
-sistemas Linux.
-  </para>
-  <para>
-Esta nueva versión incluye dos tipos distintos de robots, montones
-de basura móviles, diferentes configuraciones, la posibilidad de
-redefinir las teclas que se utilizan para jugar, sonido mediante ESD
-(si lo tiene), y el resto de características presentes en el juego
-Gnome Robots original.
-  </para>
-</sect1>
+  <sect1 id="customization">
+    <title>Personalizar Robots</title>
+    <para>Puede modificar el comportamiento y apariencia del juego seleccionando <guimenuitem>Preferencias</guimenuitem> bajo el menú <guimenu>Ajustes</guimenu>. Se mostrará un diálogo con tres solapas: <itemizedlist>
+        <listitem>
+        <para><guimenuitem>Juego</guimenuitem>: Esta página le permite elegir el tipo de partida que quiere jugar. La lista desplegable en la parte superior de la página le permite elegir de un número de juegos predefinidos, y la lista debajo muestra los ajustes para ese juego. No puede cambiar esos ajustes durante una partida, de tal forma que durante la partida se desactivarán. También existen varias opciones en la parte inferior del diálogo: <orderedlist>
+          <listitem><para>La opción «Usar movimientos seguros» le ayudará a evitar morir por error. Si intenta realizar un movimiento que le lleva a la muerte cuando existe un movimiento seguro disponible, no se le permitirá realizarlo. Pero sea consciente: si no había otro movimiento seguro disponible, a parte del teletransporte, sí que se le permitirá realizar el movimiento.</para></listitem>
+          <listitem><para>También existe la opción «Usar movimientos superseguros». Si selecciona esto, una alarma sonora se activará cuando no haya movimientos seguros y su única opción sea teletransportarse.</para></listitem>
+          <listitem><para>Si seleccione la casilla «Activar sonidos» el juego reproducirá sonidos para los diversos eventos durante la partida.</para></listitem>
+          <listitem><para>La casilla «Aplastes» indica si quiere que se reproduzca un sonido y que aparezca una pequeño «¡Splat!» en la pantalla.</para></listitem>
+        </orderedlist></para>
+	</listitem>
+        <listitem>
+        <para><guimenuitem>Gráficos</guimenuitem>: Esta página le permite seleccionar los gráficos a usar durante el juego desde la lista desplegable. Desde esta solapa también puede seleccionar el color del fondo.</para>
+        </listitem>
 
-<sect1 id="play">
-  <title>Jugando</title>
-  <para>
-Cuando empiece el juego se encontrará rodeado por robots o por algún
-extraño (pero igualmente agresivo) adversario si ha escogido algún
-escenario diferente al que viene por defecto.
-Conforme se vaya desplazando, los robots se moverán directamente
-hacia usted con un objetivo en mente - matarle. Por si fuese poco, hay
-dos tipos diferentes de robots, ¡y uno de ellos puede ir el doble de
-rápido que usted!
-Afortunadamente tiene varias formas de evitar el desafortunado desenlace.
-  </para>
-  <para>
-Primero, los robots no han sido dotados con una gran cantidad de
-inteligencia, y se destruirán si chocan entre sí o si chocan con
-los desperdicios que hayan quedado de alguna antigua colisión.
-Segundo, si se encuentra en una encerrona, puede teletransportarse
-a un lugar aleatorio de la pantalla.
-Además, si está permitido en la configuración del juego que haya
-elegido, podrá empujar los montones de basura y así hacer una
-barricada que le proteja. Si es lo bastante atrevido puede incluso
-llegar a aplastar a los robots empujando un montón de basura encima de
-ellos, obteniendo así un bonus adicional. 
-  </para>
-  <para>
-Desafortunadamente, cuando hemos dicho teletransporte aleatorio
-queremos decir que hay
-una cierta probabilidad de acabar justo al lado de un robot que acabará
-con usted cuando haga su próximo movimiento. ¡Pero todavía no está
-todo perdido!, ya que tiene una cierta cantidad de teletransportes seguros
-que le llevarán fuera del peligro inmediato. Puede ganar más teletransportes
-seguros conforme transcurre la partida, obteniendo uno por cada robot
-que se destruye mientras usted está `esperando', con un máximo de 10. Si
-no quiere gastar sus teletransportes seguros, puede elegir un teletransporte
-aleatorio si cree que es lo bastante seguro.
-Puede quitar la opción de los teletransportes seguros para hacer que el
-juego sea igual al clásico robots.
-  </para>
-  <para>
-Si presiona la tecla `Esperar' (ver más abajo) ya no será capaz de
-moverse hasta que todos los robots, que van hacia usted se hayan movido
-o hasta que haya sido asesinado. Si hace ésto también tiene la posibilidad
-de ganar teletransportes seguros adicionales, tal y como se ha descrito
-anteriormente.
-  </para>
-  <para>
-Si consigue llegar hasta un momento en el que más de la mitad de la
-pantalla está ocupada por robots, se volverá al número de robots inicial,
-permitiéndole continuar.
-  </para>
-</sect1>
+        <listitem>
+        
+        <para><guimenuitem>Teclado</guimenuitem>: Esta pantalla le permite definir sus propios controles de teclado. Los tres juegos de teclas predefinidos en la parte inferior se describieron en la sección anterior. Para seleccionar una tecla diferente para un comando, pulse en el botón para ese comando y después pulse la tecla que quiere usar.</para>
+        </listitem>
+      </itemizedlist></para>
 
-<sect1 id="kbd">
-<title>Teclas</title>
-  <para>
-Hay tres conjuntos de teclas predefinidas para controlar a su jugador -
-  </para>
-<sect2>
-<title>Estándar</title>
-<para>
-Las que vienen a continuación son las teclas estándar que hay para jugar
-en cualquier versión de robot.
-</para>
+    <para>Cualquier cambio que haga toma efecto inmediatamente y se guarda de forma automática.</para>
 
-<programlisting>
-Arriba Izquierda: Y             Arriba: K           Arriba Derecha: U
-       Izquierda: H  Mantener Posición: . o Espacio        Derecha: L
- Abajo Izquierda: B              Abajo: J            Abajo Derecha: N
+    <para>Si lo desea, puede diseñar sus propios gráficos para el juego. Los archivos de gráficos están en <filename class="directory"> $PREFIX/share/pixmaps/gnobots2 </filename>, donde $PREFIX es el prefijo bajo el que GNOME está instalado. Generalmente esto es <filename class="directory">/usr</filename> o <filename class="directory">/usr/local</filename>.</para>
+    <para>Cada carácter es de 16x16 píxeles y existen 14 de ellos almacenados en un archivo PNG de un tamaño de 224x16 píxeles. Puede mirar a los archivos ya existentes para ver el orden en el que deben de situarse para producir las secuencias de animación adecuadas.</para>
+    <para>Cualquier archivo de gráficos que sea ubicado en el directorio se autodetectará, de tal forma que no necesita alterar ningún archivo de configuración. También puede definir su propia configuración de juego creando archivos <filename> .cfg </filename> adicionales que se deberán almacenar en el directorio <filename class="directory">$PREFIX/share/gnobots2</filename>.</para>
+  </sect1> 
+ 
+  <!-- ============= Various Sections ============================= -->
+ 
+ 
+  <!-- ============= Bugs ================================== -->
+  <!-- This section should describe known bugs and limitations of
+      the program if there are any - please be frank and list all
+      problems you know of. -->
+  <sect1 id="bugs">
+    <title>Errores conocidos y limitaciones</title>
+    <para>Esta aplicación no tiene errores conocidos.</para>
+  </sect1>
 
-           Teletransporte: T
- Teletransporte aleatorio: R
-                  Esperar: W
-</programlisting>
-</sect2>
 
-<sect2>
-<title>Primer conjunto de teclas</title>
-<para>
-Estas teclas están en la parte principal del teclado y su disposición
-es en forma de estrella. Para los que no les gusten las teclas HJKL.
-</para>
+<!-- ============= Authors ================================ -->
 
-<programlisting>
-Arriba Izquierda: Q             Arriba: W  Arriba Derecha: E
-       Izquierda: A  Mantener Posición: S         Derecha: D
- Abajo Izquierda: Z              Abajo: X   Abajo Derecha: C
+  <sect1 id="authors">
+    <title>Autores</title>
+    <para>Mark Rae (<email>m.rae@inpharmatica.co.uk</email>) escribió <application>Robots</application>. Patanjali Somayaji (<email>patanjali@mindless.com</email>) escribió este manual desde la documentación original en HTML de Mark Rae. Para informar de un fallo, o hacer alguna sugerencia concerniente esta aplicación o este manual, siga las indicaciones en este <ulink url="http://bugzilla.gnome.org">documento</ulink>.</para>
 
-           Teletransporte: T
- Teletransporte aleatorio: R
-                  Esperar: Enter
-</programlisting>
-</sect2>
+    <!-- For translations: uncomment this:
 
-<sect2>
-<title>Segundo conjunto de teclas - teclado numérico</title>
-<para>
-Tiene que activar la tecla de Bloque Numérico para que estas teclas
-funcionen.
-</para>
+    <para>
+      Latin translation was done by ME
+      (<email>MYNAME@MYADDRESS</email>). Please send all  comments  and
+      suggestions regarding this translation to SOMEWHERE.
+    </para>
 
-<programlisting>
-Arriba Izquierda: 7             Arriba: 8  Arriba Derecha: 9
-       Izquierda: 4  Mantener Posición: 5         Derecha: 6
- Abajo Izquierda: 1              Abajo: 2   Abajo Derecha: 3
+    -->
 
-           Teletransporte: +
- Teletransporte aleatorio: -
-                  Esperar: Enter
-</programlisting>
-</sect2>
-<sect2>
-  <title>Defina su propio conjunto de teclas</title>
-<para>
-Por supuesto, si no le gusta ninguna de las combinaciones anteriores,
-puede definir su propio conjunto de teclas. Seleccione la caja que hay
-para el movimiento sobre el que quiere actuar y presione la tecla que
-quiere asignarle a ese movimiento. En ese momento debe aparecer en la
-caja la representación mediante texto de la tecla elegida.
-</para>
-</sect2>
-</sect1>
+  </sect1>
 
-<sect1 id="preferences">
-<title>Preferencias</title>
-<para>
-El cuadro de diálogo preferencias le permite moficicar el comportamiento
-y la apariencia del juego.
-</para>
 
-<sect2>
-<title>Configuración</title>
-<para>
-Esta página le permite elegir el tipo de juego al que quiere jugar. La
-lista que encontrará en lo alto de la página le permitirá elegir un
-juego de entre los predefinidos, y la lista de abajo le mostrará las
-características del juego elegido.</para><para>
-La opción de modo salvación evitará que muera debido a un error. Se
-le impedirá el movimiento si intenta ir a un lugar en el que moriría
-mientras todavía queden sitios en los que pueda salvarse. Además se le
-avisará si no queda ningún sitio en el que pueda salvar (excepto
-usando el teletransporte), y en este caso se le permitirá el movimiento.
-</para><para>
-Si selecciona el botón del sonido se reproducirán distintos sonidos
-para los diferentes eventos que se den en el juego. Si no tiene ESD
-instalado el juego utiliará el altavoz del PC cuando haya un
-movimiento no válido.
-</para><para>
-El botón `Splats' permite seleccionar si quiere que se reproduzca un
-sonido y que aparezca un pequeño `¡Splat!' en la pantalla.
-</para>
-</sect2>
-<sect2>
-<title>Gráficos</title>
-<para>Puede seleccionar que gráficos quiere utilizar en el juego de entre
-aquellos disponibles en la lista. Podrá ver una vista previa de los
-gráficos un poco más abajo del lugar que ocupa la lista.</para>
-</sect2>
-<sect2>
-<title>Teclado</title>
-<para>
-Esta pantalla le permite definir sus propios controles tal y como se
-describe en la sección <link linkend="kbd">Teclas</link>.
-</para>
-</sect2>
-</sect1>
+  <!-- ============= Application License ============================= -->
 
-<sect1 id="misc">
-<title>Miscelánea</title>
-<para>
-Si quiere puede diseñar sus propios gráficos para el juego. Los ficheros
-gráficos se encuentran en
-<filename class="directory">$PREFIX/share/pixmaps/gnobots2</filename>, donde <filename class="directory">$PREFIX</filename> depende de
-donde esté instalado GNOME, normalmente <filename class="directory">/usr</filename> o <filename class="directory">/usr/local</filename>.
-Cada personaje tiene 16x16 pixeles, y hay 14 de ellos alineados
-en un fichero PNG que tiene 224x16 pixeles de tamaño. Puede mirar los
-ficheros ya existentes para ver el orden en el que debén alinearse
-para producir la secuencia animada correcta.
-Se autodetectará cualquier fichero gráfico que haya en el directorio
-por lo que no tiene que modificar ningún fichero de configuración.
-</para>
-<para>También puede definir su propia configuración creando ficheros
-.cfg adicionales y guardándolos en el directorio
-<filename class="directory">$PREFIX/share/gnobots2</filename>.
-</para>
-<para>
-Si tiene cualquier sugerencia o descubre cualquier BUG, puede enviarme
-un correo-e a <email>m.rae@inpharmatica.co.uk</email>
-(en inglés).
-</para>
+  <sect1 id="license">
+    <title>Licencia</title>
+    <para>Este programa es software libre; puede redistribuirlo y/o modificarlo bajo los términos de la <ulink type="help" url="gnome-help:gpl"><citetitle>Licencia Pública General GNU</citetitle></ulink> tal como se publica por la Free Software Foundation; ya sea la versión 2 de la Licencia, o (a su elección) cualquier versión posterior.</para>
+    <para>Este programa se distribuye con la esperanza de que le sea útil, pero SIN NINGUNA GARANTÍA; sin incluso la garantía implícita de MERCANTILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Vea la <citetitle>Licencia Pública General GNU</citetitle> para más detalles.</para>
+    <para>Una copia de la <citetitle>Licencia Pública General GNU</citetitle> está incluida en el apéndice de la <citetitle>Guía de Usuario de GNOME</citetitle>. También puede obtener una copia de la <citetitle>Licencia Pública General GNU</citetitle> de la Free Software Foundation visitando <ulink url="http://www.fsf.org" type="http">su página web</ulink> o escribiendo a la Free Software Foundation, Inc. <street>59 Temple Place</street> - Suite 330 <city>Boston</city>, <state>MA</state><postcode>02111-1307</postcode><country>USA</country></para>
+  </sect1>
 
-<para>Si tiene cualquier sugerencia o comentario sobre la traducción, puede
-enviar un correo-e a <email>e98cuenc@criens.u-psud.fr</email>.</para>
-</sect1>
+
+ 
+
 </article>
