Back to index

gcompris  8.2.2
Classes | Defines | Functions | Variables
hanoi.c File Reference
#include "gcompris/gcompris.h"

Go to the source code of this file.

Classes

struct  PieceItem

Defines

#define SOUNDLISTFILE   PACKAGE
#define MAX_NUMBER_X   10
#define MAX_NUMBER_Y   10
#define NUMBER_OF_COLOR   G_N_ELEMENTS(colorlist)

Functions

static void start_board (GcomprisBoard *agcomprisBoard)
static void pause_board (gboolean pause)
static void end_board (void)
static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
static void set_level (guint level)
static void game_won (void)
static GnomeCanvasItem * hanoi_create_item (GnomeCanvasGroup *parent)
static void hanoi_destroy_all_items (void)
static void hanoi_next_level (void)
static gint item_event (GnomeCanvasItem *item, GdkEvent *event, PieceItem *data)
static gboolean is_completed ()

Variables

static GcomprisBoard * gcomprisBoard = NULL
static gboolean board_paused = TRUE
static int gamewon
static GnomeCanvasGroup * boardRootItem = NULL
static PieceItemposition [MAX_NUMBER_X][MAX_NUMBER_Y]
static int number_of_item = 0
static int number_of_item_x = 0
static int number_of_item_y = 0
static int item_width
static int item_height
static guint colorlist []
static BoardPlugin menu_bp

Class Documentation

struct PieceItem

Definition at line 44 of file hanoi.c.

Class Members
gint color
gint i
GnomeCanvasItem * item
GnomeCanvasItem * item_text
gint j
gboolean on_top
gint width
double x
double xt
double y
double yt

Define Documentation

#define MAX_NUMBER_X   10

Definition at line 60 of file hanoi.c.

#define MAX_NUMBER_Y   10

Definition at line 61 of file hanoi.c.

#define NUMBER_OF_COLOR   G_N_ELEMENTS(colorlist)

Definition at line 88 of file hanoi.c.

#define SOUNDLISTFILE   PACKAGE

Definition at line 22 of file hanoi.c.


Function Documentation

static void end_board ( void  ) [static]

Definition at line 166 of file hanoi.c.

{
  if(gcomprisBoard!=NULL)
    {
      pause_board(TRUE);
      hanoi_destroy_all_items();
    }
  gcomprisBoard = NULL;
}

Here is the call graph for this function:

static void game_won ( void  ) [static]

Definition at line 563 of file hanoi.c.

{
  gcomprisBoard->sublevel++;

  if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
    /* Try the next level */
    gcomprisBoard->sublevel=1;
    gcomprisBoard->level++;
    if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
      gc_bonus_end_display(BOARD_FINISHED_RANDOM);
      return;
    }
    gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
  }
  hanoi_next_level();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static GnomeCanvasItem * hanoi_create_item ( GnomeCanvasGroup *  parent) [static]

Definition at line 297 of file hanoi.c.

