Commit 2326bdfd authored by Colomban Wendling's avatar Colomban Wendling

Rewrite Stack in Vala

parent dfda4357
......@@ -8,7 +8,7 @@ libovcc_la_SOURCES = enumtypes.c \
game.c \
pawn.c \
player.c \
stack.c \
stack.vala \
tile.vala \
tileobject.vala \
tileset.c \
......@@ -19,7 +19,6 @@ ovccinclude_HEADERS = ovcc.h \
board.h \
game.h \
player.h \
stack.h \
tileset.h \
tilesdef.h
......
/*
*
* Copyright (C) 2009 Colomban Wendling <ban@herbesfolles.org>
* Jonathan Michalon <studios.chalmion@no-log.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
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "stack.h"
#include <glib.h>
#include <glib-object.h>
#include "tileset.h"
/**
* SECTION: stack
* @short_description: Stack for OVCC
* @include: libovcc/stack.h
*
* This is the API of the stack (where tiles will be picked up) for OVCC.
*
* Stack may generally only be created from the tileset module
* directly with ovcc_stack_new_from_tileset() or with ovcc_stack_new() then
* filled with ovcc_stack_fill(), even if they can be created and filled
* manually too, with ovcc_stack_new() followed by calls to ovcc_stack_add().
* This is because a stack is only designed to be the "game-time" data structure
* used to manage the game deck, and not the tile set itself.
* To get and remove the top tile (aka pop a tile), use ovcc_stack_pop().
*
* <example>
* <title>(Fictional) use of an #OVCCStack</title>
* <programlisting>
* void game (OVCCTileSet *set)
* {
* OVCCStack *stack;
* OVCCTile *tile;
*
* stack = ovcc_stack_new_from_tileset (set);
* while ((tile = ovcc_stack_pop ()) != NULL) {
* play_tile (tile);
* }
* g_object_unref (stack);
* }
* </programlisting>
* </example>
*
*/
struct _OVCCStackPrivate
{
GQueue *stack;
};
enum
{
SIGNAL_ITEM_ADDED,
SIGNAL_ITEM_REMOVED,
N_SIGNALS
};
enum
{
PROP_0,
PROP_SIZE
};
G_DEFINE_TYPE (OVCCStack, ovcc_stack, G_TYPE_OBJECT)
static guint ovcc_stack_signals[N_SIGNALS] = { 0 };
static void
ovcc_stack_finalize (GObject *object)
{
OVCCStack *stack = OVCC_STACK (object);
/* empty the remaining elements if any
* FIXME: perhaps we should warn/let the user choose what to do if the
* stack is not empty at free time? */
ovcc_stack_clear (stack);
g_queue_free (stack->priv->stack);
G_OBJECT_CLASS (ovcc_stack_parent_class)->finalize (object);
}
static void
ovcc_stack_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
OVCCStack *stack = OVCC_STACK (object);
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
ovcc_stack_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
OVCCStack *stack = OVCC_STACK (object);
switch (prop_id)
{
case PROP_SIZE:
g_value_set_uint (value, ovcc_stack_size (stack));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
ovcc_stack_init (OVCCStack *stack)
{
stack->priv = G_TYPE_INSTANCE_GET_PRIVATE (stack,
OVCC_TYPE_STACK,
OVCCStackPrivate);
stack->priv->stack = g_queue_new ();
}
static void
ovcc_stack_class_init (OVCCStackClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = ovcc_stack_finalize;
object_class->get_property = ovcc_stack_get_property;
object_class->set_property = ovcc_stack_set_property;
klass->item_added = NULL;
klass->item_removed = NULL;
g_object_class_install_property (object_class,
PROP_SIZE,
g_param_spec_uint ("size",
"Size",
"Stack size",
0,
G_MAXUINT,
0,
G_PARAM_READABLE));
/**
* OVCCStack::item-added:
* @stack: The object that received the signal
* @tile: The added tile
*
* This signal is emitted when a tile is added to the stack.
*/
ovcc_stack_signals[SIGNAL_ITEM_ADDED] =
g_signal_new ("item-added",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (OVCCStackClass, item_added),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
OVCC_TYPE_TILE);
/**
* OVCCStack::item-removed:
* @stack: The object that received the signal
* @tile: The removed tile
*
* This signal is emitted when a tile is removed from the stack
*/
ovcc_stack_signals[SIGNAL_ITEM_REMOVED] =
g_signal_new ("item-removed",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (OVCCStackClass, item_removed),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
OVCC_TYPE_TILE);
g_type_class_add_private (klass, sizeof (OVCCStackPrivate));
}
/**
* ovcc_stack_new:
*
* Creates a new Stack of tiles.
*
* Returns: The newly created #OVCCStack.
*/
OVCCStack *
ovcc_stack_new (void)
{
return g_object_new (OVCC_TYPE_STACK, NULL);
}
/**
* ovcc_stack_dump:
* @stack: An #OVCCStack to show.
*
* Outputs a representation of a stack, through the GLib's print
* handler. See manual of g_print() for more details.
*/
void
ovcc_stack_dump (OVCCStack *stack)
{
guint ntiles = g_queue_get_length (stack->priv->stack);
guint i;
g_print ("Current Stack's tile IDs:\n");
for (i = 0; i < ntiles; i++) {
g_print ("%d ", ovcc_tile_get_id (g_queue_peek_nth (stack->priv->stack, i)));
}
g_print ("\n");
}
/**
* ovcc_stack_is_empty:
* @stack: An #OVCCStack.
*
* Says whether a stack is empty.
*
* Returns: %TRUE if the stack is empty.
*/
gboolean
ovcc_stack_is_empty (OVCCStack *stack)
{
return g_queue_is_empty (stack->priv->stack);
}
/**
* ovcc_stack_size:
* @stack: An #OVCCStack.
*
* Gets the number of elements in an #OVCCStack.
*
* Returns: The number of elements in @stack.
*/
guint
ovcc_stack_size (const OVCCStack *stack)
{
return g_queue_get_length (stack->priv->stack);
}
/**
* ovcc_stack_new_from_tileset:
* @set: An #OVCCTileSet.
*
* Creates a new stack and fills it.
*
* Returns: The #OVCCStack, ready to use.
*/
OVCCStack *
ovcc_stack_new_from_tileset (OVCCTileSet *set)
{
OVCCStack *stack;
stack = ovcc_stack_new ();
if (stack) {
ovcc_stack_fill (stack, set);
}
return stack;
}
/**
* ovcc_stack_add_nth:
* @stack: An #OVCCStack
* @tile: An #OVCCTile
* @n: The position where insert @tile
*
* Inserts the given tile at the given position in the stack.
*/
static void
ovcc_stack_add_nth (OVCCStack *stack,
const OVCCTile *tile,
gint n)
{
g_queue_push_nth (stack->priv->stack, ovcc_tile_dup (tile), n);
}
/**
* ovcc_stack_add:
* @stack: The #OVCCStack to use.
* @tile: The #OVCCTile to add
*
* This function inserts the given tile at a random place in the stack.
* The inserted tile is copied, don't forget to release your reference if you
* want to leave the tile to the stack.
*/
void
ovcc_stack_add (OVCCStack *stack,
const OVCCTile *tile)
{
ovcc_stack_add_nth (stack, tile,
g_random_int_range (0, ovcc_stack_size (stack) + 1));
g_signal_emit (stack, ovcc_stack_signals[SIGNAL_ITEM_ADDED], 0, tile);
}
/**
* ovcc_stack_pop:
* @stack: An #OVCCStack to pop from.
*
* Pops a tile from the stack.
*
* Returns: The poped tile that should be unref'd when no longer needed, or
* %NULL if the stack is empty.
*/
OVCCTile *
ovcc_stack_pop (OVCCStack *stack)
{
OVCCTile *tile;
tile = g_queue_pop_head (stack->priv->stack);
if (tile) {
g_signal_emit (stack, ovcc_stack_signals[SIGNAL_ITEM_REMOVED], 0, tile);
}
return tile;
}
/**
* ovcc_stack_peek:
* @stack: An #OVCCStack to peek from.
*
* Peeks a tile from the stack.
*
* Returns: The tile on the top of the stack, or %NULL if the stack is empty.
* This tile should be unref'd when no longer needed.
*/
OVCCTile *
ovcc_stack_peek (OVCCStack *stack)
{
OVCCTile *tile;
tile = g_queue_peek_head (stack->priv->stack);
if (tile) {
g_object_ref (tile);
}
return tile;
}
static gboolean
tileset_foreach_cb_insert_random (OVCCTileSet *set G_GNUC_UNUSED,
OVCCTile *tile,
guint count,
gpointer data)
{
OVCCStack *stack = data;
guint i;
for (i = 0; i < count; i++) {
ovcc_stack_add (stack, tile);
}
return TRUE;
}
/**
* ovcc_stack_fill:
* @stack: The #OVCCStack to use.
* @set: The #OVCCTileSet to use.
*
* Fills a stack with the tiles of a tileset.
*
*/
void
ovcc_stack_fill (OVCCStack *stack,
OVCCTileSet *set)
{
OVCCTile *first;
ovcc_tileset_foreach (set, tileset_foreach_cb_insert_random, stack);
first = ovcc_tileset_get_first (set);
if (G_UNLIKELY (! first)) {
g_critical ("Given set has no first tile");
} else {
ovcc_stack_add_nth (stack, first, 0);
/*g_assert (g_queue_peek_head (stack->stack) == first);*/
}
}
/**
* ovcc_stack_clear:
* @stack: An #OVCCStack
*
* Removes all items in @stack.
*/
void
ovcc_stack_clear (OVCCStack *stack)
{
OVCCTile *tile;
while ((tile = ovcc_stack_pop (stack)) != NULL) {
g_object_unref (tile);
}
g_queue_clear (stack->priv->stack);
}
/*
*
* Copyright (C) 2009 Colomban Wendling <ban@herbesfolles.org>
* Jonathan Michalon <studios.chalmion@no-log.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
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef H_OVCC_STACK
#define H_OVCC_STACK
#include <glib.h>
#include <glib-object.h>
#include "tileset.h"
G_BEGIN_DECLS
#define OVCC_TYPE_STACK (ovcc_stack_get_type ())
#define OVCC_STACK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OVCC_TYPE_STACK, OVCCStack))
#define OVCC_IS_STACK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OVCC_TYPE_STACK))
#define OVCC_STACK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), OVCC_TYPE_STACK, OVCCStackClass))
#define OVCC_IS_STACK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OVCC_TYPE_STACK))
#define OVCC_STACK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OVCC_TYPE_STACK), OVCCStackClass)
typedef struct _OVCCStack OVCCStack;
typedef struct _OVCCStackPrivate OVCCStackPrivate;
typedef struct _OVCCStackClass OVCCStackClass;
/**
* OVCCStack:
*
* The object representing a stack.
*/
struct _OVCCStack
{
GObject parent_instance;
/*< private >*/
OVCCStackPrivate *priv;
};
struct _OVCCStackClass
{
GObjectClass parent_class;
void (*item_added) (OVCCStack *stack,
OVCCTile *tile);
void (*item_removed) (OVCCStack *stack,
OVCCTile *tile);
};
GType ovcc_stack_get_type (void) G_GNUC_CONST;
OVCCStack *ovcc_stack_new (void);
OVCCStack *ovcc_stack_new_from_tileset (OVCCTileSet *set);
void ovcc_stack_fill (OVCCStack *stack,
OVCCTileSet *set);
void ovcc_stack_add (OVCCStack *stack,
const OVCCTile *tile);
OVCCTile *ovcc_stack_pop (OVCCStack *stack);
OVCCTile *ovcc_stack_peek (OVCCStack *stack);
void ovcc_stack_dump (OVCCStack *stack);
gboolean ovcc_stack_is_empty (OVCCStack *stack);
guint ovcc_stack_size (const OVCCStack *stack);
void ovcc_stack_clear (OVCCStack *stack);
G_END_DECLS
#endif /* guard */
/*
*
* Copyright (C) 2009-2011 Colomban Wendling <ban@herbesfolles.org>
* Jonathan Michalon <studios.chalmion@no-log.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
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*
*/
namespace OVCC
{
public class TileSet : Object
{
public delegate void TileSetForach (TileSet ts, Tile t, int count);
public Tile first {get; set; }
public void foreach (TileSetForach f)
{
}
}
public class Stack : Object
{
private Queue<Tile> _stack = new Queue<Tile> ();
public uint size {
get {
return this._stack.length;
}
}
public signal void item_added (Tile t);
public signal void item_removed (Tile t);
public Stack ()
{
}
public Stack.from_tileset (TileSet ts)
{
this.fill (ts);
}
public void dump ()
{
stdout.printf ("Current stack tile IDs:\n");
foreach (var e in this._stack.head) {
stdout.printf (" %u\n", e.id);
}
}
public bool is_empty ()
{
return this._stack.is_empty ();
}
private void add_nth (Tile t,
int n)
{
this._stack.push_nth (t.dup (), n);
}
public void add (Tile t)
{
this.add_nth (t, Random.int_range (0, (int32)this.size + 1));
this.item_added (t);
this.notify_property ("size");
}
public Tile pop ()
{
var t = this._stack.pop_head ();
if (t != null) {
this.item_removed (t);
this.notify_property ("size");
}
return t;
}
public Tile peek ()
{
var t = this._stack.pop_head ();
if (t != null) {
t.ref ();
}
return t;
}
public void clear ()
{
this.freeze_notify ();
while (this.pop () != null);
this._stack.clear ();
this.freeze_notify ();
}
public void fill (TileSet ts)
{
this.freeze_notify ();
ts.foreach ((ts, t, count) => {
for (var i = 0; i < count; i++) {