[gnome-games/glines-vala] Add the game model classes
- From: Thomas Hindoe Paaboel Andersen <thomashpa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/glines-vala] Add the game model classes
- Date: Sun, 10 Jun 2012 15:07:17 +0000 (UTC)
commit feeac7826775d16903c7b08a2c22c2ea42d689c1
Author: Thomas Hindoe Paaboel Andersen <phomes gmail com>
Date: Sun Jun 10 17:04:33 2012 +0200
Add the game model classes
Adds board, field, piece, and preview queue.
Also adds a CLI game mode to test the model
configure.ac | 7 +
glines/src/Makefile.am | 8 +
glines/src/glines-application.vala | 13 +-
glines/src/glines-board.vala | 313 ++++++++++++++++++++++++++++++++++
glines/src/glines-field.vala | 31 ++++
glines/src/glines-piece.vala | 12 ++
glines/src/glines-preview-queue.vala | 30 ++++
glines/src/glines-view-cli.vala | 144 ++++++++++++++++
8 files changed, 553 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 9b4f7e0..ed1e1e6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -249,6 +249,7 @@ LIBCANBERRA_GTK_REQUIRED=0.26
GIO_REQUIRED=2.25.7
GSTREAMER_REQUIRED=0.10.11
CAIRO_REQUIRED=1.10.0
+GEE_REQUIRED=0.6.0
if test "$need_gmenu" = "yes"; then
GTK_REQUIRED=3.3.11
@@ -274,6 +275,12 @@ PKG_CHECK_MODULES([RSVG],[
AC_SUBST([RSVG_CFLAGS])
AC_SUBST([RSVG_LIBS])
+if test "$need_vala" = "yes"; then
+ PKG_CHECK_MODULES([GEE],[gee-1.0 >= $GEE_REQUIRED])
+ AC_SUBST([GEE_CFLAGS])
+ AC_SUBST([GEE_LIBS])
+fi
+
# GDBus
PKG_CHECK_MODULES([GIO],[gio-2.0 >= $GIO_REQUIRED])
diff --git a/glines/src/Makefile.am b/glines/src/Makefile.am
index 40627bd..47aec5f 100644
--- a/glines/src/Makefile.am
+++ b/glines/src/Makefile.am
@@ -6,6 +6,11 @@ glines_SOURCES = \
config.vapi \
main.vala \
glines-application.vala \
+ glines-board.vala \
+ glines-field.vala \
+ glines-piece.vala \
+ glines-preview-queue.vala \
+ glines-view-cli.vala \
$(BUILT_SOURCES)
glines_CPPFLAGS = \
@@ -20,6 +25,7 @@ glines_CFLAGS = \
$(GMODULE_CFLAGS) \
$(GTK_CFLAGS) \
$(RSVG_CFLAGS) \
+ $(GEE_CFLAGS) \
$(AM_CFLAGS)
glines_LDADD = \
@@ -27,6 +33,7 @@ glines_LDADD = \
$(GMODULE_LIBS) \
$(GTK_LIBS) \
$(RSVG_LIBS) \
+ $(GEE_LIBS) \
$(INTLLIBS) \
-lm
@@ -34,6 +41,7 @@ glines_VALAFLAGS = \
--pkg posix \
--pkg gtk+-3.0 \
--pkg gmodule-2.0 \
+ --pkg gee-1.0 \
--vapidir $(top_srcdir)/libgames-support \
--pkg GnomeGamesSupport-1.0
diff --git a/glines/src/glines-application.vala b/glines/src/glines-application.vala
index 3d19201..cb28587 100644
--- a/glines/src/glines-application.vala
+++ b/glines/src/glines-application.vala
@@ -27,7 +27,7 @@ namespace Glines
};
private const string[] authors = { "Thomas Andersen <phomes gmail com>", "Robert Szokovacs <szo appaloosacorp hu>", "Szabolcs B\xc3\xa1n <shooby gnome hu>" };
- private const string[] documenters = { "Tiffany Antopolski", "Lanka Rathnayaka" };
+ //private const string[] documenters = { "Tiffany Antopolski", "Lanka Rathnayaka" };
public GlinesApp ()
{
@@ -79,6 +79,9 @@ namespace Glines
public override void activate ()
{
+ var v = new ViewCli ();
+ v.run();
+
window.present ();
}
@@ -91,10 +94,10 @@ namespace Glines
{
stdout.printf ("FIXME: Showing scores does not currently work\n");
- var scores_dialog = new GnomeGamesSupport.ScoresDialog (window, highscores, _("GNOME Five or More"));
- scores_dialog.set_category_description (_("_Board size:"));
- scores_dialog.run ();
- scores_dialog.destroy ();
+ //var scores_dialog = new GnomeGamesSupport.ScoresDialog (window, highscores, _("GNOME Five or More"));
+ //scores_dialog.set_category_description (_("_Board size:"));
+ //scores_dialog.run ();
+ //scores_dialog.destroy ();
}
private void preferences_cb ()
diff --git a/glines/src/glines-board.vala b/glines/src/glines-board.vala
new file mode 100644
index 0000000..5dce374
--- /dev/null
+++ b/glines/src/glines-board.vala
@@ -0,0 +1,313 @@
+using Gee;
+
+namespace Glines
+{
+ public class GlinesBoard
+ {
+ public int cols { get; private set; }
+ public int rows { get; private set; }
+
+ public GlinesField[,] fields { get; private set; }
+ public GlinesField active_field = null;
+
+ public GlinesPreviewQueue preview_queue;
+
+ public bool show_cursor { get; set; }
+ private int _cursor_x;
+ public int cursor_x
+ {
+ get { return this._cursor_x; }
+ set { this._cursor_x = this.clamp(0, value, this.cols - 1); }
+ }
+ private int _cursor_Y;
+ public int cursor_y
+ {
+ get { return this._cursor_Y; }
+ set { this._cursor_Y = this.clamp(0, value, this.rows - 1); }
+ }
+
+ public bool move_in_progress { get; set; }
+
+ public signal void changed ();
+ public signal void move (ArrayList<GlinesField> path);
+ public signal void info (string text);
+ public signal void gameover ();
+
+ public GlinesBoard(int cols, int rows, int preview_queue_size, int n_types)
+ {
+ this.cols = cols;
+ this.rows = rows;
+
+ preview_queue = new GlinesPreviewQueue(preview_queue_size, n_types);
+
+ this.fields = new GlinesField[this.cols, this.rows];
+
+ for (int x = 0; x < this.cols; x++)
+ {
+ for (int y = 0; y < this.rows; y++)
+ {
+ this.fields[x, y] = new GlinesField();
+ }
+ }
+
+ //Connect the neigbouring fields
+ for (int x = 0; x < this.cols; x++)
+ {
+ for (int y = 0; y < this.rows; y++)
+ {
+ var field = this.fields[x, y];
+ if (x > 0)
+ field.neigbour_west = this.fields[x - 1, y];
+ if (x < this.cols - 1)
+ field.neigbour_east = this.fields[x + 1, y];
+ if (y > 0)
+ field.neigbour_north = this.fields[x, y - 1];
+ if (y < this.rows - 1)
+ field.neigbour_south = this.fields[x, y + 1];
+ }
+ }
+
+ this.move_preview_queue_to_board();
+ }
+
+ public void select_field(int x, int y)
+ {
+ if (this.move_in_progress)
+ return;
+
+ var clicked_field = this.fields[x, y];
+
+ if (this.active_field == null && !clicked_field.has_piece)
+ {
+ info("No piece to select");
+ }
+ else if (this.active_field == null && clicked_field.has_piece)
+ {
+ //select a field
+ clicked_field.active = true;
+ this.active_field = clicked_field;
+ info("Field selected");
+ }
+ else if (this.active_field == clicked_field)
+ {
+ //deselect the active field
+ clicked_field.active = false;
+ this.active_field = null;
+ info("Field deselected");
+ }
+ else
+ {
+ //attempt to move the piece
+ if (find_route(this.active_field, clicked_field))
+ {
+ info("moving");
+
+ this.move_in_progress = true;
+
+ // Let the listener do the animation.
+ this.move(this.backtrack_route(clicked_field));
+
+ //actually move the piece
+ clicked_field.piece = this.active_field.piece;
+ this.active_field.piece = null;
+
+ this.active_field.active = false;
+ this.active_field = null;
+
+ move_completed();
+ }
+ else
+ {
+ info("no route");
+ }
+ }
+
+ this.changed();
+ }
+
+ private void move_completed()
+ {
+ //remove lines to make space for adding pieces
+ this.remove_lines();
+
+ this.move_preview_queue_to_board();
+
+ //remove lines again. New once could be formed when adding the new pieces
+ this.remove_lines();
+
+ if (this.check_for_game_over())
+ {
+ gameover();
+ }
+
+ this.move_in_progress = false;
+ }
+
+ private void remove_lines()
+ {
+ //todo: check for lines to remove
+ // + add scoring
+ }
+
+ private void move_preview_queue_to_board()
+ {
+ foreach (var piece in preview_queue.pieces)
+ {
+ this.add_piece_at_random_location(piece);
+ }
+
+ preview_queue.refill();
+ }
+
+ private void add_piece_at_random_location(GlinesPiece piece)
+ {
+ var vert = new ArrayList<int>();
+ var hori = new ArrayList<int>();
+
+ for (int i = 0; i < this.cols; i++)
+ vert.add(i);
+ for (int i = 0; i < this.rows; i++)
+ hori.add(i);
+
+ shuffle(hori);
+ shuffle(vert);
+
+ foreach(int x in vert)
+ {
+ foreach(int y in hori)
+ {
+ if(!fields[x,y].has_piece)
+ {
+ fields[x, y].piece = piece;
+ return;
+ }
+ }
+ }
+ }
+
+ private void shuffle(ArrayList<int> list)
+ {
+ for (int from = list.size - 1; from > 0; from--)
+ {
+ int to = Random.int_range(0, from);
+ int temp = list[to];
+ list[to] = list[from];
+ list[from] = temp;
+ }
+ }
+
+ private bool check_for_game_over()
+ {
+ for (int x = 0; x < this.cols; x++)
+ for (int y = 0; y < this.rows; y++)
+ if (!this.fields[x, y].has_piece)
+ return false;
+
+ return true;
+ }
+
+ private void reset_path_search()
+ {
+ for (int x = 0; x < this.cols; x++)
+ for (int y = 0; y < this.rows; y++)
+ fields[x, y].path_search = null;
+ }
+
+ //After the search has been performed a route will (if possible)
+ //exist from the target to the origin. Use the Pathsearch to follow
+ //the path.
+ public bool find_route(GlinesField from, GlinesField target)
+ {
+ reset_path_search();
+
+ var check_now = new ArrayList<GlinesField> ();
+ check_now.add (from);
+
+ while (check_now.size != 0)
+ {
+ var check_next = new ArrayList<GlinesField>();
+
+ foreach (var current in check_now)
+ {
+ foreach (var neighbour in this.non_searched_neighbours(current))
+ {
+ if (neighbour == from)
+ continue;
+
+ neighbour.path_search = current;
+ check_next.add(neighbour);
+
+ // We have reached the target so there is no use in continuing
+ if (neighbour == target)
+ return true;
+ }
+ }
+
+ check_now = check_next;
+ }
+
+ return false;
+ }
+
+ private ArrayList<GlinesField> non_searched_neighbours(GlinesField field)
+ {
+ var neighbours = new ArrayList<GlinesField>();
+
+ if (field.neigbour_north != null &&
+ !field.neigbour_north.has_piece &&
+ field.neigbour_north.path_search == null)
+ neighbours.add(field.neigbour_north);
+
+ if (field.neigbour_west != null &&
+ !field.neigbour_west.has_piece &&
+ field.neigbour_west.path_search == null)
+ neighbours.add(field.neigbour_west);
+
+ if (field.neigbour_south != null &&
+ !field.neigbour_south.has_piece &&
+ field.neigbour_south.path_search == null)
+ neighbours.add(field.neigbour_south);
+
+ if (field.neigbour_east != null &&
+ !field.neigbour_east.has_piece &&
+ field.neigbour_east.path_search == null)
+ neighbours.add(field.neigbour_east);
+
+ return neighbours;
+ }
+
+ public ArrayList<GlinesField> backtrack_route(GlinesField from)
+ {
+ var route = new ArrayList<GlinesField> ();
+ route.add (from);
+
+ //the routes origin may have more than one
+ while (route[route.size -1 ].path_search != null)
+ route.add(route[route.size -1 ].path_search);
+
+ return route;
+ }
+
+ public void place_cursor(int x, int y)
+ {
+ this.cursor_x = x;
+ this.cursor_y = y;
+
+ this.changed();
+ }
+
+ public void move_cursor(int x, int y)
+ {
+ this.place_cursor(this.cursor_x + x, this.cursor_y + y);
+ }
+
+ private int clamp(int min, int val, int max)
+ {
+ if (val < min)
+ return min;
+ if (val > max)
+ return max;
+ return val;
+ }
+ }
+}
diff --git a/glines/src/glines-field.vala b/glines/src/glines-field.vala
new file mode 100644
index 0000000..7eba100
--- /dev/null
+++ b/glines/src/glines-field.vala
@@ -0,0 +1,31 @@
+namespace Glines
+{
+ public class GlinesField
+ {
+ public GlinesField()
+ {
+ this.piece = null;
+
+ this.neigbour_north = null;
+ this.neigbour_south = null;
+ this.neigbour_east = null;
+ this.neigbour_west = null;
+ this.path_search = null;
+ }
+
+ public GlinesPiece piece { get; set; }
+ public bool active { get; set; }
+
+ public GlinesField neigbour_north { get; set; }
+ public GlinesField neigbour_south { get; set; }
+ public GlinesField neigbour_east { get; set; }
+ public GlinesField neigbour_west { get; set; }
+
+ public GlinesField path_search { get; set; }
+
+ public bool has_piece
+ {
+ get { return this.piece != null; }
+ }
+ }
+}
diff --git a/glines/src/glines-piece.vala b/glines/src/glines-piece.vala
new file mode 100644
index 0000000..77d5968
--- /dev/null
+++ b/glines/src/glines-piece.vala
@@ -0,0 +1,12 @@
+namespace Glines
+{
+ public class GlinesPiece
+ {
+ public int id { get; private set; }
+
+ public GlinesPiece(int id)
+ {
+ this.id = id;
+ }
+ }
+}
diff --git a/glines/src/glines-preview-queue.vala b/glines/src/glines-preview-queue.vala
new file mode 100644
index 0000000..eac7ff1
--- /dev/null
+++ b/glines/src/glines-preview-queue.vala
@@ -0,0 +1,30 @@
+using Gee;
+
+namespace Glines
+{
+ public class GlinesPreviewQueue
+ {
+ public ArrayList<GlinesPiece> pieces { get; set; }
+ private int size { get; set; }
+ private int types { get; set; }
+
+ public GlinesPreviewQueue(int size, int types)
+ {
+ this.pieces = new ArrayList<GlinesPiece>();
+ this.size = size;
+ this.types = types;
+ this.refill();
+ }
+
+ public void refill()
+ {
+ this.pieces.clear();
+
+ for (int i = 0; i < this.size; i++)
+ {
+ int id = Random.int_range(0, types - 1);
+ this.pieces.add(new GlinesPiece(id));
+ }
+ }
+ }
+}
diff --git a/glines/src/glines-view-cli.vala b/glines/src/glines-view-cli.vala
new file mode 100644
index 0000000..cd1efd8
--- /dev/null
+++ b/glines/src/glines-view-cli.vala
@@ -0,0 +1,144 @@
+using Gee;
+
+namespace Glines
+{
+ class ViewCli
+ {
+ private GlinesBoard board = new GlinesBoard(10, 10, 5, 2);
+
+ private bool gameover = false;
+ private string message = "";
+ private char[] id_to_char_symbol = { 'a', 'b', 'c', 'd', 'e' };
+
+ public ViewCli()
+ {
+ board.show_cursor = true;
+ board.place_cursor(5,5);
+
+ board.changed.connect ((o) => this.print(null));
+ board.move.connect ((o, path) => this.animate_move(path));
+ board.info.connect ((o, info) => message = info);
+ board.gameover.connect ((o) => this.gameover = true);
+
+ this.print(null);
+ }
+
+ public void run()
+ {
+ while (!gameover)
+ {
+ var c = stdin.getc();
+
+ if (c == 49) //southwest
+ board.move_cursor(-1, 1);
+
+ if (c == 50) //south
+ board.move_cursor(0, 1);
+
+ if (c == 51) //southeast
+ board.move_cursor(1, 1);
+
+ if (c == 52) //west
+ board.move_cursor(-1, 0);
+
+ if (c == 54) //east
+ board.move_cursor(1, 0);
+
+ if (c == 55) //northwest
+ board.move_cursor(-1, -1);
+
+ if (c == 56) //north
+ board.move_cursor(0, -1);
+
+ if (c == 57) //northeast
+ board.move_cursor(1, -1);
+
+ if (c == 53) //click
+ board.select_field(board.cursor_x, board.cursor_y);
+ }
+
+ stdout.printf("Game over.\n");
+ }
+
+ private void print(ArrayList<GlinesField>? path)
+ {
+ var sb = new StringBuilder();
+
+ sb.append("Preview: ");
+ foreach (var preview in board.preview_queue.pieces)
+ sb.append_c(id_to_char_symbol[preview.id]);
+ sb.append("\n\n");
+
+ for (int n = 0; n < board.cols + 2; n++)
+ sb.append("#");
+ sb.append("\n");
+
+ for (int y = 0; y < board.rows; y++)
+ {
+ sb.append("#");
+ for (int x = 0; x < board.cols; x++)
+ {
+ var field = board.fields[x,y];
+
+ bool is_cursor = board.cursor_x == x && board.cursor_y == y;
+
+ if (field.active)
+ {
+ sb.append("@");
+ continue;
+ }
+
+ if (!field.has_piece)
+ {
+ if (is_cursor) sb.append("Â");
+ else
+ {
+ if (path != null && field.path_search != null && path.contains(field))
+ {
+ if (field.path_search == field.neigbour_north)
+ sb.append("â");
+ if (field.path_search == field.neigbour_south)
+ sb.append("â");
+ if (field.path_search == field.neigbour_west)
+ sb.append("â");
+ if (field.path_search == field.neigbour_east)
+ sb.append("â");
+ }
+ else
+ sb.append(" ");
+ }
+ }
+ else
+ {
+ char symbol = id_to_char_symbol[field.piece.id];
+
+ if (is_cursor)
+ sb.append_c(symbol.toupper());
+ else
+ sb.append_c(symbol);
+ }
+ }
+
+ sb.append("#\n");
+ }
+
+ for (int n = 0; n < board.cols + 2; n++)
+ sb.append("#");
+
+ sb.append("\n\n");
+ sb.append(message);
+ sb.append("\n");
+
+ stdout.printf(sb.str);
+ }
+
+ private void animate_move(ArrayList<GlinesField> path)
+ {
+ //"animate" the move:
+ this.message = "'Animating' the move...";
+ this.print(path);
+ this.message = "";
+ stdin.getc();
+ }
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]