Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  sliding_puzzle.c

  Sprache: C
 

/* Sliding Puzzle
 * #Keywords: GdkPaintable, GdkGesture, GtkShortcutController, game
 *
 * This demo demonstrates how to use gestures and paintables to create a
 * small sliding puzzle game.
 */


#include "config.h"
#include <gtk/gtk.h>

/* Include the header for the puzzle piece */
#include "puzzlepiece.h"
#include "paintable.h"


static GtkWidget *window = NULL;
static GtkWidget *frame = NULL;
static GtkWidget *choices = NULL;
static GtkWidget *size_spin = NULL;
static GdkPaintable *puzzle = NULL;

static gboolean solved = TRUE;
static guint width = 3;
static guint height = 3;
static guint pos_x;
static guint pos_y;

static void
ended (GObject *object)
{
  g_object_unref (object);
}

static void
celebrate (gboolean win)
{
  char *path;
  GtkMediaStream *stream;

  if (win)
    path = g_build_filename (GTK_DATADIR, "sounds""freedesktop""stereo""complete.oga", NULL);
  else
    path = g_build_filename (GTK_DATADIR, "sounds""freedesktop""stereo""suspend-error.oga", NULL);
  stream = gtk_media_file_new_for_filename (path);
  gtk_media_stream_set_volume (stream, 1.0);
  gtk_media_stream_play (stream);

  g_signal_connect (stream, "notify::ended", G_CALLBACK (ended), NULL);
  g_free (path);
}

static gboolean
move_puzzle (GtkWidget *grid,
             int        dx,
             int        dy)
{
  GtkWidget *pos, *next;
  GdkPaintable *piece;
  guint next_x, next_y;

  /* We don't move anything if the puzzle is solved */
  if (solved)
    return FALSE;

  /* Return FALSE if we can't move to where the call 
   * wants us to move.
   */

  if ((dx < 0 && pos_x < -dx) ||
      dx + pos_x >= width ||
      (dy < 0 && pos_y < -dy) ||
      dy + pos_y >= height)
    return FALSE;

  /* Compute the new position */
  next_x = pos_x + dx;
  next_y = pos_y + dy;

  /* Get the current and next image */
  pos = gtk_grid_get_child_at (GTK_GRID (grid), pos_x, pos_y);
  next = gtk_grid_get_child_at (GTK_GRID (grid), next_x, next_y);

  /* Move the displayed piece. */
  piece = gtk_picture_get_paintable (GTK_PICTURE (next));
  gtk_picture_set_paintable (GTK_PICTURE (pos), piece);
  gtk_picture_set_paintable (GTK_PICTURE (next), NULL);

  /* Update the current position */
  pos_x = next_x;
  pos_y = next_y;

  /* Return TRUE because we successfully moved the piece */
  return TRUE;
}

static void
shuffle_puzzle (GtkWidget *grid)
{
  guint i, n_steps;

  /* Do this many random moves */
  n_steps = width * height * 50;

  for (i = 0; i < n_steps; i++)
    {
      /* Get a random number for the direction to move in */
      switch (g_random_int_range (04))
        {
        case 0:
          /* left */
          move_puzzle (grid, -10);
          break;

        case 1:
          /* up */
          move_puzzle (grid, 0, -1);
          break;

        case 2:
          /* right */
          move_puzzle (grid, 10);
          break;

        case 3:
          /* down */
          move_puzzle (grid, 01);
          break;

        default:
          g_assert_not_reached ();
          continue;
        }
    }
}

