Mbed Mini Project: Snakes and Ladders Games

/media/uploads/hfu36/20170313_012438.jpg

Overview

This project uses mbedLPC1768 as platform developing a simple Snake&Ladders game. A navigation switch is used to control two dices. Pushing the Up bottom will control the first dice, and pushing the Down bottom will control the second dice. As seen in the image below, each chess piece start from position-0 and run by the number of the dice. When either of the chess pieces arrives the position-16, the game stops. The one first arrives the position-16 is the winner. During the game, position-3 and position-11 are two special positions. When a chess piece arrives position-4, it will jump to position-8 immediately. When a chess piece arrives position-11, it will drop back to position-3. Sound effects load from MicroSD Card are accompanied with the events like rolling dice, jumping, dropping and winning the games. At the end the game, an image will be loaded from the MicroSD Card as the ending visual effect. Followed by that, the winner will be displayed as text in the uLCD screen.

Game Logic

/media/uploads/hfu36/squares16.gif

Game Interface

/media/uploads/hfu36/1.jpg/media/uploads/hfu36/2.jpg/media/uploads/hfu36/3.jpg

Wiring

SparkfunNav Switch Breakout

WikiPage https://developer.mbed.org/users/4180_1/notebook/using-a-navigation-switch-digital-joystick/ /handbook

mbed LPC1768	                          SparkfunNav Switch Breakout 
gnd	                                                  -                 
p25	                                              U - up
p22                                               D - down
nc -using internal pullups	                          +

uLCD-144-G2 128 by 128 Smart Color LCD

WikiPage https://developer.mbed.org/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/ /handbook

mbed	uLCD Header	       uLCD cable
5V=VU	5V	                     5V
Gnd	    Gnd	                     Gnd
TX=P9	RX	                     TX
RX=P10	TX	                     RX
P11	    Reset	                Reset

SparkFun MicroSD Breakout Board

WikiPage https://developer.mbed.org/cookbook/SD-Card-File-System /handbook

MicroSD Breakout    mbed
   CS  o-------------o 8    (DigitalOut cs)
   DI  o-------------o 5    (SPI mosi)
   VCC o-------------o VOUT
   SCK o-------------o 7    (SPI sclk)
   GND o-------------o GND  
   DO  o-------------o 6    (SPI miso)
   CD  o

Sparkfun Class D audio amp breakout board

WikiPage https://developer.mbed.org/users/4180_1/notebook/using-a-speaker-for-audio-output/ /handbook

mbed	   TPA2005D1	       Speaker
gnd	        pwr - (gnd), in -	
Vout 	    pwr +	
p14         in +	
	        out +	            +
	        out -	            -	

Import programSnake_Ladders_Games

Using mbed LPC1768, navigation swith (Joystick), uLCD-144-G2, microSD Transflash Breakout, Class D high-efficiency audio amp and a small speaker.

Codes

main

#include "mbed.h"
#include "uLCD_4DGL.h"
#include "SDFileSystem.h"
#include "wave_player.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board
uLCD_4DGL uLCD(p13,p14,p11); // serial tx, serial rx, reset pin;
AnalogOut DACout(p18);
wave_player waver(&DACout);
Serial pc(USBTX, USBRX); 

void sanke_ladder(){
    //ladder
    uLCD.line(84, 20, 84, 44, WHITE);
    uLCD.line(92, 20, 92, 44, WHITE);
    uLCD.line(84, 24, 92, 24, WHITE);
    uLCD.line(84, 40, 92, 40, WHITE);
    
    //sanke
    uLCD.line(72, 24, 72, 56, WHITE);
    uLCD.line(64, 32, 72, 24, WHITE);
    uLCD.line(72, 24, 80, 32, WHITE);
    }

void playdice(){       
       FILE *wave_file;
       wave_file=fopen("/sd/Dice.wav","r");
       waver.play(wave_file);
       fclose(wave_file);
       wait(0.01);
}

void playTaDa(){
       FILE *wave_file;
       wave_file=fopen("/sd/TaDa.wav","r");
       waver.play(wave_file);
       fclose(wave_file);
       wait(0.01);
}

