chiark / gitweb /
Mouse-based interface for Cube: you left-click anywhere on the grid
authorSimon Tatham <anakin@pobox.com>
Tue, 31 May 2005 11:43:51 +0000 (11:43 +0000)
committerSimon Tatham <anakin@pobox.com>
Tue, 31 May 2005 11:43:51 +0000 (11:43 +0000)
and it moves the polyhedron in the general direction of the mouse
pointer. (I had this in my initial throwaway Python implementation
of this game, but never reimplemented it in this version. It's
harder with triangles, but not too much harder.)

Since the logical-to-physical coordinate mapping in Cube is
dynamically computed, this has involved an interface change which
touches all puzzles: make_move() is now passed a pointer to the
game_drawstate, which it may of course completely ignore if it
wishes.

[originally from svn r5877]

13 files changed:
cube.c
fifteen.c
midend.c
mines.c
net.c
netslide.c
nullgame.c
pattern.c
puzzles.h
rect.c
sixteen.c
solo.c
twiddle.c

diff --git a/cube.c b/cube.c
index 2bce1bdf392516c3facfde5e9b47b1c27df82bbe..bf24960c53741d487a446fe88f89f3f21baf5ef0 100644 (file)
--- a/cube.c
+++ b/cube.c
@@ -11,6 +11,8 @@
 
 #include "puzzles.h"
 
+#define PI 3.14159265358979323846264338327950884197169399
+
 #define MAXVERTICES 20
 #define MAXFACES 20
 #define MAXORDER 4
@@ -1002,7 +1004,11 @@ static void free_ui(game_ui *ui)
 {
 }
 
-static game_state *make_move(game_state *from, game_ui *ui,
+struct game_drawstate {
+    int ox, oy;                        /* pixel position of float origin */
+};
+
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
                             int x, int y, int button)
 {
     int direction;
@@ -1016,7 +1022,9 @@ static game_state *make_move(game_state *from, game_ui *ui,
     button = button & (~MOD_MASK | MOD_NUM_KEYPAD);
 
     /*
-     * All moves are made with the cursor keys or numeric keypad.
+     * Moves can be made with the cursor keys or numeric keypad, or
+     * alternatively you can left-click and the polyhedron will
+     * move in the general direction of the mouse pointer.
      */
     if (button == CURSOR_UP || button == (MOD_NUM_KEYPAD | '8'))
         direction = UP;
@@ -1034,7 +1042,69 @@ static game_state *make_move(game_state *from, game_ui *ui,
         direction = UP_RIGHT;
     else if (button == (MOD_NUM_KEYPAD | '3'))
         direction = DOWN_RIGHT;
-    else
+    else if (button == LEFT_BUTTON) {
+        /*
+         * Find the bearing of the click point from the current
+         * square's centre.
+         */
+        int cx, cy;
+        double angle;
+
+        cx = from->squares[from->current].x * GRID_SCALE + ds->ox;
+        cy = from->squares[from->current].y * GRID_SCALE + ds->oy;
+
+        if (x == cx && y == cy)
+            return NULL;               /* clicked in exact centre!  */
+        angle = atan2(y - cy, x - cx);
+
+        /*
+         * There are three possibilities.
+         * 
+         *  - This square is a square, so we choose between UP,
+         *    DOWN, LEFT and RIGHT by dividing the available angle
+         *    at the 45-degree points.
+         * 
+         *  - This square is an up-pointing triangle, so we choose
+         *    between DOWN, LEFT and RIGHT by dividing into
+         *    120-degree arcs.
+         * 
+         *  - This square is a down-pointing triangle, so we choose
+         *    between UP, LEFT and RIGHT in the inverse manner.
+         * 
+         * Don't forget that since our y-coordinates increase
+         * downwards, `angle' is measured _clockwise_ from the
+         * x-axis, not anticlockwise as most mathematicians would
+         * instinctively assume.
+         */
+        if (from->squares[from->current].npoints == 4) {
+            /* Square. */
+            if (fabs(angle) > 3*PI/4)
+                direction = LEFT;
+            else if (fabs(angle) < PI/4)
+                direction = RIGHT;
+            else if (angle > 0)
+                direction = DOWN;
+            else
+                direction = UP;
+        } else if (from->squares[from->current].directions[UP] == 0) {
+            /* Up-pointing triangle. */
+            if (angle < -PI/2 || angle > 5*PI/6)
+                direction = LEFT;
+            else if (angle > PI/6)
+                direction = DOWN;
+            else
+                direction = RIGHT;
+        } else {
+            /* Down-pointing triangle. */
+            assert(from->squares[from->current].directions[DOWN] == 0);
+            if (angle > PI/2 || angle < -5*PI/6)
+                direction = LEFT;
+            else if (angle < -PI/6)
+                direction = UP;
+            else
+                direction = RIGHT;
+        }
+    } else
         return NULL;
 
     /*
@@ -1288,10 +1358,6 @@ struct bbox {
     float l, r, u, d;
 };
 
-struct game_drawstate {
-    int ox, oy;                        /* pixel position of float origin */
-};
-
 static void find_bbox_callback(void *ctx, struct grid_square *sq)
 {
     struct bbox *bb = (struct bbox *)ctx;
index e7a41ef32fcdbdd21749c3bf1965e6579043bce3..49a31183dc8b18cd913476fe37ea8775de1e1dba 100644 (file)
--- a/fifteen.c
+++ b/fifteen.c
@@ -450,9 +450,8 @@ static void free_ui(game_ui *ui)
 {
 }
 
-static game_state *make_move(game_state *from, game_ui *ui,
-                            int x, int y, int button)
-{
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button) {
     int gx, gy, dx, dy, ux, uy, up, p;
     game_state *ret;
 
index de20e147301bf9d868b257ae2a37a080d05abf9d..1def04167a7b54b624a222c290095ee7eb908730 100644 (file)
--- a/midend.c
+++ b/midend.c
@@ -325,7 +325,7 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button)
     } else {
         game_state *s =
             me->ourgame->make_move(me->states[me->statepos-1].state,
-                                   me->ui, x, y, button);
+                                   me->ui, me->drawstate, x, y, button);
 
         if (s == me->states[me->statepos-1].state) {
             /*
diff --git a/mines.c b/mines.c
index 10ca76c3c87d44f5b1a40d6c5a0fc3577cc87991..40062942abbd66708586c494b05efa45db02f25d 100644 (file)
--- a/mines.c
+++ b/mines.c
@@ -2229,8 +2229,8 @@ static void free_ui(game_ui *ui)
     sfree(ui);
 }
 
-static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
-                            int button)
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button)
 {
     game_state *ret;
     int cx, cy;
diff --git a/net.c b/net.c
index a2204c0be04f030744dc2656c721e418dc11be82..447f4e30a18034ed607abe97b8ec868f17733146 100644 (file)
--- a/net.c
+++ b/net.c
@@ -1798,8 +1798,7 @@ static void free_ui(game_ui *ui)
  * Process a move.
  */
 static game_state *make_move(game_state *state, game_ui *ui,
-                            int x, int y, int button)
-{
+                             game_drawstate *ds, int x, int y, int button) {
     game_state *ret, *nullret;
     int tx, ty, orig;
     int shift = button & MOD_SHFT, ctrl = button & MOD_CTRL;
index 324946ee216ed91105f6fcb650b10f263d8e23cc..b81a816703081d4b9c63dad0b3ba8753e6fc4bbc 100644 (file)
@@ -1051,7 +1051,7 @@ static void slide_col(game_state *state, int dir, int col)
 }
 
 static game_state *make_move(game_state *state, game_ui *ui,
-                            int x, int y, int button)
+                             game_drawstate *ds, int x, int y, int button)
 {
     int cx, cy;
     int n, dx, dy;
index 3ec6b7555fae88868ba06c79e2579bda5ca0e4b5..56694de8dd3a0f9dba8e061ee87a4d78ca6fa784 100644 (file)
@@ -142,8 +142,8 @@ static void free_ui(game_ui *ui)
 {
 }
 
-static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
-                            int button)
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button)
 {
     return NULL;
 }
index 419e4aa7fdfdf5dafbe48a8148c0ef8cc8db0358..4cd366924b30a74cfe964e39dba735f443287f38 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -764,9 +764,8 @@ static void free_ui(game_ui *ui)
     sfree(ui);
 }
 
