Project tutorial
Portable Electronic Sudoku Game

Portable Electronic Sudoku Game © CC BY-NC-SA

Play, create and solve Sudoku puzzles using this easy to build, Arduino-based project.

  • 8 views
  • 0 comments
  • 0 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
2.8 inch TFT Touch LCD screen
×1
Li-Po Rechargeable Battery 600mAh 3.7v (30mm x 50mm x 6mm maximum physical dimensions)
×1
TP4056 Lithium Battery Charger Board Micro USB
×1

Necessary tools and machines

3D printer with a minimum 160mm x 70mm x 30mm build capacity

About this project

Years ago, just for fun, I wrote an excel macro to solve Sudoku puzzles on a desktop computer. It occurred to me that this could be incorporated into an Arduino touchscreen device. The perfect fit for this was an Arduino Uno and a compatible 2.8-inch TFT touchscreen shield.

Code

Portable Electronic Sudoku Game CodeArduino
Used with latest Arduino IDE
 // Sudoku Solver By TechKiwiGadgets May 2019

/* 
* V1 - Final Product Version for First Instructables Release based off dev version 101 
*       -  Solve now includes help test at end of solve to highlight any errors in red
*       -  Includes 5th Hard puzzle as a challenge!
*       
*       
*       
*       
*       
*       
*       
*       
*       
* ARRAY POSITIONS & KEY VARIABLES BELOW *************************************************************
// Array with following locations: {0 ,      1 ,    2   3    4, 5, 6, 7, 8, 9,10,11,12,    13 }
// Array with following Structure: {Solved, value , X , Y , V1,V2,V3,V4,V5,V6,V7,V8,V9 panel# }

colcoord[9] = { 10, 34, 58, 90, 114, 138, 170, 194, 218 };
rowcoord[9] = { 8, 33, 58, 88, 113, 138, 170, 194, 218 }; 

int location = 1;

const int sudoku[81][12]; 

 */

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>


#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8  // can be a digital pin

// Revised Touch Callibration numbers
#define TS_MINX 130
#define TS_MINY 88
#define TS_MAXX 915
//#define TS_MAXY 927
#define TS_MAXY 880

// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
// optional
#define LCD_RESET A4

// Assign human-readable names to some common 16-bit color values: 
// I had to reverse these colors for my screen
int	BLACK =  0x0000;
int	RED  =  0x001F;
int	BLUE = 0xF800;
int	GREEN  = 0x07E0;
int YELLOW = 0x07FF;
int MAGENTA = 0xF81F;
int CYAN = 0xFFE0;
int WHITE = 0xFFFF;


Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

#define BOX 78  // Block to clear screen
#define BOXSIZE 80
#define BUTTON 20

boolean debounce = false; // Used to debounce touch screen input

// Array with following Structure: {value , X , Y , Solved }

const byte colcoord[9] = { 10, 34, 58, 90, 114, 138, 170, 194, 218 };
const byte rowcoord[9] = { 8, 33, 58, 88, 113, 138, 170, 194, 218 }; 

byte location = 1;

byte puzzlenum = 1; // These identifier for 5 puzzles stored in memory

byte sudoku[82][14]; 

byte touchlocation = 0; // Used to track the array value that the stylis is closest to in the Sudoku 9x9 framework

int delay1 = 400;  // Pause input into screen

byte tempreading = 0;

void setup(void) {
//  Serial.begin(9600);
//  Serial.println(F("Paint!"));
  
  tft.reset();
  
  uint16_t identifier = tft.readID();
  identifier=0x9325;

  tft.begin(identifier);
  tft.setRotation(1);
  tft.fillScreen(BLACK);

// **** Splash Screen 


        tft.drawRoundRect(0, 0, 320, 240, 20, BLUE);
        tft.drawRoundRect(1, 1, 318, 238, 20, BLUE);
  
        byte g = 70;
 
        tft.drawCircle(46, g, 25, GREEN);         
        tft.fillCircle(46, g, 20, GREEN);  
        tft.setTextColor(BLACK);  tft.setTextSize(3);
        tft.setCursor(39, g-10);   tft.println("S"); 

        tft.drawCircle(91, g+30, 25, BLUE); 
        tft.fillCircle(91, g+30, 20, BLUE);  
        tft.setTextColor(BLACK);  tft.setTextSize(3);
        tft.setCursor(84, g+20);   tft.println("U"); 

        tft.drawCircle(137, g, 25, YELLOW);  
        tft.fillCircle(137, g, 20, YELLOW);  
        tft.setTextColor(BLACK);  tft.setTextSize(3);
        tft.setCursor(130, g-10);   tft.println("D"); 

        tft.drawCircle(183, g+30, 25, RED);  
        tft.fillCircle(183, g+30, 20, RED);  
        tft.setTextColor(BLACK);  tft.setTextSize(3);
        tft.setCursor(176, g+20);   tft.println("O"); 

        tft.drawCircle(229, g, 25, GREEN);  
        tft.fillCircle(229, g, 20, GREEN);  
        tft.setTextColor(BLACK);  tft.setTextSize(3);
        tft.setCursor(222, g-10);   tft.println("K"); 

        tft.drawCircle(274, g+30, 25, YELLOW); 
        tft.fillCircle(274, g+30, 20, YELLOW);  
        tft.setTextColor(BLACK);  tft.setTextSize(3);
        tft.setCursor(267, g+20);   tft.println("U"); 

        tft.setTextColor(WHITE);  tft.setTextSize(2);
        tft.setCursor(25, 170);   tft.println("Play, Create, Solve"); 

        tft.setTextColor(GREEN);  tft.setTextSize(1);
        tft.setCursor(25, 200);   tft.println("By TechKiwiGadgets 2019"); 



  delay(4000);
  
  tft.fillScreen(BLACK);

  drawscreen(); // Clearscreen and setup Sudoku matrix 
  resetmatrix(); // Initialize the sudoku matrix by setting all locations to zero and loading in the coordinates for each touch location
  loadpaneldata(); // Load specifc Panel identification Data into the Array for each of the 81 locations
  solvealigndata();  // Sanitize test puzzle data with correct data format
      
// Test Display by showing all values in the puzzle - White are Solved , Blue are others

  tft.setTextSize(2);

  for (byte a = 1; a < 82; a++) {      

    //Test solve or set condition
    if  (sudoku[a][1] != 0) {  
         if (sudoku[a][0] != 0) {
                tft.setTextColor(WHITE); 
            } else {
                tft.setTextColor(GREEN); // Set this colour if not a genuine set clue
            }       
          tft.setCursor( sudoku[a][3], sudoku[a][2]);   
          tft.println(sudoku[a][1]);
     }
  }


drawbuttons();
 
  pinMode(13, OUTPUT);

  //  testText();




}

#define MINPRESSURE 5
#define MAXPRESSURE 1000


  
//  tft.begin(identifier);

