/****************************************
* Written by: Sam Kristoff
* Version: 1.0
****************************************/
#include <OctoWS2811.h>
//LED Variables
const int ledsPerStrip = 108;
DMAMEM int displayMemory[ledsPerStrip*6];
int drawingMemory[ledsPerStrip*6];
const int config = WS2811_GRB | WS2811_800kHz;
OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config);
#define NUM_COLORS 7
#define BLACK 0x000000
#define RED 0xFF0000
#define GREEN 0x00FF00
#define BLUE 0x0000FF
#define YELLOW 0xFFFF00
#define PINK 0xFF1088
#define ORANGE 0xE05800
#define WHITE 0xFFFFFF
/*
// Less intense...
#define BLACK 0x000000
#define RED 0x160000
#define GREEN 0x001600
#define BLUE 0x000016
#define YELLOW 0x101400
#define PINK 0x120009
#define ORANGE 0x100400
#define WHITE 0x101010
*/
#define PLAYERWIN 0
#define COMPUTERWIN 1
#define TIE 2
int colors[NUM_COLORS] = {RED, GREEN, BLUE, YELLOW, PINK, ORANGE, WHITE};
int colorIndex = 0;
int playerColor = RED;
int computerColor = GREEN;
int drawColor = BLUE;
//Define game states
enum gameState_t {
PREGAME,
PLAYERTURN,
COMPUTERTURN,
GAMEOVER,
};
gameState_t gameState = PREGAME;
void setup() {
Serial.begin(9600);
Serial.println("Tic-Tac-Toe");
leds.begin();
setStripColor(BLACK);
leds.show();
//delay(1000);
//Set hall effect sensor pins as inputs.
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(7, INPUT);
pinMode(8, INPUT);
pinMode(9, INPUT);
pinMode(10, INPUT);
pinMode(11, INPUT);
pinMode(12, INPUT);
}
unsigned int boardState = 0;
unsigned int playerCell = 0;
unsigned int computerCell = 0;
unsigned int playerCells = 0;
unsigned int computerCells = 0;
unsigned int previousBoardState = 0;
int winner = -1;
void loop() {
//Game State Machine
switch(gameState) {
case PREGAME:
//Initialize values
previousBoardState = 0;
playerCell = 0;
computerCell = 0;
playerCells = 0;
computerCells = 0;
winner = -1;
boardState = readBoardValue();
cycleCellColors(50);
Serial.print("boardState = "); Serial.println(boardState, BIN);
if(boardState != 0){
//Clear the board, then highlight the cell the player chose
setStripColor(BLACK);
playerCell = findPlayerMoveCell(boardState, previousBoardState);
playerCells |= 0x0001 << playerCell;
setCellColor(playerCell, playerColor);
previousBoardState = boardState;
gameState = COMPUTERTURN;
Serial.println("Computer Turn");
}
break;
case COMPUTERTURN:
delay(100);
computerCell = computeMove(boardState);
computerCells |= 0x0001 << computerCell;
setCellColor(computerCell, computerColor);
boardState = boardState | 0x0001 << computerCell;
previousBoardState = boardState;
//Check for winner
winner = checkForGameOver(playerCells, computerCells);
if(winner >= 0){
gameState = GAMEOVER;
Serial.println("Game Over");
}
else
{
gameState = PLAYERTURN;
Serial.println("Player Turn");
}
break;
case PLAYERTURN:
boardState = boardState | readBoardValue();
if(boardState != previousBoardState)
{
playerCell = findPlayerMoveCell(boardState, previousBoardState);
playerCells |= 0x0001 << playerCell;
setCellColor(playerCell, playerColor);
previousBoardState = boardState;
//Check for winner
winner = checkForGameOver(playerCells, computerCells);
if(winner >= 0){
gameState = GAMEOVER;
Serial.println("Game Over");
}
else
{
gameState = COMPUTERTURN;
Serial.println("Computer Turn");
delay(1000);
}
}
break;
case GAMEOVER:
if(winner == TIE)
{
setStripColor(drawColor);
delay(1000);
}
if(winner == PLAYERWIN)
{
setStripColor(playerColor);
flashWinningLine(playerCells, computerCells, 2);
}
if(winner == COMPUTERWIN)
{
setStripColor(computerColor);
flashWinningLine(playerCells, computerCells, 2);
}
break;
default:
break;
}
//If the board is ever empty reutrn to pre-game
if(readBoardValue() == 0)
{
gameState = PREGAME;
}
}
//Set the entire strip to the specified color
void setStripColor(int color)
{
for (int i=0; i < leds.numPixels(); i++) {
leds.setPixel(i, color);
}
leds.show();
}
//Set the color of a single cell
void setCellColor(int cell, int color)
{
for (int i=0; i < 12; i++) {
leds.setPixel((cell*12) + i -1, color);
}
leds.show();
}
//Read board value
unsigned int readBoardValue(){
unsigned int boardState = 0;
for(int i=0; i<9; i++){
int set = !digitalRead(i+4);
boardState = boardState | (set << i);
}
return boardState;
}
//Find the cell number that the player just claimed
int findPlayerMoveCell(unsigned int boardState, unsigned int previousBoardState){
unsigned int diff = boardState - previousBoardState;
Serial.print("dif = ");
Serial.println(diff, BIN);
int index = 0;
//Scan through bits until we find the one that is set
while(((diff >> index) & 0x0001) == 0)
{
index++;
}
Serial.print("Player Chose ");
Serial.println(index);
return index;
}
//Calculate the comptuer's move and return the selected cell
unsigned int computeMove(unsigned int boardState){
Serial.println("Computing Move... ");
Serial.print("boardState = ");
Serial.println(boardState, BIN);
while(1) {
int cell = random(0, 9);
Serial.print("Checking Cell ");
Serial.println(cell, DEC);
/*
Serial.print("Shifted Value = ");
Serial.println((boardState >> cell), BIN);
Serial.print("ANDED Value = ");
Serial.println(((boardState >> cell) & 0x0001) == 0);
*/
if(((boardState >> cell) & 0x0001) == 0)
{
Serial.print("Computer Chose ");
Serial.println(cell);
return cell;
}
}
}
int checkForGameOver(unsigned int playerCells, unsigned int computerCells)
{
Serial.print("Player Cells = ");
Serial.println(playerCells, BIN);
Serial.print("Computer Cells = ");
Serial.println(computerCells, BIN);
if((playerCells & 0b000000111) == 0b000000111 ||
(playerCells & 0b000111000) == 0b000111000 ||
(playerCells & 0b111000000) == 0b111000000 ||
(playerCells & 0b001100001) == 0b001100001 ||
(playerCells & 0b010010010) == 0b010010010 ||
(playerCells & 0b100001100) == 0b100001100 ||
(playerCells & 0b100010001) == 0b100010001 ||
(playerCells & 0b001010100) == 0b001010100 )
{
return PLAYERWIN;
}
if((computerCells & 0b000000111) == 0b000000111 ||
(computerCells & 0b000111000) == 0b000111000 ||
(computerCells & 0b111000000) == 0b111000000 ||
(computerCells & 0b001100001) == 0b001100001 ||
(computerCells & 0b010010010) == 0b010010010 ||
(computerCells & 0b100001100) == 0b100001100 ||
(computerCells & 0b100010001) == 0b100010001 ||
(computerCells & 0b001010100) == 0b001010100 )
{
return COMPUTERWIN;
}
if((playerCells | computerCells) == 0b111111111)
{
return TIE;
}
return -1;
}
int flashWinningLine(unsigned int playerCells, unsigned int computerCells , int numFlashes) {
int winner = checkForGameOver(playerCells, computerCells);
int winningColor = BLACK;
unsigned int winningBoard = 0;
if(winner == PLAYERWIN){
winningColor = playerColor;
winningBoard = playerCells;
} else if(winner == COMPUTERWIN){
winningColor = computerColor;
winningBoard = computerCells;
}
int cell0 = 0;
int cell1 = 0;
int cell2 = 0;
if((winningBoard & 0b000000111) == 0b000000111) {
cell0 = 0;
cell1 = 1;
cell2 = 2;
} else if ((winningBoard & 0b000111000) == 0b000111000) {
cell0 = 3;
cell1 = 4;
cell2 = 5;
} else if ((winningBoard & 0b111000000) == 0b111000000) {
cell0 = 6;
cell1 = 7;
cell2 = 8;
} else if ((winningBoard & 0b001100001) == 0b001100001) {
cell0 = 0;
cell1 = 5;
cell2 = 6;
} else if ((winningBoard & 0b010010010) == 0b010010010) {
cell0 = 1;
cell1 = 4;
cell2 = 7;
} else if ((winningBoard & 0b100001100) == 0b100001100) {
cell0 = 2;
cell1 = 3;
cell2 = 8;
} else if ((winningBoard & 0b100010001) == 0b100010001) {
cell0 = 0;
cell1 = 4;
cell2 = 8;
} else if ((winningBoard & 0b001010100) == 0b001010100) {
cell0 = 2;
cell1 = 4;
cell2 = 6;
}
//Flash Colors
for(int i=0; i<numFlashes; i++){
setCellColor(cell0, winningColor);
setCellColor(cell1, winningColor);
setCellColor(cell2, winningColor);
delay(250);
setCellColor(cell0, BLACK);
setCellColor(cell1, BLACK);
setCellColor(cell2, BLACK);
delay(250);
}
}
//---------- Cycle cell colors ---------
//Cycle through all cells and all colors in order.
#define NUM_CYCLE_COLORS 7
int cycleCellIndex = 0;
int cycleColors[NUM_COLORS] = {RED, GREEN, BLUE, YELLOW, PINK, ORANGE, WHITE};
int cycleColorIndex = 0;
void cycleCellColors(int cellDelay) {
for (int i=0; i < 12; i++) {
setCellColor(cycleCellIndex, cycleColors[cycleColorIndex]);
cycleCellIndex = (cycleCellIndex + 1) % 9;
cycleColorIndex = (cycleColorIndex + 1) % NUM_CYCLE_COLORS;
delay(cellDelay);
leds.show();
}
}
Comments