]> git.cworth.org Git - dvonn/blobdiff - dvonn.c
Implement automatic pass (when there is no legal move) and end-of-game
[dvonn] / dvonn.c
diff --git a/dvonn.c b/dvonn.c
index 94146ce00c19df6418791f4910b14ece75e3512a..c1762ed19be159f67832ce71fe032e85e0331ee0 100644 (file)
--- a/dvonn.c
+++ b/dvonn.c
@@ -55,6 +55,10 @@ struct _dvonn_game {
     int selected_y;
 
     PangoFontDescription *font;
+    PangoFontDescription *ring_font;
+
+    dvonn_bool_t dual_window_mode;
+    GtkWidget *windows[2];
 };
 
 static gboolean
@@ -74,10 +78,13 @@ on_delete_event_quit (GtkWidget  *widget,
 
 #define RED_RING_COLOR 0.8, 0.2, 0.2
 
+#define DVONN_FONT "sans"
+#define DVONN_FONT_SIZE 12
+
 /* 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)
+#define RING_FONT_SIZE (RING_INNER_RADIUS * 1.5)
 
 /* XXX: This really should have an interest rectangle. */
 static void
@@ -157,16 +164,18 @@ on_button_press_event (GtkWidget  *widget,
     int x, y;
     char *error;
 
-    /* Ignore double and triple clicks. */
-    if (event->type >= GDK_2BUTTON_PRESS)
+    /* Ignore events from the non-player. (Obviously when we add more
+     * interaction abilities, we will want to allow those even for the
+     * non-player---things like quit, etc.). */
+    if (game->dual_window_mode &&
+       widget->parent != game->windows[game->board.player])
+    {
        return TRUE;
+    }
 
-    /* Right-click means pass, (yes, it would be better to add some
-     * actual UI elements... */
-    if (event->button == 3) {
-       dvonn_board_pass (&game->board);
+    /* Ignore double and triple clicks. */
+    if (event->type >= GDK_2BUTTON_PRESS)
        return TRUE;
-    }
 
     x = event->x;
     y = event->y;
@@ -196,7 +205,7 @@ on_button_press_event (GtkWidget    *widget,
     }
 
     if (! game->has_selected) {
-       if (game->board.cells[x][y].type == game->board.player &&
+       if (dvonn_board_cell_owned_by (&game->board, x, y, game->board.player) &&
            ! dvonn_board_cell_surrounded (&game->board, x, y))
            {
                    game->has_selected = TRUE;
@@ -213,7 +222,7 @@ on_button_press_event (GtkWidget    *widget,
        dvonn_game_update_windows (game);
        return TRUE;
     }
-       
+
     if (dvonn_board_move (&game->board,
                          game->selected_x, game->selected_y,
                          x, y, &error))
@@ -316,6 +325,7 @@ on_expose_event_draw (GtkWidget             *widget,
     dvonn_game_t *game = view->game;
     cairo_t *cr;
     int x, y;
+    PangoLayout *to_move;
 
     if (layout->width != widget->allocation.width ||
        layout->height != widget->allocation.height)
@@ -337,12 +347,13 @@ 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");
+       if (game->ring_font == NULL) {
+           game->ring_font = pango_font_description_new ();
+           pango_font_description_set_family (game->ring_font,
+                                              DVONN_FONT);
        }
-       pango_font_description_set_absolute_size (game->font,
-                                                 FONT_SIZE * PANGO_SCALE);
+       pango_font_description_set_absolute_size (game->ring_font,
+                                                 RING_FONT_SIZE * PANGO_SCALE);
     }
 
     cr = gdk_cairo_create (widget->window);
@@ -350,6 +361,51 @@ on_expose_event_draw (GtkWidget            *widget,
     cairo_set_source_rgb (cr, BACKGROUND_COLOR);
     cairo_paint (cr);
 
+    if (game->font == NULL) {
+       game->font = pango_font_description_new ();
+       pango_font_description_set_family (game->font, DVONN_FONT);
+       pango_font_description_set_absolute_size (game->font, DVONN_FONT_SIZE * PANGO_SCALE);
+    }
+    if (game->board.phase == DVONN_PHASE_GAME_OVER) {
+       if (game->board.score[DVONN_PLAYER_WHITE] >
+           game->board.score[DVONN_PLAYER_BLACK])
+       {
+           to_move = _create_layout_printf (cr, game->font,
+                                            "White wins (%d to %d)\n",
+                                            game->board.score[DVONN_PLAYER_WHITE],
+                                            game->board.score[DVONN_PLAYER_BLACK]);
+       }
+       else if  (game->board.score[DVONN_PLAYER_BLACK] >
+                 game->board.score[DVONN_PLAYER_WHITE])
+       {
+           to_move = _create_layout_printf (cr, game->font,
+                                            "Black wins (%d to %d)\n",
+                                            game->board.score[DVONN_PLAYER_BLACK],
+                                            game->board.score[DVONN_PLAYER_WHITE]);
+       }
+       else
+       {
+           to_move = _create_layout_printf (cr, game->font,
+                                            "Tie game (%d to %d)\n",
+                                            game->board.score[DVONN_PLAYER_WHITE],
+                                            game->board.score[DVONN_PLAYER_BLACK]);
+
+       }
+    } else {
+       to_move = _create_layout_printf (cr, game->font,
+                                        "%s to %s.",
+                                        game->board.player == DVONN_PLAYER_WHITE ?
+                                        "White" : "Black",
+                                        game->board.phase == DVONN_PHASE_PLACEMENT ?
+                                        "place" : "move");
+    }
+    cairo_move_to (cr, 2, 2);
+    if (game->board.player == DVONN_PLAYER_WHITE)
+       cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+    else
+       cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+    _show_layout (cr, to_move);
+
     cairo_translate (cr, layout->x_offset, layout->y_offset);
     cairo_scale (cr, layout->cell_size, layout->cell_size);
 
@@ -403,7 +459,7 @@ on_expose_event_draw (GtkWidget             *widget,
                cairo_move_to (cr,
                               0.5 - 0.7 * 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",
+               height = _create_layout_printf (cr, game->ring_font, "%d",
                                                game->board.cells[x][y].height);
                _show_layout (cr, height);
            }
@@ -428,6 +484,11 @@ dvonn_game_init (dvonn_game_t *game)
     dvonn_board_init (&game->board);
 
     game->font = NULL;
+    game->ring_font = NULL;
+
+    game->dual_window_mode = 0;
+    game->windows[0] = NULL;
+    game->windows[1] = NULL;
 }
 
 static void
@@ -440,7 +501,7 @@ view_init (view_t *view, dvonn_game_t *game, GtkWidget *window)
     view->layout.height = 0;
 }
 
-static void
+static GtkWidget*
 dvonn_game_create_view (dvonn_game_t *game)
 {
     view_t *view;
@@ -483,20 +544,50 @@ dvonn_game_create_view (dvonn_game_t *game)
                      G_CALLBACK (on_button_press_event), view);
 
     gtk_widget_show_all (window);
+
+    return window;
 }
 
 int
 main (int argc, char *argv[])
 {
+    GtkWidget *window0, *window1;
+    GdkDisplay *display;
+    GdkScreen *screen;
     dvonn_game_t game;
 
     dvonn_game_init (&game);
 
     gtk_init (&argc, &argv);
 
-    /* Create two views of the game (one for each player) */
-    dvonn_game_create_view (&game);
-    dvonn_game_create_view (&game);
+    /* Create a view for player 1. */
+    window0 = dvonn_game_create_view (&game);
+
+    /* Ugly little hack to get Xauthority data from keithp. Obviously
+     * won't work for any other user.
+     *
+    setenv ("XAUTHORITY", "/home/keithp/.Xauthority", 1);
+    */
+
+    /* Also ugly that localhost:10.0 is hard-coded, but this will work
+     * for many situations--both for when keithp attaches to my
+     * machine, and for when I connect to anyone's machine and then
+     * connect back, (assuming I haven't made other X forwardings
+     * first).
+     *
+     * Clearly we'll want some actual UI to select the right thing
+     * here.
+     */
+    display = gdk_display_open ("localhost:10.0");
+    if (display) {
+       screen = gdk_display_get_default_screen (display);
+       window1 = dvonn_game_create_view (&game);
+       gtk_window_set_screen (GTK_WINDOW (window1), screen);
+
+       game.dual_window_mode = 1;
+       game.windows[0] = window0;
+       game.windows[1] = window1;
+    }
     
     gtk_main ();