shithub: puzzles

Download patch

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 */