Completed Snake Program

Dependencies:   N5110 PinDetect PowerControl mbed

Fork of DocTest by Craig Evans

Revision:
9:77b83754460c
Parent:
8:b857684a3983
Child:
10:dbcb96fa049d
diff -r b857684a3983 -r 77b83754460c main.cpp
--- a/main.cpp	Thu Apr 30 20:53:56 2015 +0000
+++ b/main.cpp	Fri May 01 08:53:21 2015 +0000
@@ -17,13 +17,14 @@
     HARD,
 };
 
+// create enumerated type (0,1 for Game Mode)
 enum GameMode {
     CLASSIC,
     BOUNDARY,
 };
 
 Difficulty currentDifficulty=EASY;// initialise to easy mode
-GameMode   selectedGameMode=CLASSIC;
+GameMode   selectedGameMode=CLASSIC; //initialise to Classic Mode
 
 // struct for Joystick
 typedef struct JoyStick Joystick;
@@ -112,10 +113,11 @@
     lcd.printString("Easy",20,3);
     lcd.printString("Medium",20,4);
     lcd.printString("Hard",20,5);
-    lcd.refresh();
+
     lcd.drawCircle(10,27,2,1);
     lcd.drawCircle(10,35,2,0);
     lcd.drawCircle(10,43,2,0);
+    lcd.refresh();
 
     gameSpeed= 1.0/5; // set easy game speed(for game time)
 }
@@ -128,11 +130,12 @@
     lcd.printString("Easy",20,3);
     lcd.printString("Medium",20,4);
     lcd.printString("Hard",20,5);
-    lcd.refresh();
+
     lcd.drawCircle(10,27,2,0);
     lcd.drawCircle(10,35,2,1);
     lcd.drawCircle(10,43,2,0);
     gameSpeed=1.0/7; // set medium game speed
+    lcd.refresh();
 }
 
 void hardSelected() // display when hard is selected
@@ -144,14 +147,15 @@
     lcd.printString("Easy",20,3);
     lcd.printString("Medium",20,4);
     lcd.printString("Hard",20,5);
-    lcd.refresh();
+
     lcd.drawCircle(10,27,2,0);
     lcd.drawCircle(10,35,2,0);
     lcd.drawCircle(10,43,2,1);
+    lcd.refresh();
     gameSpeed=1.0/12; // set hard game speed
 }
 
-void classicModeSelected()
+void classicModeSelected() //display when classic mode selected
 {
 
 
@@ -161,32 +165,34 @@
     lcd.printString("Game Mode:",2,1);
     lcd.printString("Classic",20,3);
     lcd.printString("Boundary",20,4);
-    lcd.refresh();
+
     lcd.drawCircle(10,27,2,1);
     lcd.drawCircle(10,35,2,0);
+    lcd.refresh();
 
 }
 
-void boundaryModeSelected()
+void boundaryModeSelected() // display when boundary mode selected
 {
-    selectedGameMode=BOUNDARY;
+    selectedGameMode=BOUNDARY;//update selecected game mode
     lcd.clear();
     lcd.printString("Please Select",2,0);
     lcd.printString("Game Mode:",2,1);
     lcd.printString("Classic",20,3);
     lcd.printString("Boundary",20,4);
-    lcd.refresh();
+
     lcd.drawCircle(10,27,2,0);
     lcd.drawCircle(10,35,2,1);
+    lcd.refresh();
 
 }
 
 