void playSad(){
       FILE *wave_file;
       wave_file=fopen("/sd/Sad.wav","r");
       waver.play(wave_file);
       fclose(wave_file);
       wait(0.01);
}

void rollingdice1(){
       playdice();
       uLCD.filled_rectangle(17, 91, 47, 121, 0xFF0000);
       uLCD.filled_rectangle(17, 91, 47, 121, 0x000000);
       uLCD.filled_rectangle(17, 91, 47, 121, 0xFF0000);
       uLCD.filled_rectangle(17, 91, 47, 121, 0x000000);
       wait(1);
}

void rollingdice2(){
       playdice();
       uLCD.filled_rectangle(81, 91, 111, 121, 0x0080FF);
       uLCD.filled_rectangle(81, 91, 111, 121, 0x000000);
       uLCD.filled_rectangle(81, 91, 111, 121, 0x0080FF);
       uLCD.filled_rectangle(81, 91, 111, 121, 0x000000);
       wait(1);
}



class Nav_Switch
{
public:
    Nav_Switch(PinName up,PinName down);
    //int read();
//boolean functions to test each switch
    bool up();
    bool down();

private:
    BusIn _pins;
};
Nav_Switch::Nav_Switch (PinName up,PinName down):
    _pins(up, down)
{
    _pins.mode(PullUp); //needed if pullups not on board or a bare nav switch is used - delete otherwise
    wait(0.1); //delays just a bit for pullups to pull inputs high
}
inline bool Nav_Switch::up()
{
    return !(_pins[0]);
}
inline bool Nav_Switch::down()
{
    return !(_pins[1]);
}

Nav_Switch myNav( p25, p22); //pin order on Sparkfun breakout
 
