2

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.

6
  • Array does not implement equals method, which used in list for contains method Commented May 24, 2016 at 17:12
  • Your comparing col three times: col > 3 || col < 0 || row > 3 || col < 0. Just spotted it. Commented May 24, 2016 at 17:13
  • 2
    !unusedMoves.contains(move) , this code won't work, as you are comparing array objects, which will not give correct result. you need to check array elements, something like unusedMoves.get(0)[0]==move[0] && unusedMoves.get(0)[1]==move[1]. And you may need a loop to go over unusedMoves list Commented May 24, 2016 at 17:16
  • 2
    @Amit.rk3 a less verbose way would be to call Arrays.equals(unusedMoves.get(0), move). Would still require the loop like you said Commented May 24, 2016 at 17:19
  • 1
    @Hill , yup that's better :) Commented May 24, 2016 at 17:20

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.