-static game_state *make_move(game_state *from, game_ui *ui,
-                            int x, int y, int button)
-{
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button) {
     game_state *ret;
 
     button &= ~MOD_MASK;
index bf441c6b7ad5f1e02ba5a7ec4d08f39c01c66341..de0f81971d50a44da7cb67161fa1c42e4dd3edb6 100644 (file)
--- a/puzzles.h
+++ b/puzzles.h
@@ -227,8 +227,8 @@ struct game {
     char *(*text_format)(game_state *state);
     game_ui *(*new_ui)(game_state *state);
     void (*free_ui)(game_ui *ui);
-    game_state *(*make_move)(game_state *from, game_ui *ui, int x, int y,
-                            int button);
+    game_state *(*make_move)(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button);
     void (*size)(game_params *params, int *x, int *y);
     float *(*colours)(frontend *fe, game_state *state, int *ncolours);
     game_drawstate *(*new_drawstate)(game_state *state);
diff --git a/rect.c b/rect.c
index c1eaa2c25c63dc2de06ce424714f8bd1c1b88838..9e4204d46469fe8cb89acbe35f1e53ec531453e2 100644 (file)
--- a/rect.c
+++ b/rect.c
@@ -2178,9 +2178,8 @@ static void ui_draw_rect(game_state *state, game_ui *ui,
             }
 }
 
-static game_state *make_move(game_state *from, game_ui *ui,
-                            int x, int y, int button)
-{
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button) {
     int xc, yc;
     int startdrag = FALSE, enddrag = FALSE, active = FALSE;
     game_state *ret;
index c6664c138720ff8bdf0794ff1dd8b6b4dd2189cb..c202de1f129dfddb9aec946a87ec5298197cd21f 100644 (file)
--- a/sixteen.c
+++ b/sixteen.c
@@ -577,9 +577,8 @@ static void free_ui(game_ui *ui)
 {
 }
 
-static game_state *make_move(game_state *from, game_ui *ui,
-                            int x, int y, int button)
-{
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button) {
     int cx, cy;
     int dx, dy, tx, ty, n;
     game_state *ret;
diff --git a/solo.c b/solo.c
index 168551c4ed6219808adc6e42afb7a57d058084cd..f3afb02cb687091ed425a316dcc721f42ec6e9bb 100644 (file)
--- a/solo.c
+++ b/solo.c
@@ -1821,8 +1821,8 @@ static void free_ui(game_ui *ui)
     sfree(ui);
 }
 
-static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
-                            int button)
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button)
 {
     int c = from->c, r = from->r, cr = c*r;
     int tx, ty;
index f7bfd4a6e3b339452bb0e6979e2af4dbece121d3..273ce8c5c58af19937cc0e0b580af682bb2496f0 100644 (file)
--- a/twiddle.c
+++ b/twiddle.c
@@ -618,8 +618,8 @@ static void free_ui(game_ui *ui)
 {
 }
 
-static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
-                            int button)
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button)
 {
     int w = from->w, h = from->h, n = from->n, wh = w*h;
     game_state *ret;