Sudoku Game

Sudoku Game using LCD, joystick, numpad, and speaker

This program loads a pre-made sudoku game onto the LCD with blanks in some spaces that the user will fill in. A blue box is used to show which space is currently focused on. The joystick is used to navigate to other spaces on the board. Blue numbers indicate preset numbers that cannot be changed. Black numbers indicate user-entered numbers that can still be changed.

Once the user things they have completed the board, they can press the joystick (Fire Button), and the board will be checked for accuracy. If it is a properly solution, a green check will show and "We are the Champions" will play. If it is incorrect, a red X will show accompanied by a sad sound clip for 5 seconds, then the LCD will return to the board so that the user can try again.

A buzzing noise is also played each time a user enters a number.

The joystick has been reconfigured in a rotated way so that left on the joystick is actually up, based on how it was configured on my breadboard (see pictures below).

Wiring

NumPadMbed
GNDGND
SDAp9
SCLp10
IRQp20
Vcc3.3v
JoystickMbed
Up16
Cp17
Lp15
Dp19
Rp20
-GND
uLCDMbed
+5V+5V
RXp27
TXp28
GNDGND
RESp30
SDMbed
CDnc
DOp6
GNDGND
SCKp7
VCC+3.3V
DIp5

Pictures

Breadboard /media/uploads/decfrv/20161103_110218.jpg Sample Easy Test Game Board /media/uploads/decfrv/20161103_110225.jpg Successfully Completed Board /media/uploads/decfrv/20161103_110300.jpg Incorrectly Completed Board /media/uploads/decfrv/20161103_110241.jpg

Videos

Video Showing Successfully Completed Board /media/uploads/decfrv/20161103_105121.mp4

Video Showing Incorrectly Filled Out Board /media/uploads/decfrv/20161103_105004-2.mp4

Video Showing That Users Cannot Override Pre-filled Squares /media/uploads/decfrv/20161103_105218.mp4

Code:

include the listed library with this snippet

#include "mbed.h"
#include <mpr121.h>
#include "rtos.h"
#include "uLCD_4DGL.h"
#include "wave_player.h"
#include "SDFileSystem.h"
 
 class Nav_Switch
{
public:
    Nav_Switch(PinName up,PinName down,PinName left,PinName right,PinName fire);
    int read();
//boolean functions to test each switch
    bool up();
    bool down();
    bool left();
    bool right();
    bool fire();
//automatic read on RHS
    operator int ();
//index to any switch array style
    bool operator[](int index) {
        return _pins[index];
    };
private:
    BusIn _pins;
 
};
Nav_Switch::Nav_Switch (PinName up,PinName down,PinName left,PinName right,PinName fire):
    _pins(up, down, left, right, fire)
{
    _pins.mode(PullUp); //needed if pullups not on board or a bare nav switch is used - delete otherwise
    wait(0.001); //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]);
}
inline bool Nav_Switch::left()
{
    return !(_pins[2]);
}
inline bool Nav_Switch::right()
{
    return !(_pins[3]);
}
inline bool Nav_Switch::fire()
{
    return !(_pins[4]);
}
inline int Nav_Switch::read()
{
    return _pins.read();
}
inline Nav_Switch::operator int ()
{
    return _pins.read();
}
 
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
uLCD_4DGL uLCD(p28,p27,p30);
Serial pc(USBTX, USBRX);

SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card
DigitalIn sddetect(p9);

Nav_Switch myNav( p16, p19, p15, p20, p17); //pin order on Sparkfun breakout

//number pad
InterruptIn interrupt(p21);
I2C i2c(p9, p10);
Mpr121 mpr121(&i2c, Mpr121::ADD_VSS);

AnalogOut DACout(p18);
wave_player waver(&DACout);

Mutex lcdMutex;



int xndx;
int yndx;

static int nums [9][9] = {{0,5,4, 9,3,8, 2,7,6},
                  {6,7,9, 1,4,2, 8,3,5},
                  {8,2,3, 7,5,6, 4,9,1},
                  
                  {4,8,5, 2,7,9, 6,1,3},
                  {7,3,1, 6,0,4, 5,2,9},
                  {9,6,2, 3,1,5, 7,8,4},
                  
                  {5,1,6, 0,2,3, 9,4,7},
                  {2,9,7, 4,6,1, 3,5,8},
                  {3,4,8, 5,9,7, 1,6,2}};


bool preset[9][9] = {};

bool interruptChange = false;
int interruptNum = -1;

