I am currently working on a schoolproject. I am developing a classic Tic-Tac-Toe Player vs. Computer in Processing.
My issue: I have tried to declare the minimax algorithm, however the Computer still follows a loop when making the next move instead of finding the best move. The minimax algorithm is in the Computer class.
Here are my classes:
Square[][] grid; //field
int row, col,turns;
float h,w,x,y; // used variables in methods
int scoreP = 0; // scorecounter player 1
int scoreC = 0; // scorecounter computer
String[] players = {"X","O"};
String winner;
String currentPlayer;
boolean play;
float w_button = 200; // play again button
float h_button = 40;
float x_button = 200;
float y_button = 650;
void setup(){
size(602,700);
row=3;
col=3;
grid = new Square[row][col];
startGame();
}
void draw(){
textSize(30);
text("Player: " + scoreP, 20, 25);
fill(255);
textSize(30);
text("Computer: " + scoreC, 400, 25);
fill(255);
if(play == true) {
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
grid[i][j].drawSymbol();
}
}
checkWinner();
computerPlays();
} else {
playAgainButton();
if(winner.equals(players[0])) {
println("You Win");
fill(0);
rect(120,0, 30,30);
scoreP += 1;
noLoop();
} else if (winner.equals(players[1])) {
println("Computer Wins");
fill(0);
rect(555,0, 30,30);
scoreC += 1;
noLoop();
} else if (winner == "") {
println("tie");
noLoop();
}
}
}
void mousePressed() {
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
grid[i][j].click();
}
}
if (mouseX > x_button && mouseX < x_button + w_button && mouseY > y_button && mouseY < y_button + h_button){
redraw();
loop();
startGame();
}
}
boolean isEqual(String a, String b, String c){ // checks if 3 fields are equal
return a == b && b == c && a != "";
}
void checkWinner(){
//horizontal
for(int i = 0; i < 3; i++){
if(isEqual(grid[i][0].val,grid[i][1].val,grid[i][2].val)){
play = false;
winner = grid[i][0].val;
}
}
//vertical
for(int i = 0; i < 3; i++){
if(isEqual(grid[0][i].val,grid[1][i].val,grid[2][i].val)){
play = false;
winner = grid[0][i].val;
}
}
//Diagonal
if(isEqual(grid[0][0].val,grid[1][1].val,grid[2][2].val)){
play = false;
winner = grid[0][0].val;
}
if(isEqual(grid[2][0].val,grid[1][1].val,grid[0][2].val)){
play = false;
winner = grid[2][0].val;
}
if(turns == 0 && winner.equals("")) {
play = false;
}
}
public void startGame() {
currentPlayer = players[0];
winner = "";
play = true;
turns = 9;
h = 600/3;
w = 600/3;
x = 0;
y = 35;
background(0);
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
grid[i][j] = new Square(x, y, w, h);
x += w;
}
y += h;
x = 0;
}
}
void computerPlays() {
Computer c = new Computer();
if("O".equals(currentPlayer) && turns != 0) {
Move m = c.findBestMove();
grid[m.row][m.col].val = "O";
turns--;
currentPlayer = "X";
}
}
void playAgainButton(){
fill(200);
stroke(200);
rect(x_button, y_button, w_button, h_button);
stroke(0);
fill(0);
text("PLAY AGAIN", x_button+15, y_button+30);
fill(255);
}
Computer class
public class Computer {
public ArrayList<Move> getAvailableSpace() {
ArrayList<Move> availableSpace = new ArrayList<Move>();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (grid[i][j].val == "") {
availableSpace.add(new Move(i, j));
}
}
}
return availableSpace;
}
public int minimax() {
int score;
if(winner != null) {
if(winner == "O") {
score = 1;
return score;
} else if (winner == "") {
score = 0;
return score;
} else {
score = -1;
return score;
}
}
int computerCount = 0;
int humanCount = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if(grid[i][j].val == "O") {
computerCount++;
} else if (grid[i][j].val == "X") {
humanCount++;
}
}
}
int bestScore;
if(humanCount > computerCount) {
bestScore = -1;
} else {
bestScore = 1;
}
for(Move m : getAvailableSpace()) {
if(humanCount > computerCount) {
grid[m.row][m.col].val = "O";
} else {
grid[m.row][m.col].val = "X";
}
int currentScore = minimax();
grid[m.row][m.col].val = "";
if(humanCount > computerCount ? currentScore > bestScore : currentScore < bestScore) {
bestScore = currentScore;
}
}
return bestScore;
}
public Move findBestMove() {
int bestScore = -100;
Move bestMove = new Move();
for(Move m : getAvailableSpace()) {
grid[m.row][m.col].val = "O";
int score = minimax();
grid[m.row][m.col].val = "";
if(score > bestScore) {
bestScore = score;
bestMove = m;
}
}
return bestMove;
}
}
Move class:
public class Move {
int row;
int col;
public Move() {
}
public Move(int row, int col) {
this.row = row;
this.col = col;
}
}
Square class
public class Square {
float x, y, w, h;
String val;
public Square(float x, float y, float w, float h) {
this.h = h;
this.w = w;
this.x = x;
this.y = y;
val = "";
}
void drawSymbol() {
rect(x, y, w, h);
if("X".equals(val)) {
line(this.x, this.y, this.x+this.w-1, this.y+this.w-1);
line(this.x, this.y+this.w-1, this.x+this.w-1, this.y);
} else if ("O".equals(val)) {
noFill();
ellipse(this.x + (this.w/2), this.y + (this.h/2),this.w,this.w);
}
}
void click() {
if(mouseX > x && mouseX < x + w && mouseY > y && mouseY < y + h) {
if("".equals(val) && "X".equals(currentPlayer)) {
val = "X";
currentPlayer = "O";
turns--;
}
}
}
}
What am I doing wrong?