{
  int i,j;
  double gap_x, gap_y;
  double baseline;
  GnomeCanvasItem *item = NULL;
  guint color_to_place;
  guint used_colors[NUMBER_OF_COLOR];
  GnomeCanvasPathDef *path;
  guint w;
  GdkPixbuf *pixmap = NULL;

  boardRootItem = GNOME_CANVAS_GROUP(
                                 gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
                                                     gnome_canvas_group_get_type (),
                                                     "x", (double) 0,
                                                     "y", (double) 0,
                                                     NULL));

  pixmap = gc_skin_pixmap_load("gcompris-shapelabel.png");
  if(pixmap) {
    gnome_canvas_item_new (boardRootItem,
                        gnome_canvas_pixbuf_get_type (),
                        "pixbuf", pixmap,
                        "x",       (double)BOARDWIDTH/2,
                        "y",       (double)BOARDHEIGHT - 35,
                        "width", (double) BOARDWIDTH - 20,
                        "width_set", TRUE,
                        "anchor", GTK_ANCHOR_CENTER,
                        NULL);
    gdk_pixbuf_unref(pixmap);
  }

  gnome_canvas_item_new (boardRootItem,
                      gnome_canvas_text_get_type (),
                      "text", _("Build the same tower in the empty area as the one you see on the right-hand side."),
                      "font", gc_skin_font_board_medium,
                      "x", (double) BOARDWIDTH/2 +1,
                      "y", (double) BOARDHEIGHT - 50 +1,
                      "anchor", GTK_ANCHOR_NORTH,
                      "fill_color", "black",
                      "justification", GTK_JUSTIFY_CENTER,
                      NULL);

  gnome_canvas_item_new (boardRootItem,
                      gnome_canvas_text_get_type (),
                      "text", _("Build the same tower in the empty area as the one you see on the right-hand side."),
                      "font", gc_skin_font_board_medium,
                      "x", (double) BOARDWIDTH/2,
                      "y", (double) BOARDHEIGHT - 50,
                      "anchor", GTK_ANCHOR_NORTH,
                      "fill_color_rgba", gc_skin_color_text_button,
                      "justification", GTK_JUSTIFY_CENTER,
                      NULL);


  /*----------------------------------------*/
  /* Empty the solution */
  for(i=0; i<(number_of_item_x+2); i++)
    {
      for(j=0; j<number_of_item_y; j++)
       {
         position[i][j] = g_malloc(sizeof(PieceItem));
         position[i][j]->color  = -1;
         position[i][j]->i      = i;
         position[i][j]->j      = j;
         position[i][j]->on_top = FALSE;
       }
    }

  /* Clear the used colors list */
  for(i=0; i<NUMBER_OF_COLOR; i++)
    used_colors[i] = FALSE;

  /* Initialize a random goal and store the color index in position[number_of_item_x] */
  for(i=0; i<(number_of_item_y); i++)
    {
      guint color = (guint)RAND(0, NUMBER_OF_COLOR-1);
      position[number_of_item_x+1][i]->color = color;
      used_colors[color] = TRUE;

    }

  /* Randomly place the solution */
  for (color_to_place=0; color_to_place<number_of_item_y; color_to_place++)
    {
      gboolean done;

      do
       {
         done = FALSE;

         i = (guint)RAND(0, number_of_item_x-2);

         /* Restrict the goal to lowest items */
         j = (guint)RAND(0, 2);

         if(position[i][j]->color == -1)
           {
             done = TRUE;
             position[i][j]->color = position[number_of_item_x+1][color_to_place]->color;
           }
       }
      while(!done);
    }

  /* Initialize the left open positions */
  for(i=0; i<(number_of_item_x); i++)
    {
      for(j=0; j<number_of_item_y-1; j++)
       {
         if(position[i][j]->color == -1)
           {
             /* Take only a color that is not part of the goal */
             guint color = (guint)RAND(0, NUMBER_OF_COLOR-1);
             //printf(" i,j=%d,%d random color = %d used_colors[color]=%d\n", i,j,color, used_colors[color]);
             while(used_colors[color])
              {
                //printf("  used_colors[%d]=%d\n", color, used_colors[color]);
        color++;
              if(color >= NUMBER_OF_COLOR)
                color = 0;
              }

             position[i][j]->color = color;
           }
       }
    }
  //dump_solution();

  /* Mark the top pieces */
  for(i=0; i<(number_of_item_x); i++)
    {
      position[i][number_of_item_y-2]->on_top = TRUE;
    }

  /*----------------------------------------*/
  /* Display it now */

  item_width  = BOARDWIDTH / (number_of_item_x + 2);
  item_height = 30;

  gap_x = item_width  * 0.1;
  gap_y = item_height * 0.25;

  baseline = BOARDHEIGHT/2 + item_height * number_of_item_y/2;

  number_of_item = 0;

  for(i=0; i<(number_of_item_x+2); i++)
    {
      if(i==number_of_item_x+1)
       {
         /* Create the backgound for the target */
         gnome_canvas_item_new (boardRootItem,
                             gnome_canvas_rect_get_type (),
                             "x1", (double) item_width * i + gap_x/2,
                             "y1", (double) baseline - item_height * number_of_item_y - gap_y - 50,
                             "x2", (double) item_width * (i+1) - gap_x/2,
                             "y2", (double) baseline + 50,
                             "fill_color_rgba", 0x036ED8FF,
                             "outline_color", "black",
                             "width_units", (double)1,
                             NULL);
       }
      else if (i==number_of_item_x)
       {
         /* Create the backgound for the empty area */
         gnome_canvas_item_new (boardRootItem,
                             gnome_canvas_rect_get_type (),
                             "x1", (double) item_width * i + gap_x/2,
                             "y1", (double) baseline - item_height * number_of_item_y - gap_y - 50,
                             "x2", (double) item_width * (i+1) - gap_x/2,
                             "y2", (double) baseline + 50,
                             "fill_color_rgba", 0x48AAF1FF,
                             "outline_color", "black",
                             "width_units", (double)1,
                             NULL);
       }

      /* Create the vertical line */
      w = 10;
      gnome_canvas_item_new (boardRootItem,
                          gnome_canvas_rect_get_type (),
                          "x1", (double) item_width * i + item_width/2 - w,
                          "y1", (double) baseline - item_height * number_of_item_y - gap_y,
                          "x2", (double) item_width * i + item_width/2 + w,
                          "y2", (double) baseline,
                          "fill_color_rgba", 0xFF1030FF,
                          "outline_color", "black",
                          "width_units", (double)1,
                          NULL);

      /* And the base line */
      w = 40;
      path = gnome_canvas_path_def_new();
      gnome_canvas_path_def_moveto (path, item_width * i + item_width/2 - w, baseline);
      gnome_canvas_path_def_lineto (path, item_width * i + item_width/2 + w, baseline);
      gnome_canvas_path_def_curveto (path,
                                 item_width * i + item_width/2 + w , baseline,
                                 item_width * i + item_width/2, baseline + w + 10,
                                 item_width * i + item_width/2 - w, baseline);
      gnome_canvas_path_def_closepath_current (path);

      item = gnome_canvas_item_new (boardRootItem,
                                GNOME_TYPE_CANVAS_SHAPE,
                                "fill_color_rgba", 0x20FF30FF,
                                "outline_color", "black",
                                NULL);
      gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (item), path);
      gnome_canvas_item_show (item);
      gnome_canvas_path_def_unref (path);

      for(j=0; j<number_of_item_y; j++)
       {

         position[i][j]->x = item_width * i + gap_x;
         position[i][j]->y = baseline - item_height * j - item_height + gap_y;

         position[i][j]->xt = position[i][j]->x + 20;
         position[i][j]->yt = position[i][j]->y + 2;


         if(position[i][j]->color != -1)
           {
             char car[2];

             item = gnome_canvas_item_new (boardRootItem,
                                       gnome_canvas_rect_get_type (),
                                       "x1", (double) position[i][j]->x,
                                       "y1", (double) position[i][j]->y,
                                       "x2", (double) item_width * i + item_width - gap_x,
                                       "y2", (double) baseline - item_height * j,
                                       "fill_color_rgba", colorlist[position[i][j]->color],
                                       "outline_color", "black",
                                       "width_units", (double)1,
                                       NULL);

             car[0] = 'a' + position[i][j]->color;
             car[1] = '\0';

              position[i][j]->item_text = \
               gnome_canvas_item_new (boardRootItem,
                                   gnome_canvas_text_get_type (),
                                   "text", &car,
                                   "font", gc_skin_font_board_tiny,
                                   "x", (double) position[i][j]->xt,
                                   "y", (double) position[i][j]->yt,
                                   "anchor", GTK_ANCHOR_NORTH,
                                   "fill_color", "white",
                                   "justification", GTK_JUSTIFY_CENTER,
                                   NULL);

             position[i][j]->item = item;

             if(i!=number_of_item_x+1)
              gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event,  position[i][j]);

           }

       }
    }

  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void hanoi_destroy_all_items ( void  ) [static]

