]> git.cworth.org Git - dvonn/blobdiff - dvonn.c
Add display of stack height and implement movement
[dvonn] / dvonn.c
diff --git a/dvonn.c b/dvonn.c
index e19ea437e435ee262c3a1407641e095c6888e528..1442923c0acf27243f9ce42fc6de2766abb453bf 100644 (file)
--- a/dvonn.c
+++ b/dvonn.c
  * Author: Carl Worth <cworth@cworth.org>
  */
 
+#define _GNU_SOURCE /* for vasprintf */
+#include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <gtk/gtk.h>
 #include <math.h>
 
@@ -50,6 +53,8 @@ struct _dvonn_game {
     dvonn_bool_t has_selected;
     int selected_x;
     int selected_y;
+
+    PangoFontDescription *font;
 };
 
 static gboolean
@@ -66,9 +71,11 @@ on_delete_event_quit (GtkWidget  *widget,
 
 /* Something like buff */
 #define BACKGROUND_COLOR 0.89, 0.70, 0.40
-#define LIGHT_SQUARE_COLOR 0.89, 0.70, 0.40
-/* Something like mahogany */
-#define DARK_SQUARE_COLOR  0.26, 0.02, 0.01
+
+/* Relative to a unit square. */
+#define RING_OUTER_RADIUS 0.4
+#define RING_INNER_RADIUS 0.2
+#define FONT_SIZE (RING_INNER_RADIUS * 1.5)
 
 /* XXX: This really should have an interest rectangle. */
 static void
@@ -163,14 +170,17 @@ on_button_press_event (GtkWidget  *widget,
     if (game->board.cells[x][y].type == DVONN_CELL_INVALID)
        return TRUE;
 
-    if (game->board.cells[x][y].type == DVONN_CELL_EMPTY)
-       game->board.cells[x][y].type = DVONN_CELL_WHITE;
-    else if (game->board.cells[x][y].type == DVONN_CELL_WHITE)
-       game->board.cells[x][y].type = DVONN_CELL_EMPTY;
-
-    dvonn_game_update_windows (game);
+    if (game->board.phase == DVONN_PHASE_PLACEMENT) {
+       if (dvonn_board_place (&game->board, x, y, &error))
+           dvonn_game_update_windows (game);
+       else
+           printf ("Illegal placement %c%d: %s\n",
+                   'a' + x,
+                   y + 1,
+                   error);
 
-    return TRUE;
+       return TRUE;
+    }
 
     if (! game->has_selected) {
        if (game->board.cells[x][y].type == game->board.player) {
@@ -182,8 +192,7 @@ on_button_press_event (GtkWidget    *widget,
        return TRUE;
     }
 
-    if (x == game->selected_x &&
-       y == game->selected_y)
+    if (x == game->selected_x && y == game->selected_y)
     {
        game->has_selected = FALSE;
        dvonn_game_update_windows (game);
@@ -200,9 +209,9 @@ on_button_press_event (GtkWidget    *widget,
     } else {
        printf ("Illegal move %c%d%c%d: %s\n",
                'a' + game->selected_x,
-               DVONN_BOARD_Y_SIZE - game->selected_y,
+               game->selected_y + 1,
                'a' + x,
-               DVONN_BOARD_Y_SIZE - y,
+               y + 1,
                error);
     }
 
@@ -213,8 +222,73 @@ on_button_press_event (GtkWidget   *widget,
 static void
 ring_path (cairo_t *cr)
 {
-    cairo_arc (cr, 0.5, 0.5, 0.4, 0, 2 * M_PI);
-    cairo_arc_negative (cr, 0.5, 0.5, 0.2, 2 * M_PI, 0);
+    cairo_new_sub_path (cr);
+    cairo_arc (cr, 0.5, 0.5, RING_OUTER_RADIUS, 0, 2 * M_PI);
+    cairo_arc_negative (cr, 0.5, 0.5, RING_INNER_RADIUS, 2 * M_PI, 0);
+}
+
+/* Some helper functions for using pango. */
+static PangoLayout *
+_create_layout (cairo_t *cr, PangoFontDescription *font, const char *text)
+{
+    PangoLayout *layout;
+
+    layout = pango_cairo_create_layout (cr);
+    pango_layout_set_font_description (layout, font);
+    pango_layout_set_text (layout, text, -1);
+    pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
+
+    return layout;
+}
+
+#define PRINTF_FORMAT(fmt_index, va_index) __attribute__ ((__format__(__printf__, fmt_index, va_index)))
+
+static PangoLayout *
+_create_layout_vprintf (cairo_t *cr, PangoFontDescription *font, const char *fmt, va_list ap)
+{
+    PangoLayout *layout;
+    char *text;
+
+    vasprintf (&text, fmt, ap);
+
+    layout = _create_layout (cr, font, text);
+
+    free (text);
+
+    return layout;
+}
+
+static PangoLayout *
+_create_layout_printf (cairo_t *cr, PangoFontDescription *font, const char *fmt, ...)
+    PRINTF_FORMAT (3, 4);
+
+static PangoLayout *
+_create_layout_printf (cairo_t *cr, PangoFontDescription *font, const char *fmt, ...)
+{
+    va_list ap;
+    PangoLayout *layout;
+
+    va_start (ap, fmt);
+
+    layout = _create_layout_vprintf (cr, font, fmt, ap);
+
+    va_end (ap);
+
+    return layout;
+}
+
+static void
+_destroy_layout (PangoLayout *layout)
+{
+    g_object_unref (layout);
+}
+
+static void
+_show_layout (cairo_t *cr, PangoLayout *layout)
+{
+    pango_cairo_show_layout (cr, layout);
+
+    _destroy_layout (layout);
 }
 
 static gboolean
@@ -247,10 +321,17 @@ on_expose_event_draw (GtkWidget           *widget,
 
        layout->x_offset = (layout->width - x_size) / 2;
        layout->y_offset = (layout->height - y_size) / 2;
+
+       if (game->font == NULL) {
+           game->font = pango_font_description_new ();
+           pango_font_description_set_family (game->font, "sans");
+       }
+       pango_font_description_set_absolute_size (game->font,
+                                                 FONT_SIZE * PANGO_SCALE);
     }
 
     cr = gdk_cairo_create (widget->window);
-    
+
     cairo_set_source_rgb (cr, BACKGROUND_COLOR);
     cairo_paint (cr);
 
@@ -270,12 +351,40 @@ on_expose_event_draw (GtkWidget           *widget,
                            x + (y - DVONN_BOARD_Y_SIZE/2) / 2.0,
                            M_SQRT1_2 * y);
            ring_path (cr);
-           if (cell.type == DVONN_CELL_WHITE)
+           switch (cell.type) {
+           case DVONN_CELL_WHITE:
                cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
-           else
+               break;
+           case DVONN_CELL_BLACK:
+               cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+               break;
+           case DVONN_CELL_RED:
+               cairo_set_source_rgb (cr, 0.8, 0.2, 0.2); /* red */
+               break;
+           case DVONN_CELL_EMPTY:
+           default:
                cairo_set_source_rgba (cr, 0.0, 0.0, 0.2, 0.1);
+               break;
+           }
+           if (game->has_selected &&
+               x == game->selected_x &&
+               y == game->selected_y)
+           {
+               cairo_fill_preserve (cr);
+               cairo_set_source_rgba (cr, 0.2, 0.2, 1.0, 0.4);
+           }
            cairo_fill (cr);
 
+           if (game->board.cells[x][y].height) {
+               PangoLayout *height;
+               cairo_move_to (cr,
+                              0.5 - 0.8 * RING_INNER_RADIUS * cos (M_PI_4),
+                              0.5 - 1.2 * RING_INNER_RADIUS * sin (M_PI_4));
+               height = _create_layout_printf (cr, game->font, "%d",
+                                               game->board.cells[x][y].height);
+               _show_layout (cr, height);
+           }
+
            cairo_restore (cr);
        }
     }
@@ -294,6 +403,8 @@ dvonn_game_init (dvonn_game_t *game)
     game->has_selected = FALSE;
 
     dvonn_board_init (&game->board);
+
+    game->font = NULL;
 }
 
 static void