Java Minimax Tic-Tac-Toe Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Tic-tac-toe in SQL with optimal AITic-Tac-Toe game using erlang gen_fsmTic Tac Toe in JavaComputing all Tic-Tac-Toe movesTic Tac Toe Player written in PythonCallback-oriented Tic-Tac-ToeA Tic-Tac-Toe game in MonoGameModularized Tic Tac Toe in CC++/SDL2 Tic-Tac-ToeSimple text-based tic-tac-toe

What did Darwin mean by 'squib' here?

Two different pronunciation of "понял"

Is it possible to ask for a hotel room without minibar/extra services?

Working around an AWS network ACL rule limit

Fishing simulator

Do working physicists consider Newtonian mechanics to be "falsified"?

Antler Helmet: Can it work?

How do you clear the ApexPages.getMessages() collection in a test?

How are presidential pardons supposed to be used?

Estimated State payment too big --> money back; + 2018 Tax Reform

Need a suitable toxic chemical for a murder plot in my novel

I'm thinking of a number

Can smartphones with the same camera sensor have different image quality?

What is the largest species of polychaete?

How should I respond to a player wanting to catch a sword between their hands?

Why don't the Weasley twins use magic outside of school if the Trace can only find the location of spells cast?

What was the last x86 CPU that did not have the x87 floating-point unit built in?

What items from the Roman-age tech-level could be used to deter all creatures from entering a small area?

What kind of display is this?

How can I make names more distinctive without making them longer?

How does modal jazz use chord progressions?

Stars Make Stars

How to rotate it perfectly?

What computer would be fastest for Mathematica Home Edition?



Java Minimax Tic-Tac-Toe



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Tic-tac-toe in SQL with optimal AITic-Tac-Toe game using erlang gen_fsmTic Tac Toe in JavaComputing all Tic-Tac-Toe movesTic Tac Toe Player written in PythonCallback-oriented Tic-Tac-ToeA Tic-Tac-Toe game in MonoGameModularized Tic Tac Toe in CC++/SDL2 Tic-Tac-ToeSimple text-based tic-tac-toe



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








0












$begingroup$


I've been researching the minimax algorithm and how it's implemented in Tic-Tac-Toe. But for whatever reason, it loses, on average, 15% of the games against a random bot. Could someone help me figure out what's wrong with my algorithm?



Note: GameController.java, the 'middle man' between TicTacToe.java and my bot, calls the playTurn function in EustorgiusSylwester.java, and expects a integer array of length 2 with the coordinates.



EustorgiusSylwester.java (the bot)



// 0 = empty
// 1 = X
// 2 = O
public class EustorgiusSylwester extends TicTacToePlayer
public EustorgiusSylwester(String aName, int aPiece)
super(aName, aPiece);

public static int getOpp(int p)
return ((p == 1) ? 2 : 1);

public static int min(int a, int b)
return (a < b) ? a : b;

public static int max(int a, int b)
return (a > b) ? a : b;

public static void printBoard(int[][] b)
for(int[] x: b)
for(int y: x)
if(y == 1)
System.out.print('X');
else if(y == 2)
System.out.print('O');
else
System.out.print('_');


System.out.println();


public static boolean won(int[][] b, int p)
for(int[] x: b)
if(x[0] == x[1] && x[1] == x[2] && x[0] == p)
return true;


for(int i = 0; i < b.length; i++)
for(int j = 0; j < b[i].length; j++)
if(b[0][j] == b[1][j] && b[1][j] == b[2][j] && b[1][j] == p)
return true;



if(b[0][0] == b[1][1] && b[0][0] == b[2][2] && b[0][0] == p)
return true;

if(b[2][0] == b[1][1] && b[2][0] == b[0][2] && b[0][2] == p)
return true;

return false;

public static boolean drawn(int[][] b)
for(int[] x: b)
for(int y: x)
if(y == 0)
return false;



return true;

// -------------------------------------
public static int eval(int[][] board, int depth, int p, int ai)
if(won(board, p))
return 10 - depth++;
else if(won(board, getOpp(p)))
return -10 + depth++;
else if(drawn(board))
return 0 - depth++;

if(p == ai)
int best = -10000;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
if(board[i][j] != 0)
continue;

board[i][j] = p;
best = max(best, eval(board, depth++, getOpp(p), ai) - depth);
board[i][j] = 0;


return best;
else
int best = 10000;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
if(board[i][j] != 0)
continue;

board[i][j] = p;
best = min(best, eval(board, depth++, getOpp(p), ai) + depth);
board[i][j] = 0;


return best;


@Override
public int[] playTurn()
int[][] b = GameController.game.getBoard();
int p = getPiece();
int bmI = 0;
int bmJ = 0;
int bmEval = -10000;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
if(b[i][j] != 0)
continue;

b[i][j] = p;
int eval = eval(b, 0, p, getPiece());
b[i][j] = 0;
if(eval > bmEval)
bmI = i;
bmJ = j;
bmEval = eval;



printBoard(b);
System.out.println();
return new int[] bmI, bmJ;






GameController.java



//This class's job is to coordinate between the players and the game code, it is the middle man
//A game object is created, followed by two player objects, then the game is run as the players
//take turns and interact with the game code.

//**THIS IS THE FILE YOU RUN TO PLAY THE GAME**//

import java.util.Scanner;

public class GameController

// **PLAYERS ARE SET UP HERE**//
// To test your bot, replace one of the human players with your bot and play
// against it
// p1 is X and goes first
private static TicTacToePlayer p1 = new RandomPlayer("Joe", 1);
private static TicTacToePlayer p2 = new EustorgiusSylwester("Paul", 2);

// Copy of the board from TicTacToe.java for players to access
private static int[][] board;
private static int turnTimer = 0;

// initialize the game
public static TicTacToe game = new TicTacToe();

// gets a copy of the game board
public static int[][] getBoard()
board = game.getBoard();

return board;


public static int getTurnCount()
return turnTimer;


// plays a single game, returns the number of the player who won, 3 if tie
private static int playGame()
turnTimer = 0;
// game plays
int state = 0; // 0 = ongoing, 1 = X win, 2 = O win, 3 = tie
while (state == 0)
game.placePiece(p1.playTurn(), 1); // x player goes
turnTimer++;

// check state after X goes to see if the game ended
state = game.gameOver();
if (state != 0)
break;


game.placePiece(p2.playTurn(), 2); // O player goes
turnTimer++;

state = game.gameOver(); // update state after O goes, while loop condition will handle the check

if (turnTimer > 50)
state = 3;
System.out.println("Max Turns reached, game ending.");



// declare winner
if (state == 1)
System.out.println(p1.getName() + " Won!");
return 1;
else if (state == 2)
System.out.println(p2.getName() + " Won!");
return 2;
else
System.out.println("Draw");
return 3;




public static void main(String[] args)
System.out.println("+++++++++++++++++++++++");
System.out.println(p1.getName() + " VS " + p2.getName());
System.out.println("+++++++++++++++++++++++" + "n");

System.out.println("How Many Games?");
Scanner s = new Scanner(System.in);
int numGames = s.nextInt();
System.out.println("BEGINn");

int p1Victories = 0;
int p2Victories = 0;
int ties = 0;
int curWinner = 0;
for (int i = 0; i < numGames; i++)
curWinner = playGame();
if (curWinner == 1)
p1Victories++;
else if (curWinner == 2)
p2Victories++;
else
ties++;


// resets the board before the next game is played
game.resetBoard();


System.out.println("n++++++++++++");
System.out.println("FINAL TALLY");
System.out.println("++++++++++++");
System.out.println(p1.getName() + " Won " + p1Victories + " Games!");
System.out.println(p2.getName() + " Won " + p2Victories + " Games!");
System.out.println("There were " + ties + " Tie Games!");
s.close();






TicTacToe.java



/* This is the main class that contains code for the game
*
* Empty space will be represented by a 0
* X's will be represented by a 1
* O's will be represented by a 2
* Anything higher (3+) or lower (-1-) should not be added to the board
*/

public class TicTacToe

private int[][] board; //the TicTacToe board, private to avoid cheating


public TicTacToe()
board = new int[3][3];


//given a row and column, determine if placing a piece there is valid
//the space must be within the bounds of the board, AND empty
//return true if it is a legal move, false if illegal
private boolean isLegalMove(int row, int column) column >= 3)
return false;

if (board[row][column] != 0)
return false;

return true;


//this method will place a game piece (X or 0) at the row/column
//piece will be 1 for an X, 2 for an O
//*IMPORTANT* make sure the move is legal first, don't trust the AI to submit a valid move
//moves are submitted as a length 2 integer array, first number is the row, second is the column
public void placePiece(int[] move, int piece)
//if a null move is submitted, exit skipping the player's turn
if (move == null)
System.out.println("Illegal Move Attempted");
return;

int row = move[0];
int column = move[1];
if (isLegalMove(row, column))
board[row][column] = piece;

else
System.out.println("Illegal Move Attempted");




//print out the current board state so the humans can read it
public void printBoard()
int current = 0;
for (int i = 0; i < 3; i ++) ");
for (int j = 0; j < 3; j++)
current = board[i][j];
if (current == 0)
System.out.print(" " + "
else if (current == 1) ");

else if (current == 2) ");


System.out.println();




//examines the current board and determines if the game is over
//returns 0 if the game is still going
//returns 1 if X player wins
//returns 2 if O player wins
//returns 3 if the game is a tie
public int gameOver()

for (int i = 0; i < 3; i++)

//if no player has 3 in a row, check for tie
for (int i = 0; i < 3; i ++)
for (int j = 0; j < 3; j++)
if (board[i][j] == 0)
return 0; //there is an empty space on the board, game is still going.

//Yes I know sometimes draws are inevitable even if there are squares
//left, but that is outside the scope of this challenge.




//The game has tied
return 3;


//returns the number of spaces a given player occupies in a given row
//row is the row to check, 0 = first, 1 = second, 2 = third
//player will be 1 for X player 2 for O player
public int getRowCount(int row, int player)
int counter = 0;
for (int i = 0; i < 3; i++)
if (board[row][i] == player)
counter++;



return counter;


//same as getRowCount but for columns
public int getColumnCount(int column, int player)
int counter = 0;
for (int i = 0; i < 3; i++)
if (board[i][column] == player)
counter++;



return counter;


//checks if the given player has 3 in a row diagonal
public boolean getDiagonal(int player)
//left to right diagonal
if (board[0][0] == player && board[1][1] == player && board [2][2] == player)
return true;

//right to left diagonal
if (board[0][2] == player && board[1][1] == player && board [2][0] == player)
return true;

return false;


//returns a COPY of the current board for the AI's to read
//This prevents AI's from having direct access to the board, to cheat for example
public int[][] getBoard()
int[][] boardCopy = new int[3][3];
for (int i = 0; i < board.length; i++)
for (int j = 0; j < board[0].length; j++)
boardCopy[i][j] = board[i][j];


return boardCopy;


//resets the board to all 0s (empty)
public void resetBoard()
for(int i = 0; i < board.length; i++)
for (int j = 0; j < board[0].length; j++)
board[i][j] = 0;







TicTacToePlayer.java



//Defines general behavior of all players (AI and Human)
public abstract class TicTacToePlayer
private String name; //Player's name
private int piece; //Piece type, 1 = X, 2 = O

public TicTacToePlayer(String aName, int aPiece)
name = aName;
piece = aPiece;


public String getName()
return name;


public int getPiece()
return piece;


//All players must be able to play a turn
public abstract int[] playTurn();










share







New contributor




simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$


















    0












    $begingroup$


    I've been researching the minimax algorithm and how it's implemented in Tic-Tac-Toe. But for whatever reason, it loses, on average, 15% of the games against a random bot. Could someone help me figure out what's wrong with my algorithm?



    Note: GameController.java, the 'middle man' between TicTacToe.java and my bot, calls the playTurn function in EustorgiusSylwester.java, and expects a integer array of length 2 with the coordinates.



    EustorgiusSylwester.java (the bot)



    // 0 = empty
    // 1 = X
    // 2 = O
    public class EustorgiusSylwester extends TicTacToePlayer
    public EustorgiusSylwester(String aName, int aPiece)
    super(aName, aPiece);

    public static int getOpp(int p)
    return ((p == 1) ? 2 : 1);

    public static int min(int a, int b)
    return (a < b) ? a : b;

    public static int max(int a, int b)
    return (a > b) ? a : b;

    public static void printBoard(int[][] b)
    for(int[] x: b)
    for(int y: x)
    if(y == 1)
    System.out.print('X');
    else if(y == 2)
    System.out.print('O');
    else
    System.out.print('_');


    System.out.println();


    public static boolean won(int[][] b, int p)
    for(int[] x: b)
    if(x[0] == x[1] && x[1] == x[2] && x[0] == p)
    return true;


    for(int i = 0; i < b.length; i++)
    for(int j = 0; j < b[i].length; j++)
    if(b[0][j] == b[1][j] && b[1][j] == b[2][j] && b[1][j] == p)
    return true;



    if(b[0][0] == b[1][1] && b[0][0] == b[2][2] && b[0][0] == p)
    return true;

    if(b[2][0] == b[1][1] && b[2][0] == b[0][2] && b[0][2] == p)
    return true;

    return false;

    public static boolean drawn(int[][] b)
    for(int[] x: b)
    for(int y: x)
    if(y == 0)
    return false;



    return true;

    // -------------------------------------
    public static int eval(int[][] board, int depth, int p, int ai)
    if(won(board, p))
    return 10 - depth++;
    else if(won(board, getOpp(p)))
    return -10 + depth++;
    else if(drawn(board))
    return 0 - depth++;

    if(p == ai)
    int best = -10000;
    for(int i = 0; i < 3; i++)
    for(int j = 0; j < 3; j++)
    if(board[i][j] != 0)
    continue;

    board[i][j] = p;
    best = max(best, eval(board, depth++, getOpp(p), ai) - depth);
    board[i][j] = 0;


    return best;
    else
    int best = 10000;
    for(int i = 0; i < 3; i++)
    for(int j = 0; j < 3; j++)
    if(board[i][j] != 0)
    continue;

    board[i][j] = p;
    best = min(best, eval(board, depth++, getOpp(p), ai) + depth);
    board[i][j] = 0;


    return best;


    @Override
    public int[] playTurn()
    int[][] b = GameController.game.getBoard();
    int p = getPiece();
    int bmI = 0;
    int bmJ = 0;
    int bmEval = -10000;
    for(int i = 0; i < 3; i++)
    for(int j = 0; j < 3; j++)
    if(b[i][j] != 0)
    continue;

    b[i][j] = p;
    int eval = eval(b, 0, p, getPiece());
    b[i][j] = 0;
    if(eval > bmEval)
    bmI = i;
    bmJ = j;
    bmEval = eval;



    printBoard(b);
    System.out.println();
    return new int[] bmI, bmJ;






    GameController.java



    //This class's job is to coordinate between the players and the game code, it is the middle man
    //A game object is created, followed by two player objects, then the game is run as the players
    //take turns and interact with the game code.

    //**THIS IS THE FILE YOU RUN TO PLAY THE GAME**//

    import java.util.Scanner;

    public class GameController

    // **PLAYERS ARE SET UP HERE**//
    // To test your bot, replace one of the human players with your bot and play
    // against it
    // p1 is X and goes first
    private static TicTacToePlayer p1 = new RandomPlayer("Joe", 1);
    private static TicTacToePlayer p2 = new EustorgiusSylwester("Paul", 2);

    // Copy of the board from TicTacToe.java for players to access
    private static int[][] board;
    private static int turnTimer = 0;

    // initialize the game
    public static TicTacToe game = new TicTacToe();

    // gets a copy of the game board
    public static int[][] getBoard()
    board = game.getBoard();

    return board;


    public static int getTurnCount()
    return turnTimer;


    // plays a single game, returns the number of the player who won, 3 if tie
    private static int playGame()
    turnTimer = 0;
    // game plays
    int state = 0; // 0 = ongoing, 1 = X win, 2 = O win, 3 = tie
    while (state == 0)
    game.placePiece(p1.playTurn(), 1); // x player goes
    turnTimer++;

    // check state after X goes to see if the game ended
    state = game.gameOver();
    if (state != 0)
    break;


    game.placePiece(p2.playTurn(), 2); // O player goes
    turnTimer++;

    state = game.gameOver(); // update state after O goes, while loop condition will handle the check

    if (turnTimer > 50)
    state = 3;
    System.out.println("Max Turns reached, game ending.");



    // declare winner
    if (state == 1)
    System.out.println(p1.getName() + " Won!");
    return 1;
    else if (state == 2)
    System.out.println(p2.getName() + " Won!");
    return 2;
    else
    System.out.println("Draw");
    return 3;




    public static void main(String[] args)
    System.out.println("+++++++++++++++++++++++");
    System.out.println(p1.getName() + " VS " + p2.getName());
    System.out.println("+++++++++++++++++++++++" + "n");

    System.out.println("How Many Games?");
    Scanner s = new Scanner(System.in);
    int numGames = s.nextInt();
    System.out.println("BEGINn");

    int p1Victories = 0;
    int p2Victories = 0;
    int ties = 0;
    int curWinner = 0;
    for (int i = 0; i < numGames; i++)
    curWinner = playGame();
    if (curWinner == 1)
    p1Victories++;
    else if (curWinner == 2)
    p2Victories++;
    else
    ties++;


    // resets the board before the next game is played
    game.resetBoard();


    System.out.println("n++++++++++++");
    System.out.println("FINAL TALLY");
    System.out.println("++++++++++++");
    System.out.println(p1.getName() + " Won " + p1Victories + " Games!");
    System.out.println(p2.getName() + " Won " + p2Victories + " Games!");
    System.out.println("There were " + ties + " Tie Games!");
    s.close();






    TicTacToe.java



    /* This is the main class that contains code for the game
    *
    * Empty space will be represented by a 0
    * X's will be represented by a 1
    * O's will be represented by a 2
    * Anything higher (3+) or lower (-1-) should not be added to the board
    */

    public class TicTacToe

    private int[][] board; //the TicTacToe board, private to avoid cheating


    public TicTacToe()
    board = new int[3][3];


    //given a row and column, determine if placing a piece there is valid
    //the space must be within the bounds of the board, AND empty
    //return true if it is a legal move, false if illegal
    private boolean isLegalMove(int row, int column) column >= 3)
    return false;

    if (board[row][column] != 0)
    return false;

    return true;


    //this method will place a game piece (X or 0) at the row/column
    //piece will be 1 for an X, 2 for an O
    //*IMPORTANT* make sure the move is legal first, don't trust the AI to submit a valid move
    //moves are submitted as a length 2 integer array, first number is the row, second is the column
    public void placePiece(int[] move, int piece)
    //if a null move is submitted, exit skipping the player's turn
    if (move == null)
    System.out.println("Illegal Move Attempted");
    return;

    int row = move[0];
    int column = move[1];
    if (isLegalMove(row, column))
    board[row][column] = piece;

    else
    System.out.println("Illegal Move Attempted");




    //print out the current board state so the humans can read it
    public void printBoard()
    int current = 0;
    for (int i = 0; i < 3; i ++) ");
    for (int j = 0; j < 3; j++)
    current = board[i][j];
    if (current == 0)
    System.out.print(" " + "
    else if (current == 1) ");

    else if (current == 2) ");


    System.out.println();




    //examines the current board and determines if the game is over
    //returns 0 if the game is still going
    //returns 1 if X player wins
    //returns 2 if O player wins
    //returns 3 if the game is a tie
    public int gameOver()

    for (int i = 0; i < 3; i++)

    //if no player has 3 in a row, check for tie
    for (int i = 0; i < 3; i ++)
    for (int j = 0; j < 3; j++)
    if (board[i][j] == 0)
    return 0; //there is an empty space on the board, game is still going.

    //Yes I know sometimes draws are inevitable even if there are squares
    //left, but that is outside the scope of this challenge.




    //The game has tied
    return 3;


    //returns the number of spaces a given player occupies in a given row
    //row is the row to check, 0 = first, 1 = second, 2 = third
    //player will be 1 for X player 2 for O player
    public int getRowCount(int row, int player)
    int counter = 0;
    for (int i = 0; i < 3; i++)
    if (board[row][i] == player)
    counter++;



    return counter;


    //same as getRowCount but for columns
    public int getColumnCount(int column, int player)
    int counter = 0;
    for (int i = 0; i < 3; i++)
    if (board[i][column] == player)
    counter++;



    return counter;


    //checks if the given player has 3 in a row diagonal
    public boolean getDiagonal(int player)
    //left to right diagonal
    if (board[0][0] == player && board[1][1] == player && board [2][2] == player)
    return true;

    //right to left diagonal
    if (board[0][2] == player && board[1][1] == player && board [2][0] == player)
    return true;

    return false;


    //returns a COPY of the current board for the AI's to read
    //This prevents AI's from having direct access to the board, to cheat for example
    public int[][] getBoard()
    int[][] boardCopy = new int[3][3];
    for (int i = 0; i < board.length; i++)
    for (int j = 0; j < board[0].length; j++)
    boardCopy[i][j] = board[i][j];


    return boardCopy;


    //resets the board to all 0s (empty)
    public void resetBoard()
    for(int i = 0; i < board.length; i++)
    for (int j = 0; j < board[0].length; j++)
    board[i][j] = 0;







    TicTacToePlayer.java



    //Defines general behavior of all players (AI and Human)
    public abstract class TicTacToePlayer
    private String name; //Player's name
    private int piece; //Piece type, 1 = X, 2 = O

    public TicTacToePlayer(String aName, int aPiece)
    name = aName;
    piece = aPiece;


    public String getName()
    return name;


    public int getPiece()
    return piece;


    //All players must be able to play a turn
    public abstract int[] playTurn();










    share







    New contributor




    simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$














      0












      0








      0





      $begingroup$


      I've been researching the minimax algorithm and how it's implemented in Tic-Tac-Toe. But for whatever reason, it loses, on average, 15% of the games against a random bot. Could someone help me figure out what's wrong with my algorithm?



      Note: GameController.java, the 'middle man' between TicTacToe.java and my bot, calls the playTurn function in EustorgiusSylwester.java, and expects a integer array of length 2 with the coordinates.



      EustorgiusSylwester.java (the bot)



      // 0 = empty
      // 1 = X
      // 2 = O
      public class EustorgiusSylwester extends TicTacToePlayer
      public EustorgiusSylwester(String aName, int aPiece)
      super(aName, aPiece);

      public static int getOpp(int p)
      return ((p == 1) ? 2 : 1);

      public static int min(int a, int b)
      return (a < b) ? a : b;

      public static int max(int a, int b)
      return (a > b) ? a : b;

      public static void printBoard(int[][] b)
      for(int[] x: b)
      for(int y: x)
      if(y == 1)
      System.out.print('X');
      else if(y == 2)
      System.out.print('O');
      else
      System.out.print('_');


      System.out.println();


      public static boolean won(int[][] b, int p)
      for(int[] x: b)
      if(x[0] == x[1] && x[1] == x[2] && x[0] == p)
      return true;


      for(int i = 0; i < b.length; i++)
      for(int j = 0; j < b[i].length; j++)
      if(b[0][j] == b[1][j] && b[1][j] == b[2][j] && b[1][j] == p)
      return true;



      if(b[0][0] == b[1][1] && b[0][0] == b[2][2] && b[0][0] == p)
      return true;

      if(b[2][0] == b[1][1] && b[2][0] == b[0][2] && b[0][2] == p)
      return true;

      return false;

      public static boolean drawn(int[][] b)
      for(int[] x: b)
      for(int y: x)
      if(y == 0)
      return false;



      return true;

      // -------------------------------------
      public static int eval(int[][] board, int depth, int p, int ai)
      if(won(board, p))
      return 10 - depth++;
      else if(won(board, getOpp(p)))
      return -10 + depth++;
      else if(drawn(board))
      return 0 - depth++;

      if(p == ai)
      int best = -10000;
      for(int i = 0; i < 3; i++)
      for(int j = 0; j < 3; j++)
      if(board[i][j] != 0)
      continue;

      board[i][j] = p;
      best = max(best, eval(board, depth++, getOpp(p), ai) - depth);
      board[i][j] = 0;


      return best;
      else
      int best = 10000;
      for(int i = 0; i < 3; i++)
      for(int j = 0; j < 3; j++)
      if(board[i][j] != 0)
      continue;

      board[i][j] = p;
      best = min(best, eval(board, depth++, getOpp(p), ai) + depth);
      board[i][j] = 0;


      return best;


      @Override
      public int[] playTurn()
      int[][] b = GameController.game.getBoard();
      int p = getPiece();
      int bmI = 0;
      int bmJ = 0;
      int bmEval = -10000;
      for(int i = 0; i < 3; i++)
      for(int j = 0; j < 3; j++)
      if(b[i][j] != 0)
      continue;

      b[i][j] = p;
      int eval = eval(b, 0, p, getPiece());
      b[i][j] = 0;
      if(eval > bmEval)
      bmI = i;
      bmJ = j;
      bmEval = eval;



      printBoard(b);
      System.out.println();
      return new int[] bmI, bmJ;






      GameController.java



      //This class's job is to coordinate between the players and the game code, it is the middle man
      //A game object is created, followed by two player objects, then the game is run as the players
      //take turns and interact with the game code.

      //**THIS IS THE FILE YOU RUN TO PLAY THE GAME**//

      import java.util.Scanner;

      public class GameController

      // **PLAYERS ARE SET UP HERE**//
      // To test your bot, replace one of the human players with your bot and play
      // against it
      // p1 is X and goes first
      private static TicTacToePlayer p1 = new RandomPlayer("Joe", 1);
      private static TicTacToePlayer p2 = new EustorgiusSylwester("Paul", 2);

      // Copy of the board from TicTacToe.java for players to access
      private static int[][] board;
      private static int turnTimer = 0;

      // initialize the game
      public static TicTacToe game = new TicTacToe();

      // gets a copy of the game board
      public static int[][] getBoard()
      board = game.getBoard();

      return board;


      public static int getTurnCount()
      return turnTimer;


      // plays a single game, returns the number of the player who won, 3 if tie
      private static int playGame()
      turnTimer = 0;
      // game plays
      int state = 0; // 0 = ongoing, 1 = X win, 2 = O win, 3 = tie
      while (state == 0)
      game.placePiece(p1.playTurn(), 1); // x player goes
      turnTimer++;

      // check state after X goes to see if the game ended
      state = game.gameOver();
      if (state != 0)
      break;


      game.placePiece(p2.playTurn(), 2); // O player goes
      turnTimer++;

      state = game.gameOver(); // update state after O goes, while loop condition will handle the check

      if (turnTimer > 50)
      state = 3;
      System.out.println("Max Turns reached, game ending.");



      // declare winner
      if (state == 1)
      System.out.println(p1.getName() + " Won!");
      return 1;
      else if (state == 2)
      System.out.println(p2.getName() + " Won!");
      return 2;
      else
      System.out.println("Draw");
      return 3;




      public static void main(String[] args)
      System.out.println("+++++++++++++++++++++++");
      System.out.println(p1.getName() + " VS " + p2.getName());
      System.out.println("+++++++++++++++++++++++" + "n");

      System.out.println("How Many Games?");
      Scanner s = new Scanner(System.in);
      int numGames = s.nextInt();
      System.out.println("BEGINn");

      int p1Victories = 0;
      int p2Victories = 0;
      int ties = 0;
      int curWinner = 0;
      for (int i = 0; i < numGames; i++)
      curWinner = playGame();
      if (curWinner == 1)
      p1Victories++;
      else if (curWinner == 2)
      p2Victories++;
      else
      ties++;


      // resets the board before the next game is played
      game.resetBoard();


      System.out.println("n++++++++++++");
      System.out.println("FINAL TALLY");
      System.out.println("++++++++++++");
      System.out.println(p1.getName() + " Won " + p1Victories + " Games!");
      System.out.println(p2.getName() + " Won " + p2Victories + " Games!");
      System.out.println("There were " + ties + " Tie Games!");
      s.close();






      TicTacToe.java



      /* This is the main class that contains code for the game
      *
      * Empty space will be represented by a 0
      * X's will be represented by a 1
      * O's will be represented by a 2
      * Anything higher (3+) or lower (-1-) should not be added to the board
      */

      public class TicTacToe

      private int[][] board; //the TicTacToe board, private to avoid cheating


      public TicTacToe()
      board = new int[3][3];


      //given a row and column, determine if placing a piece there is valid
      //the space must be within the bounds of the board, AND empty
      //return true if it is a legal move, false if illegal
      private boolean isLegalMove(int row, int column) column >= 3)
      return false;

      if (board[row][column] != 0)
      return false;

      return true;


      //this method will place a game piece (X or 0) at the row/column
      //piece will be 1 for an X, 2 for an O
      //*IMPORTANT* make sure the move is legal first, don't trust the AI to submit a valid move
      //moves are submitted as a length 2 integer array, first number is the row, second is the column
      public void placePiece(int[] move, int piece)
      //if a null move is submitted, exit skipping the player's turn
      if (move == null)
      System.out.println("Illegal Move Attempted");
      return;

      int row = move[0];
      int column = move[1];
      if (isLegalMove(row, column))
      board[row][column] = piece;

      else
      System.out.println("Illegal Move Attempted");




      //print out the current board state so the humans can read it
      public void printBoard()
      int current = 0;
      for (int i = 0; i < 3; i ++) ");
      for (int j = 0; j < 3; j++)
      current = board[i][j];
      if (current == 0)
      System.out.print(" " + "
      else if (current == 1) ");

      else if (current == 2) ");


      System.out.println();




      //examines the current board and determines if the game is over
      //returns 0 if the game is still going
      //returns 1 if X player wins
      //returns 2 if O player wins
      //returns 3 if the game is a tie
      public int gameOver()

      for (int i = 0; i < 3; i++)

      //if no player has 3 in a row, check for tie
      for (int i = 0; i < 3; i ++)
      for (int j = 0; j < 3; j++)
      if (board[i][j] == 0)
      return 0; //there is an empty space on the board, game is still going.

      //Yes I know sometimes draws are inevitable even if there are squares
      //left, but that is outside the scope of this challenge.




      //The game has tied
      return 3;


      //returns the number of spaces a given player occupies in a given row
      //row is the row to check, 0 = first, 1 = second, 2 = third
      //player will be 1 for X player 2 for O player
      public int getRowCount(int row, int player)
      int counter = 0;
      for (int i = 0; i < 3; i++)
      if (board[row][i] == player)
      counter++;



      return counter;


      //same as getRowCount but for columns
      public int getColumnCount(int column, int player)
      int counter = 0;
      for (int i = 0; i < 3; i++)
      if (board[i][column] == player)
      counter++;



      return counter;


      //checks if the given player has 3 in a row diagonal
      public boolean getDiagonal(int player)
      //left to right diagonal
      if (board[0][0] == player && board[1][1] == player && board [2][2] == player)
      return true;

      //right to left diagonal
      if (board[0][2] == player && board[1][1] == player && board [2][0] == player)
      return true;

      return false;


      //returns a COPY of the current board for the AI's to read
      //This prevents AI's from having direct access to the board, to cheat for example
      public int[][] getBoard()
      int[][] boardCopy = new int[3][3];
      for (int i = 0; i < board.length; i++)
      for (int j = 0; j < board[0].length; j++)
      boardCopy[i][j] = board[i][j];


      return boardCopy;


      //resets the board to all 0s (empty)
      public void resetBoard()
      for(int i = 0; i < board.length; i++)
      for (int j = 0; j < board[0].length; j++)
      board[i][j] = 0;







      TicTacToePlayer.java



      //Defines general behavior of all players (AI and Human)
      public abstract class TicTacToePlayer
      private String name; //Player's name
      private int piece; //Piece type, 1 = X, 2 = O

      public TicTacToePlayer(String aName, int aPiece)
      name = aName;
      piece = aPiece;


      public String getName()
      return name;


      public int getPiece()
      return piece;


      //All players must be able to play a turn
      public abstract int[] playTurn();










      share







      New contributor




      simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      I've been researching the minimax algorithm and how it's implemented in Tic-Tac-Toe. But for whatever reason, it loses, on average, 15% of the games against a random bot. Could someone help me figure out what's wrong with my algorithm?



      Note: GameController.java, the 'middle man' between TicTacToe.java and my bot, calls the playTurn function in EustorgiusSylwester.java, and expects a integer array of length 2 with the coordinates.



      EustorgiusSylwester.java (the bot)



      // 0 = empty
      // 1 = X
      // 2 = O
      public class EustorgiusSylwester extends TicTacToePlayer
      public EustorgiusSylwester(String aName, int aPiece)
      super(aName, aPiece);

      public static int getOpp(int p)
      return ((p == 1) ? 2 : 1);

      public static int min(int a, int b)
      return (a < b) ? a : b;

      public static int max(int a, int b)
      return (a > b) ? a : b;

      public static void printBoard(int[][] b)
      for(int[] x: b)
      for(int y: x)
      if(y == 1)
      System.out.print('X');
      else if(y == 2)
      System.out.print('O');
      else
      System.out.print('_');


      System.out.println();


      public static boolean won(int[][] b, int p)
      for(int[] x: b)
      if(x[0] == x[1] && x[1] == x[2] && x[0] == p)
      return true;


      for(int i = 0; i < b.length; i++)
      for(int j = 0; j < b[i].length; j++)
      if(b[0][j] == b[1][j] && b[1][j] == b[2][j] && b[1][j] == p)
      return true;



      if(b[0][0] == b[1][1] && b[0][0] == b[2][2] && b[0][0] == p)
      return true;

      if(b[2][0] == b[1][1] && b[2][0] == b[0][2] && b[0][2] == p)
      return true;

      return false;

      public static boolean drawn(int[][] b)
      for(int[] x: b)
      for(int y: x)
      if(y == 0)
      return false;



      return true;

      // -------------------------------------
      public static int eval(int[][] board, int depth, int p, int ai)
      if(won(board, p))
      return 10 - depth++;
      else if(won(board, getOpp(p)))
      return -10 + depth++;
      else if(drawn(board))
      return 0 - depth++;

      if(p == ai)
      int best = -10000;
      for(int i = 0; i < 3; i++)
      for(int j = 0; j < 3; j++)
      if(board[i][j] != 0)
      continue;

      board[i][j] = p;
      best = max(best, eval(board, depth++, getOpp(p), ai) - depth);
      board[i][j] = 0;


      return best;
      else
      int best = 10000;
      for(int i = 0; i < 3; i++)
      for(int j = 0; j < 3; j++)
      if(board[i][j] != 0)
      continue;

      board[i][j] = p;
      best = min(best, eval(board, depth++, getOpp(p), ai) + depth);
      board[i][j] = 0;


      return best;


      @Override
      public int[] playTurn()
      int[][] b = GameController.game.getBoard();
      int p = getPiece();
      int bmI = 0;
      int bmJ = 0;
      int bmEval = -10000;
      for(int i = 0; i < 3; i++)
      for(int j = 0; j < 3; j++)
      if(b[i][j] != 0)
      continue;

      b[i][j] = p;
      int eval = eval(b, 0, p, getPiece());
      b[i][j] = 0;
      if(eval > bmEval)
      bmI = i;
      bmJ = j;
      bmEval = eval;



      printBoard(b);
      System.out.println();
      return new int[] bmI, bmJ;






      GameController.java



      //This class's job is to coordinate between the players and the game code, it is the middle man
      //A game object is created, followed by two player objects, then the game is run as the players
      //take turns and interact with the game code.

      //**THIS IS THE FILE YOU RUN TO PLAY THE GAME**//

      import java.util.Scanner;

      public class GameController

      // **PLAYERS ARE SET UP HERE**//
      // To test your bot, replace one of the human players with your bot and play
      // against it
      // p1 is X and goes first
      private static TicTacToePlayer p1 = new RandomPlayer("Joe", 1);
      private static TicTacToePlayer p2 = new EustorgiusSylwester("Paul", 2);

      // Copy of the board from TicTacToe.java for players to access
      private static int[][] board;
      private static int turnTimer = 0;

      // initialize the game
      public static TicTacToe game = new TicTacToe();

      // gets a copy of the game board
      public static int[][] getBoard()
      board = game.getBoard();

      return board;


      public static int getTurnCount()
      return turnTimer;


      // plays a single game, returns the number of the player who won, 3 if tie
      private static int playGame()
      turnTimer = 0;
      // game plays
      int state = 0; // 0 = ongoing, 1 = X win, 2 = O win, 3 = tie
      while (state == 0)
      game.placePiece(p1.playTurn(), 1); // x player goes
      turnTimer++;

      // check state after X goes to see if the game ended
      state = game.gameOver();
      if (state != 0)
      break;


      game.placePiece(p2.playTurn(), 2); // O player goes
      turnTimer++;

      state = game.gameOver(); // update state after O goes, while loop condition will handle the check

      if (turnTimer > 50)
      state = 3;
      System.out.println("Max Turns reached, game ending.");



      // declare winner
      if (state == 1)
      System.out.println(p1.getName() + " Won!");
      return 1;
      else if (state == 2)
      System.out.println(p2.getName() + " Won!");
      return 2;
      else
      System.out.println("Draw");
      return 3;




      public static void main(String[] args)
      System.out.println("+++++++++++++++++++++++");
      System.out.println(p1.getName() + " VS " + p2.getName());
      System.out.println("+++++++++++++++++++++++" + "n");

      System.out.println("How Many Games?");
      Scanner s = new Scanner(System.in);
      int numGames = s.nextInt();
      System.out.println("BEGINn");

      int p1Victories = 0;
      int p2Victories = 0;
      int ties = 0;
      int curWinner = 0;
      for (int i = 0; i < numGames; i++)
      curWinner = playGame();
      if (curWinner == 1)
      p1Victories++;
      else if (curWinner == 2)
      p2Victories++;
      else
      ties++;


      // resets the board before the next game is played
      game.resetBoard();


      System.out.println("n++++++++++++");
      System.out.println("FINAL TALLY");
      System.out.println("++++++++++++");
      System.out.println(p1.getName() + " Won " + p1Victories + " Games!");
      System.out.println(p2.getName() + " Won " + p2Victories + " Games!");
      System.out.println("There were " + ties + " Tie Games!");
      s.close();






      TicTacToe.java



      /* This is the main class that contains code for the game
      *
      * Empty space will be represented by a 0
      * X's will be represented by a 1
      * O's will be represented by a 2
      * Anything higher (3+) or lower (-1-) should not be added to the board
      */

      public class TicTacToe

      private int[][] board; //the TicTacToe board, private to avoid cheating


      public TicTacToe()
      board = new int[3][3];


      //given a row and column, determine if placing a piece there is valid
      //the space must be within the bounds of the board, AND empty
      //return true if it is a legal move, false if illegal
      private boolean isLegalMove(int row, int column) column >= 3)
      return false;

      if (board[row][column] != 0)
      return false;

      return true;


      //this method will place a game piece (X or 0) at the row/column
      //piece will be 1 for an X, 2 for an O
      //*IMPORTANT* make sure the move is legal first, don't trust the AI to submit a valid move
      //moves are submitted as a length 2 integer array, first number is the row, second is the column
      public void placePiece(int[] move, int piece)
      //if a null move is submitted, exit skipping the player's turn
      if (move == null)
      System.out.println("Illegal Move Attempted");
      return;

      int row = move[0];
      int column = move[1];
      if (isLegalMove(row, column))
      board[row][column] = piece;

      else
      System.out.println("Illegal Move Attempted");




      //print out the current board state so the humans can read it
      public void printBoard()
      int current = 0;
      for (int i = 0; i < 3; i ++) ");
      for (int j = 0; j < 3; j++)
      current = board[i][j];
      if (current == 0)
      System.out.print(" " + "
      else if (current == 1) ");

      else if (current == 2) ");


      System.out.println();




      //examines the current board and determines if the game is over
      //returns 0 if the game is still going
      //returns 1 if X player wins
      //returns 2 if O player wins
      //returns 3 if the game is a tie
      public int gameOver()

      for (int i = 0; i < 3; i++)

      //if no player has 3 in a row, check for tie
      for (int i = 0; i < 3; i ++)
      for (int j = 0; j < 3; j++)
      if (board[i][j] == 0)
      return 0; //there is an empty space on the board, game is still going.

      //Yes I know sometimes draws are inevitable even if there are squares
      //left, but that is outside the scope of this challenge.




      //The game has tied
      return 3;


      //returns the number of spaces a given player occupies in a given row
      //row is the row to check, 0 = first, 1 = second, 2 = third
      //player will be 1 for X player 2 for O player
      public int getRowCount(int row, int player)
      int counter = 0;
      for (int i = 0; i < 3; i++)
      if (board[row][i] == player)
      counter++;



      return counter;


      //same as getRowCount but for columns
      public int getColumnCount(int column, int player)
      int counter = 0;
      for (int i = 0; i < 3; i++)
      if (board[i][column] == player)
      counter++;



      return counter;


      //checks if the given player has 3 in a row diagonal
      public boolean getDiagonal(int player)
      //left to right diagonal
      if (board[0][0] == player && board[1][1] == player && board [2][2] == player)
      return true;

      //right to left diagonal
      if (board[0][2] == player && board[1][1] == player && board [2][0] == player)
      return true;

      return false;


      //returns a COPY of the current board for the AI's to read
      //This prevents AI's from having direct access to the board, to cheat for example
      public int[][] getBoard()
      int[][] boardCopy = new int[3][3];
      for (int i = 0; i < board.length; i++)
      for (int j = 0; j < board[0].length; j++)
      boardCopy[i][j] = board[i][j];


      return boardCopy;


      //resets the board to all 0s (empty)
      public void resetBoard()
      for(int i = 0; i < board.length; i++)
      for (int j = 0; j < board[0].length; j++)
      board[i][j] = 0;







      TicTacToePlayer.java



      //Defines general behavior of all players (AI and Human)
      public abstract class TicTacToePlayer
      private String name; //Player's name
      private int piece; //Piece type, 1 = X, 2 = O

      public TicTacToePlayer(String aName, int aPiece)
      name = aName;
      piece = aPiece;


      public String getName()
      return name;


      public int getPiece()
      return piece;


      //All players must be able to play a turn
      public abstract int[] playTurn();








      java tic-tac-toe ai





      share







      New contributor




      simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.










      share







      New contributor




      simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.








      share



      share






      New contributor




      simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 6 mins ago









      simplicialsimplicial

      1




      1




      New contributor




      simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      simplicial is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















          0






          active

          oldest

          votes












          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );






          simplicial is a new contributor. Be nice, and check out our Code of Conduct.









          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217463%2fjava-minimax-tic-tac-toe%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          simplicial is a new contributor. Be nice, and check out our Code of Conduct.









          draft saved

          draft discarded


















          simplicial is a new contributor. Be nice, and check out our Code of Conduct.












          simplicial is a new contributor. Be nice, and check out our Code of Conduct.











          simplicial is a new contributor. Be nice, and check out our Code of Conduct.














          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217463%2fjava-minimax-tic-tac-toe%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          名間水力發電廠 目录 沿革 設施 鄰近設施 註釋 外部連結 导航菜单23°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.7113923°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.71139計畫概要原始内容臺灣第一座BOT 模式開發的水力發電廠-名間水力電廠名間水力發電廠 水利署首件BOT案原始内容《小檔案》名間電廠 首座BOT水力發電廠原始内容名間電廠BOT - 經濟部水利署中區水資源局

          Prove that NP is closed under karp reduction?Space(n) not closed under Karp reductions - what about NTime(n)?Class P is closed under rotation?Prove or disprove that $NL$ is closed under polynomial many-one reductions$mathbfNC_2$ is closed under log-space reductionOn Karp reductionwhen can I know if a class (complexity) is closed under reduction (cook/karp)Check if class $PSPACE$ is closed under polyonomially space reductionIs NPSPACE also closed under polynomial-time reduction and under log-space reduction?Prove PSPACE is closed under complement?Prove PSPACE is closed under union?

          Is my guitar’s action too high? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)Strings too stiff on a recently purchased acoustic guitar | Cort AD880CEIs the action of my guitar really high?Μy little finger is too weak to play guitarWith guitar, how long should I give my fingers to strengthen / callous?When playing a fret the guitar sounds mutedPlaying (Barre) chords up the guitar neckI think my guitar strings are wound too tight and I can't play barre chordsF barre chord on an SG guitarHow to find to the right strings of a barre chord by feel?High action on higher fret on my steel acoustic guitar