// Key hit/release interrupt routine
void fallInterrupt() {

      int value=mpr121.read(0x00);
      value +=mpr121.read(0x01)<<8;
            
      int number = 0;
      if ((value>>9) & 0x01) {
          number = 9;
      } else if ((value>>8) & 0x01) {
          number = 8;
      } else if ((value>>7) & 0x01) {
          number = 7;
      } else if ((value>>6) & 0x01) {
          number = 6;
      } else if ((value>>5) & 0x01) {
          number = 5;
      } else if ((value>>4) & 0x01) {
          number = 4;
      } else if ((value>>3) & 0x01) {
          number = 3;
      } else if ((value>>2) & 0x01) {
          number = 2;
      } else if ((value>>1) & 0x01) {
          number = 1;
      } else if (value & 0x01) {
          number = 0;
      }

  if (!preset[yndx][xndx]) {
      interruptNum = number;
      //nums[yndx][xndx] = number;
      interruptChange = true;
  }
}

int main() {
    nums[0][0] = 1;
    interrupt.fall(&fallInterrupt);
    interrupt.mode(PullUp);
    
    uLCD.background_color(WHITE);
    uLCD.cls();
    uLCD.color(BLACK);
    uLCD.text_height(1);
    uLCD.text_width(1);
    uLCD.textbackground_color(WHITE);
    //uLCD.printf("1 2 3 4 5 6 7 8 9\n\n1 2 3 4 5 6 7 8 9\n\n1 2 3 4 5 6 7 8 9\n1 2 3 4 5 6 7 8 9\n\n1 2 3 4 5 6 7 8 9\n\n1 2 3 4 5 6 7 8 9\n1 2 3 4 5 6 7 8 9\n\n1 2 3 4 5 6 7 8 9\n\n1 2 3 4 5 6 7 8 9");
    
    /*uLCD.filled_triangle(30, 61, 13, 81, 51, 112, GREEN);
    uLCD.filled_triangle(30, 61, 51, 112, 66, 92, GREEN);
    uLCD.filled_triangle(51, 112, 104, 11, 120, 24, GREEN);
    uLCD.filled_triangle(51, 112, 31, 96, 104, 11, GREEN);*/
    
    uLCD.color(BLUE);
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (nums[i][j] == 0) {
                uLCD.printf("  ");
                preset[i][j] = false;
            } else {
                uLCD.printf("%d ", nums[i][j]);
                preset[i][j] = true;
            }
        }
        //uLCD.printf("\n");
        if (i != 2 && i != 5) {
            uLCD.printf("\n");
        }
    }
    uLCD.color(BLACK); 
    
    
    uLCD.line(40, 0, 40, 128, BLACK);
    uLCD.line(80, 0, 80, 128, BLACK);
    uLCD.line(0, 40, 128, 40, BLACK);
    uLCD.line(0, 80, 128, 80, BLACK);
    
    xndx = 0;
    yndx = 0;
    int oldxndx = 0;
    int oldyndx = 0;
    bool changed = true;
    
    bool up = false;
    bool down = false;
    bool left = false;
    bool right = false;
    bool fire = false;
    //uLCD.rectangle(0,0,7,7, BLUE);
    
    
    bool keepGoing = true;
    while (keepGoing) {
        //led1 = !led1;
        oldyndx = yndx;
        oldxndx = xndx;
        if(myNav.left() && !up) {
             if (yndx > 0) {
                 //oldyndx=yndx;
                 //do {
                    yndx--;
                 //} while (preset[yndx][xndx] && yndx != 0);
                 changed = true;
             }
             up = true;
        } else if(myNav.right() && !down) {
             if (yndx < 8) {
                 //oldyndx=yndx;
                 //do {
                    yndx++;
                 //} while (preset[yndx][xndx] && yndx != 8);
                 changed = true;
             }
             down = true;
        } else if(myNav.down() && !left) {
             if (xndx > 0) {
                 //oldxndx=xndx;
                 //do {
                    xndx--;
                 //} while (preset[yndx][xndx] && xndx != 0);
                 changed = true;
             }
             left= true;
        } else if(myNav.up() && !right) {
             if (xndx < 8) {
                 //oldxndx=xndx;
                 //do {
                    xndx++;
                 //} while (preset[yndx][xndx] && xndx != 8);
                 changed = true;
             }
             right = true;
        } else if(myNav.fire() && !fire) {
            
            bool test = true;
            ///////////////////////////////////////////////
            pc.printf("5,5: %d\r\n",nums[4][4]);
            for (int i = 0; i < 9; i++) {
                int sum = 0;
                int product = 1;
                for (int j = 0; j < 9; j++) {
                    product *= nums[i][j];
                    sum += nums[i][j];
                }
                if (sum != 45 || product != 362880) {
                    test = false;
                    pc.printf("Bad Row: %d Sum:%d Product:%d\r\n", i + 1, sum, product);
                }
            }   
            
            for (int i = 0; i < 9; i++) {
                int sum = 0;
                int product = 1;
                for (int j = 0; j < 9; j++) {
                    product *= nums[j][i];
                    sum += nums[j][i];
                }
                if (sum != 45 || product != 362880) {
                    test = false;
                    pc.printf("Bad Column: %d Sum:%d Product:%d\r\n", i + 1, sum, product);
                }
            }
            
            for (int m = 0; m < 3; m++) {
                for (int k = 0; k < 3; k++) {
                    int sum = 0;
                    int product = 1;
                    for (int i = 0; i < 3; i++) {
                        for (int j = 0; j < 3; j++) {
                            product *= nums[3*k + i][3*m + j];
                            sum += nums[3*k + i][3*m + j];
                        }
                    } 
                    if (sum != 45 || product != 362880) {
                        test = false;
                        pc.printf("Bad Box: %d Sum:%d Product:%d\r\n", m*3 + k + 1, sum, product);
                    }
                }
            }
            if (test) {
                //Play Sound
                for (int i = 0; i < 20; i++) {
                    uLCD.line(11+i,81-i, 49+i, 112-i, GREEN);
                    uLCD.line(12+i,81-i, 50+i, 112-i, GREEN);
                    uLCD.line(51-i,112-i, 120-i,24-i, GREEN);
                    uLCD.line(52-i,112-i, 121-i,24-i, GREEN);
                }
                keepGoing = false;
                pc.printf("SUCCESS :)\r\n");
                
                FILE *wave_file;
                wave_file = fopen("/sd/champs.wav","r");
                bool playing = true;
                int vol = 5;
                waver.play(wave_file, playing, vol);
            } else {
                for (int i = 0; i < 20; i++) {
                    uLCD.line(21+i,15,89+i,118, RED);
                    uLCD.line(89+i,15,21+i,118, RED);
                }
                pc.printf("FAILURE :(\r\n");
                FILE *wave_file;
                wave_file = fopen("/sd/failure.wav","r");
                bool playing = true;
                int vol = 5;
                waver.play(wave_file, playing, vol);
                //wait(5);
                //redraw
                uLCD.cls();
                uLCD.color(BLUE);
                for (int i = 0; i < 9; i++) {
                    for (int j = 0; j < 9; j++) {
                        if (nums[i][j] == 0) {
                            uLCD.printf("  ");
                            preset[i][j] = false;
                        } else {
                            uLCD.printf("%d ", nums[i][j]);
                            preset[i][j] = true;
                        }
                    }
                    //uLCD.printf("\n");
                    if (i != 2 && i != 5) {
                        uLCD.printf("\n");
                    }
                }
                uLCD.color(BLACK); 
                
                
                uLCD.line(40, 0, 40, 128, BLACK);
                uLCD.line(80, 0, 80, 128, BLACK);
                uLCD.line(0, 40, 128, 40, BLACK);
                uLCD.line(0, 80, 128, 80, BLACK);
            }
            
            ///////////////////////////////////////////////
            fire = true;
        } else {
            up = false;
            down = false;
            left = false;
            right = false;
            fire = false;
        }
        
        if (changed) {
            int xpoint = xndx * 14;
            int ypoint = yndx * 16 - (yndx/3) * 8;
            int oxpoint = oldxndx * 14;
            int oypoint = oldyndx * 16 - (oldyndx/3) * 8;
            
            uLCD.rectangle(oxpoint,oypoint-1,oxpoint+7,oypoint+7, WHITE);
            uLCD.rectangle(xpoint,ypoint-1,xpoint+7,ypoint+7, BLUE);
            changed = false;
        }
        //pc.printf("Joystick: %d %d %d %d %d\n\r", myNav[0], myNav[1], myNav[2], myNav[3], myNav[4]);
        //int number = -1;
        if (interruptChange && nums[yndx][xndx] != 0 && !preset[yndx][xndx]) {
            //number = nums[yndx][xndx];
            //pc.printf("Number: %d\r\n", nums[yndx][xndx]);
            uLCD.locate(xndx * 2, yndx *2 - (yndx/3));
            uLCD.printf("%d", nums[yndx][xndx]);
            interruptChange = false;
            
            //pc.printf("Test: %d\r\n", nums[yndx][xndx]);
            
            int xpoint = xndx * 14;
            int ypoint = yndx * 16 - (yndx/3) * 8;
            uLCD.rectangle(xpoint,ypoint-1,xpoint+7,ypoint+7, BLUE);
        }
        if (interruptNum != -1 && interruptNum != 0) {
            //pc.printf("Setting 5,5 as %d\r\n", interruptNum);
            nums[yndx][xndx] = interruptNum;
            interruptNum = -1;
            FILE *wave_file;
            wave_file = fopen("/sd/beep.wav","r");
            bool playing = true;
            int vol = 5;
            waver.play(wave_file, playing, vol);
        }
        //pc.printf("Test2: %d\r\n", nums[yndx][xndx]);
        wait(0.1);
    }
}


Please log in to post comments.