Project tutorial

# Portable Electronic Sudoku Game © CC BY-NC-SA

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

• 1,672 views
• 10 respects

## Components and supplies

 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

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 <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

void setup(void) {
//  Serial.begin(9600);
//  Serial.println(F("Paint!"));

tft.reset();

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);

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
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]);
}

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:

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
}

}

// Test Puzzle example 1 loaded into array

if (puzzlenum == 1 ){

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 ){

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 ){

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 ){

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 ){

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

// 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

• 5 projects
• 15 followers

June 3, 2019

#### Members who respect this project

and 4 others

See similar projects
you might like

#### Arduino Pocket Game Console + A-Maze - Maze Game

Project tutorial by Alojz Jakob

• 10,568 views
• 28 respects

#### The Pyramid's Secret: Arduino Electronic Board Game

Project tutorial by marcelomaximiano

• 3,183 views
• 18 respects

• 12,310 views
• 61 respects

#### Ponguino Arduino Pong Game

Project tutorial by 5vdc

• 1,130 views
• 2 respects

#### Create a Game with Arduino and Processing

Project showcase by Nicholas_N

• 7,307 views