Reputation: 79
I am writing code for a game of Tic-Tac-Toe between a computer and a user. To make a move, a list of spots not occupied on the board is provided as a parameter, which for the user is really only useful in comparing if the input is in the list or not. If so, that constitutes a legal move.
Here is my code. It keeps saying that the new move is not contained in the list and I do not know why. I have searched the database here for a similar issue and found a few related but not conclusive ones.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class UserTTTPlayer implements TicTacToePlayer{
@Override
public int[] makeMove(ArrayList<int []> unusedMoves) {
Scanner in = new Scanner (System.in);
System.out.println("Your move, user?");
String input = in.nextLine();
int [] move = checkInput(input, unusedMoves);
while (move == null){
input = in.nextLine();
move = checkInput(input, unusedMoves);
}
return move;
}
private int [] checkInput(String input, ArrayList<int []> unusedMoves){
System.out.println("Unused moves: ");
for (int [] move: unusedMoves)
System.out.println(Arrays.toString(move));
//error checking for the length of the input
if (input.length() < 1 || input.length() > 2){
System.out.println("Invalid input. Please try again.");
return null;
}
else{
//convert the input from string to int
int col = input.charAt(0) - 'a';
int row = input.charAt(1) - '0';
int [] move = {row, col};
System.out.println("Intended move: " + Arrays.toString(move));
System.out.println(unusedMoves.contains(move));
//error checking for the bounds of the board
if (col > 3 || col < 0 || row > 3 || col < 0){
System.out.println("Invalid input.");
return null;
}
//error checking for if the space is available
else if (!unusedMoves.contains(move)){
System.out.println("That space is already occupied.");
return null;
}
return move;
}
}
}
This is the output from that. The board and other printing is from a different class, but unrelated to the problem, I think. I print out the list which says that it has the new move in it, yet contains still returns false.
You go first. You will be X's.
a b c
0 - - -
1 - - -
2 - - -
Your move, user?
a0
Unused moves:
[0, 0]
[0, 1]
[0, 2]
[1, 0]
[1, 1]
[1, 2]
[2, 0]
[2, 1]
[2, 2]
Intended move: [0, 0]
false
That space is already occupied.
Any help would be appreciated.
Upvotes: 2
Views: 197
Reputation: 124804
As the comments explained, unusedMoves.contains(move)
doesn't work as you might expect. The .contains
method uses the .equals
method of the objects inside the list to check if the given value is equal to one of the elements. However, the .equals
method of arrays doesn't compare the elements, it compares only identity of the arrays using ==
.
For example:
int[] arr = {1, 2};
// prints false, as the array in the list is not *identical*
System.out.println(Arrays.asList(new int[]{1, 2}).contains(arr));
// prints true, as the array in the list *is* identical
System.out.println(Arrays.asList(arr).contains(arr));
Consider this helper method:
private boolean contains(List<int[]> list, int[] arr) {
return list.stream().anyMatch(x -> Arrays.equals(x, arr));
}
With this helper method, you can replace unusedMoves.contains(move)
with contains(unusedMoves, move)
, and it should work as expected.
Upvotes: 2