void loop()
{

// Read the Touch Screen Locations
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);

  // if sharing pins, you'll need to fix the directions of the touchscreen pins
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);


  // we have some minimum pressure we consider 'valid'
  // pressure of 0 means no pressing!

  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {

/*
          Serial.print("X = "); Serial.print(p.x);
          Serial.print("\tY = "); Serial.print(p.y);
          Serial.print("\tPressure = "); Serial.println(p.z);

 */
      // scale from 0->1023 to tft.width
      p.x = map(p.x, TS_MINX, TS_MAXX, 0, 240);
      p.y = map(p.y, TS_MINY, TS_MAXY, 0, 320); // Original Code

 /* 
          Serial.print("X = "); Serial.print(p.x);
          Serial.print("\tY = "); Serial.print(p.y);
          Serial.print("\tPressure = "); Serial.println(p.z);
  */

      // Calculate the position of the screen touch based on the input values of p.x and p.y

      if ((p.x > 0) && (p.x < 27)) {           // Coloumn 1
      
              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 1;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 2;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 3;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 4;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 5;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 6;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 7;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 8;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 9;                  
              }   
      } else 
      if ((p.x > 28) && (p.x < 53)) {          // Coloumn 2

              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 10;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 11;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 12;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 13;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 14;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 15;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 16;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 17;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 18;                  
              }   


        
      } else
       if ((p.x > 54) && (p.x < 80)) {        // Coloumn 3
        
              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 19;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 20;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 21;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 22;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 23;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 24;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 25;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 26;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 27;                  
              }   

      
      } else    
       if ((p.x > 81) && (p.x < 107)) {        // Coloumn 4

              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 28;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 29;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 30;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 31;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 32;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 33;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 34;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 35;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 36;                  
              }   
        
      }  else
       if ((p.x > 108) && (p.x < 133)) {        // Coloumn 5

              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 37;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 38;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 39;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 40;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 41;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 42;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 43;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 44;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 45;                  
              }   
     
      }  else
       if ((p.x > 134) && (p.x < 160)) {        // Coloumn 6

              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 46;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 47;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 48;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 49;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 50;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 51;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 52;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 53;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 54;                  
              }   


        
      } else
       if ((p.x > 161) && (p.x < 187)) {        // Coloumn 7
 
              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 55;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 56;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 57;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 58;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 59;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 60;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 61;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 62;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 63;                  
              }   

       
      } else
       if ((p.x > 188) && (p.x < 213)) {        // Coloumn 8
 
              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 64;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 65;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 66;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 67;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 68;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 69;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 70;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 71;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 72;                  
              }           
      }  else
       if ((p.x > 214) && (p.x < 240)) {        // Coloumn 9
 
              if ((p.y > 0) && (p.y < 27)) {           // Row 1
                  touchlocation = 73;
              }
              if ((p.y > 28) && (p.y < 53)) {          // Row 2
                   touchlocation = 74;               
              }
               if ((p.y > 54) && (p.y < 80)) {        // Row 3
                   touchlocation = 75;               
              }     
               if ((p.y > 81) && (p.y < 107)) {        // Row 4
                  touchlocation = 76;                
              }  
               if ((p.y > 108) && (p.y < 133)) {        // Row 5
                  touchlocation = 77;                
              }  
               if ((p.y > 134) && (p.y < 160)) {        // Row 6
                   touchlocation = 78;                  
              } 
               if ((p.y > 161) && (p.y < 187)) {        // Row 7
                   touchlocation = 79;                  
              }
               if ((p.y > 188) && (p.y < 213)) {        // Row 8
                  touchlocation = 80;                   
              }  
               if ((p.y > 214) && (p.y < 240)) {        // Row 9
                  touchlocation = 81;                  
              }       

      } 
 
      // debounce function to remove issue with first touch screen reading being spurious
      if (debounce == false) {
        touchlocation = 0;
        debounce = true;
        }

// This code only applies to stylis activity within the Sudokumatrix
if ( ((p.x < 235)&&(p.y < 230))&& (touchlocation != 0)) {
  
 
    
 //   tft.fillRect(250, 80, 15, 10, BLACK);

/*
      Serial.print("Y = "); Serial.print(p.x);
      Serial.print("\tX = "); Serial.print(p.y);
      Serial.print("\tLocation = "); Serial.println(touchlocation);  
*/

// Calculate the incremental changes to the data array
// Array Structure: {value , X , Y , Solved }

// Only increment if has not been solved, Debounce by checking if this is the second time the same range is selected
    if ((tempreading == touchlocation)&&(sudoku[touchlocation][0]==0)||(tempreading == touchlocation)&&(sudoku[touchlocation][0]==2)) { 
        sudoku[touchlocation][1]++;
        if (sudoku[touchlocation][1] > 9) {
          sudoku[touchlocation][1] = 0;
        }
        // Test to see if changing an item can be classified as solved
        if (sudoku[touchlocation][1]!=0) {   
            sudoku[touchlocation][0]=2;      // Set to Solved if a manually changed number however flag as manual change with va,ue of 2
        } else {
            sudoku[touchlocation][0]=0;      // Set to Not Solved if 0  
        }
    // Finally reset all of the data values in this location that have been manually changed to unsolved 
        for (byte u = 1; u < 82; u++) {    
         // If preprogrammed from a game then leave values otherwise reset data to baseline
         if (sudoku[u][0]!=1){
              for (byte q = 4; q < 13; q++) {  
                  sudoku[u][q]=q-3;
              }
         }
        }
    }

//     tft.setTextColor(WHITE);  tft.setTextSize(1);
//      tft.setCursor(250, 80);   tft.println(touchlocation);   



   // Refresh only the location concerned with new value and show colour coded
        //First Clear Location
        tft.fillRect(sudoku[touchlocation][3], sudoku[touchlocation][2], 15, 15, BLACK);      
        tft.setTextSize(2);

         if (sudoku[touchlocation][0] != 0) { // Do not draw 0 just leave blank square
             if (sudoku[touchlocation][0] == 1) {
                    tft.setTextColor(WHITE); 
                } else if (sudoku[touchlocation][0] == 2) {
                    tft.setTextColor(GREEN); // Set this colour if not a genuine set clue
                }       
              tft.setCursor( sudoku[touchlocation][3], sudoku[touchlocation][2]);   
              tft.println(sudoku[touchlocation][1]);
         }
         
    if (tempreading == touchlocation) {
        delay(delay1);
        }
    
    
    tempreading = touchlocation; // take a first sample then repeat and compare to debounce  

  
    }

    // Inside touch sensor reading if statement

    // HOME Button Pressed ************************************************   
        if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 10)&&(p.x < 40))) {


        tft.fillCircle(280, 30, 20, WHITE);  
        tft.setTextColor(BLACK);  tft.setTextSize(1);
        tft.setCursor(268, 27);   tft.println("HOME");  

        delay(delay1/2);
    
        drawscreen(); // Clearscreen and setup Sudoku matrix 
        resetmatrix(); // Initialize the sudoku matrix by setting all locations to zero:
        refreshdisplay();
        drawbuttons();       
      }

      // PLAY Button Pressed ************************************************   
        if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 80)&&(p.x < 110))) {


        //PLAY Button pressed
        //Button 2
        tft.fillCircle(280, 90, 20, WHITE);  
        tft.setTextColor(BLACK);  tft.setTextSize(1);
        tft.setCursor(268, 87);   tft.println("PLAY");   
   

        
        delay(delay1/2);       
        
        drawscreen(); // Clearscreen and setup Sudoku matrix 
        resetmatrix(); // Initialize the sudoku matrix by setting all locations to zero:

        loadtestpuzzle1(); // Loads test puzzle into the location array



        solvealigndata();  // Sanitize test puzzle data with correct data format


        refreshdisplay(); // Only display testpuzzle data locations that are 
        drawbuttons(); // Redraw buttons togive push button effect 
         tft.setCursor(277, 97);   tft.println(puzzlenum);  

        // Manage Puzzle Number
        puzzlenum++; // increment puzzle number
        if (puzzlenum > 5) { 
          puzzlenum = 1;
          }
      
      }
      
     // HELP Button Pressed ************************************************   
        if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 140)&&(p.x < 160))) {
  
        //Button 3
        tft.fillCircle(280, 150, 20, WHITE);  
        tft.setTextColor(BLACK);  tft.setTextSize(1);
        tft.setCursor(268, 147);   tft.println("HELP");  


        
        delay(delay1/2);

 //       drawscreen(); // Clearscreen and setup Sudoku matrix 
 //       solvehorizontal(); // Solve horiontal rule
 //       solvevertical(); // Solve vertical rule
 //       solvepanel(); // Solve Panel rule
          
          helpbutton(); // Run algorythm and test for incorrect locations then highlight in red
        
 //       reversesolve();
        delay(800);// Display the changes before reverting to original colors

               
        refreshdisplay(); // Only display testpuzzle data locations that are 
        drawbuttons(); // Redraw buttons togive push button effect 
        }

     // SOLVE Button Pressed ************************************************   
        if ( ((p.y > 255)&&(p.y < 300))&& ((p.x > 200)&&(p.x < 220))) {

    
        //SOLVE Button Pressed
  
         //Button 4
        tft.fillCircle(280, 210, 20, WHITE);  
        tft.setTextColor(BLACK);  tft.setTextSize(1);
        tft.setCursor(266, 207);   tft.println("SOLVE");  


        
        delay(delay1/2);


        solvepanel(); // Solve Panel rule
        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule

        reversesolvecolor();   


        uniquecandidate(); // Test
        solvealigndata();
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();

        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();


        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule
        solvepanel(); // Solve Panel rule
        reversesolvecolor();

        solvepanel(); // Solve Panel rule
        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule

        reversesolvecolor();

        uniquecandidate(); // Test
        solvealigndata();
        reversesolvecolor();
 
        solvepanel(); // Solve Panel rule
        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule

        reversesolvecolor();

        uniquecandidate(); // Test
        solvealigndata();
        reversesolvecolor();

        solvepanel(); // Solve Panel rule
        solvehorizontal(); // Solve horiontal rule
        solvevertical(); // Solve vertical rule

        reversesolvecolor();

        uniquecandidate(); // Test
        solvealigndata();
        reversesolvecolor();


        
        drawscreen(); // Clearscreen and setup Sudoku matrix 
               
        refreshdisplay(); // Only display testpuzzle data locations that are 
        helpbutton(); // Run algorythm and test for incorrect locations then highlight in red
        drawbuttons(); // Redraw buttons togive push button effect 
        }



