[gcompris-devel] Maze plugin enhancements (and cleanup)

Bruno Coudoin bruno.coudoin at free.fr
Mon Oct 14 05:16:02 UTC 2002


That's great, I applied the patch and it works fine.
Long life turbo penguin.

As for you question on how/when to set turbo mode on/off, I suggest to
stick to off for level 1 to 3 and after 4 we activate the turbo.
Small kids would be in trouble playing the first level trying to
understand the key mouvement and where tux goes. After 4, there is so
much space and move to do that it make more sense to have turbo.

What do you think ?

Bruno.

Le lun 14/10/2002 à 00:48, Christof Petig a écrit :
> Hi Bastiaan,
> 
> sorry for delaying so long, but I had a busy summer. I was the one 
> volunteering to write a 3D frontend to gmaze. Actually while enhancing 
> my own ancieant maze program to use an easier algorithm I found out that 
> everything you need to display a 3D maze is ray interception theorems 
> (yes that's about 7th class math). The only drawback of not using OpenGL 
> (matrix multiplication/hidden surface problems!) is that you cannot 
> chose viewing directions other than parallel/orthogonal to the walls.
> 
> So my algorithm boiled down to one simple function (see P3S/P4S) and 
> it's inverse and a lot of vector addition (read checking for wall 
> existance).
> 
> So after having shaken out every bug of the function (one might not 
> believe how many sign and bracket placement errors one can create from 
> this simple function) I was ready for inclusion into gmaze. [patch later 
> this week, perhaps tomorrow?]
> 
> First I tried to implement a "run until decision is needed" mode for the 
> penguin to make myself familiar with the maze code. Here's the patch.
> 
> But since I dared to simplify/fix some things I have to explain:
> 
> - the key_press function might as well be static
> 
> - since C has excellent bit field operators (which sadly are not too 
> popular ...), I replaced the A-X>=0 ... A=A-X by the bit equivalent: A&X 
> (yes one operator does all the dirty work)
> 
> Actually the operators work as following
> (X stands for the bit(s) to test/change):
> - test whether a bit is set: A&X
> - test whether a bit is clear: !(A&X)
> - set a bit: A|=X;
> - clear a bit: A&=~X; (sorry but this operation needs two operators 
> combined)
> - toggle a bit: A^=X;
> 
> - since movePos before needed to deduce the direction (richting) from 
> the movement but it was available to the caller (one_step) I passed it 
> down (extra argument)
> 
> So have fun with the turbo penguin
>       Christof
> 
> PS: If you have any questions about the bit operators feel free to ask.
> PPS: Of course I think that the turbo mode should be optional. I was not 
> sure about how to set the variable (run_fast) by an additional button in 
> gcompris.
> P3S: [s0 + w*ex + (w*(1+ez)*(2*lx-(1+ex)))/(2*ly+1+ez); e? is the 3D eye 
> position, l? the 2D wall distance, and s0 and w are screen position and 
> width]
> P4S: [s0 + w*(2*lx-1)/(2*ly+1) if you center the eye]
> ----
> 

