ref: a87bb0576073849b4d316e13132bb6c39c92e78d
parent: 3663603627809a11908dc1dfadd158cfde8e0672
author: Simon Tatham <[email protected]>
date: Sun Apr 25 16:15:22 EDT 2004
General further development. Sketched out the mid-end, added more GTK code, rudiments of event passing. [originally from svn r4141]
--- a/gtk.c
+++ b/gtk.c
@@ -41,6 +41,8 @@
*/
struct window_data {
GtkWidget *window;
+ GtkWidget *area;
+ midend_data *me;
};
static void destroy(GtkWidget *widget, gpointer data)
@@ -48,15 +50,52 @@
gtk_main_quit();
}
+gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+ struct window_data *wdata = (struct window_data *)data;
+
+ IGNORE(wdata);
+
+ if (!midend_process_key(wdata->me, 0, 0, event->keyval))
+ gtk_widget_destroy(wdata->window);
+
+ return TRUE;
+}
+
+gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ struct window_data *wdata = (struct window_data *)data;
+
+ IGNORE(wdata);
+
+ return TRUE;
+}
+
static struct window_data *new_window(void)
{
struct window_data *wdata;
+ int x, y;
wdata = snew(struct window_data);
+ wdata->me = midend_new();
+ midend_new_game(wdata->me, NULL);
+
wdata->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ wdata->area = gtk_drawing_area_new();
+ midend_size(wdata->me, &x, &y);
+ gtk_drawing_area_size(GTK_DRAWING_AREA(wdata->area), x, y);
+
+ gtk_container_add(GTK_CONTAINER(wdata->window), wdata->area);
+ gtk_widget_show(wdata->area);
+
gtk_signal_connect(GTK_OBJECT(wdata->window), "destroy",
GTK_SIGNAL_FUNC(destroy), wdata);
+ gtk_signal_connect(GTK_OBJECT(wdata->window), "key_press_event",
+ GTK_SIGNAL_FUNC(key_event), wdata);
+ gtk_signal_connect(GTK_OBJECT(wdata->area), "button_press_event",
+ GTK_SIGNAL_FUNC(button_event), wdata);
gtk_widget_show(wdata->window);
return wdata;
}
--- a/midend.c
+++ b/midend.c
@@ -4,3 +4,124 @@
* Maintains a move list, takes care of Undo and Redo commands, and
* processes standard keystrokes for undo/redo/new/restart/quit.
*/
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "puzzles.h"
+
+struct midend_data {
+ char *seed;
+ int nstates, statesize, statepos;
+ game_params *params;
+ game_state **states;
+};
+
+#define ensure(me) do { \
+ if ((me)->nstates >= (me)->statesize) { \
+ (me)->statesize = (me)->nstates + 128; \
+ (me)->states = sresize((me)->states, (me)->statesize, game_state *); \
+ } \
+} while (0)
+
+midend_data *midend_new(void)
+{
+ midend_data *me = snew(midend_data);
+
+ me->nstates = me->statesize = me->statepos = 0;
+ me->states = NULL;
+ me->params = default_params();
+ me->seed = NULL;
+
+ return me;
+}
+
+void midend_free(midend_data *me)
+{
+ sfree(me->states);
+ sfree(me->seed);
+ free_params(me->params);
+ sfree(me);
+}
+
+void midend_size(midend_data *me, int *x, int *y)
+{
+ game_size(me->params, x, y);
+}
+
+void midend_set_params(midend_data *me, game_params *params)
+{
+ free_params(me->params);
+ me->params = params;
+}
+
+void midend_new_game(midend_data *me, char *seed)
+{
+ while (me->nstates > 0)
+ free_game(me->states[--me->nstates]);
+
+ assert(me->nstates == 0);
+
+ sfree(me->seed);
+ if (seed)
+ me->seed = dupstr(seed);
+ else
+ me->seed = new_game_seed(me->params);
+
+ ensure(me);
+ me->states[me->nstates++] = new_game(me->params, me->seed);
+ me->statepos = 1;
+}
+
+void midend_restart_game(midend_data *me)
+{
+ while (me->nstates > 1)
+ free_game(me->states[--me->nstates]);
+ me->statepos = me->nstates;
+}
+
+void midend_undo(midend_data *me)
+{
+ if (me->statepos > 1)
+ me->statepos--;
+}
+
+void midend_redo(midend_data *me)
+{
+ if (me->statepos < me->nstates)
+ me->statepos++;
+}
+
+int midend_process_key(midend_data *me, int x, int y, int button)
+{
+ game_state *s;
+
+ if (button == 'n' || button == 'N' || button == '\x0E') {
+ midend_new_game(me, NULL);
+ return 1;
+ } else if (button == 'r' || button == 'R') {
+ midend_restart_game(me);
+ return 1;
+ } else if (button == 'u' || button == 'u' ||
+ button == '\x1A' || button == '\x1F') {
+ midend_undo(me);
+ return 1;
+ } else if (button == '\x12') {
+ midend_redo(me);
+ return 1;
+ } else if (button == 'q' || button == 'Q' || button == '\x11') {
+ return 0;
+ }
+
+ s = make_move(me->states[me->statepos-1], x, y, button);
+
+ if (s) {
+ while (me->nstates > me->statepos)
+ free_game(me->states[--me->nstates]);
+ ensure(me);
+ me->states[me->nstates] = s;
+ me->statepos = ++me->nstates;
+ }
+
+ return 1;
+}
--- a/net.c
+++ b/net.c
@@ -90,6 +90,26 @@
}
/* ----------------------------------------------------------------------
+ * Manage game parameters.
+ */
+game_params *default_params(void)
+{
+ game_params *ret = snew(game_params);
+
+ ret->width = 5;
+ ret->height = 5;
+ ret->wrapping = FALSE;
+ ret->barrier_probability = 0.0;
+
+ return ret;
+}
+
+void free_params(game_params *params)
+{
+ sfree(params);
+}
+
+/* ----------------------------------------------------------------------
* Randomly select a new game seed.
*/
@@ -511,8 +531,8 @@
/*
* The button must have been clicked on a valid tile.
*/
- x -= WINDOW_OFFSET;
- y -= WINDOW_OFFSET;
+ x -= WINDOW_OFFSET + TILE_BORDER;
+ y -= WINDOW_OFFSET + TILE_BORDER;
if (x < 0 || y < 0)
return NULL;
tx = x / TILE_SIZE;
@@ -585,6 +605,12 @@
/* ----------------------------------------------------------------------
* Routines for drawing the game position on the screen.
*/
+
+void game_size(game_params *params, int *x, int *y)
+{
+ *x = WINDOW_OFFSET * 2 + TILE_SIZE * params->width + TILE_BORDER;
+ *y = WINDOW_OFFSET * 2 + TILE_SIZE * params->height + TILE_BORDER;
+}
/* ----------------------------------------------------------------------
* Test code.
--- a/puzzles.h
+++ b/puzzles.h
@@ -20,6 +20,13 @@
RIGHT_BUTTON
};
+#define IGNORE(x) ( (x) = (x) )
+
+typedef struct midend_data midend_data;
+typedef struct random_state random_state;
+typedef struct game_params game_params;
+typedef struct game_state game_state;
+
/*
* Platform routines
*/
@@ -26,6 +33,19 @@
void fatal(char *fmt, ...);
/*
+ * midend.c
+ */
+midend_data *midend_new(void);
+void midend_free(midend_data *me);
+void midend_set_params(midend_data *me, game_params *params);
+void midend_size(midend_data *me, int *x, int *y);
+void midend_new_game(midend_data *me, char *seed);
+void midend_restart_game(midend_data *me);
+void midend_undo(midend_data *me);
+void midend_redo(midend_data *me);
+int midend_process_key(midend_data *me, int x, int y, int button);
+
+/*
* malloc.c
*/
void *smalloc(int size);
@@ -37,12 +57,11 @@
#define snewn(number, type) \
( (type *) smalloc ((number) * sizeof (type)) )
#define sresize(array, number, type) \
- ( (type *) srealloc ((array), (len) * sizeof (type)) )
+ ( (type *) srealloc ((array), (number) * sizeof (type)) )
/*
* random.c
*/
-typedef struct random_state random_state;
random_state *random_init(char *seed, int len);
unsigned long random_upto(random_state *state, unsigned long limit);
void random_free(random_state *state);
@@ -50,12 +69,13 @@
/*
* Game-specific routines
*/
-typedef struct game_params game_params;
-typedef struct game_state game_state;
+game_params *default_params(void);
+void free_params(game_params *params);
char *new_game_seed(game_params *params);
game_state *new_game(game_params *params, char *seed);
game_state *dup_game(game_state *state);
void free_game(game_state *state);
game_state *make_move(game_state *from, int x, int y, int button);
+void game_size(game_params *params, int *x, int *y);
#endif /* PUZZLES_PUZZLES_H */