/*
      Serial.print("Y = "); Serial.print(p.x);
      Serial.print("\tX = "); Serial.println(p.y);
*/    
          p.z = 0;// Force the sensor value below threshold to avoid ghost values  
  }

}











void loadtestpuzzle1(){

// Test Puzzle example 1 loaded into array

 if (puzzlenum == 1 ){
      
      // Load Numbers
      sudoku[1][1] = 2; sudoku[3][1] = 9; sudoku[19][1] = 3; sudoku[21][1] = 5;
      
      sudoku[5][1] = 6; sudoku[6][1] = 3; sudoku[14][1] = 2; sudoku[23][1] = 9;

      sudoku[7][1] = 4; sudoku[9][1] = 8; sudoku[26][1] = 7;

      sudoku[39][1] = 1; sudoku[46][1] = 9; sudoku[47][1] = 7; sudoku[48][1] = 2;

      sudoku[31][1] = 9; sudoku[32][1] = 8; sudoku[50][1] = 1; sudoku[51][1] = 6;

      sudoku[34][1] = 7; sudoku[35][1] = 1; sudoku[36][1] = 6; sudoku[43][1] = 2;

      sudoku[56][1] = 3; sudoku[73][1] = 5; sudoku[75][1] = 6;

      sudoku[59][1] = 7; sudoku[68][1] = 3; sudoku[76][1] = 1; sudoku[77][1] = 4;
      
      sudoku[61][1] = 6; sudoku[63][1] = 1; sudoku[79][1] = 8; sudoku[81][1] = 7;

      // Set the Solved Flag for each 
      sudoku[1][0] = 1; sudoku[3][0] = 1; sudoku[19][0] = 1; sudoku[21][0] = 1;
      
      sudoku[5][0] = 1; sudoku[6][0] = 1; sudoku[14][0] = 1; sudoku[23][0] = 1;

      sudoku[7][0] = 1; sudoku[9][0] = 1; sudoku[26][0] = 1;

      sudoku[39][0] = 1; sudoku[46][0] = 1; sudoku[47][0] = 1; sudoku[48][0] = 1;

      sudoku[31][0] = 1; sudoku[32][0] = 1; sudoku[50][0] = 1; sudoku[51][0] = 1;

      sudoku[34][0] = 1; sudoku[35][0] = 1; sudoku[36][0] = 1; sudoku[43][0] = 1;

      sudoku[56][0] = 1; sudoku[73][0] = 1; sudoku[75][0] = 1;

      sudoku[59][0] = 1; sudoku[68][0] = 1; sudoku[76][0] = 1; sudoku[77][0] = 1;
      
      sudoku[61][0] = 1; sudoku[63][0] = 1; sudoku[79][0] = 1; sudoku[81][0] = 1;

 } else

 if (puzzlenum == 2 ){
      
      // Load Numbers
      sudoku[1][1] = 4; sudoku[10][1] = 2; sudoku[19][1] = 1; 
      
      sudoku[5][1] = 2; sudoku[15][1] = 4; sudoku[24][1] = 5; 

      sudoku[25][1] = 2; sudoku[17][1] = 8; sudoku[18][1] = 6; 
      

      sudoku[29][1] = 3; sudoku[30][1] = 2; sudoku[37][1] = 9; sudoku[39][1] = 5; sudoku[46][1] = 7; sudoku[47][1] = 6; 

      sudoku[31][1] = 6; sudoku[40][1] = 4; sudoku[41][1] = 8; sudoku[42][1] = 3; sudoku[51][1] = 2;

      sudoku[35][1] = 4; sudoku[36][1] = 1; sudoku[43][1] = 6; sudoku[45][1] = 2; sudoku[52][1] = 3; sudoku[53][1] = 5; 
      

      sudoku[57][1] = 1; sudoku[64][1] = 3;  sudoku[65][1] = 8;

      sudoku[58][1] = 7; sudoku[67][1] = 5; sudoku[77][1] = 9; 
      
      sudoku[63][1] = 9; sudoku[72][1] = 7; sudoku[81][1] = 5;
      

      // Set the Solved Flag for each 
      sudoku[1][0] = 1; sudoku[10][0] = 1; sudoku[19][0] = 1; 
      
      sudoku[5][0] = 1; sudoku[15][0] = 1; sudoku[24][0] = 1; 

      sudoku[25][0] = 1; sudoku[17][0] = 1; sudoku[18][0] = 1; 
      

      sudoku[29][0] = 1; sudoku[30][0] = 1; sudoku[37][0] = 1; sudoku[39][0] = 1; sudoku[46][0] = 1; sudoku[47][0] = 1; 

      sudoku[31][0] = 1; sudoku[40][0] = 1; sudoku[41][0] = 1; sudoku[42][0] = 1; sudoku[51][0] = 1;

      sudoku[35][0] = 1; sudoku[36][0] = 1; sudoku[43][0] = 1; sudoku[45][0] = 1; sudoku[52][0] = 1; sudoku[53][0] = 1; 
      

      sudoku[57][0] = 1; sudoku[64][0] = 1;  sudoku[65][0] = 1;

      sudoku[58][0] = 1; sudoku[67][0] = 1; sudoku[77][0] = 1; 
      
      sudoku[63][0] = 1; sudoku[72][0] = 1; sudoku[81][0] = 1;

 } else 

 if (puzzlenum == 3 ){
      
      // Load Numbers
      sudoku[12][1] = 8; sudoku[19][1] = 4; 
      
      sudoku[5][1] = 2; sudoku[13][1] = 9; sudoku[14][1] = 4; sudoku[22][1] = 7; sudoku[24][1] = 8;

      sudoku[7][1] = 8; sudoku[9][1] = 7; sudoku[25][1] = 2; sudoku[27][1] = 9;
      

      sudoku[28][1] = 1; sudoku[29][1] = 2; sudoku[38][1] = 4; sudoku[39][1] = 3; sudoku[30][1] = 7;

      sudoku[31][1] = 5; sudoku[41][1] = 8; sudoku[51][1] = 7; 

      sudoku[43][1] = 5; sudoku[44][1] = 7; sudoku[52][1] = 9; sudoku[53][1] = 2; sudoku[54][1] = 4;
      

      sudoku[55][1] = 8; sudoku[57][1] = 9; sudoku[73][1] = 6; sudoku[75][1] = 4;

      sudoku[58][1] = 1; sudoku[60][1] = 2; sudoku[68][1] = 6; sudoku[69][1] = 9; sudoku[77][1] = 3;
      
      sudoku[70][1] = 1; sudoku[63][1] = 3; 
      

      // Set the Solved Flag for each 
      sudoku[12][0] = 1; sudoku[19][0] = 1; 
      
      sudoku[5][0] = 1; sudoku[13][0] = 1; sudoku[14][0] = 1; sudoku[22][0] = 1; sudoku[24][0] = 1;

      sudoku[7][0] = 1; sudoku[9][0] = 1; sudoku[25][0] = 1; sudoku[27][0] = 1;
      

      sudoku[28][0] = 1; sudoku[29][0] = 1; sudoku[38][0] = 1; sudoku[39][0] = 1;  sudoku[30][0] = 1;

      sudoku[31][0] = 1; sudoku[41][0] = 1; sudoku[51][0] = 1; 

      sudoku[43][0] = 1; sudoku[44][0] = 1; sudoku[52][0] = 1; sudoku[53][0] = 1; sudoku[54][0] = 1;
      

      sudoku[55][0] = 1; sudoku[57][0] = 1; sudoku[73][0] = 1; sudoku[75][0] = 1;

      sudoku[58][0] = 1; sudoku[60][0] = 1; sudoku[68][0] = 1; sudoku[69][0] = 1; sudoku[77][0] = 1;
      
      sudoku[70][0] = 1; sudoku[63][0] = 1; 

 } else 

 if (puzzlenum == 4 ){
      
      // Load Numbers
      sudoku[3][1] = 6; sudoku[12][1] = 2; 
      
      sudoku[5][1] = 7; sudoku[6][1] = 9; sudoku[13][1] = 1; 

      sudoku[16][1] = 6; sudoku[17][1] = 5; sudoku[18][1] = 4; sudoku[25][1] = 7; sudoku[26][1] = 1;
      

      sudoku[29][1] = 6; sudoku[30][1] = 5; sudoku[37][1] = 8; sudoku[46][1] = 1; sudoku[48][1] = 3;

      sudoku[33][1] = 4; sudoku[40][1] = 7; sudoku[41][1] = 2;  sudoku[42][1] = 5; sudoku[49][1] = 8; 

      sudoku[34][1] = 9; sudoku[36][1] = 8; sudoku[45][1] = 3; sudoku[52][1] = 4; sudoku[53][1] = 7;
      

      sudoku[56][1] = 3; sudoku[57][1] = 7; sudoku[64][1] = 6; sudoku[65][1] = 4;sudoku[66][1] = 1;

      sudoku[76][1] = 6; sudoku[77][1] = 4; sudoku[69][1] = 3; 
      
      sudoku[70][1] = 8; sudoku[79][1] = 5; 
      

      // Set the Solved Flag for each 
      sudoku[3][0] = 1; sudoku[12][0] = 1; 
      
      sudoku[5][0] = 1; sudoku[6][0] = 1; sudoku[13][0] = 1; 

      sudoku[16][0] = 1; sudoku[17][0] = 1; sudoku[18][0] = 1; sudoku[25][0] = 1; sudoku[26][0] = 1;
      

      sudoku[29][0] = 1; sudoku[30][0] = 1; sudoku[37][0] = 1; sudoku[46][0] = 1; sudoku[48][0] = 1;

      sudoku[33][0] = 1; sudoku[40][0] = 1; sudoku[41][0] = 1;  sudoku[42][0] = 1; sudoku[49][0] = 1; 

      sudoku[34][0] = 1; sudoku[36][0] = 1; sudoku[45][0] = 1; sudoku[52][0] = 1; sudoku[53][0] = 1;
      

      sudoku[56][0] = 1; sudoku[57][0] = 1; sudoku[64][0] = 1; sudoku[65][0] = 1;sudoku[66][0] = 1;

      sudoku[76][0] = 1; sudoku[77][0] = 1; sudoku[69][0] = 1; 
      
      sudoku[70][0] = 1; sudoku[79][0] = 1; 

 } else

 if (puzzlenum == 5 ){
      
      // Load Numbers
      sudoku[2][1] = 3; sudoku[3][1] = 2; sudoku[12][1] = 6; sudoku[21][1] = 9;
      
      sudoku[4][1] = 9; sudoku[5][1] = 8; sudoku[22][1] = 2; 

      sudoku[17][1] = 3; sudoku[27][1] = 7; 
      

      sudoku[30][1] = 7; sudoku[47][1] = 9; 

      sudoku[31][1] = 1; sudoku[40][1] = 3; sudoku[42][1] = 5; sudoku[51][1] = 4;

      sudoku[35][1] = 5; sudoku[52][1] = 6; 
      

      sudoku[55][1] = 2; sudoku[65][1] = 6; 

      sudoku[60][1] = 9; sudoku[77][1] = 5; sudoku[78][1] = 3; 
      
      sudoku[61][1] = 3; sudoku[70][1] = 7; sudoku[79][1] = 2; sudoku[80][1] = 6;
      

      // Set the Solved Flag for each 
      sudoku[2][0] = 1; sudoku[3][0] = 1; sudoku[12][0] = 1; sudoku[21][0] = 1;
      
      sudoku[4][0] = 1; sudoku[5][0] = 1; sudoku[22][0] = 1; 

      sudoku[17][0] = 1; sudoku[27][0] = 1; 
      

      sudoku[30][0] = 1; sudoku[47][0] = 1; 

      sudoku[31][0] = 1; sudoku[40][0] = 1; sudoku[42][0] = 1; sudoku[51][0] = 1;

      sudoku[35][0] = 1; sudoku[52][0] = 1; 
      

      sudoku[55][0] = 1; sudoku[65][0] = 1; 

      sudoku[60][0] = 1; sudoku[77][0] = 1; sudoku[78][0] = 1; 
      
      sudoku[61][0] = 1; sudoku[70][0] = 1; sudoku[79][0] = 1; sudoku[80][0] = 1;

 }

}