Definition at line 251 of file hanoi.c.

{
  guint i,j;

  if(boardRootItem!=NULL)
    {
      gtk_object_destroy (GTK_OBJECT(boardRootItem));

      /* Cleanup our memory structure */
      for(i=0; i<(number_of_item_x+2); i++)
       {
         for(j=0; j<number_of_item_y; j++)
           {
             g_free(position[i][j]);
           }
       }
    }
  boardRootItem = NULL;

}

Here is the caller graph for this function:

static void hanoi_next_level ( void  ) [static]

Definition at line 206 of file hanoi.c.

{

  gc_bar_set_level(gcomprisBoard);

  hanoi_destroy_all_items();
  gamewon = FALSE;

  /* Select level difficulty */
  switch(gcomprisBoard->level)
    {
    case 1:
      number_of_item_x = 3;
      number_of_item_y = 5;
      break;
    case 2:
      number_of_item_x = 4;
      number_of_item_y = 5;
      break;
    case 3:
      number_of_item_x = 5;
      number_of_item_y = 6;
    case 4:
      number_of_item_x = 6;
      number_of_item_y = 7;
      break;
    case 5:
      number_of_item_x = 6;
      number_of_item_y = 8;
      break;
    case 6:
      number_of_item_x = 5;
      number_of_item_y = 9;
      break;
    default:
      number_of_item_x = 5;
      number_of_item_y = 7;
    }


  /* Try the next level */
  hanoi_create_item(gnome_canvas_root(gcomprisBoard->canvas));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static gboolean is_completed ( ) [static]

Definition at line 583 of file hanoi.c.

{
  gint j;
  gboolean done = TRUE;

  for(j=0; j<number_of_item_y; j++)
    {
      if(position[number_of_item_x+1][j]->color != position[number_of_item_x][j]->color)
       done = FALSE;
    }

  return done;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static gboolean is_our_board ( GcomprisBoard *  gcomprisBoard) [static]

Definition at line 188 of file hanoi.c.

{
  if (gcomprisBoard)
    {
      if(g_strcasecmp(gcomprisBoard->type, "hanoi")==0)
       {
         /* Set the plugin entry */
         gcomprisBoard->plugin=&menu_bp;

         return TRUE;
       }
    }
  return FALSE;
}
static gint item_event ( GnomeCanvasItem *  item,
GdkEvent *  event,
PieceItem data 
) [static]

Definition at line 599 of file hanoi.c.

{
   static double x, y;
   double new_x, new_y;
   GdkCursor *fleur;
   static int dragging;
   double item_x, item_y;

   if(!gcomprisBoard)
     return FALSE;

  if(board_paused)
    return FALSE;

  if(!data->on_top)
    return FALSE;

  item_x = event->button.x;
  item_y = event->button.y;
  gnome_canvas_item_w2i(item->parent, &item_x, &item_y);

  switch (event->type)
    {
    case GDK_ENTER_NOTIFY:
      gnome_canvas_item_set(item,
                         "outline_color", "white",
                         "width_units", (double)3,
                         NULL);
      break;
    case GDK_LEAVE_NOTIFY:
      gnome_canvas_item_set(item,
                         "outline_color", "black",
                         "width_units", (double)1,
                         NULL);
      break;
    case GDK_BUTTON_PRESS:
      switch(event->button.button)
       {
       case 1:

         x = item_x;
         y = item_y;

         gnome_canvas_item_raise_to_top(data->item);
         gnome_canvas_item_raise_to_top(data->item_text);

         fleur = gdk_cursor_new(GDK_FLEUR);
         gc_canvas_item_grab(data->item,
                             GDK_POINTER_MOTION_MASK |
                             GDK_BUTTON_RELEASE_MASK,
                             fleur,
                             event->button.time);
         gdk_cursor_destroy(fleur);
         dragging = TRUE;
         break;
       }
      break;

    case GDK_MOTION_NOTIFY:
      if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
       {
         new_x = item_x;
         new_y = item_y;

         gnome_canvas_item_move(data->item     , new_x - x, new_y - y);
         gnome_canvas_item_move(data->item_text, new_x - x, new_y - y);
         x = new_x;
         y = new_y;
       }
      break;

    case GDK_BUTTON_RELEASE:
      if(dragging)
       {
         gint i;
         gint tmpi, tmpj;
         double tmpx, tmpy;
         PieceItem *piece_src;
         PieceItem *piece_dst;
         gint col = 0, line;

         gc_canvas_item_ungrab(data->item, event->button.time);
         dragging = FALSE;

         /* Search the column (x) where this item is ungrabbed */
         for(i=0; i<=number_of_item_x; i++)
           if(position[i][0]->x   < item_x &&
              position[i+1][0]->x > item_x)
             col = i;

         /* Bad drop / Outside of column area */
         /* Bad drop / On the same column */
         if(col<0 || col > number_of_item_x || col == data->i)
           {
             /* Return to the original position */
             gc_item_absolute_move (data->item     , data->x , data->y);
             gc_item_absolute_move (data->item_text, data->xt, data->yt);

             /* FIXME : Workaround for bugged canvas */
             gnome_canvas_update_now(gcomprisBoard->canvas);

             return FALSE;
           }


         /* Now search the free line (y) */
         line = number_of_item_y;
         for(i=number_of_item_y-1; i>=0; i--)
           if(position[col][i]->color == -1)
             line = i;

         /* Bad drop / Too many pieces here */
         if(line >= number_of_item_y)
           {
             /* Return to the original position */
             gc_item_absolute_move (data->item     , data->x , data->y);
             gc_item_absolute_move (data->item_text, data->xt, data->yt);

             /* FIXME : Workaround for bugged canvas */
             gnome_canvas_update_now(gcomprisBoard->canvas);

             return FALSE;
           }

         /* Update ontop values for the piece under the grabbed one */
         if(data->j>0)
           position[data->i][data->j-1]->on_top = TRUE;

         /* Update ontop values for the piece under the ungrabbed one */
         if(line>0)
           position[col][line-1]->on_top = FALSE;

         /* Move the piece */
         piece_dst = position[col][line];
         piece_src = data;
         gc_item_absolute_move (data->item     , piece_dst->x , piece_dst->y);
         gc_item_absolute_move (data->item_text, piece_dst->xt, piece_dst->yt);

         /* FIXME : Workaround for bugged canvas */
         gnome_canvas_update_now(gcomprisBoard->canvas);

         /* Swap values in the pieces */
         tmpx    = data->x;
         tmpy    = data->y;
         piece_src->x = piece_dst->x;
         piece_src->y = piece_dst->y;
         piece_dst->x = tmpx;
         piece_dst->y = tmpy;

         tmpx    = data->xt;
         tmpy    = data->yt;
         piece_src->xt = piece_dst->xt;
         piece_src->yt = piece_dst->yt;
         piece_dst->xt = tmpx;
         piece_dst->yt = tmpy;

         tmpi    = data->i;
         tmpj    = data->j;
         position[tmpi][tmpj]->i = piece_dst->i;
         position[tmpi][tmpj]->j = piece_dst->j;
         piece_dst->i  = tmpi;
         piece_dst->j  = tmpj;

         position[piece_src->i][piece_src->j] = piece_src;
         position[piece_dst->i][piece_dst->j] = piece_dst;

         //     dump_solution();
         if(is_completed())
           {
             gamewon = TRUE;
             hanoi_destroy_all_items();
             gc_bonus_display(gamewon, BONUS_SMILEY);
           }
       }
      break;

    default:
      break;
    }


  return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void pause_board ( gboolean  pause) [static]

Definition at line 128 of file hanoi.c.

{
  if(gcomprisBoard==NULL)
    return;

  if(gamewon == TRUE && pause == FALSE) /* the game is won */
    {
      game_won();
    }

  board_paused = pause;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void set_level ( guint  level) [static]

Definition at line 177 of file hanoi.c.

{

  if(gcomprisBoard!=NULL)
    {
      gcomprisBoard->level=level;
      gcomprisBoard->sublevel=1;
      hanoi_next_level();
    }
}

Here is the call graph for this function:

static void start_board ( GcomprisBoard *  agcomprisBoard) [static]

Definition at line 143 of file hanoi.c.

{
    gchar *img;

  if(agcomprisBoard!=NULL)
    {
      gcomprisBoard=agcomprisBoard;
      gcomprisBoard->level=1;
      gcomprisBoard->maxlevel=6;
      gcomprisBoard->sublevel=1;
      gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
      gc_bar_set(GC_BAR_LEVEL);

      gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
                           img = gc_skin_image_get("gcompris-bg.jpg"));
      g_free(img);
      hanoi_next_level();

      gamewon = FALSE;
      pause_board(FALSE);
    }
}

Here is the call graph for this function:


Variable Documentation

gboolean board_paused = TRUE [static]

Definition at line 25 of file hanoi.c.

GnomeCanvasGroup* boardRootItem = NULL [static]

Definition at line 35 of file hanoi.c.

guint colorlist[] [static]
Initial value:
  {
    0x00FFFFFF,
    0xA00000FF,
    0xF00000FF,
    0x00A000FF,
    0x00F000FF,
    0x0000AAFF,
    0x0000FFFF,
    0x505000FF,
    0xA0A000FF,
    0xF0F000FF,
    0x005050FF,
    0x00A0A0FF,
    0x500050FF,
    0xA000A0FF,
    0xF000F0FF
  }

Definition at line 70 of file hanoi.c.

int gamewon [static]

Definition at line 32 of file hanoi.c.

GcomprisBoard* gcomprisBoard = NULL [static]

Definition at line 24 of file hanoi.c.

int item_height [static]

Definition at line 68 of file hanoi.c.

int item_width [static]

Definition at line 67 of file hanoi.c.

BoardPlugin menu_bp [static]
Initial value:
  {
    NULL,
    NULL,
    N_("Simplified Tower of Hanoi"),
    N_("Reproduce the given tower"),
    "Bruno Coudoin <bruno.coudoin@free.fr>",
    NULL,
    NULL,
    NULL,
    NULL,
    start_board,
    pause_board,
    end_board,
    is_our_board,
    NULL,
    NULL,
    set_level,
    NULL,
    NULL,
    NULL,
    NULL
  }

Definition at line 92 of file hanoi.c.

int number_of_item = 0 [static]

Definition at line 64 of file hanoi.c.

int number_of_item_x = 0 [static]

Definition at line 65 of file hanoi.c.

int number_of_item_y = 0 [static]

Definition at line 66 of file hanoi.c.

Definition at line 62 of file hanoi.c.