[iagno] Introduce human opening.
- From: Arnaud B. <arnaudb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [iagno] Introduce human opening.
- Date: Fri, 27 Sep 2019 07:52:09 +0000 (UTC)
commit 52e78b677aa945712013b870bd74c3346d6b0566
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date: Fri Sep 13 16:30:20 2019 +0200
Introduce human opening.
For two players game.
Needs a bit love with
perhaps explaination.
data/themes/high_contrast.theme.desktop.in | 16 +-
src/game.vala | 322 ++++++++++++++++++++++-------
src/iagno.vala | 27 ++-
src/reversi-view.vala | 85 +++++++-
4 files changed, 359 insertions(+), 91 deletions(-)
---
diff --git a/data/themes/high_contrast.theme.desktop.in b/data/themes/high_contrast.theme.desktop.in
index 032451f..05c6792 100644
--- a/data/themes/high_contrast.theme.desktop.in
+++ b/data/themes/high_contrast.theme.desktop.in
@@ -53,16 +53,16 @@ Blue=0.0
Width=3
[Highlight hard]
-Red=0.7
-Green=0.7
-Blue=0.7
-Alpha=1.0
+Red=0.35
+Green=0.35
+Blue=0.35
+Alpha=0.5
[Highlight soft]
-Red=0.7
-Green=0.7
-Blue=0.7
-Alpha=0.6
+Red=0.35
+Green=0.35
+Blue=0.35
+Alpha=0.3
[Margin]
#Width=0
diff --git a/src/game.vala b/src/game.vala
index 72c39bf..3053b57 100644
--- a/src/game.vala
+++ b/src/game.vala
@@ -168,6 +168,68 @@ private struct GameStateStruct
n_opponent_tiles++;
}
+ internal GameStateStruct.empty (uint8 _size, uint8 [,] _neighbor_tiles)
+ {
+ // move color
+ current_color = Player.DARK; // Dark always starts
+ opponent_color = Player.LIGHT;
+
+ // always given
+ size = _size;
+ neighbor_tiles = _neighbor_tiles;
+
+ // tiles grid
+ tiles = new Player [_size, _size];
+ for (uint8 x = 0; x < _size; x++)
+ for (uint8 y = 0; y < _size; y++)
+ tiles [x, y] = Player.NONE;
+
+ // tiles counters
+ n_current_tiles = 0;
+ n_opponent_tiles = 0;
+ n_tiles = 0;
+
+ // empty neighbors
+ init_empty_neighbors (); // could do better
+
+ // who can move
+ current_player_can_move = true;
+ is_complete = false;
+ x_saved = size / 2 - 2;
+ y_saved = size / 2 - 2;
+ }
+
+ internal GameStateStruct.copy_and_add (GameStateStruct game, uint8 x, uint8 y)
+ {
+ // move color
+ opponent_color = game.current_color;
+ current_color = Player.flip_color (opponent_color);
+
+ // always given
+ size = game.size;
+ neighbor_tiles = game.neighbor_tiles;
+
+ // tiles grid
+ tiles = game.tiles;
+ if (tiles [x, y] != Player.NONE)
+ assert_not_reached ();
+ tiles [x, y] = opponent_color;
+
+ // tiles counters
+ n_current_tiles = game.n_opponent_tiles;
+ n_opponent_tiles = game.n_current_tiles + 1;
+ n_tiles = n_current_tiles + n_opponent_tiles;
+
+ // empty neighbors
+ init_empty_neighbors (); // lazyness
+
+ // who can move
+ current_player_can_move = true;
+ is_complete = false;
+ x_saved = size / 2 - 2;
+ y_saved = size / 2 - 2;
+ }
+
/*\
* * public information
\*/
@@ -508,6 +570,16 @@ private class GameStateObject : Object
_game_state_struct = GameStateStruct.from_grid (size, tiles, color, neighbor_tiles);
}
+ internal GameStateObject.empty (uint8 size, uint8 [,] neighbor_tiles)
+ {
+ _game_state_struct = GameStateStruct.empty (size, neighbor_tiles);
+ }
+
+ internal GameStateObject.copy_and_add (GameStateObject game, uint8 x, uint8 y)
+ {
+ _game_state_struct = GameStateStruct.copy_and_add (game.game_state_struct, x, y);
+ }
+
/*\
* * public information
\*/
@@ -556,7 +628,7 @@ private class Game : Object
[CCode (notify = false)] public uint8 size { internal get; protected
construct; }
[CCode (notify = false)] public bool reverse { internal get; protected
construct; }
- [CCode (notify = false)] public Opening opening { internal get; protected
construct; }
+ [CCode (notify = false)] public Opening opening { internal get; protected
construct set; }
[CCode (notify = false)] public GameStateObject current_state { internal get; protected
construct set; }
[CCode (notify = false)] public uint8 initial_number_of_tiles { internal get; protected
construct; }
@@ -570,78 +642,32 @@ private class Game : Object
requires (_size >= 4)
requires (_size <= 16)
{
- bool even_board = (_size % 2 == 0);
-
- Player [,] tiles = new Player [_size, _size];
-
- for (uint8 x = 0; x < _size; x++)
- for (uint8 y = 0; y < _size; y++)
- tiles [x, y] = Player.NONE;
+ uint8 [,] _neighbor_tiles;
+ init_neighbor_tiles (_size, out _neighbor_tiles);
+ GameStateObject _current_state;
uint8 _initial_number_of_tiles;
- if (even_board)
+ if (_opening == Opening.HUMANS)
{
- /* setup board with four tiles by default */
- uint8 half_size = _size / 2;
- _initial_number_of_tiles = 4;
- Player [,] start_position;
- switch (_opening)
- {
- case Opening.REVERSI: start_position = {{ Player.LIGHT, Player.DARK }, { Player.DARK ,
Player.LIGHT }}; break;
- case Opening.INVERTED: start_position = {{ Player.DARK , Player.LIGHT }, { Player.LIGHT,
Player.DARK }}; break;
- case Opening.ALTER_TOP: start_position = {{ Player.DARK , Player.DARK }, { Player.LIGHT,
Player.LIGHT }}; break;
- case Opening.ALTER_LEFT: start_position = {{ Player.DARK , Player.LIGHT }, { Player.DARK ,
Player.LIGHT }}; break;
- case Opening.ALTER_RIGHT: start_position = {{ Player.LIGHT, Player.DARK }, { Player.LIGHT,
Player.DARK }}; break;
- case Opening.ALTER_BOTTOM: start_position = {{ Player.LIGHT, Player.LIGHT }, { Player.DARK ,
Player.DARK }}; break;
- default: assert_not_reached ();
- }
- tiles [half_size - 1, half_size - 1] = start_position [0, 0];
- tiles [half_size , half_size - 1] = start_position [0, 1];
- tiles [half_size - 1, half_size ] = start_position [1, 0];
- tiles [half_size , half_size ] = start_position [1, 1];
+ _initial_number_of_tiles = 0;
+
+ _current_state = new GameStateObject.empty (_size, _neighbor_tiles);
}
else
{
- /* logical starting position for odd board */
- uint8 mid_board = (_size - 1) / 2;
- _initial_number_of_tiles = 7;
- Player [,] start_position;
- switch (_opening)
- {
- case Opening.REVERSI: start_position = {{ Player.NONE , Player.LIGHT, Player.DARK },
- { Player.LIGHT, Player.DARK , Player.LIGHT },
- { Player.DARK , Player.LIGHT, Player.NONE }};
break;
- case Opening.INVERTED: start_position = {{ Player.DARK , Player.LIGHT, Player.NONE },
- { Player.LIGHT, Player.DARK , Player.LIGHT },
- { Player.NONE , Player.LIGHT, Player.DARK }};
break;
- case Opening.ALTER_TOP: start_position = {{ Player.NONE , Player.DARK , Player.LIGHT },
- { Player.LIGHT, Player.DARK , Player.LIGHT },
- { Player.LIGHT, Player.DARK , Player.NONE }};
break;
- case Opening.ALTER_LEFT: start_position = {{ Player.LIGHT, Player.LIGHT, Player.NONE },
- { Player.DARK , Player.DARK , Player.DARK },
- { Player.NONE , Player.LIGHT, Player.LIGHT }};
break;
- case Opening.ALTER_RIGHT: start_position = {{ Player.NONE , Player.LIGHT, Player.LIGHT },
- { Player.DARK , Player.DARK , Player.DARK },
- { Player.LIGHT, Player.LIGHT, Player.NONE }};
break;
- case Opening.ALTER_BOTTOM: start_position = {{ Player.LIGHT, Player.DARK , Player.NONE },
- { Player.LIGHT, Player.DARK , Player.LIGHT },
- { Player.NONE , Player.DARK , Player.LIGHT }};
break;
- default: assert_not_reached ();
- }
- tiles [mid_board - 1, mid_board - 1] = start_position [0, 0];
- tiles [mid_board , mid_board - 1] = start_position [0, 1];
- tiles [mid_board + 1, mid_board - 1] = start_position [0, 2];
- tiles [mid_board - 1, mid_board ] = start_position [1, 0];
- tiles [mid_board , mid_board ] = Player.DARK;
- tiles [mid_board + 1, mid_board ] = start_position [1, 2];
- tiles [mid_board - 1, mid_board + 1] = start_position [2, 0];
- tiles [mid_board , mid_board + 1] = start_position [2, 1];
- tiles [mid_board + 1, mid_board + 1] = start_position [2, 2];
- }
+ Player [,] tiles = new Player [_size, _size];
- uint8 [,] _neighbor_tiles;
- init_neighbor_tiles (_size, out _neighbor_tiles);
- GameStateObject _current_state = new GameStateObject.from_grid (_size, tiles, /* Dark always starts
*/ Player.DARK, _neighbor_tiles);
+ for (uint8 x = 0; x < _size; x++)
+ for (uint8 y = 0; y < _size; y++)
+ tiles [x, y] = Player.NONE;
+
+ if (_size % 2 == 0)
+ setup_even_board (_size, _opening, ref tiles, out _initial_number_of_tiles);
+ else
+ setup_odd_board (_size, _opening, ref tiles, out _initial_number_of_tiles);
+
+ _current_state = new GameStateObject.from_grid (_size, tiles, /* Dark always starts */
Player.DARK, _neighbor_tiles);
+ }
Object (size : _size,
reverse : _reverse,
@@ -650,6 +676,65 @@ private class Game : Object
initial_number_of_tiles : _initial_number_of_tiles);
neighbor_tiles = (owned) _neighbor_tiles;
}
+ private static inline void setup_even_board (uint8 size, Opening opening, ref Player [,] tiles, out
uint8 initial_number_of_tiles)
+ {
+ /* setup board with four tiles by default */
+ uint8 half_size = size / 2;
+ initial_number_of_tiles = 4;
+ Player [,] start_position;
+ switch (opening)
+ {
+ case Opening.REVERSI: start_position = {{ Player.LIGHT, Player.DARK }, { Player.DARK ,
Player.LIGHT }}; break;
+ case Opening.INVERTED: start_position = {{ Player.DARK , Player.LIGHT }, { Player.LIGHT,
Player.DARK }}; break;
+ case Opening.ALTER_TOP: start_position = {{ Player.DARK , Player.DARK }, { Player.LIGHT,
Player.LIGHT }}; break;
+ case Opening.ALTER_LEFT: start_position = {{ Player.DARK , Player.LIGHT }, { Player.DARK ,
Player.LIGHT }}; break;
+ case Opening.ALTER_RIGHT: start_position = {{ Player.LIGHT, Player.DARK }, { Player.LIGHT,
Player.DARK }}; break;
+ case Opening.ALTER_BOTTOM: start_position = {{ Player.LIGHT, Player.LIGHT }, { Player.DARK ,
Player.DARK }}; break;
+ default: assert_not_reached ();
+ }
+ tiles [half_size - 1, half_size - 1] = start_position [0, 0];
+ tiles [half_size , half_size - 1] = start_position [0, 1];
+ tiles [half_size - 1, half_size ] = start_position [1, 0];
+ tiles [half_size , half_size ] = start_position [1, 1];
+ }
+ private static inline void setup_odd_board (uint8 size, Opening opening, ref Player [,] tiles, out uint8
initial_number_of_tiles)
+ {
+ /* logical starting position for odd board */
+ uint8 mid_board = (size - 1) / 2;
+ initial_number_of_tiles = 7;
+ Player [,] start_position;
+ switch (opening)
+ {
+ case Opening.REVERSI: start_position = {{ Player.NONE , Player.LIGHT, Player.DARK },
+ { Player.LIGHT, Player.DARK , Player.LIGHT },
+ { Player.DARK , Player.LIGHT, Player.NONE }};
break;
+ case Opening.INVERTED: start_position = {{ Player.DARK , Player.LIGHT, Player.NONE },
+ { Player.LIGHT, Player.DARK , Player.LIGHT },
+ { Player.NONE , Player.LIGHT, Player.DARK }};
break;
+ case Opening.ALTER_TOP: start_position = {{ Player.NONE , Player.DARK , Player.LIGHT },
+ { Player.LIGHT, Player.DARK , Player.LIGHT },
+ { Player.LIGHT, Player.DARK , Player.NONE }};
break;
+ case Opening.ALTER_LEFT: start_position = {{ Player.LIGHT, Player.LIGHT, Player.NONE },
+ { Player.DARK , Player.DARK , Player.DARK },
+ { Player.NONE , Player.LIGHT, Player.LIGHT }};
break;
+ case Opening.ALTER_RIGHT: start_position = {{ Player.NONE , Player.LIGHT, Player.LIGHT },
+ { Player.DARK , Player.DARK , Player.DARK },
+ { Player.LIGHT, Player.LIGHT, Player.NONE }};
break;
+ case Opening.ALTER_BOTTOM: start_position = {{ Player.LIGHT, Player.DARK , Player.NONE },
+ { Player.LIGHT, Player.DARK , Player.LIGHT },
+ { Player.NONE , Player.DARK , Player.LIGHT }};
break;
+ default: assert_not_reached ();
+ }
+ tiles [mid_board - 1, mid_board - 1] = start_position [0, 0];
+ tiles [mid_board , mid_board - 1] = start_position [0, 1];
+ tiles [mid_board + 1, mid_board - 1] = start_position [0, 2];
+ tiles [mid_board - 1, mid_board ] = start_position [1, 0];
+ tiles [mid_board , mid_board ] = Player.DARK;
+ tiles [mid_board + 1, mid_board ] = start_position [1, 2];
+ tiles [mid_board - 1, mid_board + 1] = start_position [2, 0];
+ tiles [mid_board , mid_board + 1] = start_position [2, 1];
+ tiles [mid_board + 1, mid_board + 1] = start_position [2, 2];
+ }
internal Game.from_strings (string [] setup, Player to_move, bool _reverse = false, uint8 _size = 8)
requires (_size >= 4)
@@ -657,6 +742,9 @@ private class Game : Object
requires (to_move != Player.NONE)
requires (setup.length == _size)
{
+ uint8 [,] _neighbor_tiles;
+ init_neighbor_tiles (_size, out _neighbor_tiles);
+
Player [,] tiles = new Player [_size, _size];
for (uint8 y = 0; y < _size; y++)
@@ -667,8 +755,6 @@ private class Game : Object
tiles [x, y] = Player.from_char (setup [y] [x * 2 + 1]);
}
- uint8 [,] _neighbor_tiles;
- init_neighbor_tiles (_size, out _neighbor_tiles);
GameStateObject _current_state = new GameStateObject.from_grid (_size, tiles, to_move,
_neighbor_tiles);
Object (size : _size,
@@ -709,6 +795,48 @@ private class Game : Object
internal /* success */ bool place_tile (uint8 x, uint8 y)
{
+ if (opening == Opening.HUMANS)
+ {
+ uint8 half_game_size = size / 2;
+ if (x < half_game_size - 1 || x > half_game_size
+ || y < half_game_size - 1 || y > half_game_size)
+ return false;
+
+ if (current_color == Player.LIGHT && n_light_tiles == 0)
+ {
+ uint8 opposite_x = x == half_game_size ? half_game_size - 1 : half_game_size;
+ uint8 opposite_y = y == half_game_size ? half_game_size - 1 : half_game_size;
+ if (get_owner (opposite_x, opposite_y) == Player.DARK)
+ return false;
+ }
+
+ if (current_state.n_dark_tiles == 2)
+ {
+ if (get_owner (half_game_size - 1, half_game_size - 1) == Player.DARK)
+ {
+ if (get_owner (half_game_size, half_game_size - 1) == Player.DARK) opening =
Opening.ALTER_TOP;
+ else if (get_owner (half_game_size, half_game_size) == Player.DARK) opening =
Opening.REVERSI;
+ else opening =
Opening.ALTER_LEFT;
+ }
+ else
+ {
+ if (get_owner (half_game_size, half_game_size - 1) == Player.LIGHT) opening =
Opening.ALTER_BOTTOM;
+ else if (get_owner (half_game_size, half_game_size) == Player.DARK) opening =
Opening.ALTER_RIGHT;
+ else opening =
Opening.INVERTED;
+ }
+ }
+ current_state = new GameStateObject.copy_and_add (current_state, x, y);
+
+ if (n_light_tiles == 2)
+ {
+ undo_stack.remove (0);
+ undo_stack.append (current_state);
+ }
+
+ end_of_turn (/* undoing */ false, /* no_draw */ false);
+ return true;
+ }
+
PossibleMove move;
if (!current_state.test_placing_tile (x, y, out move))
return false;
@@ -808,6 +936,28 @@ private class Game : Object
internal bool test_placing_tile (uint8 x, uint8 y, out unowned PossibleMove move)
{
+ if (opening == Opening.HUMANS)
+ {
+ move = PossibleMove (x, y); // good enough
+
+ uint8 half_game_size = size / 2;
+ if (x < half_game_size - 1 || x > half_game_size
+ || y < half_game_size - 1 || y > half_game_size)
+ return false;
+
+ if (get_owner (x, y) != Player.NONE)
+ return false;
+
+ if (current_color == Player.LIGHT && n_light_tiles == 0)
+ {
+ uint8 opposite_x = x == half_game_size ? half_game_size - 1 : half_game_size;
+ uint8 opposite_y = y == half_game_size ? half_game_size - 1 : half_game_size;
+ if (get_owner (opposite_x, opposite_y) == Player.DARK)
+ return false;
+ }
+ return true;
+ }
+
unowned SList<PossibleMove?>? test_move = possible_moves.nth (0);
while (test_move != null)
{
@@ -830,11 +980,45 @@ private class Game : Object
private inline void update_possible_moves ()
{
- current_state.get_possible_moves (out possible_moves);
+ if (opening == Opening.HUMANS)
+ {
+ possible_moves = new SList<PossibleMove?> ();
+
+ uint8 half_game_size = size / 2;
+
+ bool top_left;
+ bool top_right;
+ bool bottom_left;
+ bool bottom_right;
+
+ if (current_color == Player.LIGHT && n_light_tiles == 0)
+ {
+ top_left = get_owner (half_game_size - 1, half_game_size - 1) == Player.NONE
+ && get_owner (half_game_size , half_game_size ) == Player.NONE;
+ top_right = !top_left;
+ bottom_left = !top_left;
+ bottom_right = top_left;
+ }
+ else
+ {
+ top_left = get_owner (half_game_size - 1, half_game_size - 1) == Player.NONE;
+ top_right = get_owner (half_game_size , half_game_size - 1) == Player.NONE;
+ bottom_left = get_owner (half_game_size - 1, half_game_size ) == Player.NONE;
+ bottom_right = get_owner (half_game_size , half_game_size ) == Player.NONE;
+ }
+
+ if (top_left) possible_moves.prepend (PossibleMove (half_game_size - 1, half_game_size - 1));
+ if (top_right) possible_moves.prepend (PossibleMove (half_game_size , half_game_size - 1));
+ if (bottom_left) possible_moves.prepend (PossibleMove (half_game_size - 1, half_game_size ));
+ if (bottom_right) possible_moves.prepend (PossibleMove (half_game_size , half_game_size ));
+ }
+ else
+ current_state.get_possible_moves (out possible_moves);
}
}
private enum Opening {
+ HUMANS,
REVERSI,
INVERTED,
ALTER_TOP,
diff --git a/src/iagno.vala b/src/iagno.vala
index f1103b3..fd919a7 100644
--- a/src/iagno.vala
+++ b/src/iagno.vala
@@ -266,12 +266,6 @@ private class Iagno : Gtk.Application, BaseApplication
size_menu.append_section (null, section);
section = new GLib.Menu ();
- if (!alternative_start && !random_start && !usual_start)
- {
- /* Translators: when configuring a new game, in the first menubutton's menu, label of the entry
to choose to use randomly an alternative start position (with a mnemonic that appears pressing Alt) */
- section.append (_("_Random start position"), "app.random-start-position");
- }
-
/* Translators: when configuring a new game, in the first menubutton's menu, label of the entry to
choose to alternate who starts between human and AI (with a mnemonic that appears pressing Alt) */
section.append (_("_Alternate who starts"), "app.alternate-who-starts");
section.freeze ();
@@ -280,6 +274,7 @@ private class Iagno : Gtk.Application, BaseApplication
size_menu.freeze ();
GLib.Menu theme_menu = new GLib.Menu ();
+ section = new GLib.Menu ();
/* Translators: when configuring a new game, in the second menubutton's menu, label of the entry to
choose an easy-level computer adversary (with a mnemonic that appears pressing Alt) */
theme_menu.append (_("_Easy"), "app.change-level('1')");
@@ -290,6 +285,17 @@ private class Iagno : Gtk.Application, BaseApplication
/* Translators: when configuring a new game, in the second menubutton's menu, label of the entry to
choose an hard-level computer adversary (with a mnemonic that appears pressing Alt) */
theme_menu.append (_("_Hard"), "app.change-level('3')");
+ section.freeze ();
+ theme_menu.append_section (null, section);
+
+ if (!alternative_start && !random_start && !usual_start)
+ {
+ section = new GLib.Menu ();
+ /* Translators: when configuring a new game, in the first menubutton's menu, label of the entry
to choose to use randomly an alternative start position (with a mnemonic that appears pressing Alt) */
+ section.append (_("_Vary start position"), "app.random-start-position");
+ section.freeze ();
+ theme_menu.append_section (null, section);
+ }
theme_menu.freeze ();
/* Translators: when configuring a new game, label of the first big button; name of the usual
reversi game, where you try to have more pieces */
@@ -616,18 +622,23 @@ private class Iagno : Gtk.Application, BaseApplication
((!) computer).cancel_move ();
bool two_players = settings.get_int ("num-players") == 2;
+ bool even_board = size % 2 == 0;
Opening opening;
if (alternative_start)
{
- if (size % 2 == 0)
+ if (even_board)
opening = get_locale_direction () == TextDirection.LTR ? Opening.ALTER_LEFT :
Opening.ALTER_RIGHT;
else
opening = get_locale_direction () == TextDirection.LTR ? Opening.ALTER_RIGHT :
Opening.ALTER_LEFT;
}
else if (usual_start)
opening = Opening.REVERSI;
- else if (random_start || settings.get_boolean ("random-start-position"))
+ else if (two_players && even_board && !random_start) // TODO make work on odd board
+ opening = Opening.HUMANS;
+ else if (random_start
+ || settings.get_boolean ("random-start-position")
+ || two_players /* && !even_board */)
{
switch (Random.int_range (0, 8))
{
diff --git a/src/reversi-view.vala b/src/reversi-view.vala
index c8a94c1..f9331dd 100644
--- a/src/reversi-view.vala
+++ b/src/reversi-view.vala
@@ -103,6 +103,10 @@ private class ReversiView : Gtk.DrawingArea
/* Animation timer */
private uint animate_timeout = 0;
+ /* Humans opening */
+ private const uint8 HUMANS_OPENING_INTENSITY_MAX = 15;
+ private uint8 humans_opening_intensity = 0;
+
internal signal void move (uint8 x, uint8 y);
internal signal void clear_impossible_to_move_here_warning ();
@@ -125,6 +129,7 @@ private class ReversiView : Gtk.DrawingArea
if (game_is_set)
SignalHandler.disconnect_by_func (_game, null, this);
+
_game = value;
game_size = _game.size;
if (!game_is_set)
@@ -142,16 +147,17 @@ private class ReversiView : Gtk.DrawingArea
_game.turn_ended.connect (turn_ended_cb);
show_highlight = false;
- if (game_size % 2 != 0) // always start on center on odd games
- {
- highlight_set = true;
- highlight_x = (uint8) (game_size / 2);
- }
- else
+ bool even_board = game_size % 2 == 0;
+ if (even_board)
{
highlight_set = false;
highlight_x = (uint8) (game_size / 2 - 1);
}
+ else // always start on center on odd games
+ {
+ highlight_set = true;
+ highlight_x = (uint8) (game_size / 2);
+ }
highlight_y = highlight_x;
old_highlight_x = uint8.MAX;
old_highlight_y = uint8.MAX;
@@ -164,6 +170,15 @@ private class ReversiView : Gtk.DrawingArea
mouse_position_x = uint8.MAX;
mouse_position_y = uint8.MAX;
+ if (_game.opening == Opening.HUMANS)
+ {
+ if (!even_board)
+ assert_not_reached ();
+ humans_opening_intensity = HUMANS_OPENING_INTENSITY_MAX;
+ }
+ else
+ humans_opening_intensity = 0;
+
queue_draw ();
}
}
@@ -359,6 +374,9 @@ private class ReversiView : Gtk.DrawingArea
// draw tiles (and highlight)
cr.translate (border_width, border_width);
+ if (humans_opening_intensity != 0)
+ draw_overture (cr);
+
draw_highlight (cr);
add_highlights (cr);
draw_playables (cr);
@@ -453,6 +471,27 @@ private class ReversiView : Gtk.DrawingArea
cr.fill ();
}
+ private inline void draw_overture (Cairo.Context cr)
+ // requires (game_size % 2 == 0)
+ {
+ uint8 half_game_size = game_size / 2;
+ for (uint8 x = 0; x < game_size; x++)
+ for (uint8 y = 0; y < game_size; y++)
+ {
+ if ((x == half_game_size || x == half_game_size - 1)
+ && (y == half_game_size || y == half_game_size - 1))
+ continue;
+
+ darken_tile (cr, x, y);
+ }
+
+ if (game.opening != Opening.HUMANS)
+ {
+ humans_opening_intensity--;
+ queue_draw ();
+ }
+ }
+
private inline void draw_highlight (Cairo.Context cr)
{
if (game.is_complete) // TODO highlight last played tile on game.is_complete, even if it's the
opponent one...
@@ -660,6 +699,20 @@ private class ReversiView : Gtk.DrawingArea
cr.fill ();
}
+ private void darken_tile (Cairo.Context cr, uint8 x, uint8 y)
+ {
+ double alpha = highlight_hard_alpha * 1.6 * (double) humans_opening_intensity / (double)
HUMANS_OPENING_INTENSITY_MAX;
+ cr.set_source_rgba (highlight_hard_red, highlight_hard_green, highlight_hard_blue, alpha);
+ rounded_square (cr,
+ // TODO odd/even sizes problem
+ tile_xs [x, y],
+ tile_ys [x, y],
+ tile_size,
+ 0,
+ background_radius);
+ cr.fill ();
+ }
+
private void queue_draw_tile (uint8 x, uint8 y)
requires (x < game_size)
requires (y < game_size)
@@ -1262,6 +1315,7 @@ private class ReversiView : Gtk.DrawingArea
if (iagno_instance.computer != null && iagno_instance.player_one == Player.LIGHT)
{
/* This section is for when computer starts but player moves before.
+ It is similar to the case of a two-players game, with an opening.
The starting [highlight_x, highlight_y] tile is the top-left one.
The target tile is the one that will give correct highlight after
a move in the given direction, not directly the one to highlight. */
@@ -1292,6 +1346,25 @@ private class ReversiView : Gtk.DrawingArea
The target tile is the one that will give correct highlight after
a move in the given direction, not directly the one to highlight. */
+ case Opening.HUMANS:
+ if (Gtk.get_locale_direction () == Gtk.TextDirection.LTR)
+ switch (direction)
+ {
+ case Direction.TOP: highlight_y++; break;
+ case Direction.LEFT: highlight_x++; highlight_y++; break;
+ case Direction.RIGHT: break;
+ case Direction.BOTTOM: highlight_x++; break;
+ }
+ else
+ switch (direction)
+ {
+ case Direction.TOP: highlight_x++; highlight_y++; break;
+ case Direction.LEFT: highlight_x++; break;
+ case Direction.RIGHT: highlight_y++; break;
+ case Direction.BOTTOM: break;
+ }
+ return;
+
case Opening.REVERSI:
switch (direction)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]