void refreshdisplay() { //Refresh the display once a value has changed

    tft.setTextSize(2);

  for (byte a = 1; a < 82; a++) {      

    //Test solve or set condition
    if  (sudoku[a][1] != 0) {  

        //First Clear Location
        tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
 
         if (sudoku[a][0] != 0) { // Do not draw 0 just leave blank square
             if (sudoku[a][0] == 1) {
                    tft.setTextColor(WHITE); 
                } else if (sudoku[a][0] == 2) {
                    tft.setTextColor(GREEN); // Set this colour if not a genuine set clue
                }       
              tft.setCursor( sudoku[a][3], sudoku[a][2]);   
              tft.println(sudoku[a][1]);
         }
          
          
          
     }
  }

}


void drawscreen(){

//    tft.fillScreen(BLACK);

// Setup Screen

GREEN  = 0x07E0;


  tft.fillRect(1, 1, 239, 239, BLACK);

  tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
  tft.drawRect(0+BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
  tft.drawRect(0+BOXSIZE+BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);  
  
  tft.drawRect(0, BOXSIZE, BOXSIZE, BOXSIZE, WHITE);
  tft.drawRect(0+BOXSIZE, BOXSIZE, BOXSIZE, BOXSIZE, WHITE);
  tft.drawRect(0+BOXSIZE+BOXSIZE, BOXSIZE, BOXSIZE, BOXSIZE, WHITE); 
  
  tft.drawRect(0, BOXSIZE*2, BOXSIZE, BOXSIZE, WHITE);
  tft.drawRect(0+BOXSIZE, BOXSIZE*2, BOXSIZE, BOXSIZE, WHITE);
  tft.drawRect(0+BOXSIZE+BOXSIZE, BOXSIZE*2, BOXSIZE, BOXSIZE, WHITE);   

}


void resetmatrix(){  // Initialize the sudoku matrix by setting all locations to zero and loading in the coordinates for each touch location
byte hole = 1;
  for (byte a = 0; a < 9; a++) {
    for (byte b = 0; b < 9; b++) {
      sudoku[hole][0] = 0; // Solve Flag
      sudoku[hole][1] = 0; // Display Value
      sudoku[hole][2] = colcoord[a]; // Matrix Column coordinate
      sudoku[hole][3] = rowcoord[b]; // Matrix Row coordinate
      sudoku[hole][4] = 1; // V1
      sudoku[hole][5] = 2; // V2
      sudoku[hole][6] = 3; // V3    
      sudoku[hole][7] = 4; // V4    
      sudoku[hole][8] = 5; // V5    
      sudoku[hole][9] = 6; // V6
      sudoku[hole][10] = 7; // V7 
      sudoku[hole][11] = 8; // V8    
      sudoku[hole][12] = 9; // V9        
      hole++;
    }
  } 
}


void drawbuttons() {
  // Setup Buttons
  GREEN  = 0x07E0;

  //Button 1
  tft.drawCircle(280, 30, 24, GREEN);
  tft.fillCircle(280, 30, 20, GREEN);  
  tft.setTextColor(BLACK);  tft.setTextSize(1);
  tft.setCursor(268, 27);   tft.println("HOME");   

  //Button 2
  tft.drawCircle(280, 90, 24, YELLOW);
  tft.fillCircle(280, 90, 20, YELLOW);  
  tft.setTextColor(BLACK);  tft.setTextSize(1);
  tft.setCursor(268, 87);   tft.println("PLAY");   
  
  //Button 3
  tft.drawCircle(280, 150, 24, MAGENTA);
  tft.fillCircle(280, 150, 20, MAGENTA);  
  tft.setTextColor(BLACK);  tft.setTextSize(1);
  tft.setCursor(268, 147);   tft.println("HELP");   


   //Button 4
  tft.drawCircle(280, 210, 24, BLUE);
  tft.fillCircle(280, 210, 20, BLUE);  
  tft.setTextColor(BLACK);  tft.setTextSize(1);
  tft.setCursor(266, 207);   tft.println("SOLVE");   




}

void solvealigndata(){ // Once a location is marked as solved then all data in that location nees to be set to Zero

  for (byte a = 1; a < 82; a++) { // Cycle through all locations

    if (sudoku[a][0] > 0) { // If location solved then zero out all data in array except correct value

      /*
     Serial.print(a);      Serial.print(" "); 

     Serial.print(sudoku[a][1]);      Serial.print(" "); 

     Serial.print(3+sudoku[a][1]);       Serial.print(" "); 

     Serial.print(sudoku[a][4]);
     
     Serial.print(sudoku[a][5]);
 
     Serial.print(sudoku[a][6]);

     Serial.print(sudoku[a][7]);

     Serial.print(sudoku[a][8]);

     Serial.print(sudoku[a][9]);

     Serial.print(sudoku[a][10]);

     Serial.print(sudoku[a][11]);

     Serial.println(sudoku[a][12]);

      */
      
      sudoku[a][4] = 0; // V1
      sudoku[a][5] = 0; // V2
      sudoku[a][6] = 0; // V3    
      sudoku[a][7] = 0; // V4    
      sudoku[a][8] = 0; // V5    
      sudoku[a][9] = 0; // V6
      sudoku[a][10] = 0; // V7 
      sudoku[a][11] = 0; // V8    
      sudoku[a][12] = 0; // V9 

      // Now poke the answer into the correct location
      sudoku[a][(sudoku[a][1]+3)] = sudoku[a][1]; // Load the solved value into the array

 /*    
     Serial.print(a);      Serial.print(" "); 

     Serial.print(sudoku[a][1]);      Serial.print(" "); 

     Serial.print(3+sudoku[a][1]);       Serial.print(" "); 

     Serial.print(sudoku[a][4]);

     Serial.print(sudoku[a][5]);
 
     Serial.print(sudoku[a][6]);

     Serial.print(sudoku[a][7]);

     Serial.print(sudoku[a][8]);

     Serial.print(sudoku[a][9]);

     Serial.print(sudoku[a][10]);

     Serial.print(sudoku[a][11]);

     Serial.println(sudoku[a][12]);

*/

                 
    }    
  }
  
  
}

void reversesolve(){ // subroutine to reverse engineer solved locations in the matrix and label themas solved
byte tempcount = 0;
  for (byte a = 1; a < 82; a++) { // Cycle through all locations

/*        
     Serial.print(a);      Serial.print(" "); 

     Serial.print(sudoku[a][0]);      Serial.print(" "); 

//     Serial.print(3+sudoku[a][1]);       Serial.print(" "); 

     Serial.print(sudoku[a][4]);
     
     Serial.print(sudoku[a][5]);
 
     Serial.print(sudoku[a][6]);

     Serial.print(sudoku[a][7]);

     Serial.print(sudoku[a][8]);

     Serial.print(sudoku[a][9]);

     Serial.print(sudoku[a][10]);

     Serial.print(sudoku[a][11]);

     Serial.println(sudoku[a][12]);

 */     

     if (sudoku[a][0] == 0) { // Ignore location if already solved

        // Read each and count the number that have been elimated    
        tempcount = 0;
        for (byte b = 4; b < 13; b++) {
            if (sudoku[a][b] == 0) {// If equal to 0 then count
              tempcount++;
            }
        }
  
        if (tempcount == 8){ // If only one valid result then find again then mark location as solved
            for (byte c = 4; c < 13; c++) { // Read each and identify the only solution  
              if (sudoku[a][c] > 0) {
                sudoku[a][0] = 1;  // Set Solved Location Flag
                sudoku[a][1] = sudoku[a][c];  // Set value
              }
            }    
        }                
    }    
       
/*
     Serial.print(a);      Serial.print(" "); 

     Serial.print(sudoku[a][0]);      Serial.print(" "); 

     Serial.print(tempcount);       Serial.print(" "); 

     Serial.print(sudoku[a][4]);

     Serial.print(sudoku[a][5]);
 
     Serial.print(sudoku[a][6]);

     Serial.print(sudoku[a][7]);

     Serial.print(sudoku[a][8]);

     Serial.print(sudoku[a][9]);

     Serial.print(sudoku[a][10]);

     Serial.print(sudoku[a][11]);

     Serial.println(sudoku[a][12]);

*/
  }
}

void reversesolvecolor(){ // subroutine to reverse engineer solved locations in the matrix and label themas solved
byte tempcount = 0;
  for (byte a = 1; a < 82; a++) { // Cycle through all locations

/*        
     Serial.print(a);      Serial.print(" "); 

     Serial.print(sudoku[a][0]);      Serial.print(" "); 

//     Serial.print(3+sudoku[a][1]);       Serial.print(" "); 

     Serial.print(sudoku[a][4]);
     
     Serial.print(sudoku[a][5]);
 
     Serial.print(sudoku[a][6]);

     Serial.print(sudoku[a][7]);

     Serial.print(sudoku[a][8]);

     Serial.print(sudoku[a][9]);

     Serial.print(sudoku[a][10]);

     Serial.print(sudoku[a][11]);

     Serial.println(sudoku[a][12]);

 */     

     if (sudoku[a][0] == 0) { // Ignore location if already solved

        // Read each and count the number that have been elimated    
        tempcount = 0;
        for (byte b = 4; b < 13; b++) {
            if (sudoku[a][b] == 0) {// If equal to 0 then count
              tempcount++;
            }
        }
  
        if (tempcount == 8){ // If only one valid result then find again then mark location as solved
            for (byte c = 4; c < 13; c++) { // Read each and identify the only solution  
              if (sudoku[a][c] > 0) {
                sudoku[a][0] = 2;  // Set Solved Location Flag
                sudoku[a][1] = sudoku[a][c];  // Set value
              }
            }    
        }                
    }    
       
/*
     Serial.print(a);      Serial.print(" "); 

     Serial.print(sudoku[a][0]);      Serial.print(" "); 

     Serial.print(tempcount);       Serial.print(" "); 

     Serial.print(sudoku[a][4]);

     Serial.print(sudoku[a][5]);
 
     Serial.print(sudoku[a][6]);

     Serial.print(sudoku[a][7]);

     Serial.print(sudoku[a][8]);

     Serial.print(sudoku[a][9]);

     Serial.print(sudoku[a][10]);

     Serial.print(sudoku[a][11]);

     Serial.println(sudoku[a][12]);

*/
  }
}




void solvehorizontal(){ // Take Solved locations and apply horizontal rule
// Cycle through all locations and using solved flag remove all associate horizontal possibilities  


/*
for (byte d = 1; d < 82; d++) { // Cycle through all locations
     Serial.print(d);      Serial.print(" "); 

     Serial.print(sudoku[d][0]);      Serial.print(" "); 

     Serial.print(sudoku[d][4]);

     Serial.print(sudoku[d][5]);
 
     Serial.print(sudoku[d][6]);

     Serial.print(sudoku[d][7]);

     Serial.print(sudoku[d][8]);

     Serial.print(sudoku[d][9]);

     Serial.print(sudoku[d][10]);

     Serial.print(sudoku[d][11]);

     Serial.println(sudoku[d][12]);
}
*/
          // ROW 1 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 1; a < 10; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 1; r < 10; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // ROW 2 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 10; a < 19; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 10; r < 19; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 

           // ROW 3 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 19; a < 28; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 19; r < 28; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // ROW 4 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 28; a < 37; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 28; r < 37; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 
           // ROW 5 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 37; a < 46; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 37; r < 46; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // ROW 6 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 46; a < 55; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 46; r < 55; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 
           // ROW 7 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 55; a < 64; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 55; r < 64; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // ROW 8 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 64; a < 73; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 64; r < 73; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 

          // ROW 9 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 73; a < 82; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 73; r < 82; r++) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 

 /*
     for (byte e = 1; e < 82; e++) { // Cycle through all locations
     Serial.print(e);      Serial.print(" "); 

     Serial.print(sudoku[e][0]);      Serial.print(" "); 

     Serial.print(sudoku[e][4]);

     Serial.print(sudoku[e][5]);
 
     Serial.print(sudoku[e][6]);

     Serial.print(sudoku[e][7]);

     Serial.print(sudoku[e][8]);

     Serial.print(sudoku[e][9]);

     Serial.print(sudoku[e][10]);

     Serial.print(sudoku[e][11]);

     Serial.println(sudoku[e][12]);        

    }                
*/
}


    void solvevertical(){ // Take Solved locations and apply horizontal rule
// Cycle through all locations and using solved flag remove all associate vertical possibilities  

/*
for (byte d = 1; d < 82; d++) { // Cycle through all locations
     Serial.print(d);      Serial.print(" "); 

     Serial.print(sudoku[d][0]);      Serial.print(" "); 

     Serial.print(sudoku[d][4]);

     Serial.print(sudoku[d][5]);
 
     Serial.print(sudoku[d][6]);

     Serial.print(sudoku[d][7]);

     Serial.print(sudoku[d][8]);

     Serial.print(sudoku[d][9]);

     Serial.print(sudoku[d][10]);

     Serial.print(sudoku[d][11]);

     Serial.println(sudoku[d][12]);
}
*/
          // COL 1 ************************  
          // Step through each of Col  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 1; a < 74; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 1; r < 74; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // COL 2 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 2; a < 75; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 2; r < 75; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 

           // COL 3 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 3; a < 76; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 3; r < 76; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // COL 4 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 4; a < 77; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 4; r < 77; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 
           // COL 5 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 5; a < 78; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 5; r < 78; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // COL 6 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 6; a < 79; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 6; r < 79; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 
           // COL 7 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 7; a < 80; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 7; r < 80; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          }  

          
          // COL 8 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 8; a < 81; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 8; r < 81; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 

          // COL 9 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 9; a < 82; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 9; r < 83; r=r+9) {           
                      if ((sudoku[r][sudoku[a][1]+3] == sudoku[a][1] )&& (a!=r)) {
                        sudoku[r][sudoku[a][1]+3] = 0; 
                       }
                  }           
              }
          } 

 /*
     for (byte e = 1; e < 82; e++) { // Cycle through all locations
     Serial.print(e);      Serial.print(" "); 

     Serial.print(sudoku[e][0]);      Serial.print(" "); 

     Serial.print(sudoku[e][4]);

     Serial.print(sudoku[e][5]);
 
     Serial.print(sudoku[e][6]);

     Serial.print(sudoku[e][7]);

     Serial.print(sudoku[e][8]);

     Serial.print(sudoku[e][9]);

     Serial.print(sudoku[e][10]);

     Serial.print(sudoku[e][11]);

     Serial.println(sudoku[e][12]);        

    }                
*/
}    


