Components and supplies
Screw to suit standoffs
Pushbutton Switch, Momentary
Arduino UNO
Standoff 25mm
Resistor 220 ohm
Breadboard (generic)
Rubber feet
Dual colour LED
Shift Register- Serial to Parallel
Jumper wires (generic)
Resistor 100 ohm
Tools and machines
Laser cutter (generic)
Solder Wire, Lead Free
Soldering iron (generic)
Apps and platforms
Arduino IDE
Project description
Code
Tic Tac Toe and Lights Out Game Code
arduino
Main game code
1// #################################### 2// # # 3// # Tic Tac Toe & Lights Out Games # 4// # # 5// # for Arduino # 6// # # 7// # by Mark 2013 # 8// # # 9// # Details on Arduino Project Hub # 10// # # 11// #################################### 12 13// global constants 14const int player = 1; 15const int computer = 2; 16 17// global variables 18// variables for buttons 19// voltage for each button pressed, measured with multimeter, 10th value is minimum value for boundary setting 20float voltages[] = {4.92, 2.47, 1.65, 1.24, 0.99, 0.82, 0.70, 0.62, 0.55, 0.10}; 21float boundaries[9]; // boundary voltages for button detection 22 23int button; // last button pressed (0-8) 24 25// light variables 26int lights[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // 0 = off, 1 = red, 2 = green 27int flash[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // used for flashing winning line in tic tac toe game 28 29// game variables 30int gameSelected = 0; // 0 = none, 1 = tic tac toe, 2 = lights out 31 32// shift register variables 33int latchPin = 8; 34int clockPin = 12; 35int dataPin = 11; 36 37// binary LED values 38int byte1 = 0; 39int byte2 = 0; 40int byte3 = 0; 41 42void setup() { 43 // set pins for shift registers 44 pinMode(latchPin, OUTPUT); 45 pinMode(dataPin, OUTPUT); 46 pinMode(clockPin, OUTPUT); 47 48 // set boundaries for button voltages 49 for (int i = 0; i < 9; i++){ 50 boundaries[i] = voltages[i]-((voltages[i] - voltages[i + 1]) / 2.0); 51 } 52 53 // enable serial port 54 Serial.begin(9600); 55} 56 57void loop() { 58 button = getButtonPush(); 59 // menu selection 60 if (gameSelected == 0){ 61 displayMenu(); 62 if (button == 0 || button == 2 || button == 3 || button == 5 || button == 6 || button == 8){ 63 gameSelected = 1; 64 } 65 if (button == 1 || button == 4 || button == 7){ 66 gameSelected = 2; 67 } 68 } 69// game 1, tic tac toe 70 if (gameSelected == 1){ 71 playTickTackToe(); 72 } 73 74// game 2, lights out 75 if (gameSelected == 2){ 76 playLightsOut(); 77 } 78 refreshDisplay(); 79 delay(50); 80} 81 82int getButtonPush() { 83 int sensorValue; 84 float inputVoltage; 85 int pressed = -1; 86 87 // read input value and convert to voltage 88 sensorValue = analogRead(A0); 89 inputVoltage = sensorValue * (5.0 / 1023.0); 90 91 // convert to button number 92 if (inputVoltage > 0.1){ 93 for (int i = 8; i >= 0; i--){ 94 if (boundaries[i] < inputVoltage){ 95 pressed = i; 96 } 97 } 98 // wait until button is released before returning 99 while (inputVoltage > 0.1){ 100 sensorValue = analogRead(A0); 101 inputVoltage = sensorValue * (5.0 / 1023.0); 102 } 103 } 104 return pressed; 105} 106 107void displayMenu() { 108 // set led pattern for menu 109 lights[0] = 1; 110 lights[1] = 2; 111 lights[2] = 1; 112 lights[3] = 1; 113 lights[4] = 2; 114 lights[5] = 1; 115 lights[6] = 1; 116 lights[7] = 2; 117 lights[8] = 1; 118} 119 120void refreshDisplay() { 121 byte1 = 0; 122 byte2 = 0; 123 byte3 = 0; 124 if (lights[0] == 1){byte1 = byte1 ^ B00000001;} 125 if (lights[1] == 1){byte1 = byte1 ^ B00000010;} 126 if (lights[2] == 1){byte1 = byte1 ^ B00000100;} 127 if (lights[3] == 1){byte1 = byte1 ^ B00001000;} 128 if (lights[4] == 1){byte1 = byte1 ^ B00010000;} 129 if (lights[5] == 1){byte1 = byte1 ^ B00100000;} 130 if (lights[6] == 1){byte1 = byte1 ^ B01000000;} 131 if (lights[7] == 1){byte1 = byte1 ^ B10000000;} 132 if (lights[8] == 1){byte2 = byte2 ^ B00000001;} 133 134 if (lights[0] == 2){byte2 = byte2 ^ B00000010;} 135 if (lights[1] == 2){byte2 = byte2 ^ B00000100;} 136 if (lights[2] == 2){byte2 = byte2 ^ B00001000;} 137 if (lights[3] == 2){byte2 = byte2 ^ B00010000;} 138 if (lights[4] == 2){byte2 = byte2 ^ B00100000;} 139 if (lights[5] == 2){byte2 = byte2 ^ B01000000;} 140 if (lights[6] == 2){byte2 = byte2 ^ B10000000;} 141 if (lights[7] == 2){byte3 = byte3 ^ B00000001;} 142 if (lights[8] == 2){byte3 = byte3 ^ B00000010;} 143 144 setLEDs(); 145} 146 147void setLEDs(){ 148 digitalWrite(latchPin, LOW); 149 shiftOut(dataPin, clockPin, MSBFIRST, byte3); 150 shiftOut(dataPin, clockPin, MSBFIRST, byte2); 151 shiftOut(dataPin, clockPin, MSBFIRST, byte1); 152 digitalWrite(latchPin, HIGH); 153} 154 155void playTickTackToe() { 156 int gameState = 1; 157 clearBoard(); 158 while (gameState == 1) { 159 button = -1; 160 refreshDisplay(); 161 button = getButtonPush(); 162 if (lights[button] == 0) { 163 lights[button] = 1; 164 gameState = checkForWin(); 165 refreshDisplay(); 166 if (gameState == 1) { 167 delay(500); 168 computerMove(); 169 refreshDisplay(); 170 gameState = checkForWin(); 171 } 172 } 173 } 174 showWinner(gameState); 175 clearBoard(); 176 refreshDisplay(); 177 delay(2000); 178 gameState = 0; 179 gameSelected = 0; 180} 181 182void showWinner(int gameState) { 183 flash[0] = lights[0]; 184 flash[1] = lights[1]; 185 flash[2] = lights[2]; 186 flash[3] = lights[3]; 187 flash[4] = lights[4]; 188 flash[5] = lights[5]; 189 flash[6] = lights[6]; 190 flash[7] = lights[7]; 191 flash[8] = lights[8]; 192 if (lights[0] == player && lights[1] == player && lights[2] == player) { flash[0] = 0; flash[1] = 0; flash[2] = 0; } 193 if (lights[3] == player && lights[4] == player && lights[5] == player) { flash[3] = 0; flash[4] = 0; flash[5] = 0; } 194 if (lights[6] == player && lights[7] == player && lights[8] == player) { flash[6] = 0; flash[7] = 0; flash[8] = 0; } 195 if (lights[0] == player && lights[3] == player && lights[6] == player) { flash[0] = 0; flash[3] = 0; flash[6] = 0; } 196 if (lights[1] == player && lights[4] == player && lights[7] == player) { flash[1] = 0; flash[4] = 0; flash[7] = 0; } 197 if (lights[2] == player && lights[5] == player && lights[8] == player) { flash[2] = 0; flash[5] = 0; flash[8] = 0; } 198 if (lights[0] == player && lights[4] == player && lights[8] == player) { flash[0] = 0; flash[4] = 0; flash[8] = 0; } 199 if (lights[2] == player && lights[4] == player && lights[6] == player) { flash[2] = 0; flash[4] = 0; flash[6] = 0; } 200 if (lights[0] == computer && lights[1] == computer && lights[2] == computer) { flash[0] = 0; flash[1] = 0; flash[2] = 0; } 201 if (lights[3] == computer && lights[4] == computer && lights[5] == computer) { flash[3] = 0; flash[4] = 0; flash[5] = 0; } 202 if (lights[6] == computer && lights[7] == computer && lights[8] == computer) { flash[6] = 0; flash[7] = 0; flash[8] = 0; } 203 if (lights[0] == computer && lights[3] == computer && lights[6] == computer) { flash[0] = 0; flash[3] = 0; flash[6] = 0; } 204 if (lights[1] == computer && lights[4] == computer && lights[7] == computer) { flash[1] = 0; flash[4] = 0; flash[7] = 0; } 205 if (lights[2] == computer && lights[5] == computer && lights[8] == computer) { flash[2] = 0; flash[5] = 0; flash[8] = 0; } 206 if (lights[0] == computer && lights[4] == computer && lights[8] == computer) { flash[0] = 0; flash[4] = 0; flash[8] = 0; } 207 if (lights[2] == computer && lights[4] == computer && lights[6] == computer) { flash[2] = 0; flash[4] = 0; flash[6] = 0; } 208 swapLightsAndFlash(); 209 refreshDisplay(); 210 for (int i = 0; i < 20; i++) { 211 delay(200); 212 swapLightsAndFlash(); 213 refreshDisplay(); 214 } 215} 216 217void swapLightsAndFlash() { 218 int temp[] = {lights[0], lights[1], lights[2], lights[3], lights[4], lights[5], lights[6], lights[7], lights[8]}; 219 lights[0] = flash[0]; 220 lights[1] = flash[1]; 221 lights[2] = flash[2]; 222 lights[3] = flash[3]; 223 lights[4] = flash[4]; 224 lights[5] = flash[5]; 225 lights[6] = flash[6]; 226 lights[7] = flash[7]; 227 lights[8] = flash[8]; 228 flash[0] = temp[0]; 229 flash[1] = temp[1]; 230 flash[2] = temp[2]; 231 flash[3] = temp[3]; 232 flash[4] = temp[4]; 233 flash[5] = temp[5]; 234 flash[6] = temp[6]; 235 flash[7] = temp[7]; 236 flash[8] = temp[8]; 237} 238 239void computerMove() { 240 int bias[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 241 int bestMove = -1; 242 int topBias = 0; 243 // can computer win 244 bias[0] = bias[0] + getBiasWin(0, 1, 2); 245 bias[0] = bias[0] + getBiasWin(0, 4, 8); 246 bias[0] = bias[0] + getBiasWin(0, 3, 6); 247 bias[1] = bias[1] + getBiasWin(1, 0, 2); 248 bias[1] = bias[1] + getBiasWin(1, 4, 7); 249 bias[2] = bias[2] + getBiasWin(2, 0, 1); 250 bias[2] = bias[2] + getBiasWin(2, 4, 6); 251 bias[2] = bias[2] + getBiasWin(2, 5, 8); 252 bias[3] = bias[3] + getBiasWin(3, 0, 6); 253 bias[3] = bias[3] + getBiasWin(3, 4, 5); 254 bias[4] = bias[4] + getBiasWin(4, 0, 8); 255 bias[4] = bias[4] + getBiasWin(4, 1, 7); 256 bias[4] = bias[4] + getBiasWin(4, 2, 6); 257 bias[4] = bias[4] + getBiasWin(4, 3, 5); 258 bias[5] = bias[5] + getBiasWin(5, 2, 8); 259 bias[5] = bias[5] + getBiasWin(5, 3, 4); 260 bias[6] = bias[6] + getBiasWin(6, 0, 3); 261 bias[6] = bias[6] + getBiasWin(6, 2, 4); 262 bias[6] = bias[6] + getBiasWin(6, 7, 8); 263 bias[7] = bias[7] + getBiasWin(7, 1, 4); 264 bias[7] = bias[7] + getBiasWin(7, 6, 8); 265 bias[8] = bias[8] + getBiasWin(8, 0, 4); 266 bias[8] = bias[8] + getBiasWin(8, 2, 5); 267 bias[8] = bias[8] + getBiasWin(8, 6, 7); 268 // can computer stop the human from winning 269 bias[0] = bias[0] + getBiasStop(0, 1, 2); 270 bias[0] = bias[0] + getBiasStop(0, 4, 8); 271 bias[0] = bias[0] + getBiasStop(0, 3, 6); 272 bias[1] = bias[1] + getBiasStop(1, 0, 2); 273 bias[1] = bias[1] + getBiasStop(1, 4, 7); 274 bias[2] = bias[2] + getBiasStop(2, 0, 1); 275 bias[2] = bias[2] + getBiasStop(2, 4, 6); 276 bias[2] = bias[2] + getBiasStop(2, 5, 8); 277 bias[3] = bias[3] + getBiasStop(3, 0, 6); 278 bias[3] = bias[3] + getBiasStop(3, 4, 5); 279 bias[4] = bias[4] + getBiasStop(4, 0, 8); 280 bias[4] = bias[4] + getBiasStop(4, 1, 7); 281 bias[4] = bias[4] + getBiasStop(4, 2, 6); 282 bias[4] = bias[4] + getBiasStop(4, 3, 5); 283 bias[5] = bias[5] + getBiasStop(5, 2, 8); 284 bias[5] = bias[5] + getBiasStop(5, 3, 4); 285 bias[6] = bias[6] + getBiasStop(6, 0, 3); 286 bias[6] = bias[6] + getBiasStop(6, 2, 4); 287 bias[6] = bias[6] + getBiasStop(6, 7, 8); 288 bias[7] = bias[7] + getBiasStop(7, 1, 4); 289 bias[7] = bias[7] + getBiasStop(7, 6, 8); 290 bias[8] = bias[8] + getBiasStop(8, 0, 4); 291 bias[8] = bias[8] + getBiasStop(8, 2, 5); 292 bias[8] = bias[8] + getBiasStop(8, 6, 7); 293 // add a small random value to each possible move 294 for (int i = 0; i < 9; i++) { 295 if (lights[i] == 0) { 296 bias[i] = bias[i] + random(1, 5); 297 } 298 } 299 // get best move 300 for (int i = 0; i < 9; i++) { 301 if (bias[i] > topBias) { 302 topBias = bias[i]; 303 bestMove = i; 304 } 305 } 306 // make move 307 if (bestMove != -1) { 308 lights[bestMove] = computer; 309 } 310} 311 312int getBiasWin(int thisPosition, int checkPosition1, int checkPosition2) { 313 if (lights[thisPosition] == 0 && lights[checkPosition1] == computer && lights[checkPosition2] == computer) { 314 return 100; 315 } 316 else { 317 return 0; 318 } 319} 320 321int getBiasStop(int thisPosition, int checkPosition1, int checkPosition2) { 322 if (lights[thisPosition] == 0 && lights[checkPosition1] == player && lights[checkPosition2] == player) { 323 return 20; 324 } 325 else { 326 return 0; 327 } 328} 329 330int checkForWin() { 331 int winState = 1; 332 // check for player win 333 if (lights[0] == player && lights[1] == player && lights[2] == player) { winState = 11; } 334 if (lights[3] == player && lights[4] == player && lights[5] == player) { winState = 11; } 335 if (lights[6] == player && lights[7] == player && lights[8] == player) { winState = 11; } 336 if (lights[0] == player && lights[3] == player && lights[6] == player) { winState = 11; } 337 if (lights[1] == player && lights[4] == player && lights[7] == player) { winState = 11; } 338 if (lights[2] == player && lights[5] == player && lights[8] == player) { winState = 11; } 339 if (lights[0] == player && lights[4] == player && lights[8] == player) { winState = 11; } 340 if (lights[2] == player && lights[4] == player && lights[6] == player) { winState = 11; } 341 // check for computer win 342 if (lights[0] == computer && lights[1] == computer && lights[2] == computer) { winState = 12; } 343 if (lights[3] == computer && lights[4] == computer && lights[5] == computer) { winState = 12; } 344 if (lights[6] == computer && lights[7] == computer && lights[8] == computer) { winState = 12; } 345 if (lights[0] == computer && lights[3] == computer && lights[6] == computer) { winState = 12; } 346 if (lights[1] == computer && lights[4] == computer && lights[7] == computer) { winState = 12; } 347 if (lights[2] == computer && lights[5] == computer && lights[8] == computer) { winState = 12; } 348 if (lights[0] == computer && lights[4] == computer && lights[8] == computer) { winState = 12; } 349 if (lights[2] == computer && lights[4] == computer && lights[6] == computer) { winState = 12; } 350 // check for draw 351 int draw = 1; 352 for (int i = 0; i < 9; i++) { 353 if (lights[i] == 0) { 354 draw = 0; 355 } 356 } 357 if (draw == 1) { 358 winState = 13; 359 } 360 return winState; 361} 362 363void clearBoard() { 364 for (int i = 0; i < 9; i++) { 365 lights[i] = 0; 366 } 367} 368 369void playLightsOut() { 370 int gameState = 1; 371 int lit = 0; 372 resetBoard(); 373 while (gameState == 1) { 374 button = -1; 375 lit = 0; 376 refreshDisplay(); 377 button = getButtonPush(); 378 if (lights[button] == 1) { 379 switch (button) { 380 case 0: 381 lights[0] = abs(lights[0] - 1); 382 lights[1] = abs(lights[1] - 1); 383 lights[3] = abs(lights[3] - 1); 384 lights[4] = abs(lights[4] - 1); 385 break; 386 case 1: 387 lights[0] = abs(lights[0] - 1); 388 lights[1] = abs(lights[1] - 1); 389 lights[2] = abs(lights[2] - 1); 390 break; 391 case 2: 392 lights[1] = abs(lights[1] - 1); 393 lights[2] = abs(lights[2] - 1); 394 lights[4] = abs(lights[4] - 1); 395 lights[5] = abs(lights[5] - 1); 396 break; 397 case 3: 398 lights[0] = abs(lights[0] - 1); 399 lights[3] = abs(lights[3] - 1); 400 lights[6] = abs(lights[6] - 1); 401 break; 402 case 4: 403 lights[1] = abs(lights[1] - 1); 404 lights[3] = abs(lights[3] - 1); 405 lights[4] = abs(lights[4] - 1); 406 lights[5] = abs(lights[5] - 1); 407 lights[7] = abs(lights[7] - 1); 408 break; 409 case 5: 410 lights[2] = abs(lights[2] - 1); 411 lights[5] = abs(lights[5] - 1); 412 lights[8] = abs(lights[8] - 1); 413 break; 414 case 6: 415 lights[3] = abs(lights[3] - 1); 416 lights[4] = abs(lights[4] - 1); 417 lights[6] = abs(lights[6] - 1); 418 lights[7] = abs(lights[7] - 1); 419 break; 420 case 7: 421 lights[6] = abs(lights[6] - 1); 422 lights[7] = abs(lights[7] - 1); 423 lights[8] = abs(lights[8] - 1); 424 break; 425 case 8: 426 lights[4] = abs(lights[4] - 1); 427 lights[5] = abs(lights[5] - 1); 428 lights[7] = abs(lights[7] - 1); 429 lights[8] = abs(lights[8] - 1); 430 } 431 } 432 for (int i = 0; i < 9; i++) { 433 if (lights[i] == 1) { 434 lit++; 435 } 436 } 437 if (lit == 0) { 438 gameState = 0; 439 gameSelected = 0; 440 delay(200); 441 victoryDisplay(); 442 } 443 delay(50); 444 } 445} 446 447void resetBoard() { 448 int lit = 0; 449 randomSeed(analogRead(5)); 450 while (lit < 3 || lit > 5) { 451 lit = 0; 452 for (int i = 0; i < 9; i++) { 453 lights[i] = random(2); 454 if (lights[i] == 1) { 455 lit++; 456 } 457 } 458 } 459} 460 461void victoryDisplay() { 462 victoryItem(0, 0, 0, 0, 0, 0, 0, 0, 0); 463 for (int i = 0; i < 7; i++) { 464 victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0); 465 victoryItem(1, 0, 0, 0, 1, 0, 0, 0, 1); 466 victoryItem(0, 0, 0, 1, 1, 1, 0, 0, 0); 467 victoryItem(0, 0, 1, 0, 1, 0, 1, 0, 0); 468 } 469 for (int i = 0; i < 4; i++) { 470 victoryItem(2, 2, 2, 0, 0, 0, 0, 0, 0); 471 victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0); 472 victoryItem(0, 0, 0, 0, 0, 0, 2, 2, 2); 473 victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0); 474 } 475 for (int i = 0; i < 4; i++) { 476 victoryItem(1, 0, 0, 1, 0, 0, 1, 0, 0); 477 victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0); 478 victoryItem(0, 0, 1, 0, 0, 1, 0, 0, 1); 479 victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0); 480 } 481 for (int i = 0; i < 7; i++) { 482 victoryItem(2, 0, 0, 0, 2, 0, 0, 0, 2); 483 victoryItem(0, 2, 0, 0, 2, 0, 0, 2, 0); 484 victoryItem(0, 0, 2, 0, 2, 0, 2, 0, 0); 485 victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0); 486 } 487} 488 489void victoryItem(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8) { 490 lights[0] = i0; 491 lights[1] = i1; 492 lights[2] = i2; 493 lights[3] = i3; 494 lights[4] = i4; 495 lights[5] = i5; 496 lights[6] = i6; 497 lights[7] = i7; 498 lights[8] = i8; 499 refreshDisplay(); 500 delay(100); 501} 502
Buttons
arduino
Used to help set up the buttons array in the main program.
1/* 2 Tic Tac Toe Buttons 3 Reads analogue input and outputs it to the serial monitor. 4*/ 5 6float voltages[] = {4.92, 2.47, 1.65, 1.24, 0.99, 0.82, 0.70, 0.62, 0.55, 0.10}; // standard voltage for each button plus minimum value at the end 7float boundaries[9]; // boundary voltages for button detection 8 9int button; // number (0-8) of button pressed 10 11void setup() { 12 // set boundaries for button voltages 13 for (int i = 0; i < 9; i++){ 14 boundaries[i] = voltages[i]-((voltages[i] - voltages[i + 1]) / 2.0); 15 } 16 // enable serial port for debug monitoring 17 Serial.begin(9600); 18} 19 20void loop() { 21 button = getButton(); 22 delay(500); 23} 24 25int getButton() { 26 int sensorValue; 27 float inputVoltage; 28 button = -1; 29 30 // read input value and convert to voltage 31 sensorValue = analogRead(A0); 32 inputVoltage = sensorValue * (5.0 / 1023.0); 33 34 // convert to button number 35 if (inputVoltage > 0.1){ 36 for (int i = 8; i >= 0; i--){ 37 if (boundaries[i] < inputVoltage){ 38 button = i; 39 } 40 } 41 } 42 43// if (button > -1){ 44 Serial.print(inputVoltage); 45 Serial.print("v = button "); 46 Serial.println(button); 47// } 48 49 return button; 50} 51 52
Tic Tac Toe and Lights Out Game Code
arduino
Main game code
1// #################################### 2// # # 3// # Tic Tac Toe & Lights Out Games # 4// # # 5// # for Arduino # 6// # # 7// # by Mark 2013 # 8// # # 9// # Details on Arduino Project Hub # 10// # # 11// #################################### 12 13// global constants 14const int player = 1; 15const int computer = 2; 16 17// global variables 18// variables for buttons 19// voltage for each button pressed, measured with multimeter, 10th value is minimum value for boundary setting 20float voltages[] = {4.92, 2.47, 1.65, 1.24, 0.99, 0.82, 0.70, 0.62, 0.55, 0.10}; 21float boundaries[9]; // boundary voltages for button detection 22 23int button; // last button pressed (0-8) 24 25// light variables 26int lights[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // 0 = off, 1 = red, 2 = green 27int flash[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // used for flashing winning line in tic tac toe game 28 29// game variables 30int gameSelected = 0; // 0 = none, 1 = tic tac toe, 2 = lights out 31 32// shift register variables 33int latchPin = 8; 34int clockPin = 12; 35int dataPin = 11; 36 37// binary LED values 38int byte1 = 0; 39int byte2 = 0; 40int byte3 = 0; 41 42void setup() { 43 // set pins for shift registers 44 pinMode(latchPin, OUTPUT); 45 pinMode(dataPin, OUTPUT); 46 pinMode(clockPin, OUTPUT); 47 48 // set boundaries for button voltages 49 for (int i = 0; i < 9; i++){ 50 boundaries[i] = voltages[i]-((voltages[i] - voltages[i + 1]) / 2.0); 51 } 52 53 // enable serial port 54 Serial.begin(9600); 55} 56 57void loop() { 58 button = getButtonPush(); 59 // menu selection 60 if (gameSelected == 0){ 61 displayMenu(); 62 if (button == 0 || button == 2 || button == 3 || button == 5 || button == 6 || button == 8){ 63 gameSelected = 1; 64 } 65 if (button == 1 || button == 4 || button == 7){ 66 gameSelected = 2; 67 } 68 } 69// game 1, tic tac toe 70 if (gameSelected == 1){ 71 playTickTackToe(); 72 } 73 74// game 2, lights out 75 if (gameSelected == 2){ 76 playLightsOut(); 77 } 78 refreshDisplay(); 79 delay(50); 80} 81 82int getButtonPush() { 83 int sensorValue; 84 float inputVoltage; 85 int pressed = -1; 86 87 // read input value and convert to voltage 88 sensorValue = analogRead(A0); 89 inputVoltage = sensorValue * (5.0 / 1023.0); 90 91 // convert to button number 92 if (inputVoltage > 0.1){ 93 for (int i = 8; i >= 0; i--){ 94 if (boundaries[i] < inputVoltage){ 95 pressed = i; 96 } 97 } 98 // wait until button is released before returning 99 while (inputVoltage > 0.1){ 100 sensorValue = analogRead(A0); 101 inputVoltage = sensorValue * (5.0 / 1023.0); 102 } 103 } 104 return pressed; 105} 106 107void displayMenu() { 108 // set led pattern for menu 109 lights[0] = 1; 110 lights[1] = 2; 111 lights[2] = 1; 112 lights[3] = 1; 113 lights[4] = 2; 114 lights[5] = 1; 115 lights[6] = 1; 116 lights[7] = 2; 117 lights[8] = 1; 118} 119 120void refreshDisplay() { 121 byte1 = 0; 122 byte2 = 0; 123 byte3 = 0; 124 if (lights[0] == 1){byte1 = byte1 ^ B00000001;} 125 if (lights[1] == 1){byte1 = byte1 ^ B00000010;} 126 if (lights[2] == 1){byte1 = byte1 ^ B00000100;} 127 if (lights[3] == 1){byte1 = byte1 ^ B00001000;} 128 if (lights[4] == 1){byte1 = byte1 ^ B00010000;} 129 if (lights[5] == 1){byte1 = byte1 ^ B00100000;} 130 if (lights[6] == 1){byte1 = byte1 ^ B01000000;} 131 if (lights[7] == 1){byte1 = byte1 ^ B10000000;} 132 if (lights[8] == 1){byte2 = byte2 ^ B00000001;} 133 134 if (lights[0] == 2){byte2 = byte2 ^ B00000010;} 135 if (lights[1] == 2){byte2 = byte2 ^ B00000100;} 136 if (lights[2] == 2){byte2 = byte2 ^ B00001000;} 137 if (lights[3] == 2){byte2 = byte2 ^ B00010000;} 138 if (lights[4] == 2){byte2 = byte2 ^ B00100000;} 139 if (lights[5] == 2){byte2 = byte2 ^ B01000000;} 140 if (lights[6] == 2){byte2 = byte2 ^ B10000000;} 141 if (lights[7] == 2){byte3 = byte3 ^ B00000001;} 142 if (lights[8] == 2){byte3 = byte3 ^ B00000010;} 143 144 setLEDs(); 145} 146 147void setLEDs(){ 148 digitalWrite(latchPin, LOW); 149 shiftOut(dataPin, clockPin, MSBFIRST, byte3); 150 shiftOut(dataPin, clockPin, MSBFIRST, byte2); 151 shiftOut(dataPin, clockPin, MSBFIRST, byte1); 152 digitalWrite(latchPin, HIGH); 153} 154 155void playTickTackToe() { 156 int gameState = 1; 157 clearBoard(); 158 while (gameState == 1) { 159 button = -1; 160 refreshDisplay(); 161 button = getButtonPush(); 162 if (lights[button] == 0) { 163 lights[button] = 1; 164 gameState = checkForWin(); 165 refreshDisplay(); 166 if (gameState == 1) { 167 delay(500); 168 computerMove(); 169 refreshDisplay(); 170 gameState = checkForWin(); 171 } 172 } 173 } 174 showWinner(gameState); 175 clearBoard(); 176 refreshDisplay(); 177 delay(2000); 178 gameState = 0; 179 gameSelected = 0; 180} 181 182void showWinner(int gameState) { 183 flash[0] = lights[0]; 184 flash[1] = lights[1]; 185 flash[2] = lights[2]; 186 flash[3] = lights[3]; 187 flash[4] = lights[4]; 188 flash[5] = lights[5]; 189 flash[6] = lights[6]; 190 flash[7] = lights[7]; 191 flash[8] = lights[8]; 192 if (lights[0] == player && lights[1] == player && lights[2] == player) { flash[0] = 0; flash[1] = 0; flash[2] = 0; } 193 if (lights[3] == player && lights[4] == player && lights[5] == player) { flash[3] = 0; flash[4] = 0; flash[5] = 0; } 194 if (lights[6] == player && lights[7] == player && lights[8] == player) { flash[6] = 0; flash[7] = 0; flash[8] = 0; } 195 if (lights[0] == player && lights[3] == player && lights[6] == player) { flash[0] = 0; flash[3] = 0; flash[6] = 0; } 196 if (lights[1] == player && lights[4] == player && lights[7] == player) { flash[1] = 0; flash[4] = 0; flash[7] = 0; } 197 if (lights[2] == player && lights[5] == player && lights[8] == player) { flash[2] = 0; flash[5] = 0; flash[8] = 0; } 198 if (lights[0] == player && lights[4] == player && lights[8] == player) { flash[0] = 0; flash[4] = 0; flash[8] = 0; } 199 if (lights[2] == player && lights[4] == player && lights[6] == player) { flash[2] = 0; flash[4] = 0; flash[6] = 0; } 200 if (lights[0] == computer && lights[1] == computer && lights[2] == computer) { flash[0] = 0; flash[1] = 0; flash[2] = 0; } 201 if (lights[3] == computer && lights[4] == computer && lights[5] == computer) { flash[3] = 0; flash[4] = 0; flash[5] = 0; } 202 if (lights[6] == computer && lights[7] == computer && lights[8] == computer) { flash[6] = 0; flash[7] = 0; flash[8] = 0; } 203 if (lights[0] == computer && lights[3] == computer && lights[6] == computer) { flash[0] = 0; flash[3] = 0; flash[6] = 0; } 204 if (lights[1] == computer && lights[4] == computer && lights[7] == computer) { flash[1] = 0; flash[4] = 0; flash[7] = 0; } 205 if (lights[2] == computer && lights[5] == computer && lights[8] == computer) { flash[2] = 0; flash[5] = 0; flash[8] = 0; } 206 if (lights[0] == computer && lights[4] == computer && lights[8] == computer) { flash[0] = 0; flash[4] = 0; flash[8] = 0; } 207 if (lights[2] == computer && lights[4] == computer && lights[6] == computer) { flash[2] = 0; flash[4] = 0; flash[6] = 0; } 208 swapLightsAndFlash(); 209 refreshDisplay(); 210 for (int i = 0; i < 20; i++) { 211 delay(200); 212 swapLightsAndFlash(); 213 refreshDisplay(); 214 } 215} 216 217void swapLightsAndFlash() { 218 int temp[] = {lights[0], lights[1], lights[2], lights[3], lights[4], lights[5], lights[6], lights[7], lights[8]}; 219 lights[0] = flash[0]; 220 lights[1] = flash[1]; 221 lights[2] = flash[2]; 222 lights[3] = flash[3]; 223 lights[4] = flash[4]; 224 lights[5] = flash[5]; 225 lights[6] = flash[6]; 226 lights[7] = flash[7]; 227 lights[8] = flash[8]; 228 flash[0] = temp[0]; 229 flash[1] = temp[1]; 230 flash[2] = temp[2]; 231 flash[3] = temp[3]; 232 flash[4] = temp[4]; 233 flash[5] = temp[5]; 234 flash[6] = temp[6]; 235 flash[7] = temp[7]; 236 flash[8] = temp[8]; 237} 238 239void computerMove() { 240 int bias[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 241 int bestMove = -1; 242 int topBias = 0; 243 // can computer win 244 bias[0] = bias[0] + getBiasWin(0, 1, 2); 245 bias[0] = bias[0] + getBiasWin(0, 4, 8); 246 bias[0] = bias[0] + getBiasWin(0, 3, 6); 247 bias[1] = bias[1] + getBiasWin(1, 0, 2); 248 bias[1] = bias[1] + getBiasWin(1, 4, 7); 249 bias[2] = bias[2] + getBiasWin(2, 0, 1); 250 bias[2] = bias[2] + getBiasWin(2, 4, 6); 251 bias[2] = bias[2] + getBiasWin(2, 5, 8); 252 bias[3] = bias[3] + getBiasWin(3, 0, 6); 253 bias[3] = bias[3] + getBiasWin(3, 4, 5); 254 bias[4] = bias[4] + getBiasWin(4, 0, 8); 255 bias[4] = bias[4] + getBiasWin(4, 1, 7); 256 bias[4] = bias[4] + getBiasWin(4, 2, 6); 257 bias[4] = bias[4] + getBiasWin(4, 3, 5); 258 bias[5] = bias[5] + getBiasWin(5, 2, 8); 259 bias[5] = bias[5] + getBiasWin(5, 3, 4); 260 bias[6] = bias[6] + getBiasWin(6, 0, 3); 261 bias[6] = bias[6] + getBiasWin(6, 2, 4); 262 bias[6] = bias[6] + getBiasWin(6, 7, 8); 263 bias[7] = bias[7] + getBiasWin(7, 1, 4); 264 bias[7] = bias[7] + getBiasWin(7, 6, 8); 265 bias[8] = bias[8] + getBiasWin(8, 0, 4); 266 bias[8] = bias[8] + getBiasWin(8, 2, 5); 267 bias[8] = bias[8] + getBiasWin(8, 6, 7); 268 // can computer stop the human from winning 269 bias[0] = bias[0] + getBiasStop(0, 1, 2); 270 bias[0] = bias[0] + getBiasStop(0, 4, 8); 271 bias[0] = bias[0] + getBiasStop(0, 3, 6); 272 bias[1] = bias[1] + getBiasStop(1, 0, 2); 273 bias[1] = bias[1] + getBiasStop(1, 4, 7); 274 bias[2] = bias[2] + getBiasStop(2, 0, 1); 275 bias[2] = bias[2] + getBiasStop(2, 4, 6); 276 bias[2] = bias[2] + getBiasStop(2, 5, 8); 277 bias[3] = bias[3] + getBiasStop(3, 0, 6); 278 bias[3] = bias[3] + getBiasStop(3, 4, 5); 279 bias[4] = bias[4] + getBiasStop(4, 0, 8); 280 bias[4] = bias[4] + getBiasStop(4, 1, 7); 281 bias[4] = bias[4] + getBiasStop(4, 2, 6); 282 bias[4] = bias[4] + getBiasStop(4, 3, 5); 283 bias[5] = bias[5] + getBiasStop(5, 2, 8); 284 bias[5] = bias[5] + getBiasStop(5, 3, 4); 285 bias[6] = bias[6] + getBiasStop(6, 0, 3); 286 bias[6] = bias[6] + getBiasStop(6, 2, 4); 287 bias[6] = bias[6] + getBiasStop(6, 7, 8); 288 bias[7] = bias[7] + getBiasStop(7, 1, 4); 289 bias[7] = bias[7] + getBiasStop(7, 6, 8); 290 bias[8] = bias[8] + getBiasStop(8, 0, 4); 291 bias[8] = bias[8] + getBiasStop(8, 2, 5); 292 bias[8] = bias[8] + getBiasStop(8, 6, 7); 293 // add a small random value to each possible move 294 for (int i = 0; i < 9; i++) { 295 if (lights[i] == 0) { 296 bias[i] = bias[i] + random(1, 5); 297 } 298 } 299 // get best move 300 for (int i = 0; i < 9; i++) { 301 if (bias[i] > topBias) { 302 topBias = bias[i]; 303 bestMove = i; 304 } 305 } 306 // make move 307 if (bestMove != -1) { 308 lights[bestMove] = computer; 309 } 310} 311 312int getBiasWin(int thisPosition, int checkPosition1, int checkPosition2) { 313 if (lights[thisPosition] == 0 && lights[checkPosition1] == computer && lights[checkPosition2] == computer) { 314 return 100; 315 } 316 else { 317 return 0; 318 } 319} 320 321int getBiasStop(int thisPosition, int checkPosition1, int checkPosition2) { 322 if (lights[thisPosition] == 0 && lights[checkPosition1] == player && lights[checkPosition2] == player) { 323 return 20; 324 } 325 else { 326 return 0; 327 } 328} 329 330int checkForWin() { 331 int winState = 1; 332 // check for player win 333 if (lights[0] == player && lights[1] == player && lights[2] == player) { winState = 11; } 334 if (lights[3] == player && lights[4] == player && lights[5] == player) { winState = 11; } 335 if (lights[6] == player && lights[7] == player && lights[8] == player) { winState = 11; } 336 if (lights[0] == player && lights[3] == player && lights[6] == player) { winState = 11; } 337 if (lights[1] == player && lights[4] == player && lights[7] == player) { winState = 11; } 338 if (lights[2] == player && lights[5] == player && lights[8] == player) { winState = 11; } 339 if (lights[0] == player && lights[4] == player && lights[8] == player) { winState = 11; } 340 if (lights[2] == player && lights[4] == player && lights[6] == player) { winState = 11; } 341 // check for computer win 342 if (lights[0] == computer && lights[1] == computer && lights[2] == computer) { winState = 12; } 343 if (lights[3] == computer && lights[4] == computer && lights[5] == computer) { winState = 12; } 344 if (lights[6] == computer && lights[7] == computer && lights[8] == computer) { winState = 12; } 345 if (lights[0] == computer && lights[3] == computer && lights[6] == computer) { winState = 12; } 346 if (lights[1] == computer && lights[4] == computer && lights[7] == computer) { winState = 12; } 347 if (lights[2] == computer && lights[5] == computer && lights[8] == computer) { winState = 12; } 348 if (lights[0] == computer && lights[4] == computer && lights[8] == computer) { winState = 12; } 349 if (lights[2] == computer && lights[4] == computer && lights[6] == computer) { winState = 12; } 350 // check for draw 351 int draw = 1; 352 for (int i = 0; i < 9; i++) { 353 if (lights[i] == 0) { 354 draw = 0; 355 } 356 } 357 if (draw == 1) { 358 winState = 13; 359 } 360 return winState; 361} 362 363void clearBoard() { 364 for (int i = 0; i < 9; i++) { 365 lights[i] = 0; 366 } 367} 368 369void playLightsOut() { 370 int gameState = 1; 371 int lit = 0; 372 resetBoard(); 373 while (gameState == 1) { 374 button = -1; 375 lit = 0; 376 refreshDisplay(); 377 button = getButtonPush(); 378 if (lights[button] == 1) { 379 switch (button) { 380 case 0: 381 lights[0] = abs(lights[0] - 1); 382 lights[1] = abs(lights[1] - 1); 383 lights[3] = abs(lights[3] - 1); 384 lights[4] = abs(lights[4] - 1); 385 break; 386 case 1: 387 lights[0] = abs(lights[0] - 1); 388 lights[1] = abs(lights[1] - 1); 389 lights[2] = abs(lights[2] - 1); 390 break; 391 case 2: 392 lights[1] = abs(lights[1] - 1); 393 lights[2] = abs(lights[2] - 1); 394 lights[4] = abs(lights[4] - 1); 395 lights[5] = abs(lights[5] - 1); 396 break; 397 case 3: 398 lights[0] = abs(lights[0] - 1); 399 lights[3] = abs(lights[3] - 1); 400 lights[6] = abs(lights[6] - 1); 401 break; 402 case 4: 403 lights[1] = abs(lights[1] - 1); 404 lights[3] = abs(lights[3] - 1); 405 lights[4] = abs(lights[4] - 1); 406 lights[5] = abs(lights[5] - 1); 407 lights[7] = abs(lights[7] - 1); 408 break; 409 case 5: 410 lights[2] = abs(lights[2] - 1); 411 lights[5] = abs(lights[5] - 1); 412 lights[8] = abs(lights[8] - 1); 413 break; 414 case 6: 415 lights[3] = abs(lights[3] - 1); 416 lights[4] = abs(lights[4] - 1); 417 lights[6] = abs(lights[6] - 1); 418 lights[7] = abs(lights[7] - 1); 419 break; 420 case 7: 421 lights[6] = abs(lights[6] - 1); 422 lights[7] = abs(lights[7] - 1); 423 lights[8] = abs(lights[8] - 1); 424 break; 425 case 8: 426 lights[4] = abs(lights[4] - 1); 427 lights[5] = abs(lights[5] - 1); 428 lights[7] = abs(lights[7] - 1); 429 lights[8] = abs(lights[8] - 1); 430 } 431 } 432 for (int i = 0; i < 9; i++) { 433 if (lights[i] == 1) { 434 lit++; 435 } 436 } 437 if (lit == 0) { 438 gameState = 0; 439 gameSelected = 0; 440 delay(200); 441 victoryDisplay(); 442 } 443 delay(50); 444 } 445} 446 447void resetBoard() { 448 int lit = 0; 449 randomSeed(analogRead(5)); 450 while (lit < 3 || lit > 5) { 451 lit = 0; 452 for (int i = 0; i < 9; i++) { 453 lights[i] = random(2); 454 if (lights[i] == 1) { 455 lit++; 456 } 457 } 458 } 459} 460 461void victoryDisplay() { 462 victoryItem(0, 0, 0, 0, 0, 0, 0, 0, 0); 463 for (int i = 0; i < 7; i++) { 464 victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0); 465 victoryItem(1, 0, 0, 0, 1, 0, 0, 0, 1); 466 victoryItem(0, 0, 0, 1, 1, 1, 0, 0, 0); 467 victoryItem(0, 0, 1, 0, 1, 0, 1, 0, 0); 468 } 469 for (int i = 0; i < 4; i++) { 470 victoryItem(2, 2, 2, 0, 0, 0, 0, 0, 0); 471 victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0); 472 victoryItem(0, 0, 0, 0, 0, 0, 2, 2, 2); 473 victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0); 474 } 475 for (int i = 0; i < 4; i++) { 476 victoryItem(1, 0, 0, 1, 0, 0, 1, 0, 0); 477 victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0); 478 victoryItem(0, 0, 1, 0, 0, 1, 0, 0, 1); 479 victoryItem(0, 1, 0, 0, 1, 0, 0, 1, 0); 480 } 481 for (int i = 0; i < 7; i++) { 482 victoryItem(2, 0, 0, 0, 2, 0, 0, 0, 2); 483 victoryItem(0, 2, 0, 0, 2, 0, 0, 2, 0); 484 victoryItem(0, 0, 2, 0, 2, 0, 2, 0, 0); 485 victoryItem(0, 0, 0, 2, 2, 2, 0, 0, 0); 486 } 487} 488 489void victoryItem(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8) { 490 lights[0] = i0; 491 lights[1] = i1; 492 lights[2] = i2; 493 lights[3] = i3; 494 lights[4] = i4; 495 lights[5] = i5; 496 lights[6] = i6; 497 lights[7] = i7; 498 lights[8] = i8; 499 refreshDisplay(); 500 delay(100); 501} 502
Buttons
arduino
Used to help set up the buttons array in the main program.
1/* 2 Tic Tac Toe Buttons 3 Reads analogue input and outputs it to the serial monitor. 4*/ 5 6float voltages[] = {4.92, 2.47, 1.65, 1.24, 0.99, 0.82, 0.70, 0.62, 0.55, 0.10}; // standard voltage for each button plus minimum value at the end 7float boundaries[9]; // boundary voltages for button detection 8 9int button; // number (0-8) of button pressed 10 11void setup() { 12 // set boundaries for button voltages 13 for (int i = 0; i < 9; i++){ 14 boundaries[i] = voltages[i]-((voltages[i] - voltages[i + 1]) / 2.0); 15 } 16 // enable serial port for debug monitoring 17 Serial.begin(9600); 18} 19 20void loop() { 21 button = getButton(); 22 delay(500); 23} 24 25int getButton() { 26 int sensorValue; 27 float inputVoltage; 28 button = -1; 29 30 // read input value and convert to voltage 31 sensorValue = analogRead(A0); 32 inputVoltage = sensorValue * (5.0 / 1023.0); 33 34 // convert to button number 35 if (inputVoltage > 0.1){ 36 for (int i = 8; i >= 0; i--){ 37 if (boundaries[i] < inputVoltage){ 38 button = i; 39 } 40 } 41 } 42 43// if (button > -1){ 44 Serial.print(inputVoltage); 45 Serial.print("v = button "); 46 Serial.println(button); 47// } 48 49 return button; 50} 51 52
Downloadable files
Circuit diagram
Circuit diagram
Documentation
Baseplate
DXF file of the baseplate, laser or hand cut from 2mm material.
Baseplate
Mounting plate
Plate for mounting the swithes and LEDs into, laser or hand cut from 2mm material.
Mounting plate
Mounting plate
Plate for mounting the swithes and LEDs into, laser or hand cut from 2mm material.
Mounting plate
Baseplate
DXF file of the baseplate, laser or hand cut from 2mm material.
Baseplate
Comments
Only logged in users can leave comments
markbennettuk
0 Followers
•0 Projects
Table of contents
Intro
3
0