> --- maze.c.orig	2002-10-13 23:35:57.000000000 +0200
> +++ maze.c	2002-10-13 23:53:43.000000000 +0200
> @@ -44,7 +44,6 @@
>  static int Maze[MAX_BREEDTE][MAX_HOOGTE];
>  static int position[MAX_BREEDTE*MAX_HOOGTE][2];
>  
> -
>  static int ind=0;
>  static int begin;
>  static int end; 
> @@ -55,6 +54,7 @@
>  static int board_border_x=20;
>  static int board_border_y=3;
>  static int thickness=2;
> +static gboolean run_fast=TRUE;
>  /*-----------------------*/
>  
>  GcomprisBoard *gcomprisBoard = NULL;
> @@ -80,7 +80,7 @@
>  static void maze_destroy_all_items(void);
>  static void maze_next_level(void);
>  static void set_level (guint level);
> -gint key_press(guint keyval);
> +static gint key_press(guint keyval);
>  /*--------------------*/
>  static void draw_a_rect(GnomeCanvasGroup *group, int x1, int y1, int x2, int y2, char *color);
>  static void draw_a_line(GnomeCanvasGroup *group, int x1, int y1, int x2, int y2, char *color);
> @@ -492,7 +492,7 @@
>  
>  static int check(int x,int y)
>  {
> -	if ((Maze[x][y]-SET)>=0)
> +	if (Maze[x][y]&SET)
>  	    return 1;
>  	else return 0;
>  }
> @@ -501,59 +501,55 @@
>  {
>  	int wall=Maze[x][y];
>  	static int pos[5];
> -	wall=wall-SET;
> +	wall&=~SET;
>  	pos[0]=0;
>  	if(x==0)
>  	{
> -	    wall=wall-WEST;
> +	    wall&=~WEST;
>  	}
>  	if (y==0)
>  	{
> -	    wall=wall-NORTH;
> +	    wall&=~NORTH;
>  	}
>  	if(x==(breedte-1))
>  	{
> -	    wall=wall-EAST;
> +	    wall&=~EAST;
>  	}
>  	if (y==(hoogte-1))
>  	{
> -	    wall=wall-SOUTH;
> +	    wall&=~SOUTH;
>  	}
> -	if (wall-EAST>=0)
> +	if (wall&EAST)
>  	{
>  	    if(check(x+1,y)==0)
>  	    {
>  			pos[0]=pos[0]+1;
>  			pos[(pos[0])]=EAST;
>  	    }
> -	    wall=wall-EAST;
>  	}
> -	if (wall-SOUTH>=0)
> +	if (wall&SOUTH)
>  	{
>  	    if (check(x,y+1)==0)
>  	    {
>  			pos[0]=pos[0]+1;
>  			pos[(pos[0])]=SOUTH;
>  	    }
> -	    wall=wall-SOUTH;
>  	}
> -	if (wall-WEST>=0)
> +	if (wall&WEST)
>  	{
>  	    if (check(x-1,y)==0)
>  	    {
>  			pos[0]=pos[0]+1;
>  			pos[(pos[0])]=WEST;
>  	    }
> -	    wall=wall-WEST;
>  	}
> -	if (wall-NORTH>=0)
> +	if (wall&NORTH)
>  	{
>  	    if (check(x,y-1)==0)
>  	    {
>  			pos[0]=pos[0]+1;
>  			pos[(pos[0])]=NORTH;
>  	    }
> -	    wall=wall-NORTH;
>  	}
>  	return &pos[0];
>  }
> @@ -574,23 +570,23 @@
>  	    switch (ran)
>  	    {
>  		case EAST:
> -		    Maze[x][y]=Maze[x][y]-EAST;
> -		    Maze[x+1][y]=Maze[x+1][y]-WEST;
> +		    Maze[x][y]&=~EAST;
> +		    Maze[x+1][y]&=~WEST;
>  		    generateMaze(x+1,y);
>  		    break;
>  		case SOUTH:
> -		    Maze[x][y]=Maze[x][y]-SOUTH;
> -		    Maze[x][y+1]=Maze[x][y+1]-NORTH;
> +		    Maze[x][y]&=~SOUTH;
> +		    Maze[x][y+1]&=~NORTH;
>  		    generateMaze(x,y+1);
>  		    break;
>  		case WEST:
> -		    Maze[x][y]=Maze[x][y]-WEST;
> -		    Maze[x-1][y]=Maze[x-1][y]-EAST;		
> +		    Maze[x][y]&=~WEST;
> +		    Maze[x-1][y]&=~EAST;		
>  		    generateMaze(x-1,y);
>  		    break;
>  		case NORTH:
> -		    Maze[x][y]=Maze[x][y]-NORTH;
> -		    Maze[x][y-1]=Maze[x][y-1]-SOUTH;
> +		    Maze[x][y]&=~NORTH;
> +		    Maze[x][y-1]&=~SOUTH;
>  		    generateMaze(x,y-1);
>  		    break;
>  		
> @@ -607,8 +603,7 @@
>  	{
>  	    for (y=0; y < hoogte; y++)
>  	    {
> -		if (Maze[x][y]>=16)
> -		    Maze[x][y]=Maze[x][y]-SET;
> +			Maze[x][y]&=~SET;
>  	    }
>  	}
>  }
> @@ -633,74 +628,26 @@
>  
>  			if (y1==0)
>  				draw_a_line(boardRootItem,x, y, x+cellsize, y, LINE_COLOR);
> -			if ((wall-EAST>=0))
> -			{
> -				draw_a_line(boardRootItem,x+cellsize, y, x+cellsize, y+cellsize, LINE_COLOR);			
> -				wall=wall-EAST;
> -			}
>  
> -			if ((wall-SOUTH)>=0)
> -			{
> +			if (wall&EAST)
> +				draw_a_line(boardRootItem,x+cellsize, y, x+cellsize, y+cellsize, LINE_COLOR);
> +
> +			if (wall&SOUTH)
>  				draw_a_line(boardRootItem,x, y+cellsize, x+cellsize, y+cellsize, LINE_COLOR);
> -				wall=wall-SOUTH;
> -			}
>  
>  	    }
>  	}
>  }
> -static void movePos(int x1, int y1, int x2,int y2)
> +
> +static void movePos(int x1, int y1, int x2,int y2, int richting)
>  {
> -	int richting,ret,wall,i,bo=1;
> -	richting=0;
> +	int ret,wall,i,bo=1;
>  	ret=1;
>  	wall=Maze[x1][y1];
> -	if (x1==x2 && y1>y2)
> -	{	
> -		richting=NORTH;
> -	}
> -	if (x1==x2 && y1<y2)
> -	{	
> -		richting=SOUTH;
> -	}
> -	if (x1>x2 && y1==y2)
> -	{
> -		richting=WEST;
> -	}
> -	if (x1<x2 && y1==y2)
> -	{
> -		richting=EAST;
> -	}
> -	if((wall-SET)>=0)
> -	{
> -		wall=wall-SET;
> -	}
> -	if((wall-EAST)>=0)
> -	{
> -		wall=wall-EAST;
> -		if (richting==EAST)
> -			ret=0;
> -	}
> -	if((wall-SOUTH)>=0)
> -	{
> -		wall=wall-SOUTH;
> -		if (richting==SOUTH)
> -			ret=0;
> -	}
> -	if((wall-WEST)>=0)
> -	{
> -		wall=wall-WEST;
> -		if (richting==WEST)
> -			ret=0;
> -	}
> -	if((wall-NORTH)>=0)
> -	{
> -		wall=wall-NORTH;
> -		if (richting==NORTH)
> -			ret=0;
> -	}
> +	if (wall&richting) ret=0;
>  	if (ret)
>  	{
> -		if (Maze[x2][y2]-SET>=0)
> +		if (Maze[x2][y2]&SET)
>  		{
>  			for (i=(ind); i>=0 && bo; i--)
>  			{
> @@ -713,7 +660,7 @@
>  				}
>  				else
>  				{
> -					Maze[position[i][0]][position[i][1]]=Maze[position[i][0]][position[i][1]]-SET;
> +					Maze[position[i][0]][position[i][1]]&=~SET;
>  					draw_rect(mazegroup,position[i][0],position[i][1],"red");
>  					draw_combined_rect(mazegroup,position[i-1][0],position[i-1][1],position[i][0],position[i][1],"red");
>  					ind--;
> @@ -727,7 +674,7 @@
>  			ind++;
>  			position[ind][0]=x2;
>  			position[ind][1]=y2;
> -			Maze[x2][y2]=Maze[x2][y2]+SET;
> +			Maze[x2][y2]|=SET;
>  			if (position[ind][0]==(breedte-1) && position[ind][1]==(end))
>  				game_won();
>  			else
> @@ -738,32 +685,53 @@
>  			}
>  		}
>  	}
> -	
>  }
>  
> -
> -
> -gint key_press(guint keyval){
> -
> -	if ( keyval== GDK_Left)
> -	{
> -		movePos(position[ind][0],position[ind][1],position[ind][0]-1,position[ind][1]);
> -		return TRUE;
> -	}
> -	else if (keyval==GDK_Right)
> -	{
> -		movePos(position[ind][0],position[ind][1],position[ind][0]+1,position[ind][1]);
> -		return TRUE;		
> -	}
> -	else if (keyval==GDK_Up)
> -	{
> -		movePos(position[ind][0],position[ind][1],position[ind][0],position[ind][1]-1);
> -		return TRUE;		
> +/* return available directions, do not count direction we are coming from
> +   returns 0 if no or more than one direction is possible */
> +static guint available_direction(guint last_step)
> +{	guint number=0,result=0;
> +	if (last_step!=WEST && !(Maze[position[ind][0]][position[ind][1]]&EAST))
> +	{  number++; result|=EAST; }
> +	if (last_step!=EAST && !(Maze[position[ind][0]][position[ind][1]]&WEST))
> +	{  number++; result|=WEST; }
> +	if (last_step!=NORTH && !(Maze[position[ind][0]][position[ind][1]]&SOUTH))
> +	{  number++; result|=SOUTH; }
> +	if (last_step!=SOUTH && !(Maze[position[ind][0]][position[ind][1]]&NORTH))
> +	{  number++; result|=NORTH; }
> +	if (number>1) return 0;
> +	return result;
> +}
> +
> +static void one_step(guint richting)
> +{	switch (richting)
> +	{   case WEST: movePos(position[ind][0],position[ind][1],position[ind][0]-1,position[ind][1],richting);
> +			return;
> +		case EAST: movePos(position[ind][0],position[ind][1],position[ind][0]+1,position[ind][1],richting);
> +			return;
> +		case NORTH: movePos(position[ind][0],position[ind][1],position[ind][0],position[ind][1]-1,richting);
> +			return;	
> +		case SOUTH: movePos(position[ind][0],position[ind][1],position[ind][0],position[ind][1]+1,richting);
> +			return;
>  	}
> -	else if (keyval==GDK_Down)
> -	{
> -		movePos(position[ind][0],position[ind][1],position[ind][0],position[ind][1]+1);
> -		return TRUE;		
> +}
> +
> +static gint key_press(guint keyval)
> +{	guint richting=0,level=gcomprisBoard->level;
> +	switch (keyval)
> +	{	case GDK_Left: richting=WEST; break;
> +		case GDK_Right: richting=EAST; break;
> +		case GDK_Up: richting=NORTH; break;
> +		case GDK_Down: richting=SOUTH; break;
> +		default: return FALSE;
> +	}
> +	if (Maze[position[ind][0]][position[ind][1]]&richting) return TRUE;
> +	one_step(richting);
> +
> +	/* run until we come to a fork, (make sure to stop on next level!) */
> +	while (run_fast && (richting=available_direction(richting))
> +		&& gcomprisBoard->level==level)
> +	{	one_step(richting);
>  	}
> -  return FALSE;
> +	return TRUE;
>  }






More information about the Gcompris-devel mailing list