3
* Copyright (C) 2002 Bastiaan Verhoef
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
#include "gcompris/gcompris.h"
25
#define SOUNDLISTFILE PACKAGE
26
/*-------------------*/
42
/* array of the board */
43
static int Maze[MAX_WIDTH][MAX_HEIGHT];
45
static int pathhistory[MAX_WIDTH*MAX_HEIGHT][2];
52
static int cellsize=20;
54
static int board_border_x=20;
55
static int board_border_y=3;
56
static int thickness=2;
59
/*-----------------------*/
61
GcomprisBoard *gcomprisBoard = NULL;
62
gboolean board_paused = TRUE;
64
static void start_board (GcomprisBoard *agcomprisBoard);
65
static void pause_board (gboolean pause);
66
static void end_board (void);
67
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
68
static gboolean won=FALSE;
69
static gboolean computer_solving=FALSE;
71
static void repeat(void);
72
static void game_won(gboolean computersolve);
74
/* ================================================================ */
75
static GnomeCanvasGroup *boardRootItem = NULL;
76
static GnomeCanvasGroup *mazegroup = NULL;
77
static GnomeCanvasItem *tuxitem = NULL;
79
static GnomeCanvasItem *maze_create_item(GnomeCanvasGroup *parent);
80
static void maze_destroy_all_items(void);
81
static void maze_next_level(void);
82
static void set_level (guint level);
83
gint key_press(guint keyval);
84
/*--------------------*/
85
static void draw_a_rect(GnomeCanvasGroup *group, int x1, int y1, int x2, int y2, char *color);
86
static void draw_a_line(GnomeCanvasGroup *group, int x1, int y1, int x2, int y2, char *color);
87
static GnomeCanvasItem *draw_image(GnomeCanvasGroup *group, int x,int y, GdkPixbuf *pixmap);
88
static void move_image(GnomeCanvasGroup *group, int x,int y, GnomeCanvasItem *item);
89
static void draw_rect(GnomeCanvasGroup *group, int x,int y,char *color);
90
static void draw_combined_rect(GnomeCanvasGroup *group, int x1, int y1, int x2,int y2, char *color);
91
static void initMaze(void);
92
static int check(int x,int y);
93
static int* isPossible(int x, int y);
94
static void generateMaze(int x, int y);
95
static void removeSet(void);
96
static void draw_maze(void);
97
static void setlevelproperties(void);
98
static void solveMaze(void);
99
static gboolean movePos(int x1, int y1, int x2,int y2,gboolean computersolve);
100
static int* checkPos(int x, int y);
101
static gint solvM(GtkWidget *widget, gpointer data);
102
/*----------------------*/
104
/* Description of this plugin */
105
BoardPlugin menu_bp =
110
N_("Click on the right color"),
111
"Bastiaan Verhoef <b.f.verhoef@student.utwente.nl>",
122
set_level,//set_level,
127
/* =====================================================================
129
* =====================================================================*/
130
BoardPlugin *get_bplugin_info(void) {
134
/* =====================================================================
135
* in : boolean TRUE = PAUSE : FALSE = CONTINUE
136
* =====================================================================*/
137
static void pause_board (gboolean pause)
139
if(gcomprisBoard==NULL)
142
// if(gamewon == TRUE && pause == FALSE) /* the game is won */
145
board_paused = pause;
148
static void set_level (guint level) {
149
if(gcomprisBoard!=NULL) {
150
gcomprisBoard->level=level;
155
/* =====================================================================
157
* =====================================================================*/
158
static void start_board (GcomprisBoard *agcomprisBoard) {
160
if(agcomprisBoard!=NULL) {
161
gcomprisBoard=agcomprisBoard;
162
gcompris_set_background(gnome_canvas_root(gcomprisBoard->canvas), "gcompris/gcompris-bg.jpg");
163
gcomprisBoard->level=1;
164
gcomprisBoard->maxlevel=9;
165
gcompris_bar_set(GCOMPRIS_BAR_LEVEL|GCOMPRIS_BAR_REPEAT);
172
/* =====================================================================
174
* =====================================================================*/
175
static void end_board () {
177
if(gcomprisBoard!=NULL){
179
gcompris_score_end();
180
maze_destroy_all_items();
182
gcomprisBoard = NULL;
185
/* =====================================================================
187
* =====================================================================*/
188
gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
190
if(g_strcasecmp(gcomprisBoard->type, "maze")==0) {
191
/* Set the plugin entry */
192
gcomprisBoard->plugin=&menu_bp;
198
/* =====================================================================
199
* set initial values for the next level
200
* =====================================================================*/
201
static void maze_next_level() {
202
GdkPixbuf *pixmap = NULL;
203
if (!computer_solving)
205
maze_destroy_all_items();
206
gcompris_bar_set_level(gcomprisBoard);
207
setlevelproperties();
211
generateMaze((random()%width),(random()%height));
214
/* Try the next level */
215
maze_create_item(gnome_canvas_root(gcomprisBoard->canvas));
218
/* make a new group for the items */
219
begin=random()%height;
223
pixmap = gcompris_load_pixmap("gcompris/misc/tux.png");
226
tuxitem = draw_image(mazegroup,0,begin,pixmap);
227
gdk_pixbuf_unref(pixmap);
230
/* Draw the target */
231
pixmap = gcompris_load_pixmap("gcompris/misc/door.png");
234
draw_image(mazegroup,width-1,end,pixmap);
235
gdk_pixbuf_unref(pixmap);
237
pathhistory[p_index][0]=0;
238
pathhistory[p_index][1]=begin;
239
Maze[0][begin]=Maze[0][begin]+SET;
240
Maze[width-1][end]=Maze[width-1][end]+DOOR;
243
/* ======================================= */
244
static void setlevelproperties(){
245
if (gcomprisBoard->level==1)
252
board_border_x=(int) (BASE_X2-width*cellsize)/2;
253
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
255
else if (gcomprisBoard->level==2)
262
board_border_x=(int) (BASE_X2-width*cellsize)/2;
263
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
265
else if (gcomprisBoard->level==3)
271
board_border_x=(int) (BASE_X2-width*cellsize)/2;
272
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
274
else if (gcomprisBoard->level==4)
280
board_border_x=(int) (BASE_X2-width*cellsize)/2;
281
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
283
else if (gcomprisBoard->level==5)
289
board_border_x=(int) (BASE_X2-width*cellsize)/2;
290
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
292
else if (gcomprisBoard->level==6)
297
board_border_x=(int) (BASE_X2-width*cellsize)/2;
298
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
300
else if (gcomprisBoard->level==7)
305
board_border_x=(int) (BASE_X2-width*cellsize)/2;
306
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
308
else if (gcomprisBoard->level==8)
313
board_border_x=(int) (BASE_X2-width*cellsize)/2;
314
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
316
else if (gcomprisBoard->level==9)
321
board_border_x=(int) (BASE_X2-width*cellsize)/2;
322
board_border_y=(int) (BASE_Y2-height*cellsize)/2;
325
/* =====================================================================
326
* Destroy all the items
327
* =====================================================================*/
328
static void maze_destroy_all_items() {
330
gtk_object_destroy (GTK_OBJECT(mazegroup));
331
if(boardRootItem!=NULL)
332
gtk_object_destroy (GTK_OBJECT(boardRootItem));
334
boardRootItem = NULL;
339
/* =====================================================================
341
* =====================================================================*/
342
static GnomeCanvasItem *maze_create_item(GnomeCanvasGroup *parent) {
343
boardRootItem = GNOME_CANVAS_GROUP(
344
gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
345
gnome_canvas_group_get_type (),
349
mazegroup=GNOME_CANVAS_GROUP(gnome_canvas_item_new(boardRootItem,
350
gnome_canvas_group_get_type(),
357
/* =====================================================================
359
* =====================================================================*/
360
static void game_won(gboolean computersolve) {
361
gcompris_play_sound (SOUNDLISTFILE, "bonus");
362
/* Try the next level */
364
gcomprisBoard->level++;
365
else computer_solving=FALSE;
366
if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
367
board_finished(BOARD_FINISHED_RANDOM);
372
/* =====================================================================
374
* =====================================================================*/
375
static void repeat() {
376
if (!computer_solving)
379
computer_solving=TRUE;
380
don = gtk_timeout_add (speed, (GtkFunction) solvM, NULL);
384
/* =====================================================================
386
* =====================================================================*/
387
static void draw_a_rect(GnomeCanvasGroup *group, int x1, int y1, int x2, int y2, char *color)
390
gnome_canvas_item_show(gnome_canvas_item_new(group,gnome_canvas_rect_get_type(),
399
/* =====================================================================
401
* =====================================================================*/
402
static void draw_a_line(GnomeCanvasGroup *group, int x1, int y1, int x2, int y2, char *color)
404
GnomeCanvasPoints *points;
407
points = gnome_canvas_points_new (2);
409
points->coords[0] = x1;
410
points->coords[1] = y1;
411
points->coords[2] = x2;
412
points->coords[3] = y2;
413
gnome_canvas_item_new(group,
414
gnome_canvas_line_get_type(),
417
"width_units", (double)thickness,
420
gnome_canvas_points_free(points);
424
/* =====================================================================
425
* Draw a rectangle on the right position
426
* =====================================================================*/
427
static void draw_rect(GnomeCanvasGroup *group, int x,int y,char *color)
432
y1=cellsize*(y)-height + board_border_y;
433
x1=cellsize*(x)-width + board_border_x;
434
draw_a_rect(group,x1+buffer,y1+buffer ,x1+cellsize-buffer ,y1+cellsize-buffer ,color);
438
/* =====================================================================
439
* Combines rectangles
440
* =====================================================================*/
441
static void draw_combined_rect(GnomeCanvasGroup *group, int x1,int y1,int x2,int y2,char *color)
446
yy1=cellsize*(y1)-height + board_border_y;
447
xx1=cellsize*(x1)-width + board_border_x;
448
yy2=cellsize*(y2)-height + board_border_y;
449
xx2=cellsize*(x2)-width + board_border_x;
452
draw_a_rect(group,xx1+cellsize-buffer,yy1+buffer,xx2+buffer,yy2+cellsize-buffer,color);
454
else if (y1==y2 && x1>x2)
456
draw_a_rect(group,xx2+cellsize-buffer,yy2+buffer,xx1+buffer,yy1+cellsize-buffer,color);
458
else if (x1==x2 && y1<y2)
460
draw_a_rect(group,xx1+buffer,yy1+cellsize-buffer,xx2+cellsize-buffer,yy2+buffer,color);
462
else if (x1==x2 && y1>y2)
464
draw_a_rect(group,xx2+buffer,yy2+cellsize-buffer,xx1+cellsize-buffer,yy1+buffer,color);
470
/* =====================================================================
472
* =====================================================================*/
473
static GnomeCanvasItem *draw_image(GnomeCanvasGroup *group, int x,int y, GdkPixbuf *pixmap)
475
GnomeCanvasItem *item = NULL;
479
y1=cellsize*(y)-height + board_border_y;
480
x1=cellsize*(x)-width + board_border_x;
482
item = gnome_canvas_item_new (group,
483
gnome_canvas_pixbuf_get_type (),
485
"x", (double)x1+buffer,
486
"y", (double)y1+buffer,
487
"width", (double)cellsize-buffer*2,
488
"height",(double)cellsize-buffer*2,
499
* Same as draw rect but for an image
501
static void move_image(GnomeCanvasGroup *group, int x,int y, GnomeCanvasItem *item)
506
y1=cellsize*(y)-height + board_border_y;
507
x1=cellsize*(x)-width + board_border_x;
509
gnome_canvas_item_set (item,
510
"x", (double)x1+buffer,
511
"y", (double)y1+buffer,
513
gnome_canvas_item_raise_to_top(item);
517
/* =====================================================================
518
* Init of the mazeboard.
519
* set initvalue to 15= NORTH+SOUTH+WEST+EAST
520
* So each cell in the bord have four walls
521
* =====================================================================*/
522
static void initMaze(void)
525
for (x=0; x<width;x++)
527
for (y=0; y <height; y++)
534
/* =====================================================================
536
* =====================================================================*/
537
static void draw_maze(void)
542
for (x1=0; x1< width; x1++)
544
for (y1=0; y1 < height; y1++)
547
y=cellsize*(y1)+board_border_y;
548
x=cellsize*(x1)+board_border_x;
550
draw_a_line(boardRootItem,x, y, x, y+cellsize, "black");
553
draw_a_line(boardRootItem,x, y, x+cellsize, y, "black");
556
draw_a_line(boardRootItem,x+cellsize, y, x+cellsize, y+cellsize, "black");
562
draw_a_line(boardRootItem,x, y+cellsize, x+cellsize, y+cellsize, "black");
570
static int check(int x,int y)
572
if ((Maze[x][y]-DOOR)>=0)
576
if ((Maze[x][y]-BAD)>=0)
578
if ((Maze[x][y]-SET)>=0)
582
/* =====================================================================
583
* checks what are the possibilities to move
584
* =====================================================================*/
585
static int* isPossible(int x, int y)
646
/* =====================================================================
648
* =====================================================================*/
649
static void generateMaze(int x, int y)
652
Maze[x][y]= Maze[x][y] + SET;
653
possible = isPossible(x,y);
659
ran=*(possible + in);
664
Maze[x][y]=Maze[x][y]-EAST;
665
Maze[x+1][y]=Maze[x+1][y]-WEST;
669
Maze[x][y]=Maze[x][y]-SOUTH;
670
Maze[x][y+1]=Maze[x][y+1]-NORTH;
674
Maze[x][y]=Maze[x][y]-WEST;
675
Maze[x-1][y]=Maze[x-1][y]-EAST;
679
Maze[x][y]=Maze[x][y]-NORTH;
680
Maze[x][y-1]=Maze[x][y-1]-SOUTH;
685
possible=isPossible(x,y);
690
static int* checkPos(int x, int y)
693
gboolean found_door=FALSE;
706
else if(check(x+1,y)==2)
722
else if(check(x,y+1)==2)
738
else if(check(x-1,y)==2)
754
else if(check(x,y-1)==2)
766
static gint solvM(GtkWidget *widget, gpointer data)
769
if (!won && mazegroup!=NULL)
770
don = gtk_timeout_add (speed, (GtkFunction) solvM, NULL);
774
/* =====================================================================
775
* computersolving algoritme
776
* =====================================================================*/
777
static void solveMaze()
780
possible = checkPos(pathhistory[p_index][0],pathhistory[p_index][1]);
781
if (*possible>0 && !won)
792
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0]+1,pathhistory[p_index][1],TRUE);
795
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0],pathhistory[p_index][1]+1,TRUE);
798
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0]-1,pathhistory[p_index][1],TRUE);
801
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0],pathhistory[p_index][1]-1,TRUE);
804
possible=checkPos(pathhistory[p_index][0],pathhistory[p_index][1]);
807
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index-1][0],pathhistory[p_index-1][1],TRUE);
810
static void removeSet(void)
813
for (x=0; x< width;x++)
815
for (y=0; y < height; y++)
818
Maze[x][y]=Maze[x][y]-SET;
823
/* =====================================================================
824
* move from position (x1,y1) to (x2,y2) if possible
825
* =====================================================================*/
826
static gboolean movePos(int x1, int y1, int x2,int y2, gboolean computersolve)
828
int direction,wall,i;
829
gboolean pos_to_move,found_cycle;
834
/* looking for what is the direction */
856
/* check if move to that direction is possible */
866
if (direction==SOUTH)
878
if (direction==NORTH)
884
if (Maze[x2][y2]-DOOR>=0)
889
gtk_timeout_remove(don);
890
game_won(computersolve);
895
else if (Maze[x2][y2]-SET>=0)
897
for (i=(p_index); i>=0 && !found_cycle; i--)
900
if(pathhistory[i][0]==x2 && pathhistory[i][1]==y2)
903
move_image(mazegroup,x2,y2,tuxitem);
907
Maze[pathhistory[i][0]][pathhistory[i][1]]=Maze[pathhistory[i][0]][pathhistory[i][1]]-SET;
908
draw_rect(mazegroup,pathhistory[i][0],pathhistory[i][1],"red");
909
Maze[pathhistory[i][0]][pathhistory[i][1]]=Maze[pathhistory[i][0]][pathhistory[i][1]]+BAD;
910
draw_combined_rect(mazegroup,pathhistory[i-1][0],pathhistory[i-1][1],pathhistory[i][0],pathhistory[i][1],"red");
920
pathhistory[p_index][0]=x2;
921
pathhistory[p_index][1]=y2;
922
Maze[x2][y2]=Maze[x2][y2]+SET;
923
move_image(mazegroup,x2,y2,tuxitem);
924
draw_combined_rect(mazegroup,x1,y1,x2,y2,"green");
925
draw_rect(mazegroup,x1,y1,"green");
935
gint key_press(guint keyval){
937
if ( keyval== GDK_Left)
939
if (!computer_solving)
940
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0]-1,pathhistory[p_index][1],FALSE);
943
else if (keyval==GDK_Right)
945
if (!computer_solving)
946
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0]+1,pathhistory[p_index][1],FALSE);
949
else if (keyval==GDK_Up)
951
if (!computer_solving)
952
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0],pathhistory[p_index][1]-1,FALSE);
955
else if (keyval==GDK_Down)
957
if (!computer_solving)
958
movePos(pathhistory[p_index][0],pathhistory[p_index][1],pathhistory[p_index][0],pathhistory[p_index][1]+1,FALSE);