Source code of my entry for Retro gaming contest (www.outrageouscircuits.com)
Fork of LCD_DEMO by
NOTE: I don't why mbed says that it's a fork form LCD_DEMO by Chris Taylor -> I don't use that library
SHAKE THE MAZE!!!
Shake your RETRO board and solve the maze!!!
Different maze everytime!
Here a case I built.
More details in main.cpp comments
video:
main.cpp
- Committer:
- gbr1mbed
- Date:
- 2015-03-01
- Revision:
- 1:600980390cf7
- Parent:
- 0:7260a2716edf
File content as of revision 1:600980390cf7:
/* * SHAKE THE MAZE!!! * * Author: BRUNO Giovanni di Dio [ aka GBr1 ] * site: www.gbr1industries.altervista.org * * video: http://youtu.be/puCMuQ1Li1I * * * * HOW TO PLAY: * 1. You need only the RETRO board by Outrageous Circuit * 2. After loaded the file (I use "cp" command in mac osx terminal ) * Note: file .bin is about 32KB I don't try if Windows drag and drop works well :( * 3. Reset * 4. Left LED is turned on * 5. Shake the board * 6. Press start button (alien spaceship button) * 7. Left LED is turned off * 8. Wait beep end * 9. Move the board to put green ball into red square (finish) * 10. When you finish Right LED is turned on * 11. Press start to play again * 12. Right LED is turned off * 13. You have a new maze to solve (go to 8) * * * NOTE: don't update to a newer version */ #include "mbed.h" //RETRO board display #include "DisplayN18.h" //C++ standard stack class #include <stack> //RETRO board accelerometer #include "MMA8453.h" //accelerometer MMA8453 acc(P0_5,P0_4); //x axis double xx=0; //y axis double yy=0; //z axis (it will be used in initRand()) double zz=0; //Alien Spaceship button DigitalIn start(P0_1,PullUp); //Left LED -> capturing accelerometer data to random seed DigitalOut ledL(P0_9); //Right LED -> Do you want to play? DigitalOut ledR(P0_8); //Buzzer (due low program memory I use software PWM) DigitalOut buzzer(P0_18); //numbers for random function unsigned int m_z=0; unsigned int m_w=0; //display object DisplayN18 Surface; //colors used static const unsigned short CLINE = DisplayN18::BLUE; //blue static const unsigned short CBALL = DisplayN18::GREEN; //green static const unsigned short CEND = DisplayN18::RED; //red static const unsigned short CBACK = DisplayN18::BLACK; //black static const unsigned short CTEXT1 = 0xF81F; //yellow static const unsigned short CTEXT2 = 0xFFE0; //violet static const unsigned short CTEXT3 = 0xFFFF; //white //constants to indicate cardinal coordinates //I used 0 to 3 because I will do random from 0 to 3 const int NORTH=0; const int SOUTH=1; const int EAST=2; const int WEST=3; //maze blocks size const int SIZEX=32; const int SIZEY=23; //create maze variables int nGood = 0; int locX = 1, locY = 1; //ball and generally print coordinates int x=0; int y=0; /*my function to explore maze and generate random values*/ //pseudo-random function //on lpc11u24 random doesn't work (it equals rand() ) unsigned int rnd(); //random seed & initial window (it equals srand and a simple text show function) void initRand(); //estabilish on which type of pattern you are //you have to remember that in this case N=1 S=2 E=4 W=8 it allows you to have unique combinations int evaluateCell(int i, int j,bool grid[SIZEY][SIZEX]); //redraw ball and check if there are collisions void updateBall(int direction, bool grid[SIZEY][SIZEX]); //draw the maze void printGrid(bool grid[SIZEY][SIZEX]); /*maze creation functions*/ //I used recoursive backtracker http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker //move on x axis int moveEW(int direction, int i); //move on y axis int moveNS(int direction, int j); //check if it can go here bool isGood(int i, int j, int direction, bool grid[SIZEY][SIZEX]); //create maze void createMaze(bool grid[SIZEY][SIZEX]); //draw finish pattern and mark it on the maze and check also if it will be possible to go there void checkEnd(bool grid[SIZEY][SIZEX]); /*---game functions---*/ //simple beep void sound(); //initialize game void initGame(bool grid[SIZEY][SIZEX]); //function which allows you to play void coreGame(bool grid[SIZEY][SIZEX]); /*---main---*/ int main(){ //create grid //using recoursive function is better if grid is here bool grid[SIZEY][SIZEX]; //initialize random (first screen) initRand(); //initialize game (second screen - play) initGame(grid); //play ;) while(1){ coreGame(grid); } } /*---implementations---*/ unsigned int rnd(){ //pseudo-random function m_z = 36969 * (m_z & 65535) + (m_z >>16); m_w = 18000 * (m_w & 65535) + (m_w >>16); return ((m_z <<16) + m_w); } void initRand(){ //preserve for pressing button before the game while(start==0); //show initial screen ledL=1; Surface.clear(); Surface.drawString(16,30,"Shake it!!!",CTEXT1,CBACK,2); Surface.drawString(32,90,"press start",CTEXT2,CBACK); Surface.drawString(48,100,"to continue...",CTEXT2,CBACK); //wait for checking alien spaceship button while(start==1){ //simple function to read values and sum them //NOTE: you need to do abs because accelerometer values could be negative acc.getXYZ(xx,yy,zz); xx=abs(xx)*200; yy=abs(yy)*200; zz=abs(zz)*200; m_z=m_z+xx*yy+zz; m_w=m_w+xx+yy*zz; } ledL=0; } int evaluateCell(int i, int j,bool grid[SIZEY][SIZEX]){ int cell=0; //estabilish type of pattern (just sum values of walls if ((i>=0)&&(i<(SIZEX-1))){ if (grid[j][i+1]==true) { cell+=4; } } if ((i>0)&&(i<=(SIZEX-1))){ if (grid[j][i-1]==true) { cell+=8; } } if ((j>=0)&&(j<(SIZEY-1))){ if (grid[j+1][i]==true) { cell+=2; } } if ((j>0)&&(j<=(SIZEY-1))){ if (grid[j-1][i]==true) { cell+=1; } } return cell; } void updateBall(int direction, bool grid[SIZEY][SIZEX]){ //clear old ball Surface.fillCircle(x+2,y+15,2,CBACK); //check if is possible to move ball in "direction" //it checks every situation int cell=evaluateCell(x/5,y/5,grid); if ((direction==NORTH)&&((cell%2)==0)){ y=y-5; } if ((direction==SOUTH)&&((cell==0)||(cell==1)||(cell==4)||(cell==5)||(cell==8)||(cell==9)||(cell==12)||(cell==13))){ y=y+5; } if ((direction==EAST)&&((cell==0)||(cell==1)||(cell==2)||(cell==3)||(cell==8)||(cell==9)||(cell==10)||(cell==11))){ x=x+5; } if ((direction==WEST)&&((cell>=0)&&(cell<=7))){ x=x-5; } //draw ball Surface.fillCircle(x+2,y+15,2,CBALL); } void printGrid(bool grid[SIZEY][SIZEX]){ Surface.clear(); Surface.drawString(2,2,"Shake the Maze!!! GBr1_15",CTEXT3,CBACK); int cell=0; for (int j = 0; j < SIZEY; j++){ for(int i = 0; i < SIZEX; i++){ cell=0; if (grid[j][i]==true) { cell=evaluateCell(i,j,grid); //offset and 5pixels maze block x=i*5; y=(j*5)+13; //show 16 different cases of maze patterns //using N=1 E=4 S=2 W=8 -> do combination //example 11 is // // OXO // XXO // OXO //where O is free pattern X is a wall switch (cell) { case 0: Surface.setPixel(x+2,y+2,CLINE); break; case 1: Surface.drawLine(x+2,y,x+2,y+3,CLINE); break; case 2: Surface.drawLine(x+2,y+2,x+2,y+5,CLINE); break; case 3: Surface.drawLine(x+2,y,x+2,y+5,CLINE); break; case 4: Surface.drawLine(x+2,y+2,x+5,y+2,CLINE); break; case 5: Surface.drawLine(x+2,y,x+2,y+3,CLINE); Surface.drawLine(x+3,y+2,x+5,y+2,CLINE); break; case 6: Surface.drawLine(x+2,y+2,x+5,y+2,CLINE); Surface.drawLine(x+2,y+3,x+2,y+5,CLINE); break; case 7: Surface.drawLine(x+2,y,x+2,y+5,CLINE); Surface.drawLine(x+3,y+2,x+5,y+2,CLINE); break; case 8: Surface.drawLine(x,y+2,x+3,y+2,CLINE); break; case 9: Surface.drawLine(x+2,y,x+2,y+3,CLINE); Surface.drawLine(x,y+2,x+2,y+2,CLINE); break; case 10: Surface.drawLine(x+2,y+2,x+2,y+5,CLINE); Surface.drawLine(x,y+2,x+2,y+2,CLINE); break; case 11: Surface.drawLine(x+2,y,x+2,y+5,CLINE); Surface.drawLine(x,y+2,x+2,y+2,CLINE); break; case 12: Surface.drawLine(x,y+2,x+5,y+2,CLINE); break; case 13: Surface.drawLine(x+2,y,x+2,y+2,CLINE); Surface.drawLine(x,y+2,x+5,y+2,CLINE); break; case 14: Surface.drawLine(x+2,y+3,x+2,y+5,CLINE); Surface.drawLine(x,y+2,x+5,y+2,CLINE); break; case 15: Surface.drawLine(x+2,y,x+2,y+5,CLINE); Surface.drawLine(x,y+2,x+5,y+2,CLINE); break; } } } } } int moveEW(int direction, int i){ if (direction == EAST) return i + 1; else if (direction == WEST) return i - 1; else return i; } int moveNS(int direction, int j){ if (direction == NORTH) return j - 1; else if (direction == SOUTH) return j + 1; else return j; } bool isGood(int i, int j, int direction, bool grid[SIZEY][SIZEX]){ i = moveEW(direction,i); j = moveNS(direction,j); //check if it should be the end if ((grid[j][i]==false)||(i>=(SIZEX - 1))||(i<=0)||(j<= 0)||(j>=(SIZEY - 1))){ return false; } //check cardinal directions if (direction == NORTH){ if ((grid[j][i-1]!=false)&&(grid[j-1][i]!=false)&&(grid[j][i+1]!=false)&&(grid[j-1][i-1]!=false)&&(grid[j-1][i+1]!=false)){ return true; } } if (direction == SOUTH){ if ((grid[j][i-1]!=false)&&(grid[j+1][i]!=false)&&(grid[j][i+1]!=false)&&(grid[j+1][i-1]!=false)&&(grid[j+1][i+1]!=false)){ return true; } } if (direction == EAST){ if ((grid[j][i+1]!=false)&&(grid[j-1][i]!=false)&&(grid[j+1][i]!=false)&&(grid[j-1][i+1]!=false)&&(grid[j+1][i+1]!=false)){ return true; } } if (direction == WEST){ if ((grid[j][i-1]!=false)&&(grid[j-1][i]!=false)&&(grid[j+1][i]!=false)&&(grid[j-1][i-1]!=false)&&(grid[j+1][i-1]!=false)){ return true; } } return false; } void createMaze(bool grid[SIZEY][SIZEX]){ //initialize grid for (int i = 0; i < SIZEY; i++){ for(int j = 0; j < SIZEX; j++){ grid[i][j] = true; } } //initialize stacks for xy coordinates stack<int> xValues; stack<int> yValues; nGood = 0; int direction = 0; do{ //find n good moves for (int i = 0; i < 4; i++){ if (isGood(locX,locY,i,grid)) nGood++; } // if only 1 good move, move there if (nGood == 1){ if (isGood(locX,locY,NORTH,grid)) locY = moveNS(NORTH,locY); else if (isGood(locX,locY,SOUTH,grid)) locY = moveNS(SOUTH,locY); else if (isGood(locX,locY,EAST,grid)) locX = moveEW(EAST,locX); else if (isGood(locX,locY,WEST,grid)) locX = moveEW(WEST,locX); } // if no good moves, move back in stack else if (nGood == 0){ locX = xValues.top(); locY = yValues.top(); xValues.pop(); yValues.pop(); } //if more than 1 good move, push stack else if (nGood > 1){ xValues.push(locX); yValues.push(locY); //direction to move randomly chosen do{ direction = rnd()%4; }while (!isGood(locX,locY,direction,grid)); locX = moveEW(direction,locX); locY = moveNS(direction,locY); } //set grid grid[locY][locX] = false; //reset nGood value nGood = 0; }while(!xValues.empty()); } void checkEnd(bool grid[SIZEY][SIZEX]){ //check low right angle if (grid[SIZEY-2][SIZEX-2]==true){ grid[SIZEY-2][SIZEX-2]=false; } int k=1; while(((grid[SIZEY-3][SIZEX-2]==false)&&(grid[SIZEY-2][SIZEX-2-k]==false))&&(k<SIZEX-3)){ grid[SIZEY-2][SIZEX-2-k]=false; Surface.fillRect((SIZEX-2-k)*5,(SIZEY-2)*5+13,5,5,CBACK); k++; } if(k>=SIZEX-3){ initGame(grid); } //draw finish square Surface.fillRect((SIZEX-2)*5,(SIZEY-2)*5+13,5,5,CEND); } void sound(){ //simulate pwm for(int i=0; i<1000; i++){ buzzer=1; wait(0.0005); buzzer=0; } } void initGame(bool grid[SIZEY][SIZEX]){ createMaze(grid); printGrid(grid); checkEnd(grid); //it is for checking the possible maze finish (low right angle) x=5; y=5; Surface.fillCircle(x+2,y+15,2,CBALL); sound(); } void coreGame(bool grid[SIZEY][SIZEX]){ //read x and y on accelerometer xx=acc.getX(); yy=acc.getY(); //increase accelerometer value (generally 0.xx and standard value 0.5G and not G); xx=2*xx*10; yy=2*yy*10; //conditions and relative next move //I put 2 as filter value so, if you leave you RETRO on a table ball will not move if(xx<-2){ updateBall(WEST,grid); } else{ if(xx>2){ updateBall(EAST,grid); } } if(yy>2){ updateBall(SOUTH,grid); } else{ if(yy<-2){ updateBall(NORTH,grid); } } //check if the ball is at the end of the pattern (low right angle) if ((x/5==(SIZEX-2))&&(y/5==SIZEY-2)){ ledR=1; sound(); //wait for start button while(start==1); //init game initGame(grid); ledR=0; } }