#define SIMULATOR // For Wokwi
#include "splash_screen.h"
//----------------------------------------Include Library
#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h> // this is needed for display
#include <Adafruit_ILI9341.h>
#include <Wire.h> // this is needed for FT6206
#include <Adafruit_FT6206.h> // Hardware-specific library
#include <TouchScreen.h>
//----------------------------------------
//----------------------------------------
byte press = 0;
const int ButtonZero[4] = {57, 17, 62, 62};
const int ButtonOne[4] = {132, 17, 62, 62};
const int ButtonTwo[4] = {207, 17, 62, 62};
const int ButtonThree[4] = {57, 87, 62, 62};
const int ButtonFour[4] = {132, 87, 62, 62};
const int ButtonFive[4] = {207, 87, 62, 62};
const int ButtonSix[4] = {57, 157, 62, 62};
const int ButtonSeven[4] = {132, 157, 62, 62};
const int ButtonEight[4] = {207, 157, 62, 62};
const int Start[4] = {60, 180, 200, 40};
const int PlayAgain[4] = {60, 180, 200, 40};
void drawGameScreen(bool refreshAll);
//----------------------------------------
//----------------------------------------Variable for the x, y and z points on the touch screen
int x_set;
int y_set;
int z_set;
//----------------------------------------
Adafruit_FT6206 ctp = Adafruit_FT6206();
//----------------------------------------Pin configuration and initialization for LCD TFT
#define LCD_CS 10
#define LCD_CD 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(LCD_CS, LCD_CD);
/*______Assign names to colors and pressure_______*/
#define BLACK 0x0000
#define BROWN 0x7980
#define RED 0xF800
#define ORANGE 0xFBE0
#define YELLOW 0xFFE0
#define GREEN 0x07E0
#define BLUE 0x001F
#define VIOLET 0xA81F
#define GREY 0x7BEF
#define WHITE 0xFFFF
#define CYAN 0x07FF
#define MAGENTA 0xF81F
int gameScreen = 1;
int moves = 1;
int winner = 0; //0 = Draw, 1 = Human, 2 = CPU
boolean buttonEnabled = true;
int board[]={0,0,0,0,0,0,0,0,0};// holds position data 0 is blank, 1 human, 2 is computer
void setup() {
Serial.begin(115200); //Use serial monitor for debugging
tft.begin(); //--> SPFD5408/ILI9341
if (! ctp.begin(40)) { // pass in 'sensitivity' coefficient
Serial.println("Couldn't start FT6206 touchscreen controller");
while (1);
}
tft.setRotation(3); // I just roated so that the power jack faces up - optional
// initDisplay();
drawStartScreen();
}
//========================================================================GetTSPoint()
void GetTSPoint() {
// Retrieve a point
TS_Point p = ctp.getPoint();
// Wait for a touch
if (! ctp.touched()) {
y_set = map(p.x, 0, 240, 0, tft.height());
x_set = map(tft.width() - p.x, 0, 320, 0, tft.width());
return;
}
}
//========================================================================
//========================================================================
void loop()
{
#ifdef SIMULATOR
TS_Point p = ctp.getPoint();
if (ctp.touched())
#endif
{
processMyTouch();
}
}
//========================================================================
//========================================================================
void drawStartScreen()
{
tft.fillScreen(BLACK);
//Draw white frame
tft.drawRect(0, 0, 319, 240, WHITE);
//Print "Tic Tac Toe" Text
tft.setCursor(30, 100);
tft.setTextColor(WHITE);
tft.setTextSize(4);
tft.print("Tic Tac Toe");
//Print "YouTube!" text
tft.setCursor(80, 30);
tft.setTextColor(GREEN);
tft.setTextSize(4);
tft.print("Arduino");
printRecButton("Start Game", Start[0], Start[1], Start[2], Start[3], RED, WHITE);
}
//========================================================================
//========================================================================
void resetGame(bool refreshAll = false)
{
if (refreshAll == true)
{
buttonEnabled = false;
for(int i = 0; i < 9; i++)
{
board[i] = 0;
}
moves = 1;
winner = 0;
}
}
//========================================================================
//========================================================================
void printRecButton(const char* text, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t backColor, uint16_t textColor)
{
int stl = strlen(text);
const int fontWidth = 5; // default font size is 5 x 7?
const int fontHeight = 7;
const int fontSize = 2;
int cursorX = (x + (w / 2) - (stl * fontWidth) - fontWidth);
int cursorY = ((y + (h / 2) - fontHeight));
tft.fillRect(x, y, w, h, backColor);
tft.drawRect(x, y, w, h, BLACK);
tft.setCursor(cursorX, cursorY);
tft.setTextSize(fontSize);
tft.setTextColor(textColor);
tft.println(text);
}
//========================================================================
//========================================================================
void drawGameScreen(bool refreshAll = false)
{
if (refreshAll == true)
{
tft.fillScreen(BLACK);
//Draw frame
tft.drawRect(0, 0, 319, 240,WHITE);
drawVerticalLine(125);
drawVerticalLine(195);
drawHorizontalLine(80);
drawHorizontalLine(150);
printRecButton("", ButtonZero[0], ButtonZero[1], ButtonZero[2], ButtonZero[3], BLACK, BLACK);
printRecButton("", ButtonOne[0], ButtonOne[1], ButtonOne[2], ButtonOne[3], BLACK, BLACK);
printRecButton("", ButtonTwo[0], ButtonTwo[1], ButtonTwo[2], ButtonTwo[3], BLACK, BLACK);
printRecButton("", ButtonThree[0], ButtonThree[1], ButtonThree[2], ButtonThree[3], BLACK, BLACK);
printRecButton("", ButtonFour[0], ButtonFour[1], ButtonFour[2], ButtonFour[3], BLACK, BLACK);
printRecButton("", ButtonFive[0], ButtonFive[1], ButtonFive[2], ButtonFive[3], BLACK, BLACK);
printRecButton("", ButtonSix[0], ButtonSix[1], ButtonSix[2], ButtonSix[3], BLACK, BLACK);
printRecButton("", ButtonSeven[0], ButtonSeven[1], ButtonSeven[2], ButtonSeven[3], BLACK, BLACK);
printRecButton("", ButtonEight[0], ButtonEight[1], ButtonEight[2], ButtonEight[3], BLACK, BLACK);
}
}
//========================================================================
//========================================================================
void drawVerticalLine(int x)
{
int i = 0;
for(i = 0; i < 7; i++)
{
tft.drawLine(x + i, 20, x + i, 220, WHITE);
}
}
//========================================================================
//========================================================================
void drawHorizontalLine(int y)
{
int i = 0;
for(i = 0; i < 7; i++)
{
tft.drawLine(60, y + i, 270, y + i, WHITE);
}
}
//========================================================================
//========================================================================
void arduinoMove(bool refreshAll = false)
{
if (refreshAll == true)
{
int b = 0;
int counter = 0;
int movesPlayed = 0;
Serial.print("\nArduino Move:");
int firstMoves[]={0, 1, 2, 3, 4, 5, 6, 7, 8}; // will use these positions first
for(counter = 0; counter < 2; counter++) //Count first moves played
{
if(board[firstMoves[counter]] != 0) // First move is played by someone
{
movesPlayed++;
}
}
do
{
if(moves <= 2)
{
int randomMove = random(9);
int c = firstMoves[randomMove];
if (board[c] == 0)
{
delay(500);
board[c] = 2;
Serial.print(firstMoves[randomMove]);
Serial.println();
drawCpuMove(firstMoves[randomMove]);
b = 1;
}
}
else
{
int nextMove = checkOpponent();
if(movesPlayed == 4) //All first moves are played
{
int randomMove = random(9);
if (board[randomMove] == 0)
{
delay(500);
board[randomMove] = 2;
Serial.print(randomMove);
Serial.println();
drawCpuMove(randomMove);
b = 1;
}
}
else
{
int randomMove = random(9);
int c = firstMoves[randomMove];
if (nextMove < 10 && board[nextMove] == 0)
{
delay(500);
board[nextMove] = 2;
drawCpuMove(nextMove);
b = 1;
}
else if (board[c] == 0)
{
delay(500);
board[c] = 2;
Serial.print(firstMoves[randomMove]);
Serial.println();
drawCpuMove(firstMoves[randomMove]);
b = 1;
}
}
}
}
while (b < 1);
}
}
//========================================================================
//========================================================================
void checkWinner()
// checks board to see if there is a winner
// places result in the global variable 'winner'
{
int qq = 0;
// noughts win?
if (board[0] == 1 && board[1] == 1 && board[2] == 1) {
winner = 1;
}
else if (board[3] == 1 && board[4] == 1 && board[5] == 1) {
winner = 1;
}
else if (board[6] == 1 && board[7] == 1 && board[8] == 1) {
winner = 1;
}
else if (board[0] == 1 && board[3] == 1 && board[6] == 1) {
winner =1;
}
else if (board[1] == 1 && board[4] == 1 && board[7] == 1) {
winner = 1;
}
else if (board[2] == 1 && board[5] == 1 && board[8] == 1) {
winner = 1;
}
else if (board[0] == 1 && board[4] == 1 && board[8] == 1) {
winner = 1;
}
else if (board[2] == 1 && board[4] == 1 && board[6] == 1) {
winner = 1;
}
// crosses win?
else if (board[0] == 2 && board[1] == 2 && board[2] == 2) {
winner = 2;
}
else if (board[3] == 2 && board[4] == 2 && board[5] == 2) {
winner = 2;
}
else if (board[6] == 2 && board[7] == 2 && board[8] == 2) {
winner = 2;
}
else if (board[0] == 2 && board[3] == 2 && board[6] == 2) {
winner = 2;
}
else if (board[1] == 2 && board[4] == 2 && board[7] == 2) {
winner = 2;
}
else if (board[2] == 2 && board[5] == 2 && board[8] == 2) {
winner = 2;
}
else if (board[0] == 2 && board[4] == 2 && board[8] == 2) {
winner = 2;
}
else if (board[2] == 2 && board[4] == 2 && board[6] == 2) {
winner = 2;
}
else if (moves == 10) {
winner = 3;
}
else {
winner = 0;
}
}
//========================================================================
//========================================================================
void printBoard()
{
int i = 0;
Serial.println("Board: [");
for(i = 0; i < 9; i++)
{
if (i < 8) {
Serial.print(board[i]);
Serial.print(",");
} else {
Serial.print(board[i]);
}
}
Serial.print("]");
Serial.println();
}
//========================================================================
//========================================================================
int checkOpponent()
{
if(board[0] == 1 && board[1] == 1 && board[2] == 0)
return 2;
else if(board[8] == 1 && board[5] == 1 && board[2] == 0)
return 2;
else if(board[4] == 1 && board[6] == 1 && board[2] == 0)
return 2;
else if(board[0] == 1 && board[1] == 0 && board[2] == 1)
return 1;
else if(board[1] == 0 && board[4] == 1 && board[7] == 1)
return 1;
else if(board[1] == 1 && board[2] == 1 && board[0] == 0)
return 0;
else if(board[3] == 1 && board[6] == 1 && board[0] == 0)
return 0;
else if(board[8] == 1 && board[4] == 1 && board[0] == 0)
return 0;
else if(board[3] == 1 && board[4] == 1 && board[5] == 0)
return 5;
else if(board[5] == 0 && board[2] == 1 && board[8] == 1)
return 5;
else if(board[2] == 1 && board[4] == 1 && board[6] == 0)
return 6;
else if(board[0] == 1 && board[3] == 1 && board[6] == 0)
return 6;
else if(board[6] == 0 && board[7] == 1 && board[8] == 1)
return 6;
else if(board[4] == 1 && board[5] == 1 && board[3] == 0)
return 3;
else if(board[0] == 1 && board[7] == 1 && board[3] == 0)
return 3;
else if(board[3] == 1 && board[4] == 0 && board[5] == 1)
return 4;
else if(board[0] == 1 && board[4] == 0 && board[8] == 1)
return 4;
else if(board[2] == 1 && board[4] == 0 && board[6] == 1)
return 4;
else if(board[1] == 1 && board[4] == 1 && board[7] == 0)
return 7;
else if(board[7] == 0 && board[6] == 1 && board[8] == 1)
return 7;
else if(board[8] == 0 && board[0] == 1 && board[4] == 1)
return 8;
else if(board[8] == 0 && board[2] == 1 && board[5] == 1)
return 8;
else if(board[8] == 0 && board[6] == 1 && board[7] == 1)
return 8;
else
return 100;
}
//========================================================================
//========================================================================
void drawGameOverScreen(bool refreshAll = false)
{
if (refreshAll == true)
{
tft.fillScreen(BLACK);
//Draw frame
tft.drawRect(0, 0, 319, 240, WHITE);
//Print "Game Over" Text
tft.setCursor(50, 30);
tft.setTextColor(WHITE);
tft.setTextSize(4);
tft.print("GAME OVER");
if(winner == 3)
{
//Print "DRAW!" text
tft.setCursor(110, 100);
tft.setTextColor(YELLOW);
tft.setTextSize(4);
tft.print("DRAW");
}
else if(winner == 1)
{
//Print "HUMAN WINS!" text
tft.setCursor(60,100);
tft.setTextColor(BLUE);
tft.setTextSize(4);
tft.print("YOU WINS");
}
else if(winner == 2)
{
//Print "CPU WINS!" text
tft.setCursor(60, 100);
tft.setTextColor(RED);
tft.setTextSize(4);
tft.print("CPU WINS");
}
printRecButton("Play Again", PlayAgain[0], PlayAgain[1], PlayAgain[2], PlayAgain[3], RED, WHITE);
DrawButtonBack(10, 200);
}
}
//========================================================================
//========================================================================DrawButtonBack(x, y)
void DrawButtonBack(int x_btn_back, int y_btn_back) {
tft.fillRoundRect(x_btn_back, y_btn_back, 30, 30, 5, BLACK);
tft.fillRoundRect(x_btn_back+2, y_btn_back+2, 26, 26, 5, YELLOW);
tft.setTextSize(2);
tft.setTextColor(BLACK);
tft.setCursor(x_btn_back+7, y_btn_back+7);
tft.print("<");
}
//========================================================================
//========================================================================DrawButtonBackPress(x, y)
void DrawButtonBackPress(int x_btn_back, int y_btn_back) {
tft.fillRoundRect(x_btn_back, y_btn_back, 30, 30, 5, BLACK);
}
//========================================================================
//========================================================================
void drawCpuMove(int move)
{
switch(move)
{
case 0: drawCircle(55, 15); break;
case 1: drawCircle(130, 15); break;
case 2: drawCircle(205, 15); break;
case 3: drawCircle(55, 85); break;
case 4: drawCircle(130, 85); break;
case 5: drawCircle(205, 85); break;
case 6: drawCircle(55, 155); break;
case 7: drawCircle(130, 155);break;
case 8: drawCircle(205, 155);break;
}
}
//========================================================================
//========================================================================
void drawPlayerMove(int move)
{
switch(move)
{
case 0: drawX(55, 15); break;
case 1: drawX(130, 15); break;
case 2: drawX(205, 15); break;
case 3: drawX(55, 85); break;
case 4: drawX(130, 85); break;
case 5: drawX(205, 85); break;
case 6: drawX(55, 155); break;
case 7: drawX(130, 155);break;
case 8: drawX(205, 155);break;
}
}
//========================================================================
//========================================================================
void drawCircle(int x, int y)
{
drawBitmap(x, y, circle, 65, 65, RED);
}
void drawX(int x, int y)
{
drawBitmap(x, y, x_bitmap, 65, 65, BLUE);
}
//========================================================================
//========================================================================
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
{
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t byte;
for(j = 0; j < h; j++){
for(i = 0; i < w; i++){
if(i & 7) byte <<= 1;
else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
if(byte & 0x80) tft.drawPixel(x + i, y + j, color);
}
}
}
//========================================================================
//========================================================================
void processMyTouch()
{
switch (press)
{
case 0:
{
if (checkButton(Start[0], Start[1], Start[2], Start[3]) == true)
{
Serial.println("Button Pressed");
drawGameScreen(true);
arduinoMove(true);
printBoard();
moves++;
press = 2;
delay(500);
}
break;
}
case 2:
{
if (winner == 0 && moves < 10 && moves % 2 == 1)
{
arduinoMove(true);
moves++;
printBoard();
checkWinner();
Serial.println(moves);
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonZero[0], ButtonZero[1], ButtonZero[2], ButtonZero[3]) == true && board[0] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 0");
drawPlayerMove(0);
board[0] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonOne[0], ButtonOne[1], ButtonOne[2], ButtonOne[3]) == true && board[1] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 1");
drawPlayerMove(1);
board[1] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonTwo[0], ButtonTwo[1], ButtonTwo[2], ButtonTwo[3]) == true && board[2] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 2");
drawPlayerMove(2);
board[2] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonThree[0], ButtonThree[1], ButtonThree[2], ButtonThree[3]) == true && board[3] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 3");
drawPlayerMove(3);
board[3] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonFour[0], ButtonFour[1], ButtonFour[2], ButtonFour[3]) == true && board[4] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 4");
drawPlayerMove(4);
board[4] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonFive[0], ButtonFive[1], ButtonFive[2], ButtonFive[3]) == true && board[5] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 5");
drawPlayerMove(5);
board[5] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonSix[0], ButtonSix[1], ButtonSix[2], ButtonSix[3]) == true && board[6] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 6");
drawPlayerMove(6);
board[6] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonSeven[0], ButtonSeven[1], ButtonSeven[2], ButtonSeven[3]) == true && board[7] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 7");
drawPlayerMove(7);
board[7] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (checkButton(ButtonEight[0], ButtonEight[1], ButtonEight[2], ButtonEight[3]) == true && board[8] == 0 && winner == 0 && moves < 10 && moves % 2 == 0)
{
Serial.println("Player Move: 8");
drawPlayerMove(8);
board[8] = 1;
printBoard();
moves++;
checkWinner();
Serial.println("Drawing player move");
press = 2;
return processMyTouch();
delay(500);
}
else if (winner == 1)
{
drawGameOverScreen(true);
Serial.println("HUMAN WINS");
delay(250);
gameScreen = 3;
press = 1;
return processMyTouch();
}
else if (winner == 2)
{
drawGameOverScreen(true);
Serial.println("CPU WINS");
delay(250);
gameScreen = 3;
press = 1;
return processMyTouch();
}
else if (winner == 3)
{
drawGameOverScreen(true);
Serial.println("DRAW");
delay(250);
gameScreen = 3;
press = 1;
return processMyTouch();
}
break;
}
case 1:
{
if (checkButton(PlayAgain[0], PlayAgain[1], PlayAgain[2], PlayAgain[3]) == true)
{
Serial.println("Play Again");
resetGame(true);
drawGameScreen(true);
press = 2;
return processMyTouch();
}
else if (checkButton(10, 200, 30, 30) == true)
{
DrawButtonBackPress(10, 200);
delay(100);
DrawButtonBack(10, 200);
delay(100);
tft.fillScreen(BLACK);
delay(100);
resetGame(true);
drawStartScreen();
press = 0;
return processMyTouch();
}
break;
}
default:
{
break;
}
}
delay(100);
}
//========================================================================
//========================================================================
bool checkButton(int x1, int y1, int w, int h)
{
#ifdef SIMULATOR
TS_Point p = ctp.getPoint();
int touch_x = 319 - p.y;
int touch_y = p.x;
#endif
int x2 = x1 + w;
int y2 = y1 + h;
bool match = false;
if ((touch_x >= x1) && (touch_x <= x2) && (touch_y >= y1) && (touch_y <= y2))
{
match = true;
}
Serial.print("X = ");
Serial.print(touch_x);
Serial.print(", Y = ");
Serial.print(touch_y);
Serial.print(", match = ");
Serial.println(match);
return match;
}
//========================================================================
Loading
ili9341-cap-touch
ili9341-cap-touch