-void checkSelectedGameMode()
+void checkSelectedGameMode()// updates selected game mode menu depending on joystick direction
 {
 
     switch(selectedGameMode) {
-        case CLASSIC://classicMode;
+        case CLASSIC:
 
             switch (joystick.direction) {
 
@@ -285,9 +291,9 @@
 
 void startingSnake()
 {
-    snakeX.resize(5);
-    snakeY.resize(5);
-    snakeX[0]=20;
+    snakeX.resize(5); // ensure that when game is reset snake vectors are resized back to 5
+    snakeY.resize(5);//
+    snakeX[0]=20; // initial snake position
     snakeX[1]=22;
     snakeX[2]=24;
     snakeX[3]=26;
@@ -300,8 +306,8 @@
 
 
     for (int i=0; i<5; i++) {
-        // lcd.setPixel(snakeX[i],snakeY[i]);
-        lcd.drawRect(snakeX[i],snakeY[i],1,1,1);
+
+        lcd.drawRect(snakeX[i],snakeY[i],1,1,1); // snake is 2X2 pixels so draw rect with one width and 1 height
     }
 
 }
@@ -312,9 +318,9 @@
 //   http://stackoverflow.com/questions/3383286/create-a-random-even-number-between-range
 
 
-    srand(time(NULL));
+    srand(time(NULL)); // using time as a seed for rand
 
-    int randomX = 2 * (1 + rand() % (40 - 1 + 1)) ; //generate random even number between 2 and 80
+    int randomX = 2 * (1 + rand() % (40 - 1 + 1)) ; //generate random even number between 2 and 80 // these are the only coordinates the snake operates in
 
     int randomY = (2 * (4 + rand() % (22 - 4 + 1))) +1; // generate random even number between 8 and 44 then plus 1 for odd number in range of 9-45
 
@@ -322,13 +328,12 @@
     while(lcd.getPixel(randomX,randomY)==1) { // if that pixel is already filled keep generating till a empty space is found
 
         int randomX = 2 * (1 + rand() % (40 - 1 + 1)) ;
-        int randomY = (2 * (4 + rand() % (22 - 4 + 1))) +1; // generate random even number between 8 and 44 then plus 1 for odd number in range of 9-45
+        int randomY = (2 * (4 + rand() % (22 - 4 + 1))) +1;
 
 
     }
-    // lcd.setPixel(randomX,randomY) ;// set the food
-    lcd.drawRect(randomX,randomY,1,1,1);
-    //lcd.setPixel(randomX,randomY);
+
+    lcd.drawRect(randomX,randomY,1,1,1); // set the food to screen
 
     foodX[0]=randomX; // update food position
     foodY[0]=randomY;// update food position
@@ -336,7 +341,7 @@
 //serial.printf("%d",randomX);
 }
 
-void hardBoundary()
+void hardBoundary() // use these boundary conditions if gamemode is BOUNDARY
 {
 
 
@@ -356,7 +361,7 @@
     lcd.refresh();
 
 }
-void classicBoundary()
+void classicBoundary() // use these boundaries if gamemode is classic
 {
 
 
@@ -380,108 +385,115 @@
 
 void updateSnakeArray()
 {
-
-    if (joystick.direction==LEFT && previousDirection==RIGHT) {
-        joystick.direction=RIGHT;
+// code to prevent snake moving in opposite direction to its current path of travel
+    if (joystick.direction==LEFT && previousDirection==RIGHT) { // if snake is travelling right but joystick is left
+        joystick.direction=RIGHT; // cary on right
     }
 
-    if (joystick.direction==RIGHT && previousDirection==LEFT) {
-        joystick.direction=LEFT;
+    if (joystick.direction==RIGHT && previousDirection==LEFT) { // if snake is travelling left but joystick is right
+        joystick.direction=LEFT; //carry on left
     }
 
-    if (joystick.direction==UP && previousDirection==DOWN) {
-        joystick.direction=DOWN;
+    if (joystick.direction==UP && previousDirection==DOWN) {// if snake is travelling down but joystick is up
+        joystick.direction=DOWN; // carry on down
     }
 
-    if (joystick.direction==DOWN && previousDirection==UP) {
-        joystick.direction=UP;
+    if (joystick.direction==DOWN && previousDirection==UP) { // if snake is travelling up but joystick is down
+        joystick.direction=UP; // carry on up
     }
 
-    if (joystick.direction==UNKNOWN || joystick.direction==CENTRE) {
-        joystick.direction= previousDirection;
+    if (joystick.direction==UNKNOWN || joystick.direction==CENTRE) { // if joystick is unknown or centred
+        joystick.direction= previousDirection;  // carry on in previous direction
     }
 
 
-    // lcd.clearPixel(snakeX[0],snakeY[0]);//delete tail
-    lcd.drawRect(snakeX[0],snakeY[0],1,1,2);
+    lcd.drawRect(snakeX[0],snakeY[0],1,1,2); // delete tail of snake by drawing a clear 2x2 block at first element in vectors
 
     for (int i =0; i<snakeX.size(); i++) {  // shift elements
         snakeX[i]=snakeX[i + 1]; // apart from head
         snakeY[i]=snakeY[i+ 1];
     }
 
+//code to set new head coordinates
     switch(joystick.direction) {
 
-        case UP:
-            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2];
-            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2]-2;
+        case UP:  // if travelling up
+            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]; // snake new head x coordinate = previous head c coordinate
+            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2]-2; // snake new head y cordinate = previous head y coordinate -2 as it moves up
 
-           if (selectedGameMode==CLASSIC){
-             if(snakeY[snakeY.size()-1] <9) snakeY[snakeY.size()-1]=45;
-             }
+            if (selectedGameMode==CLASSIC) { // when in classic mode no boundaries so need to check if new head is beyond edge limit
+                if(snakeY[snakeY.size()-1] <9) snakeY[snakeY.size()-1]=45; // when travelling up check head against upper edge
+            }
             break;
 
-        case DOWN:
-            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2];
-            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2]+2;
-            
-          if (selectedGameMode==CLASSIC){
-            if(snakeY[snakeY.size()-1] >45) snakeY[snakeY.size()-1]=9;
+        case DOWN:// if travelling down
+            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2];   // snake new head x coordinate = previous head c coordinate
+            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2]+2;// snake new head y cordinate = previous head y coordinate +2 as it moves down
+
+            if (selectedGameMode==CLASSIC) { // when in classic mode no boundaries so need to check if new head is beyond edge limit
+                if(snakeY[snakeY.size()-1] >45) snakeY[snakeY.size()-1]=9; // check new head against bottom edge
             }
             break;
 
         case LEFT:
-            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]-2;
-            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
-            
-             if (selectedGameMode==CLASSIC){
-             if(snakeX[snakeX.size()-1] <2) snakeX[snakeX.size()-1]=80;
-             }
+            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]-2;  // snake new head x coordinate = previous head x coordinate - 2
+            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];// snake new head y coordinate = previous head y coordinate
+
+            if (selectedGameMode==CLASSIC) { //  when in classic mode no boundaries so need to check if new head is beyond edge limit
+                if(snakeX[snakeX.size()-1] <2) snakeX[snakeX.size()-1]=80; // check head against left edge
+            }
             break;
 
         case RIGHT:
-            snakeX[snakeX.size()-1]= snakeX[snakeX.size()-2]+2;
-            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
-            
-             if (selectedGameMode==CLASSIC){
-             if(snakeX[snakeX.size()-1] >80) snakeX[snakeX.size()-1]=2;
-             }
+            snakeX[snakeX.size()-1]= snakeX[snakeX.size()-2]+2; // snake new head x coordinate = previous head x coordinate + 2
+            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];// snake new head y coordinate = previous head y coordinate
+
+            if (selectedGameMode==CLASSIC) { //  when in classic mode no boundaries so need to check if new head is beyond edge limit
+                if(snakeX[snakeX.size()-1] >80) snakeX[snakeX.size()-1]=2;
+            }
 
             break;
 
-        case CENTRE:
-            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]+2;
-            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
-            break;
-        case UNKNOWN:
-            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]+2;
-            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
-            break;
+            /* case CENTRE:
+                 snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]+2;
+                 snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
+                 break;
+             case UNKNOWN:
+                 snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]+2;
+                 snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
+                 break;*/
 
     }
 }
-void playTune()
+void gameOverTune() //
 {
 
-    //float frequency[]={440,659};
-    // float beat[]={1,1,};
-    // Buzzer=0.3;
-    //  Buzzer.period(1/(440));// time =1/f
-    //wait(1);
-    //Buzzer.period(1/(659));
+ //   float frequency[]={440,659};
+    //float beat[]={1,1,};
+    
+      Buzzer.period(1.0/(220)); // set PWM period 1/f  A
+Buzzer=0.5; // set duty cycle
+wait(0.5); // wait time 
+Buzzer.period(1.0/(164)); // E
+wait(0.5);//
+Buzzer=0;// set duty cycle 0
 
-    //Buzzer=0;
+  //   set PWM period
 
-    // set PWM period
+}
 
-// set duty cycle
-    //wait(0.5*beat[i]);
-}
+void eatFoodTune(){
+      Buzzer.period(1.0/(440)); // set PWM period 1/f  A
+Buzzer=0.5; // set duty cycle
+wait(0.1); // wait time 
+Buzzer=0;// set duty cycle 0
+    }
+    
 void gameOver()
 {
     leds=1;
-    startGame.detach();
-    lcd.drawRect(snakeX.back(),snakeY.back(),1,1,2);
+    startGame.detach(); // stop snake game from updating
+    lcd.drawRect(snakeX.back(),snakeY.back(),1,1,2); // highlight the point of game over
     wait(0.2);
     lcd.refresh();
     lcd.drawRect(snakeX.back(),snakeY.back(),1,1,1);
@@ -497,7 +509,7 @@
     lcd.inverseMode();
 
 
-    lcd.printString("Your Score" ,12,0);
+    lcd.printString("Your Score" ,12,0);// print score
     lcd.printString("=" ,34,1);
 
     int updatedScore=score;
@@ -512,29 +524,22 @@
 
     //
     lcd.refresh();
-    playTune();
+    gameOverTune();
 
     //gamePlaying=0;
-
-
-
 }
 
-
-
-void checkForCollision()
+void checkForCollision() // when in BOUNDARY MODE check snake head every move against walls
 {
 
     if (snakeX.back()==0|| snakeX.back()==82 || snakeY.back()==7 ||snakeY.back()>=47) {
         myleds=15;
 
-        gameOver();
+        gameOver(); // if collision then end game
     }
 }
 
-
-
-void checkForFood()
+void checkForFood() // check if snake has eaten food
 {
 
     if (snakeX.back()==foodX[0] && snakeY.back()==foodY[0]) {   // if  x and y of head match food
@@ -543,7 +548,7 @@
         switch(joystick.direction) {
 
             case RIGHT:
-                snakeX.insert (snakeX.begin() +0,foodX[0]-2 );
+                snakeX.insert (snakeX.begin() +0,foodX[0]-2 ); // insert new element to tail of snake vector
                 snakeY.insert (snakeY.begin() ,foodY[0]);
                 //snakeX.push_back(foodX[0]+2);
                 // snakeY.push_back(foodY[0]);
@@ -573,21 +578,21 @@
                 // snakeY.push_back(foodY[0]+2);
                 break;
         }
-        lcd.drawRect(snakeX[0],snakeY[0],1,1,1);
+eatFoodTune();
+        lcd.drawRect(snakeX[0],snakeY[0],1,1,1); // draw the new tail
+
+        int updatedScore; // to store updated score
 
-        int updatedScore;
-        // snakeX.insert (snakeX.begin() + 0, );
-        //snakeY.insert (snakeY.begin() + 0, );
 
-        updatedScore= score+5;
+        updatedScore= score+5; // 5 points for every food eaten
         score=updatedScore;
-        int length = sprintf(buffer,"%2d",updatedScore);
+        int length = sprintf(buffer,"%2d",updatedScore);// print updated score to screen
 
         if (length <= 14)  // if string will fit on display
             lcd.printString(buffer,0,0);
         // lcd.refresh();
 
-        randomiseFood();
+        randomiseFood(); // randomise new food
 
     }
 
@@ -596,12 +601,12 @@
 
 void startButtonPressed()
 {
-    if (menuState==0) {
-        menuState=1;
+    if (gameState==0) { // when at first menu if pressed
+        gameState=1; // move to second menu
     }
 
-  else  if (menuState==1) {
-        menuState=2;
+    else  if (gameState==1) { // when at second menu
+        gameState=2; // move to gameplay
     }
 
 }
@@ -633,18 +638,16 @@
 void pauseButtonPressed()
 {
 
-    if (gamePaused==0) {
+    if (gamePaused==0) { // if game isnt already paused
 
-        startGame.detach();
+        startGame.detach(); // stop game updating
 
-        gamePaused=1;
-        leds=2;
+        gamePaused=1; // update paused status
+        leds=2; // show amber led
 
     }
 
-    else {
-
-
+    else { // if game is paused start game
         startGame.attach(&updateGameISR,gameSpeed);
 
         gamePaused=0;
@@ -654,10 +657,10 @@
 
 }
 
-void checkForCollisionWithSelf(int i)
+void checkForCollisionWithSelf(int i) // checks snake head with all other parts of snake
 {
-    if(snakeX.back()==snakeX[i] && snakeY.back()==snakeY[i]) {
-        gameOver();
+    if(snakeX.back()==snakeX[i] && snakeY.back()==snakeY[i]) { // if both x and y coordinates of any part of snake match head
+        gameOver(); // end game
     }
 
 
@@ -666,7 +669,7 @@
 {
     lcd.inverseMode();
     easySelected();
-    joystick.direction=UNKNOWN;
+    joystick.direction=UNKNOWN; // unknown so does not start scrolling
     calibrateJoystick();  // get centred values of joystick
 
 }
@@ -674,105 +677,97 @@
 void ModeMenu()
 {
     classicModeSelected();
-    joystick.direction=UNKNOWN;
+    joystick.direction=UNKNOWN;// unknown so does not start scrolling
     calibrateJoystick();  // get centred values of joystick
 }
 
 void resetButtonPressed()
 {
-    //gamePlaying=0;
-    menuState=0;
+
+    gameState=0; // when reset button pressed bring back to first menu screen
 }
 
 
 int main()
 {
-   
+ startButton.setSampleFrequency();
     lcd.init();
     resetButton.mode(PullDown);
     startButton.mode(PullDown);
     button.mode(PullDown);
-    startButton.rise(&startButtonPressed);
+  //  startButton.rise(&startButtonPressed);
+    startButton.attach_asserted( &startButtonPressed );
     resetButton.rise(&resetButtonPressed);
     button.rise(&pauseButtonPressed);
     displaySplash();
-     leds=1;
+    leds=1;
     wait(4);
-//serial.printf("starting");
+
     while(1) {
-        leds=1;
+        leds=1;// red light
         startUpMenu();
-        while (menuState==0) {
+        while (gameState==0) { // wait until user has selected difficulty
             updateJoystick();
             checkSelectedDifficulty();
             updateBrightness();
             //serial.printf("check difficulty loop");
-            
-             if (menuState==1){
+
+            if (gameState==1) { // initialise mode menu
                 ModeMenu();
-                }
+            }
         }
 
 
-        while(menuState==1) {
-           // ModeMenu();
-           
+        while(gameState==1) { // wait unit user has pressed start button and selected a game mode
+
             updateJoystick();
             checkSelectedGameMode();
             updateBrightness();
-           
+
         }
 
-        if (menuState==2) {
+        if (gameState==2) { // initialise game
 
             lcd.clear();
-            lcd.normalMode();  
-            if (selectedGameMode==BOUNDARY) hardBoundary();
+            lcd.normalMode(); // normal colours for gameplay
+            if (selectedGameMode==BOUNDARY) hardBoundary(); // depending on game mode selcted set walls
             if (selectedGameMode==CLASSIC) classicBoundary();
-            
-   // normal colour mode
-         
-            previousDirection=RIGHT;
+            previousDirection=RIGHT; // snake has to be moving right when reset (reset bug fix)
             joystick.direction=RIGHT; // make sure when game reset that joystick is reset to right
-            startingSnake();
-            randomiseFood();
-            int score=5;
+            startingSnake(); // print starting snake
+            randomiseFood(); // show random food
+            int score=5;// initial score is 5
             int length = sprintf(buffer,"%2d",score);
             if (length <= 14)  // if string will fit on display
                 lcd.printString(buffer,0,0);
             // lcd.drawRect(0,0,83,7,0);
             lcd.refresh();
-            startGame.attach(&updateGameISR,gameSpeed);
+            startGame.attach(&updateGameISR,gameSpeed); // start game isr speed determined by difficulty chosen
 
-            while (menuState==2) {
+            while (gameState==2) { // while user doesnt press reset
 
                 //  serial.printf("enter game loop");
-                if(updateGameFlag==1) {
-                    leds=4;
-                    //updateJoystick();
-                    updateGameFlag=0;
-                    updateJoystick();
-                    // lcd.clearPixel(snakeX[0],snakeY[0]);
-                    // updateSnakeDirection();
-                    updateSnakeArray();
-                    for (int i=0; i<snakeX.size(); i++) {
+                if(updateGameFlag==1) { // check flag
+                    leds=4; // green LED when game playing
+
+                    updateGameFlag=0; // reset flag
+                    updateJoystick(); // check joystick direction
+
+                    updateSnakeArray(); // update the array
+                    for (int i=0; i<snakeX.size(); i++) { // for all elements of snake draw 2x2 image
                         lcd.drawRect(snakeX[i],snakeY[i],1,1,1);
-                        // lcd.setPixel(snakeX[i],snakeY[i]);
+
                     }
                     lcd.refresh();
-                    previousDirection=joystick.direction;
+                    previousDirection=joystick.direction; // update previous joystick direction
 
-                    if (selectedGameMode==BOUNDARY) checkForCollision();
-                    
-                    
-                    checkForFood();
+                    if (selectedGameMode==BOUNDARY) checkForCollision();// if in boundary mode check for a collision
 
+                    checkForFood(); // check if snake has eaten food
 
                     for (int i=0; i<snakeX.size()-1; i++) {
                         checkForCollisionWithSelf(i);
                         updateBrightness();
-                        //serial.printf("%d",snakeX.size());
-                        // printVectorContent();
 
                     }