[iagno] Analyse the game at the end of turn.
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [iagno] Analyse the game at the end of turn.
- Date: Wed, 1 Oct 2014 15:01:54 +0000 (UTC)
commit b066c3db7abefaa417b8a51293ded3c15ffff96c
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date: Tue Sep 30 23:22:30 2014 +0200
Analyse the game at the end of turn.
https://bugzilla.gnome.org/show_bug.cgi?id=737410
src/computer-player.vala | 57 +++++++++++++++++++-----------------
src/game-view.vala | 4 +-
src/game.vala | 72 +++++++++++++++++++++++++---------------------
src/iagno.vala | 65 +++++++++++++++++++++++------------------
src/test-iagno.vala | 6 ++--
5 files changed, 111 insertions(+), 93 deletions(-)
---
diff --git a/src/computer-player.vala b/src/computer-player.vala
index 4b18459..871c312 100644
--- a/src/computer-player.vala
+++ b/src/computer-player.vala
@@ -160,7 +160,7 @@ public class ComputerPlayer : Object
}
private void run_search (ref int x, ref int y)
- requires (game.can_move (game.current_color))
+ requires (game.current_player_can_move)
{
/* For the first two moves play randomly so the game is not always the same */
if (game.n_tiles < 8)
@@ -180,46 +180,40 @@ public class ComputerPlayer : Object
requires (a <= b)
{
/* End of the game, return a near-infinite evaluation */
- if (g.is_complete ())
+ if (g.is_complete)
{
var n_current_tiles = g.n_current_tiles;
var n_enemy_tiles = g.n_opponent_tiles;
return n_current_tiles > n_enemy_tiles ? POSITIVE_INFINITY - n_enemy_tiles : NEGATIVE_INFINITY +
n_current_tiles;
}
- /* End of the search, calculate how good a result this is.
- * Checking move_pending here is optional. It helps avoid a long unnecessary search
+ /* Checking move_pending here is optional. It helps avoid a long unnecessary search
* if the move has been cancelled, but is expensive because it requires taking a mutex. */
- if (depth == 0 || !move_pending)
+ if (!move_pending)
+ return 0;
+
+ /* End of the search, calculate how good a result this is. */
+ if (depth == 0)
return calculate_heuristic (g);
- /* Find all possible moves and sort from most new tiles to least new tiles */
List<PossibleMove?> moves = null;
- for (var x = 0; x < g.size; x++)
+ if (g.current_player_can_move)
{
- for (var y = 0; y < g.size; y++)
+ /* Find all possible moves and sort from most new tiles to least new tiles */
+ for (var x = 0; x < g.size; x++)
{
- var n_tiles = g.place_tile (x, y);
- if (n_tiles <= 0)
- continue;
-
- var move = PossibleMove (x, y, n_tiles);
- moves.insert_sorted (move, compare_move);
- g.undo ();
+ for (var y = 0; y < g.size; y++)
+ {
+ var n_tiles = g.place_tile (x, y);
+ if (n_tiles <= 0)
+ continue;
+
+ var move = PossibleMove (x, y, n_tiles);
+ moves.insert_sorted (move, compare_move);
+ g.undo ();
+ }
}
- }
- if (moves == null)
- {
- /* The move.ntiles = 0 is used next to know we have to pass.
- * The move.x = move.y = 0 is never used: move.x, move.y, move_x & move_y
- * are only used at first iteration… and the game passes if there’s no move.
- */
- var move = PossibleMove (0, 0, 0);
- moves.append (move);
- }
- else
- {
/* We use (0, 0) as our default move; if we don't change that,
* a search could select it even if invalid at the end of the game.
*/
@@ -227,6 +221,15 @@ public class ComputerPlayer : Object
move_x = move.x;
move_y = move.y;
}
+ else
+ {
+ /* The move.ntiles = 0 is used next to know we have to pass.
+ * The move.x = move.y = 0 is never used: move.x, move.y, move_x & move_y
+ * are only used at first iteration… and the game passes if there's no move.
+ */
+ var move = PossibleMove (0, 0, 0);
+ moves.append (move);
+ }
/* Try each move using alpha-beta pruning to optimise finding the best branch */
foreach (var move in moves)
diff --git a/src/game-view.vala b/src/game-view.vala
index d863ae1..3eb5bfd 100644
--- a/src/game-view.vala
+++ b/src/game-view.vala
@@ -188,7 +188,7 @@ public class GameView : Gtk.DrawingArea
var pixmap = get_pixmap (game.get_owner (x, y));
/* Show the result by laying the tiles with winning color first */
- if (flip_final_result_now && game.is_complete ())
+ if (flip_final_result_now && game.is_complete)
{
var n = y * game.size + x;
var winning_color = Player.LIGHT;
@@ -218,7 +218,7 @@ public class GameView : Gtk.DrawingArea
set_square (x, y, pixmap);
- if (game.is_complete () && game.n_light_tiles > 0 && game.n_dark_tiles > 0)
+ if (game.is_complete && game.n_light_tiles > 0 && game.n_dark_tiles > 0)
{
/*
* Show the actual final positions of the pieces before flipping the board.
diff --git a/src/game.vala b/src/game.vala
index 41e0d96..b9fb156 100644
--- a/src/game.vala
+++ b/src/game.vala
@@ -30,12 +30,14 @@ public class Game : Object
public Player current_color { get; private set; default = Player.DARK; }
public int number_of_moves { get; private set; default = 0; }
+ /* Indicate who's the next player who can move */
+ public bool current_player_can_move { get; private set; default = true; }
+ public bool is_complete { get; private set; default = false; }
+
/* Indicate that a player should move */
- public signal void move ();
+ public signal void turn_ended ();
/* Indicate a square has changed */
public signal void square_changed (int x, int y);
- /* Indicate the game is complete */
- public signal void complete ();
/*\
* * Number of tiles on the board
@@ -171,26 +173,6 @@ public class Game : Object
return tiles[x, y];
}
- public bool is_complete ()
- ensures (result || n_tiles < size * size)
- {
- return !can_move (null);
- }
-
- public bool can_move (Player? color)
- requires (color != Player.NONE)
- {
- for (var x = 0; x < size; x++)
- for (var y = 0; y < size; y++)
- {
- if (color != Player.DARK && can_place (x, y, Player.LIGHT))
- return true;
- if (color != Player.LIGHT && can_place (x, y, Player.DARK))
- return true;
- }
- return false;
- }
-
public bool can_place (int x, int y, Player color)
requires (is_valid_location (x, y))
requires (color != Player.NONE)
@@ -235,20 +217,13 @@ public class Game : Object
set_tile (x, y);
end_of_turn ();
- if (is_complete ())
- complete ();
- else
- move ();
-
return tiles_turned;
}
public void pass ()
- requires (!can_move (current_color))
+ requires (!current_player_can_move)
{
end_of_turn ();
-
- move ();
}
private void end_of_turn ()
@@ -258,6 +233,30 @@ public class Game : Object
number_of_moves++;
history_index++;
undo_stack[history_index] = null;
+ update_who_can_move ();
+ turn_ended ();
+ }
+
+ private void update_who_can_move ()
+ {
+ var enemy = Player.flip_color (current_color);
+ var opponent_can_move = false;
+ for (var x = 0; x < size; x++)
+ {
+ for (var y = 0; y < size; y++)
+ {
+ if (can_place (x, y, current_color))
+ {
+ current_player_can_move = true;
+ return;
+ }
+ if (can_place (x, y, enemy))
+ opponent_can_move = true;
+ }
+ }
+ current_player_can_move = false;
+ if (!opponent_can_move)
+ is_complete = true;
}
/*\
@@ -337,8 +336,15 @@ public class Game : Object
}
}
- if (count == 2)
- undo (1);
+ if (count == 1)
+ {
+ is_complete = false;
+ update_who_can_move ();
+ }
+ else
+ {
+ undo (count - 1);
+ }
}
private void unset_tile (int tile_number, Player replacement_color)
diff --git a/src/iagno.vala b/src/iagno.vala
index 0a8c7ac..ed897fd 100644
--- a/src/iagno.vala
+++ b/src/iagno.vala
@@ -316,8 +316,7 @@ public class Iagno : Gtk.Application
show_game_board ();
game = new Game (size);
- game.move.connect (game_move_cb);
- game.complete.connect (game_complete_cb);
+ game.turn_ended.connect (turn_ended_cb);
view.game = game;
view.show ();
game_box.pack_start (view);
@@ -367,7 +366,7 @@ public class Iagno : Gtk.Application
if (computer == null)
{
game.undo (1);
- if (!game.can_move (game.current_color))
+ if (!game.current_player_can_move)
game.undo (1);
}
else
@@ -381,11 +380,12 @@ public class Iagno : Gtk.Application
game.undo (2);
/* If forced to pass, undo to last chosen move so the computer doesn't play next */
- while (!game.can_move (game.current_color))
+ while (!game.current_player_can_move)
game.undo (2);
}
- game_move_cb ();
+ update_ui ();
+ play_sound ("flip-piece");
}
private void about_cb ()
@@ -427,27 +427,21 @@ public class Iagno : Gtk.Application
}
}
- private void game_move_cb ()
+ private void turn_ended_cb ()
{
- play_sound ("flip-piece");
-
- if (!game.can_move (game.current_color))
- {
- game.pass ();
- if (game.current_color == Player.DARK)
- {
- /* Message to display when Light has no possible moves */
- headerbar.set_subtitle (_("Light must pass, Dark’s move"));
- }
- else
- {
- /* Message to display when Dark has no possible moves */
- headerbar.set_subtitle (_("Dark must pass, Light’s move"));
- }
- return;
- }
-
update_ui ();
+ if (game.current_player_can_move)
+ prepare_move ();
+ else if (game.is_complete)
+ game_complete ();
+ else
+ pass ();
+ }
+
+ private void prepare_move ()
+ {
+ /* for the move that just ended */
+ play_sound ("flip-piece");
/*
* Get the computer to move after a delay, so it looks like it's
@@ -463,10 +457,26 @@ public class Iagno : Gtk.Application
}
}
- private void game_complete_cb ()
+ private void pass ()
{
- update_ui ();
+ /* for the move that just ended */
+ play_sound ("flip-piece");
+ game.pass ();
+ if (game.current_color == Player.DARK)
+ {
+ /* Message to display when Light has no possible moves */
+ headerbar.set_subtitle (_("Light must pass, Dark’s move"));
+ }
+ else
+ {
+ /* Message to display when Dark has no possible moves */
+ headerbar.set_subtitle (_("Dark must pass, Light’s move"));
+ }
+ }
+
+ private void game_complete ()
+ {
if (game.n_light_tiles > game.n_dark_tiles)
{
/* Message to display when Light has won the game */
@@ -477,12 +487,11 @@ public class Iagno : Gtk.Application
/* Message to display when Dark has won the game */
headerbar.set_subtitle (_("Dark wins!"));
}
- else if (game.n_light_tiles == game.n_dark_tiles)
+ else
{
/* Message to display when the game is a draw */
headerbar.set_subtitle (_("The game is draw."));
}
- else assert_not_reached ();
play_sound ("gameover");
}
diff --git a/src/test-iagno.vala b/src/test-iagno.vala
index 73fc4fa..8f9759a 100644
--- a/src/test-iagno.vala
+++ b/src/test-iagno.vala
@@ -34,7 +34,7 @@ public class TestIagno : Object
assert (game.number_of_moves == 0);
assert (game.place_tile (7, 2) > 0);
assert (game.number_of_moves == 1);
- assert (!game.can_move (Player.LIGHT));
+ assert (!game.current_player_can_move);
game.pass ();
assert (game.number_of_moves == 2);
game.undo (2);
@@ -42,7 +42,7 @@ public class TestIagno : Object
assert (game.to_string ().strip () == string.joinv ("\n", board).strip ());
assert (game.place_tile (7, 2) > 0);
assert (game.number_of_moves == 1);
- assert (!game.can_move (Player.LIGHT));
+ assert (!game.current_player_can_move);
game.undo (1);
assert (game.number_of_moves == 0);
assert (game.to_string ().strip () == string.joinv ("\n", board).strip ());
@@ -72,7 +72,7 @@ public class TestIagno : Object
assert (game.current_color == Player.DARK);
assert (game.place_tile (1, 2) > 0);
assert (game.current_color == Player.LIGHT);
- assert (!game.can_move (Player.LIGHT));
+ assert (!game.current_player_can_move);
game.pass ();
assert (game.current_color == Player.DARK);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]