Hi friends ,
Please, I need some help. I don´t have much experience with Arduino (in this case - Uno). I built a game based in W2812B adressable LED by Robert Polzer - 3x3 Games. It is a very nice tic tac toe game. It is possible play just the game - human x computer. I´d like to include in this game (code) also a second option : Human x Human. Thanks in advance.
#include <FastLED.h>
#include <Keypad.h>
// Definitions
#define DATA_PIN 2 // Data pin in Arduino
#define NUM_LEDS 9 // Set number of LEDs
#define BRIGHTNESS 255 // Ribbon Brightness (0-255)
const byte ROWS = 3; // three lines
const byte COLS = 3; // three columns
byte rowPins[ROWS] = { 9, 8, 7 }; // Connect the COL0, COL1, and COL2 keyboard to these Arduino pins.
byte colPins[COLS] = { 12, 11, 10 };
CRGB leds[NUM_LEDS]; // Array with RGB color values of individual LEDs
int field[NUM_LEDS]; // Matrix with hue values of individual LEDs (-1 = off, -2 = white)
byte key = 0; // Key pressed
#define SPEED_V 1 // Victory Screen Speed
byte keys[ROWS][COLS] = {
{1,2,3},
{4,5,6},
{7,8,9},
};
// Create Keyboard
Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//******************
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
playVictory();
//******************
void loop() {
playTicTacToe();
}
//******************
// TIC TAC TOE GAME
//******************
void playTicTacToe() {
//Sprachausgabe "TicTacToe"
int player = 2; // START : 1 = HUMAN - 2 = COMPUTER
do { // Loop as long as you want to continue
clearField(); // Delete display
showField();
int board[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // create empty playing field
for(int turn=0; turn < 9 && win(board) == 0; ++turn) { // maximum 9 moves, as long as nobody has won yet
if((turn + player)%2 == 0) { // Computer is on the train
if(turn != 0) { // not the first move -> calculate
computerMove(board);
}
else { // first move -> random field
randomSeed(millis());
board[random(0,9)] = 1;
}
}
else { // Player is on the move
drawboard(board);
playerMove(board);
}
}
//----------------
switch(win(board)) { // who won?
case 0: // draw
drawboard(board);
delay(3000);
break;
case 1: // Computer won
showWinner(board);
delay(3000);
break;
case -1: // Player has won
playVictory();
showWinner(board);
delay(3000);
break;
}
player = abs(player - 3); // change of the first player
}
while (playAgain() == true); // Once again ?
}
//**************
// COMPUTER MOVE
//**************
void computerMove(int board[])
{
int moveval=-1;
int score=-2;
int i;
for(i=0;i<9;++i)
{
if(board[i]==0)
{
board[i]=1;
int tempScore=-minimax(board,-1);
board[i]=0;
if(tempScore>score)
{
score=tempScore;
moveval=i; // The field is assigned to the computer.
}
}
}
// returns a score based on the minimax tree on a given node.
board[moveval]=1;
}
//***********
// HUMAN MOVE
//***********
void playerMove(int board[]) {
int moveval=0,flag=0;
while (moveval == 0) { // wait at the touch of a button
moveval = kpd.getKey();
}
moveval--; // map buttons 1-9 to 0-8
if(board[moveval]== 1 || board[moveval]== -1)
{
playerMove(board); // Field already busy
}
else if(board[moveval]==0)
{
board[moveval]= -1; // The field is assigned to the players.
}
drawboard(board);
}
//***********
// WIN
//***********
int win(int board[]) {
// Definition of profit situations
int wins[][8] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
for(int i=0;i<8;++i) {
if(board[wins[i][0]] != 0 && board[wins[i][0]] == board[wins[i][1]] && board[wins[i][0]] == board[wins[i][2]])
return board[wins[i][2]]; // one player has gained feedback, otherwise "0"
}
return 0;
}
//-----------------
int minimax(int board[],int player) {
int winner=win(board);
if(winner!=0)
return winner*player;
int moveval=-1;
int score=-2; // Lost moves are preferred to no moves.
for(int i=0;i<9;++i)
{
if(board[i]==0)
{
board[i]=player; // Experience the change
int thisScore=-minimax(board,player*-1);
if(thisScore>score)
{
score=thisScore;
moveval=i;
} // Choose the worst for the opponent
board[i]=0; // Reset card after attempt
}
}
if(moveval==-1) return 0;
return score;
}
//************
// Draw Board
//************
void drawboard(int board[]) {
clearField();
for (int i=0; i < NUM_LEDS; i++) {
switch(board[i])
{
case 0:
field[i] = -1; // the empty field is black
break;
case -1:
field[i] = 160; // BLUE - PLAYER
break;
case 1:
field[i] = 0; // RED - COMPUTER
break;
}
}
showField();
}
//************
// Show Winner
//************
void showWinner(int board[]) {
clearField();
int wins[][8] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
for(int i=0;i<8;++i) { // consult all 8 profit situations
if(board[wins[i][0]] != 0 && board[wins[i][0]] == board[wins[i][1]] && board[wins[i][0]] == board[wins[i][2]]) {
for(int j=0;j<3;j++) {
switch(board[wins[i][j]]) {
case -1:
field[wins[i][j]] = 160;
break;
case 1:
field[wins[i][j]] = 0;
break;
}
}
showField();
break;
}
}
}
// ********
// Clear Field
//*********
void clearField() {
for (int i=0; i < NUM_LEDS; i++) {
field[i] = -1;
}
}
//**********
// Show Field
//**********
// Output all fields on LED display
void showField() {
// Assign field color to individual LEDs
for (int i=0; i < NUM_LEDS; i++) {
if (field[i] >= 0) {
leds[i] = CHSV(field[i], 255, BRIGHTNESS); // Tint "color" when active
}
else
{
if (field[i] == -1) {
leds[i] = CRGB::Black; // black if -1
}
else
{
leds[i] = CRGB::White; //
}
}
}
FastLED.show(); // activate the LEDs
}
//*************
// Dimmout Display
//*************
void dimmoutDisplay() {
for (int hell=255; hell >= 0; hell--) {
for (int i=0; i < NUM_LEDS; i++) {
if (field[i] >= 0) {
leds[i] = CHSV(field[i], 255, hell); // Tint "color" when active
}
else {
if (field[i] == -1) {
leds[i] = CRGB::Black; // black if -1
}
else {
leds[i] = CHSV(0, 0, hell); //
}
}
}
FastLED.show(); // activate the LEDs
delay(5);
}
}
//************
// Multi-Color Field
//************
void playVictory() {
int i, j;
for (j=0; j < 256*5 ; j++) { // a total of 5 passes
for (i=0; i < NUM_LEDS; i++)
{
leds[i] = CHSV(((i * 256 / NUM_LEDS) + j) % 256, 255, BRIGHTNESS);
}
FastLED.show();
delay(SPEED_V);
}
clearField();
delay(500);
showField();
}
//************
// Play it Again ???
//************
boolean playAgain() {
clearField();
field[0] = 0;
field[8] = 96;
showField();
// Interrogated Keys (1-9)
byte key = 0; // wait at the touch of a button
while (key != 1 && key != 9) { // until key 1 or 9 is pressed
key = kpd.getKey();
}
if(key == 1) {
dimmoutDisplay();
return false;
}
dimmoutDisplay();
return true;
}