I am trying to make an Android Tic-Tac-Toe application, of course, in Java. After debugging, perhaps in a few hours, fixing things here and there, I ran into a problem that I cannot solve on my own at this time, with this knowledge. I came to the conclusion that the problem was found in the AndroidPerform () method, where the first line suggests finding the best move and putting it in the corresponding named variable bestMove, which is a Move object.
public void AndroidPerform(){
Move bestMove = AndroidMove(NOUGHT);
placeAMove(bestMove.x, bestMove.y, NOUGHT);
minimaxActivity.setMove(bestMove.x, bestMove.y, NOUGHT);
}
Now, obviously, looking at the above code, we see that the AndroidMove method (player) is called, which is basically a minimax algorithm, or at least should be. During debugging, I saw that it finds good moves, but when it comes to this line
Move bestMove = AndroidMove(NOUGHT);
It returns null for x and for y and this is where I get my problem, which I cannot fix. I have provided the two most important classes, in fact it is in these classes where all the work is done. Anyway, hope you can help, however that may be, thanks in advance.
Class mygame
public class MyGame {
public final int EMPTY = 0;
public final int CROSS = 1;
public final int NOUGHT = 2;
public final int PLAYING = 0;
public final int CROSS_WON = 1;
public final int NOUGHT_WON = 2;
public final int DRAW = 3;
public static final int ROWS = 3, COLS = 3;
public static int[][] board = new int[ROWS][COLS];
public static int currentState;
public static int currentPlayer;
public static int currentRow, currentCol;
public int AndroidPlayer, HumanPlayer;
MinimaxActivity minimaxActivity = new MinimaxActivity();
class Move {
int x, y, score, player;
public Move(int score){
this.score = score;
}
public Move(int x, int y) {
this.x = x;
this.y = y;
}
public Move(int x, int y, int player) {
this.x = x;
this.y = y;
this.player = player;
}
}
public void resetBoard() {
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
board[i][j] = 0;
}
}
}
List<Move> availableMoves;
public Move AndroidMove(int player) {
int State = CheckGameState();
if (State == NOUGHT_WON){
return new Move(10);
} else if (State == CROSS_WON){
return new Move(-10);
} else if (State == DRAW){
return new Move(0);
}
List<Move> moves = getAvailableStates();
for (int i = 0; i < ROWS; ++i) {
for (int j = 0; j < COLS; ++j) {
if (board[i][j] == EMPTY){
Move move = new Move(i, j, player);
placeAMove(i, j, player);
if (player == NOUGHT){
move.score = AndroidMove(CROSS).score;
} else {
move.score = AndroidMove(NOUGHT).score;
}
moves.add(move);
placeAMove(i, j, EMPTY);
}
}
}
int bestMove = 0;
if (player == NOUGHT) {
int bestScore = -1000000;
for (int i = 0; i < moves.size(); i++) {
if (moves.get(i).score > bestScore) {
bestMove = i;
bestScore = moves.get(i).score;
}
}
} else {
int bestScore = 1000000;
for (int i = 0; i < moves.size(); i++) {
if (moves.get(i).score < bestScore) {
bestMove = i;
bestScore = moves.get(i).score;
}
}
}
return moves.get(bestMove);
}
public void AndroidPerform(){
Move bestMove = AndroidMove(NOUGHT);
placeAMove(bestMove.x, bestMove.y, NOUGHT);
minimaxActivity.setMove(bestMove.x, bestMove.y, NOUGHT);
}
public void placeAMove(int x, int y, int player) {
board[x][y] = player;
}
public void placeAMove(Point point, int player) {
board[point.x][point.y] = player;
}
public List<Move> getAvailableStates() {
availableMoves = new ArrayList<>();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (board[i][j] == EMPTY) {
availableMoves.add(new Move(i, j));
}
}
}
return availableMoves;
}
public int CheckGameState() {
for (int i = 0; i< ROWS; i++){
if (board[i][0] == CROSS &&
board[i][1] == CROSS &&
board[i][2] == CROSS){
return CROSS_WON;
}
if (board[i][0] == NOUGHT &&
board[i][1] == NOUGHT &&
board[i][2] == NOUGHT){
return NOUGHT_WON;
}
}
for (int i = 0; i< COLS; i++){
if (board[0][i] == CROSS &&
board[1][i] == CROSS &&
board[2][i] == CROSS){
return CROSS_WON;
}
if (board[0][i] == NOUGHT &&
board[1][i] == NOUGHT &&
board[2][i] == NOUGHT){
return NOUGHT_WON;
}
}
if (board[0][0] == CROSS &&
board[1][1] == CROSS &&
board[2][2] == CROSS){
return CROSS_WON;
}
if (board[0][0] == NOUGHT &&
board[1][1] == NOUGHT &&
board[2][2] == NOUGHT){
return NOUGHT_WON;
}
if (board[0][2] == CROSS &&
board[1][1] == CROSS &&
board[2][0] == CROSS){
return CROSS_WON;
}
if (board[0][2] == NOUGHT &&
board[1][1] == NOUGHT &&
board[2][0] == NOUGHT){
return NOUGHT_WON;
}
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (board[i][j] != CROSS && board[i][j] != NOUGHT){
return PLAYING;
}
}
}
return DRAW;
}
}
Class MinimaxActivity
public class MinimaxActivity extends AppCompatActivity {
private Board BoardGame;
private MyGame myGame;
private Button mBoardButtons[][];
private TextView mInfoTextView;
private TextView mPlayerOneCount;
private TextView mTieCount;
private TextView mPlayerTwoCount;
private TextView mPlayerOneText;
private TextView mPlayerTwoText;
private int mPlayerOneCounter = 0;
private int mTieCounter = 0;
private int mPlayerTwoCounter = 0;
private Button newGame, exitGame;
public int HUMAN = 1;
public int COMPUTER = 2;
Random random;
private int First=0;
private int Counter = 0;
private boolean isGameOver = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
mBoardButtons = new Button[3][3];
mBoardButtons[0][0] = (Button) findViewById(R.id.one);
mBoardButtons[0][1] = (Button) findViewById(R.id.two);
mBoardButtons[0][2] = (Button) findViewById(R.id.three);
mBoardButtons[1][0] = (Button) findViewById(R.id.four);
mBoardButtons[1][1] = (Button) findViewById(R.id.five);
mBoardButtons[1][2] = (Button) findViewById(R.id.six);
mBoardButtons[2][0] = (Button) findViewById(R.id.seven);
mBoardButtons[2][1] = (Button) findViewById(R.id.eight);
mBoardButtons[2][2] = (Button) findViewById(R.id.nine);
newGame = (Button) findViewById(R.id.newGame1);
exitGame = (Button) findViewById(R.id.exitGame1);
mInfoTextView = (TextView) findViewById(R.id.information);
mPlayerOneCount = (TextView) findViewById(R.id.humanCount);
mTieCount = (TextView) findViewById(R.id.tiesCount);
mPlayerTwoCount = (TextView) findViewById(R.id.androidCount);
mPlayerOneText = (TextView) findViewById(R.id.human);
mPlayerTwoText = (TextView) findViewById(R.id.android);
mPlayerOneCount.setText(Integer.toString(mPlayerOneCounter));
mTieCount.setText(Integer.toString(mTieCounter));
mPlayerTwoCount.setText(Integer.toString(mPlayerTwoCounter));
random = new Random();
exitGame.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MinimaxActivity.this.finish();
}
});
final CharSequence[] items = {"Computer", "Player"};
final AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setCancelable(false);
alertDialog.setTitle("Who goes first?");
alertDialog.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
if (items[item] == "Computer") {
First = 1;
} else if (items[item] == "Player") {
First = 2;
}
dialog.dismiss();
myGame = new MyGame();
if (First == 1) {
startNewGame(true);
}
if (First == 2) {
startNewGame(false);
}
}
});
alertDialog.show();
newGame.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Counter % 2 == 0) {
startNewGame(false);
Counter++;
} else {
startNewGame(true);
Counter++;
}
}
});
}
private void startNewGame(boolean GoesFirst) {
MyResetBoard();
mPlayerOneText.setText("Human:");
mPlayerTwoText.setText("Android:");
if(GoesFirst){
mInfoTextView.setText("Android Turn.");
setMove(random.nextInt(3), random.nextInt(3), COMPUTER);
GoesFirst = false;
}else{
mInfoTextView.setText("Human Turn.");
GoesFirst = true;
}
isGameOver = false;
}
private void MyResetBoard(){
myGame.resetBoard();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
mBoardButtons[i][j].setText("");
mBoardButtons[i][j].setEnabled(true);
mBoardButtons[i][j].setOnClickListener(new ButtonClickListener(i,j));
mBoardButtons[i][j].setBackgroundResource(R.drawable.empty);
}
}
}
private class ButtonClickListener implements View.OnClickListener {
int x,y;
public ButtonClickListener(int i, int j) {
this.x = i;
this.y = j;
}
@Override
public void onClick(View v) {
if (!isGameOver){
if (mBoardButtons[x][y].isEnabled()){
setMove(x, y, myGame.CROSS);
int winner = myGame.CheckGameState();
if (winner == myGame.PLAYING) {
mInfoTextView.setText(R.string.turn_computer);
myGame.AndroidPerform();
winner = myGame.CheckGameState();
}
if (winner == myGame.PLAYING){
mInfoTextView.setText(R.string.turn_human);
}
else if (winner == myGame.DRAW) {
mInfoTextView.setText(R.string.result_tie);
mTieCounter++;
mTieCount.setText(Integer.toString(mTieCounter));
isGameOver = true;
} else if (winner == myGame.CROSS_WON) {
mInfoTextView.setText(R.string.result_human_wins);
mPlayerOneCounter++;
mPlayerOneCount.setText(Integer.toString(mPlayerOneCounter));
isGameOver = true;
} else if (winner == myGame.NOUGHT_WON){
mInfoTextView.setText(R.string.result_android_wins);
mPlayerTwoCounter++;
mPlayerTwoCount.setText(Integer.toString(mPlayerTwoCounter));
isGameOver = true;
}
}
}
}
}
public void setMove(int x, int y, int player){
myGame.placeAMove(x, y, player);
mBoardButtons[x][y].setEnabled(false);
if (player == 1) {
mBoardButtons[x][y].setBackgroundResource(R.drawable.x);
} else {
mBoardButtons[x][y].setBackgroundResource(R.drawable.o);
}
}