void solvepanel(){ // Take Solved locations and apply horizontal rule
// Cycle through all locations and using solved flag remove all associate panel possibilities  

/*

for (byte d = 1; d < 82; d++) { // Cycle through all locations
     Serial.print(d);      Serial.print(" "); 

     Serial.print(sudoku[d][0]);      Serial.print(" "); 
     Serial.print(sudoku[d][4]);
     Serial.print(sudoku[d][5]); 
     Serial.print(sudoku[d][6]);
     Serial.print(sudoku[d][7]);
     Serial.print(sudoku[d][8]);
     Serial.print(sudoku[d][9]);
     Serial.print(sudoku[d][10]);
     Serial.print(sudoku[d][11]);
     Serial.println(sudoku[d][12]);
     }

*/



          // PANEL Algorythm ************************  
          // Step through each of locations and delete duplicates of the Solved location using the panel formulae. Ignore the current location you are solving for
          for (byte a = 1; a < 82; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry                 
                   for (byte r = 1; r < 82; r++) { // Step through all locations           
                       if ((sudoku[a][13] == sudoku[r][13]) && (a!=r)) { // Identify the locations on the Same Panel                           
                          if ((sudoku[a][13] == sudoku[r][13]) && (a!=r)) { 
                               sudoku[r][sudoku[a][1]+3] = 0;                             
                          }

                      }   
                  }           
              }
          }  

    /*      
  

     for (byte e = 1; e < 82; e++) { // Cycle through all locations
     Serial.print(e);      Serial.print(" "); 
     Serial.print(sudoku[e][0]);      Serial.print(" "); 
     Serial.print(sudoku[e][4]);
     Serial.print(sudoku[e][5]); 
     Serial.print(sudoku[e][6]);
     Serial.print(sudoku[e][7]);
     Serial.print(sudoku[e][8]);
     Serial.print(sudoku[e][9]);
     Serial.print(sudoku[e][10]);
     Serial.print(sudoku[e][11]);
     Serial.println(sudoku[e][12]);        
    */                

}