static gboolean
check_solved (GtkWidget *grid)
{
  GtkWidget *picture;
  GdkPaintable *piece;
  guint x, y;

  /* Nothing to check if the puzzle is already solved */
  if (solved)
    return TRUE;

  /* If the empty cell isn't in the bottom right,
   * the puzzle is obviously not solved */

  if (pos_x != width - 1 ||
      pos_y != height - 1)
    return FALSE;

  /* Check that all pieces are in the right position */
  for (y = 0; y < height; y++)
    {
      for (x = 0; x < width; x++)
        {
          picture = gtk_grid_get_child_at (GTK_GRID (grid), x, y);
          piece = gtk_picture_get_paintable (GTK_PICTURE (picture));

          /* empty cell */
          if (piece == NULL)
            continue;

          if (gtk_puzzle_piece_get_x (GTK_PUZZLE_PIECE (piece)) != x ||
              gtk_puzzle_piece_get_y (GTK_PUZZLE_PIECE (piece)) != y)
            return FALSE;
        }
    }

  /* We solved the puzzle!
   */

  solved = TRUE;

  /* Fill the empty cell to show that we're done.
   */

  picture = gtk_grid_get_child_at (GTK_GRID (grid), 00);
  piece = gtk_picture_get_paintable (GTK_PICTURE (picture));

  piece = gtk_puzzle_piece_new (gtk_puzzle_piece_get_puzzle (GTK_PUZZLE_PIECE (piece)),
                                pos_x, pos_y,
                                width, height);
  picture = gtk_grid_get_child_at (GTK_GRID (grid), pos_x, pos_y);
  gtk_picture_set_paintable (GTK_PICTURE (picture), piece);

  celebrate (TRUE);

  return TRUE;
}

static gboolean
puzzle_key_pressed (GtkWidget *grid,
                    GVariant  *args,
                    gpointer   unused)
{
  int dx, dy;

  g_variant_get (args, "(ii)", &dx, &dy);

  if (!move_puzzle (grid, dx, dy))
    {
      /* Make the error sound and then return TRUE.
       * We handled this key, even though we didn't
       * do anything to the puzzle.
       */

      gtk_widget_error_bell (grid);
      return TRUE;
    }

  check_solved (grid);

  return TRUE;
}

static void
puzzle_button_pressed (GtkGestureClick *gesture,
                       int              n_press,
                       double           x,
                       double           y,
                       GtkWidget       *grid)
{
  GtkWidget *child;
  int l, t, i;
  int pos;

  child = gtk_widget_pick (grid, x, y, GTK_PICK_DEFAULT);

  if (!child)
    {
      gtk_widget_error_bell (grid);
      return;
    }

  gtk_grid_query_child (GTK_GRID (grid), child, &l, &t, NULL, NULL);

  if (l == pos_x && t == pos_y)
    {
      gtk_widget_error_bell (grid);
    }
  else if (l == pos_x)
    {
      pos = pos_y;
      for (i = t; i < pos; i++)
        {
          if (!move_puzzle (grid, 0, -1))
            gtk_widget_error_bell (grid);
        }
      for (i = pos; i < t; i++)
        {
          if (!move_puzzle (grid, 01))
            gtk_widget_error_bell (grid);
        }
    }
  else if (t == pos_y)
    {
      pos = pos_x;
      for (i = l; i < pos; i++)
        {
          if (!move_puzzle (grid, -10))
            gtk_widget_error_bell (grid);
        }
      for (i = pos; i < l; i++)
        {
          if (!move_puzzle (grid, 10))
            gtk_widget_error_bell (grid);
        }
    }
  else
    {
      gtk_widget_error_bell (grid);
    }

  check_solved (grid);
}

static void
add_move_binding (GtkShortcutController *controller,
                  guint                  keyval,
                  int                    dx,
                  int                    dy)
{
  GtkShortcut *shortcut;

  shortcut = gtk_shortcut_new_with_arguments (
                 gtk_shortcut_trigger_create_with_aliases (keyval, 0),
                 gtk_callback_action_new (puzzle_key_pressed, NULL, NULL),
                 "(ii)", dx, dy);
  gtk_shortcut_controller_add_shortcut (controller, shortcut);
}