int main()
{
    pc.printf("GAME START\r\n"); 
    
    //draw the board
    //horizongtal line
    uLCD.line(32, 16, 96, 16, WHITE);
    uLCD.line(32, 32, 96, 32, WHITE);
    uLCD.line(32, 48, 96, 48, WHITE);
    uLCD.line(32, 64, 96, 64, WHITE);
    uLCD.line(32, 80, 96, 80, WHITE);
    
    //veritical line
    uLCD.line(32, 16, 32, 80, WHITE);
    uLCD.line(48, 16, 48, 80, WHITE);
    uLCD.line(64, 16, 64, 80, WHITE);
    uLCD.line(80, 16, 80, 80, WHITE);
    uLCD.line(96, 16, 96, 80, WHITE);
    
    //sanke%ladder
    sanke_ladder();
     
    //draw the dice1
    //horizontal
    uLCD.line(16, 90, 48, 90, WHITE);
    uLCD.line(16, 122, 48, 122, WHITE);
    //vertical
    uLCD.line(16, 90, 16, 122, WHITE);
    uLCD.line(48, 90, 48, 122, WHITE);  
    
    //draw the dice2
    //horizontal
    uLCD.line(80, 90, 112, 90, WHITE);
    uLCD.line(80, 122, 112, 122, WHITE);
    //vertical
    uLCD.line(80, 90, 80, 122, WHITE);
    uLCD.line(112, 90, 112, 122, WHITE); 
    //initialize the positions of dot1 and dot 2
    int p1=0;
    int p2=0;
    while(1) {

        //Push to roll the dice1
        if(myNav.up()) {
        led1=1;led2=0;
        pc.printf("rolling Dice 1\r\n"); 
        wait(0.5); 
        int move1=rand()%6+1;
        pc.printf(" Move1:%d\r\n",move1); 
        
       switch (move1){
       case 1:
       rollingdice1();
       uLCD.filled_circle(32, 106, 3, 0xFF0000);
       break;
       
       case 2:
       rollingdice1();
       uLCD.filled_circle(40, 98, 3, 0xFF0000);
       uLCD.filled_circle(24, 114, 3, 0xFF0000);       
       break;
       
       case 3:
       rollingdice1();
       uLCD.filled_circle(40, 98, 3, 0xFF0000);
       uLCD.filled_circle(32, 106, 3, 0xFF0000);
       uLCD.filled_circle(24, 114, 3, 0xFF0000);     
       break;
       
       case 4:
       rollingdice1();
       uLCD.filled_circle(24, 98, 3, 0xFF0000);
       uLCD.filled_circle(40, 98, 3, 0xFF0000);
       uLCD.filled_circle(24, 113, 3, 0xFF0000);
       uLCD.filled_circle(40, 113, 3, 0xFF0000);      
       break;
       
       case 5:
       rollingdice1();
       uLCD.filled_circle(24, 98, 3, 0xFF0000);
       uLCD.filled_circle(40, 98, 3, 0xFF0000);
       uLCD.filled_circle(24, 113, 3, 0xFF0000);
       uLCD.filled_circle(40, 113, 3, 0xFF0000);
       uLCD.filled_circle(32, 105, 3, 0xFF0000);       
       break;
       
       case 6:
       rollingdice1();
       uLCD.filled_circle(24, 98, 3, 0xFF0000);
       uLCD.filled_circle(40, 98, 3, 0xFF0000);
       uLCD.filled_circle(24, 105.5, 3, 0xFF0000);
       uLCD.filled_circle(40, 105.5, 3, 0xFF0000);
       uLCD.filled_circle(24, 113, 3, 0xFF0000);
       uLCD.filled_circle(40, 113, 3, 0xFF0000);
       break; }//end of switch move1
       
       //draw dot 1
           if (p1 + move1>16){
            //clear screen
            int x1; int y1;
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            uLCD.filled_circle(x1, y1, 3, 0x000000);
            //new P1
            p1 =16-(p1+move1 -16);   
            pc.printf("New P1: %d\r\n",p1);
            //draw P1 dot
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            pc.printf("x1:%d\r\n",x1);
            pc.printf("y1:%d\r\n\n",y1);
            
            //draw P1 dot
            sanke_ladder();
            uLCD.filled_circle(x1, y1, 3, 0xFF0000);
            wait(1);
            
            //snake and ladder
            if(p1==4){
            uLCD.filled_circle(x1, y1, 3, 0x000000);
            sanke_ladder();
            playTaDa();
            p1=8;
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            uLCD.filled_circle(x1, y1, 3, 0xFF0000);
            pc.printf("x1 jump to:%d\r\n",x1);
            pc.printf("y1 jump to:%d\r\n\n",y1);  
            }//end of if(p1==4)
            
            else if (p1==11) {
            uLCD.filled_circle(x1, y1, 3, 0x000000);
            sanke_ladder();
            playSad();
            p1=3;
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            uLCD.filled_circle(x1, y1, 3, 0xFF0000);
            pc.printf("x1 drop to:%d\r\n",x1);
            pc.printf("y1 drop to:%d\r\n\n",y1);
            }//end of else if (p1==1)
    
            }//end of if(p1 + move1>16)
          else {
            //clear screen
            int x1; int y1;
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            uLCD.filled_circle(x1, y1, 3, 0x000000);
            //new P1
            p1 =p1 + move1;
            pc.printf("New P1:%d\r\n",p1);
                   
            //calculate P1 (x,y)
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            pc.printf("x1:%d\r\n",x1);
            pc.printf("y1:%d\r\n\n",y1);
            sanke_ladder();
            uLCD.filled_circle(x1, y1, 3, 0xFF0000);
            wait(0.1);
            
            //snake and ladder
            if(p1==4){
            uLCD.filled_circle(x1, y1, 3, 0x000000);
            sanke_ladder();
            playTaDa();
            p1=8;
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            uLCD.filled_circle(x1, y1, 3, 0xFF0000);
            pc.printf("x1 jump to:%d\r\n",x1);
            pc.printf("y1 jump to:%d\r\n\n",y1);  
            }//end of if(p1==4)
            
            else if (p1==11) {
            uLCD.filled_circle(x1, y1, 3, 0x000000);
            sanke_ladder();
            playSad();
            p1=3;
            x1=(((p1%4)+3)%4)*16+36;
            y1=((p1-((((p1%4)+3)%4)+1))/4)*16+20;
            uLCD.filled_circle(x1, y1, 3, 0xFF0000);
            pc.printf("x1 drop to:%d\r\n",x1);
            pc.printf("y1 drop to:%d\r\n\n",y1);
            } //end of elseif(p1==11)
            
            //draw P1 dot
            uLCD.filled_circle(x1, y1, 3, 0xFF0000);
            wait(1);
            }//end of else_p1<16
            
    if (p1 ==16){
    //SD card needed with image and video files for last two demos
    uLCD.cls();
    uLCD.media_init();
    uLCD.set_sector_address(0x0000, 0x0000);
    uLCD.display_image(0,0);
    
    //Play the wave file
    FILE *wave_file;
    //printf("\n\n\nHello, wave world!\n");
    wave_file=fopen("/sd/Cheering.wav","r");
    waver.play(wave_file);
    fclose(wave_file);
    wait(0.01);
    
        pc.printf("P1 WIN!");
        uLCD.cls();
        uLCD.color(RED);
        uLCD.locate(2,6);
        uLCD.text_width(2); 
        uLCD.text_height(2);
        uLCD.printf("P1 WON!");
        break;
    }//end of if(p1==16)
    
       wait(0.5);  
       }//end of if(myNav.up())
        
    //push to roll the dice2 
    else if(myNav.down()){
       led1=0;
       led2=1;
       pc.printf("rolling Dice 2\r\n");
       int move2 = rand()%6+1; 
       pc.printf("DICE2: %d\r\n\n",move2);
       
       switch (move2){
       case 1:  
       rollingdice2();
       uLCD.filled_circle(96, 106, 3, 0x0080FF);
       break;
       
       case 2:
       rollingdice2();
       uLCD.filled_circle(104, 98, 3, 0x0080FF);
       uLCD.filled_circle(88, 114, 3, 0x0080FF);       
       break;
       
       case 3:
       rollingdice2();
       uLCD.filled_circle(104, 98, 3, 0x0080FF);
       uLCD.filled_circle(96, 106, 3, 0x0080FF);
       uLCD.filled_circle(88, 114, 3, 0x0080FF);     
       break;
       
       case 4:
       rollingdice2();
       uLCD.filled_rectangle(81, 91, 111, 121, 0x000000);
       uLCD.filled_circle(88, 98, 3, 0x0080FF);
       uLCD.filled_circle(104, 98, 3, 0x0080FF);
       uLCD.filled_circle(88, 113, 3, 0x0080FF);
       uLCD.filled_circle(104, 113, 3, 0x0080FF);      
       break;
       
       case 5:
       rollingdice2();
       uLCD.filled_rectangle(81, 91, 111, 121, 0x000000);
       uLCD.filled_circle(88, 98, 3, 0x0080FF);
       uLCD.filled_circle(104, 98, 3, 0x0080FF);
       uLCD.filled_circle(88, 113, 3, 0x0080FF);
       uLCD.filled_circle(104, 113, 3, 0x0080FF);
       uLCD.filled_circle(96, 105, 3, 0x0080FF);       
       break;
       
       case 6:
       rollingdice2();
       uLCD.filled_circle(88, 98, 3, 0x0080FF);
       uLCD.filled_circle(104, 98, 3, 0x0080FF);
       uLCD.filled_circle(88, 105.5, 3, 0x0080FF);
       uLCD.filled_circle(104, 105.5, 3, 0x0080FF);
       uLCD.filled_circle(88, 113, 3, 0x0080FF);
       uLCD.filled_circle(104, 113, 3, 0x0080FF);
       break; 
       }//end of switch move2
    
       //draw dot 2
        if (p2 + move2>16){
            //clear screen
            int x2; int y2;
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p2%4)+3)%4)+1))/4)*16+28;
            uLCD.filled_circle(x2, y2, 3, 0x000000);
            //new P2
            p2 =16-(p2+move2 -16);   
            pc.printf("New P2: %d\r\n",p2);
            //draw P1 dot
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p2%4)+3)%4)+1))/4)*16+28;
            pc.printf("x2:%d\r\n",x2);
            pc.printf("y2:%d\r\n\n",y2);
            
            //draw P1 dot
            uLCD.filled_circle(x2, y2, 3, 0x0080FF);
            wait(1);
            
            //snake and ladder
            if(p2==4){
            uLCD.filled_circle(x2, y2, 3, 0x000000);
            sanke_ladder();
            playTaDa();
            p2=8;
            pc.printf("P2 jump to:%d\r\n",p2);
                
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p2%4)+3)%4)+1))/4)*16+28;
            pc.printf("x2 jump to:%d\r\n",x2);
            pc.printf("y2 jump to:%d\r\n\n",y2);
            
            uLCD.filled_circle(x2, y2, 3, 0x0080FF);
            }//end of if(p2==4)
            
            else if (p2==11) {
            uLCD.filled_circle(x2, y2, 3, 0x000000);
            sanke_ladder();
            playSad();
            p2=3;
            pc.printf("P2 drop to:%d\r\n",p2);
            
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p1%4)+3)%4)+1))/4)*16+28;
            pc.printf("x2 drop to:%d\r\n",x2);
            pc.printf("y2 drop to:%d\r\n\n",y2);
            uLCD.filled_circle(x2, y2, 3, 0x0080FF);
            }//end of elseif(p2==1)   
        }//end of if(p2 + move2>16)
        
        else {
            //clear screen
            int x2; int y2;
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p2%4)+3)%4)+1))/4)*16+28;
            uLCD.filled_circle(x2, y2, 3, 0x000000);
            //new P2
            p2 =p2 + move2;
            pc.printf("New P2:%d\r\n",p2);        
            //calculate P2(x,y)
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p2%4)+3)%4)+1))/4)*16+28;
            pc.printf("x2:%d\r\n",x2);
            pc.printf("y2:%d\r\n\n",y2);
            
            //draw P2 dot
            sanke_ladder();
            uLCD.filled_circle(x2, y2, 3, 0x0080FF);
            wait(0.5);
            
            //snake and ladder
            if(p2==4){
            uLCD.filled_circle(x2, y2, 3, 0x000000);
            sanke_ladder();
            playTaDa();
            p2=8;
            pc.printf("P2 jump to:%d\r\n",p2);
                
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p2%4)+3)%4)+1))/4)*16+28;
            pc.printf("x2 jump to:%d\r\n",x2);
            pc.printf("y2 jump to:%d\r\n\n",y2);
            
            uLCD.filled_circle(x2, y2, 3, 0x0080FF);
            }//end of if
            
            else if (p2==11) {
            uLCD.filled_circle(x2, y2, 3, 0x000000);
            sanke_ladder();
            playSad();
            p2=3;
            pc.printf("P2 drop to:%d\r\n",p2);
            
            x2=(((p2%4)+3)%4)*16+36;
            y2=((p2-((((p1%4)+3)%4)+1))/4)*16+28;
            pc.printf("x2 drop to:%d\r\n",x2);
            pc.printf("y2 drop to:%d\r\n\n",y2);
            uLCD.filled_circle(x2, y2, 3, 0x0080FF);
            } //end of elseif
             
            wait(1);
        }//end of else
       
           if (p2 ==16){    
           //SD card needed with image and video files for last two demos
           uLCD.cls();
           uLCD.media_init();
           uLCD.set_sector_address(0x0000, 0x0000);
           uLCD.display_image(0,0);
    
           //Play the wave file
           FILE *wave_file;
           //printf("\n\n\nHello, wave world!\n");
           wave_file=fopen("/sd/Cheering.wav","r");
           waver.play(wave_file);
           fclose(wave_file);
           wait(0.01);
    
           pc.printf("P2 WIN!");
        
           uLCD.cls();
           uLCD.color(BLUE);
           uLCD.locate(2,6);
           uLCD.text_width(2);
           uLCD.text_height(2);
           uLCD.printf("P2 WON!");
           break;
           }//end of if(p2 ==16)
        
           wait(0.5); 
    }//end of else if(myNav.down())
           wait(0.02);
    }//end of while(1)
}//end of main  

Video Demo

With better Sound Quality

The bit resolution is changed to 16 bit, and the sampling rate is change to 1,6000 Hz.


Please log in to post comments.