// ####################################
// # #
// # Tic Tac Toe & Lights Out Games #
// # #
// # for Arduino #
// # #
// # by Mark 2013 #
// # #
// # Details on Arduino Project Hub #
// # #
// ####################################
// global constants
const int player = 1;
const int computer = 2;
// global variables
// variables for buttons
// voltage for each button pressed, measured with multimeter, 10th value is minimum value for boundary setting
float voltages[] = {4.92, 2.47, 1.65, 1.24, 0.99, 0.82, 0.70, 0.62, 0.55, 0.10};
float boundaries[9]; // boundary voltages for button detection
int button; // last button pressed (0-8)
// light variables
int lights[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // 0 = off, 1 = red, 2 = green
int flash[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // used for flashing winning line in tic tac toe game
// game variables
int gameSelected = 0; // 0 = none, 1 = tic tac toe, 2 = lights out
// shift register variables
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
// binary LED values
int byte1 = 0;
int byte2 = 0;
int byte3 = 0;
void setup() {
// set pins for shift registers
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
// set boundaries for button voltages
for (int i = 0; i < 9; i++){
boundaries[i] = voltages[i]-((voltages[i] - voltages[i + 1]) / 2.0);
}
// enable serial port
Serial.begin(9600);
}
void loop() {
button = getButtonPush();
// menu selection
if (gameSelected == 0){
displayMenu();
if (button == 0 || button == 2 || button == 3 || button == 5 || button == 6 || button == 8){
gameSelected = 1;
}
if (button == 1 || button == 4 || button == 7){
gameSelected = 2;
}
}
// game 1, tic tac toe
if (gameSelected == 1){
playTickTackToe();
}
// game 2, lights out
if (gameSelected == 2){
playLightsOut();
}
refreshDisplay();
delay(50);
}
int getButtonPush() {
int sensorValue;
float inputVoltage;
int pressed = -1;
// read input value and convert to voltage
sensorValue = analogRead(A0);
inputVoltage = sensorValue * (5.0 / 1023.0);
// convert to button number
if (inputVoltage > 0.1){
for (int i = 8; i >= 0; i--){
if (boundaries[i] < inputVoltage){
pressed = i;
}
}
// wait until button is released before returning
while (inputVoltage > 0.1){
sensorValue = analogRead(A0);
inputVoltage = sensorValue * (5.0 / 1023.0);
}
}
return pressed;
}
void displayMenu() {
// set led pattern for menu
lights[0] = 1;
lights[1] = 2;
lights[2] = 1;
lights[3] = 1;
lights[4] = 2;
lights[5] = 1;
lights[6] = 1;
lights[7] = 2;
lights[8] = 1;
}
void refreshDisplay() {
byte1 = 0;
byte2 = 0;
byte3 = 0;
if (lights[0] == 1){byte1 = byte1 ^ B00000001;}
if (lights[1] == 1){byte1 = byte1 ^ B00000010;}
if (lights[2] == 1){byte1 = byte1 ^ B00000100;}
if (lights[3] == 1){byte1 = byte1 ^ B00001000;}
if (lights[4] == 1){byte1 = byte1 ^ B00010000;}
if (lights[5] == 1){byte1 = byte1 ^ B00100000;}
if (lights[6] == 1){byte1 = byte1 ^ B01000000;}
if (lights[7] == 1){byte1 = byte1 ^ B10000000;}
if (lights[8] == 1){byte2 = byte2 ^ B00000001;}
if (lights[0] == 2){byte2 = byte2 ^ B00000010;}
if (lights[1] == 2){byte2 = byte2 ^ B00000100;}
if (lights[2] == 2){byte2 = byte2 ^ B00001000;}
if (lights[3] == 2){byte2 = byte2 ^ B00010000;}
if (lights[4] == 2){byte2 = byte2 ^ B00100000;}
if (lights[5] == 2){byte2 = byte2 ^ B01000000;}
if (lights[6] == 2){byte2 = byte2 ^ B10000000;}
if (lights[7] == 2){byte3 = byte3 ^ B00000001;}
if (lights[8] == 2){byte3 = byte3 ^ B00000010;}
setLEDs();
}
void setLEDs(){
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, byte3);
shiftOut(dataPin, clockPin, MSBFIRST, byte2);
shiftOut(dataPin, clockPin, MSBFIRST, byte1);
digitalWrite(latchPin, HIGH);
}
void playTickTackToe() {
int gameState = 1;
clearBoard();
while (gameState == 1) {
button = -1;
refreshDisplay();
button = getButtonPush();
if (lights[button] == 0) {
lights[button] = 1;
gameState = checkForWin();
refreshDisplay();
if (gameState == 1) {
delay(500);
computerMove();
refreshDisplay();
gameState = checkForWin();
}
}
}
showWinner(gameState);
clearBoard();
refreshDisplay();
delay(2000);
gameState = 0;
gameSelected = 0;
}
void showWinner(int gameState) {
flash[0] = lights[0];
flash[1] = lights[1];
flash[2] = lights[2];
flash[3] = lights[3];
flash[4] = lights[4];
flash[5] = lights[5];
flash[6] = lights[6];
flash[7] = lights[7];
flash[8] = lights[8];
if (lights[0] == player && lights[1] == player && lights[2] == player) { flash[0] = 0; flash[1] = 0; flash[2] = 0; }
if (lights[3] == player && lights[4] == player && lights[5] == player) { flash[3] = 0; flash[4] = 0; flash[5] = 0; }
if (lights[6] == player && lights[7] == player && lights[8] == player) { flash[6] = 0; flash[7] = 0; flash[8] = 0; }
if (lights[0] == player && lights[3] == player && lights[6] == player) { flash[0] = 0; flash[3] = 0; flash[6] = 0; }
if (lights[1] == player && lights[4] == player && lights[7] == player) { flash[1] = 0; flash[4] = 0; flash[7] = 0; }
if (lights[2] == player && lights[5] == player && lights[8] == player) { flash[2] = 0; flash[5] = 0; flash[8] = 0; }
if (lights[0] == player && lights[4] == player && lights[8] == player) { flash[0] = 0; flash[4] = 0; flash[8] = 0; }
if (lights[2] == player && lights[4] == player && lights[6] == player) { flash[2] = 0; flash[4] = 0; flash[6] = 0; }
if (lights[0] == computer && lights[1] == computer && lights[2] == computer) { flash[0] = 0; flash[1] = 0; flash[2] = 0; }
if (lights[3] == computer && lights[4] == computer && lights[5] == computer) { flash[3] = 0; flash[4] = 0; flash[5] = 0; }
if (lights[6] == computer && lights[7] == computer && lights[8] == computer) { flash[6] = 0; flash[7] = 0; flash[8] = 0; }
if (lights[0] == computer && lights[3] == computer && lights[6] == computer) { flash[0] = 0; flash[3] = 0; flash[6] = 0; }
if (lights[1] == computer && lights[4] == computer && lights[7] == computer) { flash[1] = 0; flash[4] = 0; flash[7] = 0; }
if (lights[2] == computer && lights[5] == computer && lights[8] == computer) { flash[2] = 0; flash[5] = 0; flash[8] = 0; }
if (lights[0] == computer && lights[4] == computer && lights[8] == computer) { flash[0] = 0; flash[4] = 0; flash[8] = 0; }
if (lights[2] == computer && lights[4] == computer && lights[6] == computer) { flash[2] = 0; flash[4] = 0; flash[6] = 0; }
swapLightsAndFlash();
refreshDisplay();
for (int i = 0; i < 20; i++) {
delay(200);
swapLightsAndFlash();
refreshDisplay();
}
}
void swapLightsAndFlash() {
int temp[] = {lights[0], lights[1], lights[2], lights[3], lights[4], lights[5], lights[6], lights[7], lights[8]};
lights[0] = flash[0];
lights[1] = flash[1];
lights[2] = flash[2];
lights[3] = flash[3];
lights[4] = flash[4];
lights[5] = flash[5];
lights[6] = flash[6];
lights[7] = flash[7];
lights[8] = flash[8];
flash[0] = temp[0];
flash[1] = temp[1];
flash[2] = temp[2];
flash[3] = temp[3];
flash[4] = temp[4];
flash[5] = temp[5];
flash[6] = temp[6];
flash[7] = temp[7];
flash[8] = temp[8];
}
void computerMove() {
int bias[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
int bestMove = -1;
int topBias = 0;
// can computer win
bias[0] = bias[0] + getBiasWin(0, 1, 2);
bias[0] = bias[0] + getBiasWin(0, 4, 8);
bias[0] = bias[0] + getBiasWin(0, 3, 6);
bias[1] = bias[1] + getBiasWin(1, 0, 2);
bias[1] = bias[1] + getBiasWin(1, 4, 7);
bias[2] = bias[2] + getBiasWin(2, 0, 1);
bias[2] = bias[2] + getBiasWin(2, 4, 6);
bias[2] = bias[2] + getBiasWin(2, 5, 8);
bias[3] = bias[3] + getBiasWin(3, 0, 6);
bias[3] = bias[3] + getBiasWin(3, 4, 5);
bias[4] = bias[4] + getBiasWin(4, 0, 8);
bias[4] = bias[4] + getBiasWin(4, 1, 7);
bias[4] = bias[4] + getBiasWin(4, 2, 6);
bias[4] = bias[4] + getBiasWin(4, 3, 5);
bias[5] = bias[5] + getBiasWin(5, 2, 8);
bias[5] = bias[5] + getBiasWin(5, 3, 4);
bias[6] = bias[6] + getBiasWin(6, 0, 3);
bias[6] = bias[6] + getBiasWin(6, 2, 4);
bias[6] = bias[6] + getBiasWin(6, 7, 8);
bias[7] = bias[7] + getBiasWin(7, 1, 4);
bias[7] = bias[7] + getBiasWin(7, 6, 8);
bias[8] = bias[8] + getBiasWin(8, 0, 4);
bias[8] = bias[8] + getBiasWin(8, 2, 5);
bias[8] = bias[8] + getBiasWin(8, 6, 7);
// can computer stop the human from winning
bias[0] = bias[0] + getBiasStop(0, 1, 2);
bias[0] = bias[0] + getBiasStop(0, 4, 8);
bias[0] = bias[0] + getBiasStop(0, 3, 6);
bias[1] = bias[1] + getBiasStop(1, 0, 2);
bias[1] = bias[1] + getBiasStop(1, 4, 7);
bias[2] = bias[2] + getBiasStop(2, 0, 1);
bias[2] = bias[2] + getBiasStop(2, 4, 6);
bias[2] = bias[2] + getBiasStop(2, 5, 8);
bias[3] = bias[3] + getBiasStop(3, 0, 6);
bias[3] = bias[3] + getBiasStop(3, 4, 5);
bias[4] = bias[4] + getBiasStop(4, 0, 8);
bias[4] = bias[4] + getBiasStop(4, 1, 7);
bias[4] = bias[4] + getBiasStop(4, 2, 6);
bias[4] = bias[4] + getBiasStop(4, 3, 5);
bias[5] = bias[5] + getBiasStop(5, 2, 8);
bias[5] = bias[5] + getBiasStop(5, 3, 4);
bias[6] = bias[6] + getBiasStop(6, 0, 3);
bias[6] = bias[6] + getBiasStop(6, 2, 4);
bias[6] = bias[6] + getBiasStop(6, 7, 8);
bias[7] = bias[7] + getBiasStop(7, 1, 4);
bias[7] = bias[7] + getBiasStop(7, 6, 8);
bias[8] = bias[8] + getBiasStop(8, 0, 4);
bias[8] = bias[8] + getBiasStop(8, 2, 5);
bias[8] = bias[8] + getBiasStop(8, 6, 7);
// add a small random value to each possible move
for (int i = 0; i < 9; i++) {
if (lights[i] == 0) {
bias[i] = bias[i] + random(1, 5);
}
}
// get best move
for (int i = 0; i < 9; i++) {
if (bias[i] > topBias) {
topBias = bias[i];
bestMove = i;
}
}
// make move
if (bestMove != -1) {
lights[bestMove] = computer;
}
}
int getBiasWin(int thisPosition, int checkPosition1, int checkPosition2) {
if (lights[thisPosition] == 0 && lights[checkPosition1] == computer && lights[checkPosition2] == computer) {
return 100;
}
else {
return 0;
}
}
int getBiasStop(int thisPosition, int checkPosition1, int checkPosition2) {
if (lights[thisPosition] == 0 && lights[checkPosition1] == player && lights[checkPosition2] == player) {
return 20;
}
else {
return 0;
}
}
int checkForWin() {
int winState = 1;
// check for player win
if (lights[0] == player && lights[1] == player && lights[2] == player) { winState = 11; }
if (lights[3] == player && lights[4] == player && lights[5] == player) { winState = 11; }
if (lights[6] == player && lights[7] == player && lights[8] == player) { winState = 11; }
if (lights[0] == player && lights[3] == player && lights[6] == player) { winState = 11; }
if (lights[1] == player && lights[4] == player && lights[7] == player) { winState = 11; }
if (lights[2] == player && lights[5] == player && lights[8] == player) { winState = 11; }
if (lights[0] == player && lights[4] == player && lights[8] == player) { winState = 11; }
if (lights[2] == player && lights[4] == player && lights[6] == player) { winState = 11; }
// check for computer win
if (lights[0] == computer && lights[1] == computer && lights[2] == computer) { winState = 12; }
if (lights[3] == computer && lights[4] == computer && lights[5] == computer) { winState = 12; }
if (lights[6] == computer && lights[7] == computer && lights[8] == computer) { winState = 12; }
if (lights[0] == computer && lights[3] == computer && lights[6] == computer) { winState = 12; }
if (lights[1] == computer && lights[4] == computer && lights[7] == computer) { winState = 12; }
if (lights[2] == computer && lights[5] == computer && lights[8] == computer) { winState = 12; }
if (lights[0] == computer && lights[4] == computer && lights[8] == computer) { winState = 12; }
if (lights[2] == computer && lights[4] == computer && lights[6] == computer) { winState = 12; }
// check for draw
int draw = 1;
for (int i = 0; i < 9; i++) {
if (lights[i] == 0) {
draw = 0;
}
}
if (draw == 1) {
winState = 13;
}
return winState;
}
void clearBoard() {
for (int i = 0; i < 9; i++) {
lights[i] = 0;
}
}
void playLightsOut() {
int gameState = 1;
int lit = 0;
resetBoard();
while (gameState == 1) {
button = -1;
lit = 0;
refreshDisplay();
button = getButtonPush();
if (lights[button] == 1) {
switch (button) {
case 0:
lights[0] = abs(lights[0] - 1);
lights[1] = abs(lights[1] - 1);
lights[3] = abs(lights[3] - 1);
lights[4] = abs(lights[4] - 1);
break;
case 1:
lights[0] = abs(lights[0] - 1);
lights[1] = abs(lights[1] - 1);
lights[2] = abs(lights[2] - 1);
break;
case 2:
lights[1] = abs(lights[1] - 1);
lights[2] = abs(lights[2] - 1);
lights[4] = abs(lights[4] - 1);
lights[5] = abs(lights[5] - 1);
break;
case 3:
lights[0] = abs(lights[0] - 1);
lights[3] = abs(lights[3] - 1);
lights[6] = abs(lights[6] - 1);
break;
case 4:
lights[1] = abs(lights[1] - 1);
lights[3] = abs(lights[3] - 1);
lights[4] = abs(lights[4] - 1);
lights[5] = abs(lights[5] - 1);
lights[7] = abs(lights[7] - 1);
break;
case 5:
lights[2] = abs(lights[2] - 1);
lights[5] = abs(lights[5] - 1);
lights[8] = abs(lights[8] - 1);
break;
case 6:
lights[3] = abs(lights[3] - 1);
lights[4] = abs(lights[4] - 1);
lights[6] = abs(lights[6] - 1);
lights[7] = abs(lights[7] - 1);
break;
case 7:
lights[6] = abs(lights[6] - 1);
lights[7] = abs(lights[7] - 1);
lights[8] = abs(lights[8] - 1);
break;
case 8:
lights[4] = abs(lights[4] - 1);
lights[5] = abs(lights[5] - 1);
lights[7] = abs(lights[7] - 1);
lights[8] = abs(lights[8] - 1);
}
}
for (int i = 0; i < 9; i++) {
if (lights[i] == 1) {
lit++;
}
}
if (lit == 0) {
gameState = 0;
gameSelected = 0;
delay(200);
victoryDisplay();
}
delay(50);
}
}
void resetBoard() {
int lit = 0;
randomSeed(analogRead(5));
while (lit < 3 || lit > 5) {
lit = 0;
for (int i = 0; i < 9; i++) {
lights[i] = random(2);
if (lights[i] == 1) {
lit++;
}
}
}
}
void victoryDisplay() {
victoryItem(0, 0, 0, 0, 0, 0, 0, 0, 0);
for (int i = 0; i < 7; i++) {
victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0);
victoryItem(1, 0, 0, 0, 1, 0, 0, 0, 1);
victoryItem(0, 0, 0, 1, 1, 1, 0, 0, 0);
victoryItem(0, 0, 1, 0, 1, 0, 1, 0, 0);
}
for (int i = 0; i < 4; i++) {
victoryItem(2, 2, 2, 0, 0, 0, 0, 0, 0);
victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0);
victoryItem(0, 0, 0, 0, 0, 0, 2, 2, 2);
victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0);
}
for (int i = 0; i < 4; i++) {
victoryItem(1, 0, 0, 1, 0, 0, 1, 0, 0);
victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0);
victoryItem(0, 0, 1, 0, 0, 1, 0, 0, 1);
victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0);
}
for (int i = 0; i < 7; i++) {
victoryItem(2, 0, 0, 0, 2, 0, 0, 0, 2);
victoryItem(0, 2, 0, 0, 2, 0, 0, 2, 0);
victoryItem(0, 0, 2, 0, 2, 0, 2, 0, 0);
victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0);
}
}
void victoryItem(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8) {
lights[0] = i0;
lights[1] = i1;
lights[2] = i2;
lights[3] = i3;
lights[4] = i4;
lights[5] = i5;
lights[6] = i6;
lights[7] = i7;
lights[8] = i8;
refreshDisplay();
delay(100);
}
Comments
Please log in or sign up to comment.