static void
start_puzzle (GdkPaintable *paintable)
{
  GtkWidget *picture, *grid;
  GtkEventController *controller;
  guint x, y;
  float aspect_ratio;

  /* Create a new grid */
  grid = gtk_grid_new ();
  gtk_widget_set_focusable (grid, TRUE);
  gtk_aspect_frame_set_child (GTK_ASPECT_FRAME (frame), grid);
  aspect_ratio = gdk_paintable_get_intrinsic_aspect_ratio (paintable);
  if (aspect_ratio == 0.0)
    aspect_ratio = 1.0;
  gtk_aspect_frame_set_ratio (GTK_ASPECT_FRAME (frame), aspect_ratio);
  gtk_aspect_frame_set_obey_child (GTK_ASPECT_FRAME (frame), FALSE);

  /* Add shortcuts so people can use the arrow
   * keys to move the puzzle
   */

  controller = gtk_shortcut_controller_new ();
  gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
                                     GTK_SHORTCUT_SCOPE_LOCAL);
  add_move_binding (GTK_SHORTCUT_CONTROLLER (controller), GDK_KEY_Left, -10);
  add_move_binding (GTK_SHORTCUT_CONTROLLER (controller), GDK_KEY_Right, 10);
  add_move_binding (GTK_SHORTCUT_CONTROLLER (controller), GDK_KEY_Up, 0, -1);
  add_move_binding (GTK_SHORTCUT_CONTROLLER (controller), GDK_KEY_Down, 01);
  gtk_widget_add_controller (GTK_WIDGET (grid), controller);

  controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
  g_signal_connect (controller, "pressed",
                    G_CALLBACK (puzzle_button_pressed),
                    grid);
  gtk_widget_add_controller (GTK_WIDGET (grid), controller);

  /* Make sure the cells have equal size */
  gtk_grid_set_row_homogeneous (GTK_GRID (grid), TRUE);
  gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);

  /* Reset the variables */
  solved = FALSE;
  pos_x = width - 1;
  pos_y = height - 1;

  /* add a picture for every cell */
  for (y = 0; y < height; y++)
    {
      for (x = 0; x < width; x++)
        {
          GdkPaintable *piece;

          /* Don't paint anything for the lsiding part of the video */
          if (x == pos_x && y == pos_y)
            piece = NULL;
          else
            piece = gtk_puzzle_piece_new (paintable,
                                          x, y,
                                          width, height);
          picture = gtk_picture_new_for_paintable (piece);
          gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_FILL);
          gtk_grid_attach (GTK_GRID (grid),
                           picture,
                           x, y,
                           11);
        }
    }

  shuffle_puzzle (grid);
}

static void
reshuffle (void)
{
  GtkWidget *grid;

  if (solved)
    {
      start_puzzle (puzzle);
      grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
    }
  else
    {
      grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
      shuffle_puzzle (grid);
    }
  gtk_widget_grab_focus (grid);
}

static void
reconfigure (void)
{
  GtkWidget *popover;
  GtkWidget *grid;
  GtkWidget *child;
  GtkWidget *image;
  GList *selected;

  width = height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (size_spin));

  selected = gtk_flow_box_get_selected_children (GTK_FLOW_BOX (choices));
  if (selected == NULL)
    child = gtk_widget_get_first_child (choices);
  else
    {
      child = selected->data;
      g_list_free (selected);
    }

  image = gtk_flow_box_child_get_child (GTK_FLOW_BOX_CHILD (child));
  puzzle = gtk_image_get_paintable (GTK_IMAGE (image));

  start_puzzle (puzzle);
  popover = gtk_widget_get_ancestor (size_spin, GTK_TYPE_POPOVER);
  gtk_popover_popdown (GTK_POPOVER (popover));
  grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
  gtk_widget_grab_focus (grid);
}

static void
add_choice (GtkWidget    *container,
            GdkPaintable *paintable)
{
  GtkWidget *icon;

  icon = gtk_image_new_from_paintable (paintable);
  gtk_image_set_icon_size (GTK_IMAGE (icon), GTK_ICON_SIZE_LARGE);

  gtk_flow_box_insert (GTK_FLOW_BOX (container), icon, -1);
}