void loadpaneldata(){  // Load specifc Panel identification Data into the Array for each of the 81 locations



      // Load Numbers
      // Panel 1
      sudoku[1][13] = 1; sudoku[2][13] = 1; sudoku[3][13] = 1; 
      sudoku[10][13] = 1; sudoku[11][13] = 1; sudoku[12][13] = 1; 
      sudoku[19][13] = 1; sudoku[20][13] = 1; sudoku[21][13] = 1; 
      // Panel 2
      sudoku[4][13] = 2; sudoku[5][13] = 2; sudoku[6][13] = 2; 
      sudoku[13][13] = 2; sudoku[14][13] = 2; sudoku[15][13] = 2; 
      sudoku[22][13] = 2; sudoku[23][13] = 2; sudoku[24][13] = 2; 
      // Panel 3
      sudoku[7][13] = 3; sudoku[8][13] = 3; sudoku[9][13] = 3; 
      sudoku[16][13] = 3; sudoku[17][13] = 3; sudoku[18][13] = 3; 
      sudoku[25][13] = 3; sudoku[26][13] = 3; sudoku[27][13] = 3;       
      // Panel 4
      sudoku[28][13] = 4; sudoku[29][13] = 4; sudoku[30][13] = 4; 
      sudoku[37][13] = 4; sudoku[38][13] = 4; sudoku[39][13] = 4; 
      sudoku[46][13] = 4; sudoku[47][13] = 4; sudoku[48][13] = 4; 
      // Panel 5
      sudoku[31][13] = 5; sudoku[32][13] = 5; sudoku[33][13] = 5; 
      sudoku[40][13] = 5; sudoku[41][13] = 5; sudoku[42][13] = 5; 
      sudoku[49][13] = 5; sudoku[50][13] = 5; sudoku[51][13] = 5; 
      // Panel 6
      sudoku[34][13] = 6; sudoku[35][13] = 6; sudoku[36][13] = 6; 
      sudoku[43][13] = 6; sudoku[44][13] = 6; sudoku[45][13] = 6; 
      sudoku[52][13] = 6; sudoku[53][13] = 6; sudoku[54][13] = 6; 
      // Panel 7
      sudoku[55][13] = 7; sudoku[56][13] = 7; sudoku[57][13] = 7; 
      sudoku[64][13] = 7; sudoku[65][13] = 7; sudoku[66][13] = 7; 
      sudoku[73][13] = 7; sudoku[74][13] = 7; sudoku[75][13] = 7; 
      // Panel 8
      sudoku[58][13] = 8; sudoku[59][13] = 8; sudoku[60][13] = 8; 
      sudoku[67][13] = 8; sudoku[68][13] = 8; sudoku[69][13] = 8; 
      sudoku[76][13] = 8; sudoku[77][13] = 8; sudoku[78][13] = 8;       
      // Panel 9
      sudoku[61][13] = 9; sudoku[62][13] = 9; sudoku[63][13] = 9; 
      sudoku[70][13] = 9; sudoku[71][13] = 9; sudoku[72][13] = 9; 
      sudoku[79][13] = 9; sudoku[80][13] = 9; sudoku[81][13] = 9; 

}     

// Used to identify and highlight errors in a current matrix - use solve method however instead of solving outcome just highlight conflicts in red
void helpbutton(){


// Horizontal *********************
          // ROW 1 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 1; a < 10; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 1; r < 10; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }
                  }           
              }  

          
          // ROW 2 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 10; a < 19; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 10; r < 19; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          } 

           // ROW 3 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 19; a < 28; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 19; r < 28; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          }  

          
          // ROW 4 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 28; a < 37; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 28; r < 37; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }          
              }
          } 
           // ROW 5 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 37; a < 46; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 37; r < 46; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          }  

          
          // ROW 6 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 46; a < 55; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 46; r < 55; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          } 
           // ROW 7 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 55; a < 64; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 55; r < 64; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          }  

          
          // ROW 8 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 64; a < 73; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 64; r < 73; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          } 

          // ROW 9 ************************  
          // Step through each of ROW  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 73; a < 82; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 73; r < 82; r++) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          } 

// Vertical ****************
          // COL 1 ************************  
          // Step through each of Col  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 1; a < 74; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 1; r < 74; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }          
              }
          }  

          
          // COL 2 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 2; a < 75; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 2; r < 75; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          } 

           // COL 3 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 3; a < 76; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 3; r < 76; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          }  

          
          // COL 4 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 4; a < 77; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 4; r < 77; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          } 
           // COL 5 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 5; a < 78; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 5; r < 78; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }                       
                       }           
              }
          }  

          
          // COL 6 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 6; a < 79; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 6; r < 79; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }
                  }           
              }
          } 
           // COL 7 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 7; a < 80; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 7; r < 80; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }
                  }           
              }
          }  

          
          // COL 8 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 8; a < 81; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 8; r < 81; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }
                  }           
              }
          } 

          // COL 9 ************************  
          // Step through each of COL  locations and delete duplicates of the Solved location. Ignore the current location you are solving for
          for (byte a = 9; a < 82; a=a+9) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry 
                  for (byte r = 9; r < 83; r=r+9) {           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }
                  }           
              }
          }
// Panels *******************

          // PANEL Algorythm ************************  
          // Step through each of locations and delete duplicates of the Solved location using the Oanel formulae. Ignore the current location you are solving for
          for (byte a = 1; a < 82; a++) { // Cycle through all locations
              if (sudoku[a][0] > 0) { // Identify the locations that are already solved and delete any occurences that are already in scope of enquiry                 
                   for (byte r = 1; r < 82; r++) { // Step through all locations           
                       if ((sudoku[a][13] == sudoku[r][13]) && (a!=r)) { // Identify the locations on the Same Panel                           
                      if ((sudoku[a][1] == sudoku[r][1] ) && (a!=r)) { // Current location is not a master value and it is duplicate then color RED                        
                           // Refresh only the location concerned with new value and show colour coded
                                //First Clear Location
                                tft.fillRect(sudoku[a][3], sudoku[a][2], 15, 15, BLACK);      
                                tft.setTextSize(2);
                                tft.setTextColor(RED);    
                                tft.setCursor( sudoku[a][3], sudoku[a][2]); tft.println(sudoku[a][1]);
                                 }

                      }   
                  }           
              }
          }  


// Horizontal conflict help function - Step through data and identify manually changed locations as conflicts in RED. Leave items set at WHITE as WHITE

// Vertical conflict help function - Step through data and identify manually changed locations as conflicts in RED. Leave items set at WHITE as WHITE

// Panel conflict help function - Step through data and identify manually changed locations as conflicts in RED. Leave items set at WHITE as WHITE
    

}


void uniquecandidate() { // Each panel, row and column on a Sudoku board must contain every number between 1 and 9. 
                         // Therefore, if a number, say 4, can only be put in a single cell within a block/column/row, then that number is guaranteed to fit there.

/*

for (byte d = 1; d < 82; d++) { // Cycle through all locations
     Serial.print(d);      Serial.print(" "); 

     Serial.print(sudoku[d][0]);      Serial.print(" "); 
     Serial.print(sudoku[d][1]);      Serial.print(" "); 
     Serial.print(sudoku[d][4]);
     Serial.print(sudoku[d][5]); 
     Serial.print(sudoku[d][6]);
     Serial.print(sudoku[d][7]);
     Serial.print(sudoku[d][8]);
     Serial.print(sudoku[d][9]);
     Serial.print(sudoku[d][10]);
     Serial.print(sudoku[d][11]);
     Serial.println(sudoku[d][12]);
     }

*/

byte tempcount = 0;

  for (byte p = 1; p < 10; p++) { // Cycle through all panels 1 to 9

      for (byte v = 1; v < 10; v++) { // Step through all possible unique location values in each panel                
 

          for (byte r = 1; r < 82; r++) { // Step through all locations  
   
                  if (sudoku[r][13] == p) {  //Only operate on those locations that are in this panel
    
                      if (sudoku[r][v+3] == v) {// Count this if value is what we are looking for
                        tempcount++;
                      }               
                  }                       
          }
          // Check if unique
          if ( tempcount == 1) { // This is a unique value so reset the location with this being a solved location
              // Repeat process to locate unique location
              for (byte r = 1; r < 82; r++) { // Step through all locations and then mark as solved
 
                  if (sudoku[r][13] == p) {  //Only operate on those locations that are in this panel
                      if (sudoku[r][v+3] == v) {// Count this if value is what we are looking for
                       
                            // Now poke the answer into the correct location
                            if (sudoku[r][0] == 0) { // Change to solved but remain green
                              sudoku[r][0] = 2;
                            }
                            sudoku[r][1] = v;
                      }               
                  }           
              }      
          } 
          // Reset temp counter
          tempcount = 0;
      }
  }  
/*
for (byte d = 1; d < 82; d++) { // Cycle through all locations
     Serial.print(d);      Serial.print(" "); 

     Serial.print(sudoku[d][0]);      Serial.print(" "); 
     Serial.print(sudoku[d][1]);      Serial.print(" "); 
     Serial.print(sudoku[d][4]);
     Serial.print(sudoku[d][5]); 
     Serial.print(sudoku[d][6]);
     Serial.print(sudoku[d][7]);
     Serial.print(sudoku[d][8]);
     Serial.print(sudoku[d][9]);
     Serial.print(sudoku[d][10]);
     Serial.print(sudoku[d][11]);
     Serial.println(sudoku[d][12]);
     }
*/                        
  
}

Custom parts and enclosures

3D Enclosure files
The 3D case was printed with White PLA with each part oriented so that Lid and Base are facing upwards using the following settings Layer Height: 0.2mm Speed: 40mm/s Nozzle Diameter: 0.4mm Supports: Enabled Nozzle Temperature: 210 Degrees

Schematics

Circuit Diagram
Arduino sudoku solver circuit v1 vxclapovcx

Comments

Similar projects you might like

Arduino Pocket Game Console + A-Maze - Maze Game

Project tutorial by Alojz Jakob

  • 7,860 views
  • 8 comments
  • 22 respects

The Pyramid's Secret: Arduino Electronic Board Game

Project tutorial by marcelomaximiano

  • 2,492 views
  • 1 comment
  • 16 respects

Create a Game with Arduino and Processing

Project showcase by Nicholas_N

  • 5,622 views
  • 3 comments
  • 5 respects

Portable Biometric Lockable Case

Project tutorial by NZDoug

  • 3,505 views
  • 0 comments
  • 20 respects

Arduino Controlled LED Multi-Player Game on Arduino "Shield"

Project tutorial by 22warehamD

  • 1,415 views
  • 1 comment
  • 6 respects

Arduino Game to Test Your Reflexes!

Project showcase by Bie

  • 940 views
  • 0 comments
  • 0 respects
Add projectSign up / Login