2.8" tft tic tac toe game problems

I am trying to use a 2.8" tft LCD touchscreen but I keep getting the error message:

C:\Users\BR194904\AppData\Local\Temp\ccla2Ihe.ltrans0.ltrans.o: In function drawX': C:\Users\BR194904\Downloads\TicTacToeEasy/TicTacToeEasy.ino:531: undefined reference to x_bitmap'
C:\Users\BR194904\Downloads\TicTacToeEasy/TicTacToeEasy.ino:531: undefined reference to x_bitmap' C:\Users\BR194904\AppData\Local\Temp\ccla2Ihe.ltrans0.ltrans.o: In function drawCircle':
C:\Users\BR194904\Downloads\TicTacToeEasy/TicTacToeEasy.ino:526: undefined reference to circle' C:\Users\BR194904\Downloads\TicTacToeEasy/TicTacToeEasy.ino:526: undefined reference to circle'
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino Uno.

Here is the code:

//////////////////////////////////////////////
// 2.8" TOUCH SCREEN TIC TAC TOE //
// //
// http://www.educ8s.tv //
/////////////////////////////////////////////

#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

#define TS_MINX 204
#define TS_MINY 195
#define TS_MAXX 948
#define TS_MAXY 910

#define YP A2 // must be an analog pin, use "An" notation!
#define XM A3 // must be an analog pin, use "An" notation!
#define YM 8 // can be a digital pin
#define XP 9 // can be a digital pin

#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF

extern uint8_t circle;
extern uint8_t x_bitmap;

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

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(9600);
Serial.print("Starting...");
randomSeed(analogRead(0));

initDisplay();
drawStartScreen();
}

void loop()
{
TSPoint p = ts.getPoint(); //Get touch point

if(gameScreen==3)
{
buttonEnabled =true;
}

if (p.z > ts.pressureThreshhold) {

p.x = map(p.x, TS_MAXX, TS_MINX, 0, 320);
p.y = map(p.y, TS_MAXY, TS_MINY, 0, 240);

Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\n");

if(p.x>60 && p.x<260 && p.y>180 && p.y<220 && buttonEnabled)// The user has pressed inside the red rectangle
{
buttonEnabled = false; //Disable button
Serial.println("Button Pressed");
resetGame();
//This is important, because the libraries are sharing pins
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);

drawGameScreen();
playGame();

}
delay(10);
}
}

void resetGame()
{
buttonEnabled = false;
for(int i=0;i<9;i++)
{
board[i]=0;
}
moves = 1;
winner = 0;
gameScreen=2;
}

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");

createStartButton();

}

void createStartButton()
{
//Create Red Button
tft.fillRect(60,180, 200, 40, RED);
tft.drawRect(60,180,200,40,WHITE);
tft.setCursor(72,188);
tft.setTextColor(WHITE);
tft.setTextSize(3);
tft.print("Start Game");
}

void initDisplay()
{
tft.reset();
tft.begin(0x9341);
tft.setRotation(3);
}

void drawGameScreen()
{
tft.fillScreen(BLACK);

//Draw frame
tft.drawRect(0,0,319,240,WHITE);

drawVerticalLine(125);

drawVerticalLine(195);

drawHorizontalLine(80);

drawHorizontalLine(150);
}

void drawGameOverScreen()
{

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 == 0)
{
//Print "DRAW!" text
tft.setCursor(110,100);
tft.setTextColor(YELLOW);
tft.setTextSize(4);
tft.print("DRAW");
}
if(winner == 1)
{
//Print "HUMAN WINS!" text
tft.setCursor(40,100);
tft.setTextColor(BLUE);
tft.setTextSize(4);
tft.print("HUMAN WINS");
}

if(winner == 2)
{
//Print "CPU WINS!" text
tft.setCursor(60,100);
tft.setTextColor(RED);
tft.setTextSize(4);
tft.print("CPU WINS");
}

createPlayAgainButton();

pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);

}

void createPlayAgainButton()
{
//Create Red Button
tft.fillRect(60,180, 200, 40, RED);
tft.drawRect(60,180,200,40,WHITE);
tft.setCursor(72,188);
tft.setTextColor(WHITE);
tft.setTextSize(3);
tft.print("Play Again");
}

void drawHorizontalLine(int y)
{
int i=0;
for(i=0;i<7;i++)
{
tft.drawLine(60,y+i,270,y+i,WHITE);
}
}

void drawVerticalLine(int x)
{
int i=0;
for(i=0;i<7;i++)
{
tft.drawLine(x+i,20,x+i,220,WHITE);
}
}

void playGame()
{
do
{
if(moves%2==1)
{
arduinoMove();
printBoard();
checkWinner();
}else
{
playerMove();
printBoard();
checkWinner();
}
moves++;
}
while (winner==0 && moves<10);
if(winner == 1)
{
Serial.println("HUMAN WINS");
delay(3000);
gameScreen=3;
drawGameOverScreen();
}else if(winner ==2)
{
Serial.println("CPU WINS");
delay(3000);
gameScreen=3;
drawGameOverScreen();
}else
{
Serial.println("DRAW");
delay(3000);
gameScreen=3;
drawGameOverScreen();
}

}

void playerMove()
{
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
TSPoint p;
boolean validMove = false;
Serial.print("\nPlayer Move:");
do
{
p = ts.getPoint(); //Get touch point
if (p.z > ts.pressureThreshhold)
{
p.x = map(p.x, TS_MAXX, TS_MINX, 0, 320);
p.y = map(p.y, TS_MAXY, TS_MINY, 0, 240);
Serial.println(p.x);
Serial.println(p.y);

  if((p.x<115)&& (p.y>=150)) //6
  {
    if(board[6]==0)
    {
      Serial.println("Player Move: 6");
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[6]=1;
      drawPlayerMove(6);  
      Serial.println("Drawing player move");
    }
  }
   else if((p.x>0 && p.x<115)&& (p.y<150 && p.y>80)) //3
  {
   
    if(board[3]==0)
    {
     Serial.println("Player Move: 3");
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[3]=1;
      drawPlayerMove(3);  
      Serial.println("Drawing player move");
    }
  }
   else if((p.x<125)&& (p.y<80)) //0
  {
    if(board[0]==0)
    {
      Serial.println("Player Move: 0");          
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[0]=1;
      drawPlayerMove(0);  
    }
  }

else if((p.x>125 && p.x<=195)&& (p.y<80)) //1
  {
    if(board[1]==0)
    {
      Serial.println("Player Move: 1");          
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[1]=1;
      drawPlayerMove(1);  
    }
  }

   else if((p.x>195)&& (p.y<80)) //2
  {
    if(board[2]==0)
    {
      Serial.println("Player Move: 2");          
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[2]=1;
      drawPlayerMove(2);  
    }
  }

  else if((p.x>125 && p.x<=195)&& (p.y<150 && p.y>80)) //4
  {
    if(board[4]==0)
    {
      Serial.println("Player Move: 4");          
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[4]=1;
      drawPlayerMove(4);  
    }
  }

   else if((p.x>195)&& (p.y<150 && p.y>80)) //5
  {
    if(board[5]==0)
    {
      Serial.println("Player Move: 5");          
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[5]=1;
      drawPlayerMove(5);  
    }
  }

    else if((p.x>125 && p.x<=195)&& (p.y>150)) //7
  {
    if(board[7]==0)
    {
      Serial.println("Player Move: 7");          
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[7]=1;
      drawPlayerMove(7);  
    }
  }

   else if((p.x>195)&& (p.y>150)) //8
  {
    if(board[8]==0)
    {
      Serial.println("Player Move: 8");          
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      board[8]=1;
      drawPlayerMove(8);  
    }
  }
  
}

}while(p.z<ts.pressureThreshhold);
}

void printBoard()
{
int i=0;
Serial.println("Board: [");
for(i=0;i<9;i++)
{
Serial.print(board[i]);
Serial.print(",");
}
Serial.print("]");
}

int checkOpponent()
{
if(board[0]==1 && board[1]==1 && board[2]==0)
return 2;
else if(board[0]==1 && board[1]==0 && board[2]==1)
return 1;
else if (board[1]==1 && board [2]==1 && board[0]==0)
return 0;
else if (board[3]==1 && board[4]==1 && board[5]==0)
return 5;
else if (board[4]==1 && board[5]==1&& board[3]==0)
return 3;
else if (board[3]==1 && board[4]==0&& board[5]==1)
return 4;
else if (board[1]==0 && board[4]==1&& board[7]==1)
return 1;
else
return 100;
}

void arduinoMove()
{
int b = 0;
int counter =0;
int movesPlayed = 0;
Serial.print("\nArduino Move:");

int firstMoves={0,2,6,8}; // will use these positions first

for(counter=0;counter<4;counter++) //Count first moves played
{
if(board[firstMoves[counter]]!=0) // First move is played by someone
{
movesPlayed++;
}
}
do{
if(moves<=2)
{
int randomMove =random(4);
int c=firstMoves[randomMove];

  if (board[c]==0)
  {  
    delay(1000);
    board[c]=2;
    Serial.print(firstMoves[randomMove]);
    Serial.println();
    drawCpuMove(firstMoves[randomMove]);
    b=1;
  }   
    
}else
{
int nextMove = checkOpponent();
if(nextMove == 100)
{  
if(movesPlayed == 4) //All first moves are played
{
  int randomMove =random(9); 
  if (board[randomMove]==0)
  {  
    delay(1000);
    board[randomMove]=2;
    Serial.print(randomMove);
    Serial.println();
    drawCpuMove(randomMove);
    b=1;
  }   
}else
{
  int randomMove =random(4); 
  int c=firstMoves[randomMove];
  
  if (board[c]==0)
  {  
    delay(1000);
    board[c]=2;
    Serial.print(firstMoves[randomMove]);
    Serial.println();
    drawCpuMove(firstMoves[randomMove]);
    b=1;
  }   

}
}else
{
delay(1000);
board[nextMove]=2;
drawCpuMove(nextMove);
b=1;
}
}
}
while (b<1);
}

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 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 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;
}
if (board[3]==1 && board[4]==1 && board[5]==1) {
winner=1;
}
if (board[6]==1 && board[7]==1 && board[8]==1) {
winner=1;
}
if (board[0]==1 && board[3]==1 && board[6]==1) {
winner=1;
}
if (board[1]==1 && board[4]==1 && board[7]==1) {
winner=1;
}
if (board[2]==1 && board[5]==1 && board[8]==1) {
winner=1;
}
if (board[0]==1 && board[4]==1 && board[8]==1) {
winner=1;
}
if (board[2]==1 && board[4]==1 && board[6]==1) {
winner=1;
}
// crosses win?
if (board[0]==2 && board[1]==2 && board[2]==2) {
winner=2;
}
if (board[3]==2 && board[4]==2 && board[5]==2) {
winner=2;
}
if (board[6]==2 && board[7]==2 && board[8]==2) {
winner=2;
}
if (board[0]==2 && board[3]==2 && board[6]==2) {
winner=2;
}
if (board[1]==2 && board[4]==2 && board[7]==2) {
winner=2;
}
if (board[2]==2 && board[5]==2 && board[8]==2) {
winner=2;
}
if (board[0]==2 && board[4]==2 && board[8]==2) {
winner=2;
}
if (board[2]==2 && board[4]==2 && board[6]==2) {
winner=2;
}

}
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);
}
}
}

Please edit your post, select all code and click </> above the edit textbox; next save your post.

The extern indicates that somewhere must be a piece of code that contains the actual declaration of those variables. That piece of code is missing.

Did you write this yourself? Or did you copy it from somewhere and forgot to copy some other files? If the latter, please provide a link.

I found this on the Arduino project hub.

Did you download graphics.c from that page? If not, download it and copy it to the same directory as the sketch.

How do you do that?

If you don't know where your sketches are stored, use File -> Preferences in the IDE and check the Sketchbook location. Unless you saved the tictactoe sketch somewhere else, it will be as a subdirectory in that directory.

In that subdirectory, you will find your ino file as shown below

C:\Users\sterretje\Documents\Arduino\>tree /F /A
Folder PATH listing for volume Win7
Volume serial number is 1234-5678
C:.
+- - -855804
|   \- - -arduino_analog
|           arduino_analog.ino
|
+- - -tictactoe
|       graphics.c
|       tictactoe.ino
|

You an either directly download graphics.h into that directory or you can download first and next copy.

This is what it looks like:

So your sketchbook directory is C:\Users\BR192904\Documents\Arduino. But looking at the error in your opening post, you are working in the download directory C:\Users\BR194904\Downloads\TicTacToeEasy; sorry that I had forgotten about that. So copy (or download) the graphics.c file to that directory.

I’ve heard the term trajectory before but I dont know what it means.

Like this?

Basically yes. I would call the file graphics.c but it should work with graphics (1).c as well (unless the IDE does not like that).

Just try it as is, if it fails, rename the file.

I think I need to come and thank this post, it has inspired me and I am now planning to do a tic-tac-toe project using other TFT LCDs. I think it is very interesting and suitable for newbies like me.