static void
widget_destroyed (gpointer data,
                  GObject *widget)
{
  if (data)
    *(gpointer *) data = NULL;
}


GtkWidget *
do_sliding_puzzle (GtkWidget *do_widget)
{
  if (!window)
    {
      GtkWidget *header;
      GtkWidget *restart;
      GtkWidget *tweak;
      GtkWidget *popover;
      GtkWidget *tweaks;
      GtkWidget *apply;
      GtkWidget *label;
      GtkWidget *sw;
      GtkMediaStream *media;

      puzzle = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));

      tweaks = gtk_grid_new ();
      gtk_grid_set_row_spacing (GTK_GRID (tweaks), 10);
      gtk_grid_set_column_spacing (GTK_GRID (tweaks), 10);
      gtk_widget_set_margin_start (tweaks, 10);
      gtk_widget_set_margin_end (tweaks, 10);
      gtk_widget_set_margin_top (tweaks, 10);
      gtk_widget_set_margin_bottom (tweaks, 10);

      choices = gtk_flow_box_new ();
      gtk_widget_add_css_class (choices, "view");
      add_choice (choices, puzzle);
      add_choice (choices, gtk_nuclear_animation_new (TRUE));
      media = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
      gtk_media_stream_set_loop (media, TRUE);
      gtk_media_stream_set_muted (media, TRUE);
      gtk_media_stream_play (media);
      add_choice (choices, GDK_PAINTABLE (media));
      sw = gtk_scrolled_window_new ();
      gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), choices);
      gtk_grid_attach (GTK_GRID (tweaks), sw, 0021);

      label = gtk_label_new ("Size");
      gtk_label_set_xalign (GTK_LABEL (label), 0.0);
      gtk_grid_attach (GTK_GRID (tweaks), label, 0111);
      size_spin = gtk_spin_button_new_with_range (2101);
      gtk_spin_button_set_value (GTK_SPIN_BUTTON (size_spin), width);
      gtk_grid_attach (GTK_GRID (tweaks), size_spin, 1111);

      apply = gtk_button_new_with_label ("Apply");
      gtk_widget_set_halign (apply, GTK_ALIGN_END);
      gtk_grid_attach (GTK_GRID (tweaks), apply, 1211);
      g_signal_connect (apply, "clicked", G_CALLBACK (reconfigure), NULL);

      popover = gtk_popover_new ();
      gtk_popover_set_child (GTK_POPOVER (popover), tweaks);

      tweak = gtk_menu_button_new ();
      gtk_menu_button_set_popover (GTK_MENU_BUTTON (tweak), popover);
      gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (tweak), "open-menu-symbolic");

      restart = gtk_button_new_from_icon_name ("view-refresh-symbolic");
      g_signal_connect (restart, "clicked", G_CALLBACK (reshuffle), NULL);

      header = gtk_header_bar_new ();
      gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
      gtk_header_bar_pack_end (GTK_HEADER_BAR (header), tweak);
      window = gtk_window_new ();
      gtk_window_set_display (GTK_WINDOW (window),
                              gtk_widget_get_display (do_widget));
      gtk_window_set_title (GTK_WINDOW (window), "Sliding Puzzle");
      gtk_window_set_titlebar (GTK_WINDOW (window), header);
      gtk_window_set_default_size (GTK_WINDOW (window), 400300);
      g_object_weak_ref (G_OBJECT (window), widget_destroyed, &window);

      frame = gtk_aspect_frame_new (0.50.5, (float) gdk_paintable_get_intrinsic_aspect_ratio (puzzle), FALSE);
      gtk_window_set_child (GTK_WINDOW (window), frame);

      start_puzzle (puzzle);
    }

  if (!gtk_widget_get_visible (window))
    gtk_widget_set_visible (window, TRUE);
  else
    gtk_window_destroy (GTK_WINDOW (window));

  return window;
}

Messung V0.5 in Prozent
C=97 H=96 G=96

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik