Tic-Tac-Toe not working

So me and a friend are trying to make a tic-tac-toe game. Everything was going fine and I ran into this problem: The program is working as long as you don’t press on a cell you have already put an X or an O. Though we have made our program so it wouldn’t have such a problem. Whenever you press a cell you have already put an X or an O the program freezes and doesn’t even let you press Esc. do not care about the width/height stuff it is all correct for sure. just pls check the mousePressed function and the Cell class. Thank you.

  1. cell[0] is top left
  2. cell[1] is top middle
  3. cell[2] is top right
  4. cell[3] is middle left etc.

Also pl is a variable to determine who has the cell. 2 means it is neutral 1 that it is an X and 0 means an O

This is the class in one tab:

class Cells{
  
  float x;
  float y; 
  int pl = 2;
  int count;
  
  Cells(float xpos,float ypos,int num){
    x = xpos;
    y = ypos;
    count = num;
  }
  
  void xoro(int num){
    strokeWeight(8);
    if(num == 1){
      stroke(255,0,0);
      line(width/42.6+x,height/42.6+y,width/3.87+x,height/3.87+y);
      line(width/42.6+x,height/3.87+y,width/3.87+x,height/42.6+y);
      }
    else if(num == 0){
      stroke(0,0,255);
      noFill();
      ellipse(width/7.1+x,height/7.1+y,width/4.26,height/4.26);
      }
    }

and the main program in another:

Cells[] cell = new Cells[9];
int moves = 9;
float adjx,adjy;
boolean win = false;
int m;

void setup(){
    //fullScreen();
    size(640,640);
    if (width >= height){
      adjx = (width - height)/2;
      adjy = 0;
      width=height;
    }
    else{
      adjy = (height - width)/2;
      adjx = 0;
      height=width;
    }
    background(0);
    stroke(150);
    strokeWeight(1);
    line(adjx+(width/12.8),adjy+(height/3.5+height/12.8),adjx+(width-width/12.8),adjy+(height/3.5+height/12.8));
    line(adjx+(width/12.8),adjy+(height-height/2.5+(height/12.8)/2),adjx+(width-width/12.8),adjy+(height-height/2.5+(height/12.8)/2));
    line(adjx+(width/3.5+width/12.8),adjy+(height-height/12.8),adjx+(width/3.5+width/12.8),adjy+(height/12.8));
    line(adjx+(width-width/2.5+(width/12.8)/2),adjy+(height-height/12.8),adjx+(width-width/2.5+(width/12.8)/2),adjy+(height/12.8));
    stroke(100);
    text("Press Esc to exit",adjx+(width/2-35),adjy+(height-height/128));
    cell[0] = new Cells(adjx+(width/12.8),adjy+(height/12.8), 0);
    cell[1] = new Cells(adjx+(width/3.5+width/12.8),adjy+(height/12.8), 1);
    cell[2] = new Cells(adjx+(width-width/2.5+(width/12.8)/2),adjy+(height/12.8), 2);
    cell[3] = new Cells(adjx+(width/12.8),adjy+(height/3.5+height/12.8), 3);
    cell[4] = new Cells(adjx+(width/3.5+width/12.8),adjy+(height/3.5+height/12.8), 4);
    cell[5] = new Cells(adjx+(width-width/2.5+(width/12.8)/2),adjy+(height/3.5+height/12.8), 5);
    cell[6] = new Cells(adjx+(width/12.8),adjy+(height-height/2.5+(height/12.8)/2), 6);
    cell[7] = new Cells(adjx+(width/3.5+width/12.8),adjy+(height-height/2.5+(height/12.8)/2), 7);
    cell[8] = new Cells(adjx+(width-width/2.5+(width/12.8)/2),adjy+(height-height/2.5+(height/12.8)/2), 8);
}

  
void draw(){
}


void mousePressed(){
    m = moves % 2;
    win = false;
    while(win == false){
        if (moves > 0){
          if (mouseX<adjx+(width/3.5+width/12.8) && mouseY<adjy+(height/3.5+height/12.8) && mouseX>adjx && mouseY>adjy && cell[0].pl == 2){
            cell[0].xoro(m);
            cell[0].pl = m; 
            win = true;
          }
          if (mouseX<adjx+(width-width/2.5+(width/12.8)/2) && mouseY<adjy+(height/3.5+height/12.8) && mouseX>adjx+(width/3.5+width/12.8) && mouseY>adjy && cell[1].pl == 2){
            cell[1].xoro(m);
            cell[1].pl = m;
            win = true;
          }
          if (mouseX<adjx+width && mouseY<adjy+(height/3.5+height/12.8) && mouseX>adjx+(width-width/2.5+(width/12.8)/2) && mouseY>adjy && cell[2].pl == 2){
            cell[2].xoro(m);
            cell[2].pl = m;
            win = true;
          }
          if (mouseX<adjx+(width/3.5+width/12.8) && mouseY<adjy+(height-height/2.5+(height/12.8)/2) && mouseX>adjx && mouseY>adjy+(height/3.5+height/12.8) && cell[3].pl == 2){
            cell[3].xoro(m);
            cell[3].pl = m;
            win = true;
          }
          if (mouseX<adjx+(width-width/2.5+(width/12.8)/2) && mouseY<adjy+(height-height/2.5+(height/12.8)/2) && mouseX>adjx+(width/3.5+width/12.8) && mouseY>adjy+(height/3.5+height/12.8) && cell[4].pl == 2){
            cell[4].xoro(m);
            cell[4].pl = m;
            win = true;
          }
          if (mouseX<adjx+width && mouseY<adjy+(height-height/2.5+(height/12.8)/2) && mouseX>adjx+(width-width/2.5+(width/12.8)/2) && mouseY>adjy+(height/3.5+height/12.8) && cell[5].pl == 2){
            cell[5].xoro(m);
            cell[5].pl = m;
            win = true;
          }
          if (mouseX<adjx+(width/3.5+width/12.8) && mouseY<adjy+height && mouseX>adjx && mouseY>adjy+(height-height/2.5+(height/12.8)/2) && cell[6].pl == 2){
            cell[6].xoro(m);
            cell[6].pl = m;
            win = true;
          }
          if (mouseX<adjx+(width-width/2.5+(width/12.8)/2) && mouseY<adjy+height && mouseX>adjx+(width/3.5+width/12.8) && mouseY>adjy+(height-height/2.5+(height/12.8)/2) && cell[7].pl == 2){
            cell[7].xoro(m);
            cell[7].pl = m;
            win = true;
          }
          if (mouseX<adjx+width && mouseY<adjy+height && mouseX>adjx+(width-width/2.5+(width/12.8)/2) && mouseY>adjy+(height-height/2.5+(height/12.8)/2) && cell[8].pl == 2){
            cell[8].xoro(m);
            cell[8].pl = m;
            win = true;
          }
          if (win == true){
            moves--;
          }
        }
    }
}

1 Like

Your sketch is getting stuck in an infinite loop! When you click, your mousePressed() function is called, and there’s a while loop in there that runs until win is no longer false.

Normally, win would get set to true by one of the blocks in a conditional statement inside the loop. But if you click a cell that is already occupied, then none of those conditions will ever be met!

You could simply fix this by removing the while loop… I don’t think it is useful anyway. Your code has several other major issues too, however, and so I feel they should also be addressed…

You have a Cells class, but this class represents just one cell, not many cells. So call your class Cell, not Cells.

Inside your Cell class would be a great place to have “was this Cell clicked on?” logic, but instead you have a mass of messy if statements in mousePressed(). Bleh.

Your draw() function is empty. But you are drawing things! You should do all your drawing in draw()!

This code is still not perfect - there is a lot you could clean up - but it’s certainly better (and fixes your click -> infinite loop issue):

class Cell {
  float x;
  float y; 
  int pl = 2;
  int count;

  Cell(float xpos, float ypos, int num) {
    x = xpos;
    y = ypos;
    count = num;
  }
  void draw() {
    strokeWeight(8);
    if (pl == 1) {
      stroke(255, 0, 0);
      line(width/42.6+x, height/42.6+y, width/3.87+x, height/3.87+y);
      line(width/42.6+x, height/3.87+y, width/3.87+x, height/42.6+y);
    } else if (pl == 0) {
      stroke(0, 0, 255);
      noFill();
      ellipse(width/7.1+x, height/7.1+y, width/4.26, height/4.26);
    }
  }
  void mousePressed(){
    if( over() && pl == 2 ){
      pl = turn;
      turn++;
      turn%=2;
    }
  }
  boolean over(){
    return(mouseX > x && mouseX < x + width/3.5 && mouseY > y && mouseY < y + height/3.5);
  }
}

Cell[] cells = new Cell[9];
int moves = 9;
float adjx, adjy;
boolean win = false;
int m;
int turn;

void setup() {
  //fullScreen();
  size(640, 640);
  if (width >= height) {
    adjx = (width - height)/2;
    adjy = 0;
    width=height;
  } else {
    adjy = (height - width)/2;
    adjx = 0;
    height=width;
  }
  cells[0] = new Cell(adjx+(width/12.8), adjy+(height/12.8), 0);
  cells[1] = new Cell(adjx+(width/3.5+width/12.8), adjy+(height/12.8), 1);
  cells[2] = new Cell(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height/12.8), 2);
  cells[3] = new Cell(adjx+(width/12.8), adjy+(height/3.5+height/12.8), 3);
  cells[4] = new Cell(adjx+(width/3.5+width/12.8), adjy+(height/3.5+height/12.8), 4);
  cells[5] = new Cell(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height/3.5+height/12.8), 5);
  cells[6] = new Cell(adjx+(width/12.8), adjy+(height-height/2.5+(height/12.8)/2), 6);
  cells[7] = new Cell(adjx+(width/3.5+width/12.8), adjy+(height-height/2.5+(height/12.8)/2), 7);
  cells[8] = new Cell(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height-height/2.5+(height/12.8)/2), 8);
}


void draw() {
  background(0);
  draw_board();
  for(int i=0;i<cells.length;cells[i++].draw());
}

void draw_board(){
  stroke(150);
  strokeWeight(1);
  line(adjx+(width/12.8), adjy+(height/3.5+height/12.8), adjx+(width-width/12.8), adjy+(height/3.5+height/12.8));
  line(adjx+(width/12.8), adjy+(height-height/2.5+(height/12.8)/2), adjx+(width-width/12.8), adjy+(height-height/2.5+(height/12.8)/2));
  line(adjx+(width/3.5+width/12.8), adjy+(height-height/12.8), adjx+(width/3.5+width/12.8), adjy+(height/12.8));
  line(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height-height/12.8), adjx+(width-width/2.5+(width/12.8)/2), adjy+(height/12.8));
  stroke(100);
  text("Press Esc to exit", adjx+(width/2-35), adjy+(height-height/128));
}

void mousePressed() {
  for(int i=0;i<cells.length;cells[i++].mousePressed());
}

Oh, that is really nice (especially the turn thing :P). So we are new to processing and programming generally. So could you please explain the return of the boolean over(). Thanks a lot really really helped.

P.S. You may freak out but our plan is after making the multiplayer version, ( which we have already actually made in python mode but it is really messy) we are planning to impor a neural network to play with the user. Propably with back propagation.

Oh, ok. never mind I understood the way of thinking. I was stuck with the x and y and then I realised I could have used them in such way. I will need your help though on something else.

void check(){
    stroke(255);
    strokeWeight(2);
    if (cells[0].pl==cells[1].pl && cells[1].pl==cells[2].pl){
        line(adjx+width/8,adjy+height/4.57,adjx+width-width/8,adjy+height/4.57);
        noLoop();
    }
    if (cells[3].pl==cells[4].pl && cells[4].pl==cells[5].pl){
        line(adjx+width/8,adjy+height/2,adjx+width-width/8,adjy+height/2);
        noLoop();
    }
    if (cells[6].pl==cells[7].pl && cells[7].pl==cells[8].pl){
        line(adjx+width/8,adjy+height-height/4.57,adjx+width-width/8,adjy+height-height/4.57);
        noLoop();
    }
    if (cells[0].pl==cells[4].pl && cells[4].pl==cells[8].pl){
        line(adjx+width/8,adjy+height/8,adjx+width-width/8,adjy+height-height/8);
        noLoop();
    }
    if (cells[2].pl==cells[4].pl && cells[4].pl==cells[6].pl){
        line(adjx+width-width/8,adjy+height/8,adjx+width/8,adjy+height-height/8);
        noLoop();
    }
    if (cells[0].pl==cells[3].pl && cells[3].pl==cells[6].pl){
        line(adjx+width/4.57,adjy+width/8,adjx+width/4.57,adjy+height-height/8);
        noLoop();
    }
    if (cells[1].pl==cells[4].pl && cells[4].pl==cells[7].pl){
        line(adjx+width/2,adjy+height/8,adjx+width/2,adjy+height-height/8);
        noLoop();
    }
    if (cells[2].pl==cells[5].pl && cells[5].pl==cells[8].pl){
        line(adjx+width-width/4.57,adjy+height/8,adjx+width-width/4.57,adjy+height-height/8);
        noLoop();
    }
}

You said it is better to try and draw anything inside the Draw() function. so could yoy please tell me how could I convert this function so I draw the line in the draw ?

also forgot to mention that I changed the pl and now for each cell it is the count of it + 10 so this funtion works properly

Instead of drawing things when you know they should appear, you need to have data that tells draw everything it should be drawing.

That is, instead of:

  1. We know we need to draw a thing!
  2. Draw the thing now!

Do:

  1. We know we need to draw a thing!
  2. Store or change a value in memory that draw() uses to know what to draw in a way that will cause this thing to be drawn.
  3. Make sure what draw() draws is based on the values stored in memory.

Here’s the same code as above, but with the “win lines” added. Notice that if a win line should be drawn or not is now stored in the new winLines array, and a function that draw() calls, draw_win_lines(), uses that array to know which lines to draw.

The values in this array are only updated when a win check occurs, and that check only needs to occur when the user has clicked (because a new piece might have been placed).

class Cell {
  float x;
  float y; 
  int pl = 2;
  int count;

  Cell(float xpos, float ypos, int num) {
    x = xpos;
    y = ypos;
    count = num;
  }
  void draw() {
    strokeWeight(8);
    if (pl == 1) {
      stroke(255, 0, 0);
      line(width/42.6+x, height/42.6+y, width/3.87+x, height/3.87+y);
      line(width/42.6+x, height/3.87+y, width/3.87+x, height/42.6+y);
    } else if (pl == 0) {
      stroke(0, 0, 255);
      noFill();
      ellipse(width/7.1+x, height/7.1+y, width/4.26, height/4.26);
    }
  }
  void mousePressed() {
    if ( over() && pl == 2 ) {
      pl = turn;
      turn++;
      turn%=2;
    }
  }
  boolean over() {
    return(mouseX > x && mouseX < x + width/3.5 && mouseY > y && mouseY < y + height/3.5);
  }
}

Cell[] cells = new Cell[9];
int moves = 9;
float adjx, adjy;
boolean win = false;
int m;
int turn;

void setup() {
  //fullScreen();
  size(640, 640);
  if (width >= height) {
    adjx = (width - height)/2;
    adjy = 0;
    width=height;
  } else {
    adjy = (height - width)/2;
    adjx = 0;
    height=width;
  }
  cells[0] = new Cell(adjx+(width/12.8), adjy+(height/12.8), 0);
  cells[1] = new Cell(adjx+(width/3.5+width/12.8), adjy+(height/12.8), 1);
  cells[2] = new Cell(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height/12.8), 2);
  cells[3] = new Cell(adjx+(width/12.8), adjy+(height/3.5+height/12.8), 3);
  cells[4] = new Cell(adjx+(width/3.5+width/12.8), adjy+(height/3.5+height/12.8), 4);
  cells[5] = new Cell(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height/3.5+height/12.8), 5);
  cells[6] = new Cell(adjx+(width/12.8), adjy+(height-height/2.5+(height/12.8)/2), 6);
  cells[7] = new Cell(adjx+(width/3.5+width/12.8), adjy+(height-height/2.5+(height/12.8)/2), 7);
  cells[8] = new Cell(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height-height/2.5+(height/12.8)/2), 8);
}


void draw() {
  background(0);
  draw_board();
  for (int i=0; i<cells.length; cells[i++].draw());
  draw_win_lines();
}

void draw_board() {
  stroke(150);
  strokeWeight(1);
  line(adjx+(width/12.8), adjy+(height/3.5+height/12.8), adjx+(width-width/12.8), adjy+(height/3.5+height/12.8));
  line(adjx+(width/12.8), adjy+(height-height/2.5+(height/12.8)/2), adjx+(width-width/12.8), adjy+(height-height/2.5+(height/12.8)/2));
  line(adjx+(width/3.5+width/12.8), adjy+(height-height/12.8), adjx+(width/3.5+width/12.8), adjy+(height/12.8));
  line(adjx+(width-width/2.5+(width/12.8)/2), adjy+(height-height/12.8), adjx+(width-width/2.5+(width/12.8)/2), adjy+(height/12.8));
  stroke(100);
  text("Press Esc to exit", adjx+(width/2-35), adjy+(height-height/128));
}

void mousePressed() {
  for (int i=0; i<cells.length; cells[i++].mousePressed());
  check_for_win();
}

boolean[] winLines = new boolean[8];

void draw_win_lines() {
  stroke(255);
  strokeWeight(2);
  for ( int i = 0; i<8; i++) {
    if ( winLines[i] ) { 
      switch( i ) {
      case 0:
        line(adjx+width/8, adjy+height/4.57, adjx+width-width/8, adjy+height/4.57);
        break;
      case 1:
        line(adjx+width/8, adjy+height/2, adjx+width-width/8, adjy+height/2);
        break;
      case 2:
        line(adjx+width/8, adjy+height-height/4.57, adjx+width-width/8, adjy+height-height/4.57);
        break;
      case 3:
        line(adjx+width/8, adjy+height/8, adjx+width-width/8, adjy+height-height/8);
        break;
      case 4:
        line(adjx+width-width/8, adjy+height/8, adjx+width/8, adjy+height-height/8);
        break;
      case 5:
        line(adjx+width/4.57, adjy+width/8, adjx+width/4.57, adjy+height-height/8);
        break;
      case 6:
        line(adjx+width/2, adjy+height/8, adjx+width/2, adjy+height-height/8);
        break;
      case 7:
        line(adjx+width-width/4.57, adjy+height/8, adjx+width-width/4.57, adjy+height-height/8);
        break;
      }
    }
  }
}

void check_for_win() {
  int[][] wins = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 4, 8}, {2, 4, 6}, {0, 3, 6}, {1, 4, 7}, {2, 5, 8}};
  for ( int i = 0; i<8; i++) {
    if ( cells[wins[i][0]].pl==cells[wins[i][1]].pl && cells[wins[i][1]].pl==cells[wins[i][2]].pl && cells[wins[i][0]].pl != 2 ) {
      winLines[i] = true;
    }
  }
}
1 Like

Wow, we didn’t evenknow you can make a boolean list… Ok so again thanks a lot .We might come in contact at some point again :stuck_out_tongue: