Question (short version): How do I compare elements in an ArrayList to each other?
I've got most of the basics of ArrayList down pretty well (add, get, set, size...). I'm having trouble stepping into the ArrayList to compare objects (playing cards' values and suits) in order to determine best poker hands. I have a class to store information about a card.
Card class:
/** class Card : for creating playing card objects
* it is an immutable class.
* Rank - valid values are 1 to 13
* Suit - valid values are 0 to 3
* Do not modify this class!
*/
class Card {
/* constant suits and ranks */
static final String[] Suit = {"Clubs", "Diamonds", "Hearts", "Spades" };
static final String[] Rank = {"","A","2","3","4","5","6","7","8","9","10","J","Q","K"};
/* Data field of a card: rank and suit */
private int cardRank; /* values: 1-13 (see Rank[] above) */
private int cardSuit; /* values: 0-3 (see Suit[] above) */
/* Constructor to create a card */
/* throw PlayingCardException if rank or suit is invalid */
public Card(int rank, int suit) throws PlayingCardException {
if ((rank < 1) || (rank > 13))
throw new PlayingCardException("Invalid rank:"+rank);
else
cardRank = rank;
if ((suit < 0) || (suit > 3))
throw new PlayingCardException("Invalid suit:"+suit);
else
cardSuit = suit;
}
/* Accessor and toString */
/* You may impelemnt equals(), but it will not be used */
public int getRank() { return cardRank; }
public int getSuit() { return cardSuit; }
public String toString() { return Rank[cardRank] + " " + Suit[cardSuit]; }
/* Few quick tests here */
public static void main(String args[])
{
try {
Card c1 = new Card(1,3); // A Spades
System.out.println(c1);
c1 = new Card(10,0); // 10 Clubs
System.out.println(c1);
//c1 = new Card(10,5); // generate exception here
}
catch (PlayingCardException e)
{
System.out.println("PlayingCardException: "+e.getMessage());
}
}
}
And a class to check each hand of cards (this is the class I'm having trouble figuring out). I have currently added code to make this add an ArrayList and print each hand over again (just to make sure I can create a separate ArrayList because I wasn't too comfortable with my ability), but I can't figure out how to compare elements of each card (rank and suit).
Check hands class:
/** Check current currentHand using multipliers and goodHandTypes arrays
* Must print yourHandType (default is "Sorry, you lost") at the end o function.
* This can be checked by testCheckHands() and main() method.
*/
private void checkHands()
{
// implement this method!
ArrayList<Card> multiplierCheck = new ArrayList<Card>();
String yourhandtype = "Sorry, you lost";
for (int toList = 0; toList<5; toList++) {
multiplierCheck.add(currentHand.get(toList));
}
System.out.println(multiplierCheck);
System.out.println(yourhandtype);
}
And a method to test check hands that creates hands which are winning hands (straight, flush, three of a kind). I can't figure out how to compare the cards to each other in my Check Hands Class.
testCheckHands() Method
public void testCheckHands()
{
try {
currentHand = new ArrayList<Card>();
// set Royal Flush
currentHand.add(new Card(1,3));
currentHand.add(new Card(10,3));
currentHand.add(new Card(12,3));
currentHand.add(new Card(11,3));
currentHand.add(new Card(13,3));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// set Straight Flush
currentHand.set(0,new Card(9,3));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// set Straight
currentHand.set(4, new Card(8,1));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// set Flush
currentHand.set(4, new Card(5,3));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// "Royal Pair" , "Two Pairs" , "Three of a Kind", "Straight", "Flush ",
// "Full House", "Four of a Kind", "Straight Flush", "Royal Flush" };
// set Four of a Kind
currentHand.clear();
currentHand.add(new Card(8,3));
currentHand.add(new Card(8,0));
currentHand.add(new Card(12,3));
currentHand.add(new Card(8,1));
currentHand.add(new Card(8,2));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// set Three of a Kind
currentHand.set(4, new Card(11,3));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// set Full House
currentHand.set(2, new Card(11,1));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// set Two Pairs
currentHand.set(1, new Card(9,1));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// set Royal Pair
currentHand.set(0, new Card(3,1));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
// non Royal Pair
currentHand.set(2, new Card(3,3));
System.out.println(currentHand);
checkHands();
System.out.println("-----------------------------------");
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
To evaluate Poker hands probably the most common thing you're going to do is loop through the data structure (could be an array, list, whatever) and compare the cards to each other. For example here's some pseudo-Java to compare a straight:
for (int i = 1; i < /* length of hand */; i++) {
if (/* rank for card i is not 1 greater
than rank for card i - 1 */) {
/* not a straight */
}
}
Note that the above assumes the structure is sorted which I'll get to. Also since Poker hands are so different there's not really a 'best way' to do all of them. You will have to write a routine for each one. So I would recommend you come up with some abstraction that helps you out. What I would do is use Enum. Here's a basic example:
enum PokerHand {
STRAIGHT {
#Override
boolean matches(List<Card> hand) {
for (int i = 1; i < hand.size(); i++) {
if (
card.get(i).getRank() !=
card.get(i - 1).getRank() + 1
) {
return false;
}
}
return true;
}
},
FOUR_OF_A_KIND {
#Override
boolean matches(List<Card> hand) {
int[] rankCount = new int[14];
/* count up the ranks in the hand */
for (Card card : hand) {
rankCount[card.getRank()]++;
}
boolean foundHasOne = false;
boolean foundHasFour = false;
/* now evaluate exclusively
* there must be only a 1 count and a 4 count
*/
for (int i = 1; i < rankCount.length; i++) {
if (rankCount[i] == 1) {
if (!foundHasOne) {
foundHasOne = true;
} else {
return false;
}
} else if (rankCount[i] == 4) {
if (!foundHasFour) {
foundHasFour = true;
} else {
return false;
}
} else if (rankCount[i] != 0) {
return false;
}
}
return true;
}
},
ROYAL_FLUSH {
final int[] rfRanks = {
1, 10, 11, 12, 13
};
#Override
boolean matches(List<Card> hand) {
for (int i = 0; i < rfRanks.length; i++) {
if (rfRanks[i] != hand.get(i).getRank())
return false;
}
return true;
}
};
abstract boolean matches(List<Card> hand);
}
Of course the above does not cover all Poker hands, just a few examples. Also I don't play Poker so those could be a little wrong but the point is to show some evaluation examples.
As I said before this becomes much simpler if you sort your lists ahead of time. java.util.Collections and java.util.Arrays have utility methods for this so it is fairly trivial. Just make sure to make a copy before sorting if you don't want the sort to persist after you check the hands.
/* make a shallow copy */
List<Card> sortedHand = new ArrayList<Card>(playerHand);
/* sort based on rank */
Collections.sort(sortedHand, new Comparator<Card>() {
#Override
public int compare(Card card1, Card card2) {
int rank1 = card1.getRank();
int rank2 = card2.getRank();
if (rank1 > rank2) {
return 1;
if (rank1 < rank2)
return -1;
return 0;
}
});
See Comparator#compare for a description of how that works but that's basically it to sort.
Using an enum or something like it then makes the evaluation fairly trivial logically.
Now what I recommend is to make a method for the evaluation because then you can conveniently return the constant for what the hand is.
static PokerHand evaluateHand(List<Card> hand) {
for (PokerHand potential : PokerHand.values()) {
if (potential.matches(hand))
return potential;
}
/* imply there is not a matching hand */
return null;
}
So after you make your copy of the hand and have sorted it you can call to evaluate it:
PokerHand evaluated = evaluateHand(sortedHand);
if (evaluated != null) {
/* it's a recognized hand */
}
You don't have to make a method, you could do something like the following:
PokerHand evaluated = null;
for (PokerHand potential : PokerHand.values()) {
if (potential.matches(sortedHand)) {
evaluated = potential;
break;
}
}
if (evaluated != null) {
/* it's a recognized hand */
}
But using helper methods helps organize your code.
I hope that helps. If you also need to score the hands to decide if there is a winner, just add another method to the enum that returns a score. Then see which one is the biggest.
Not sure if you said how it isn't working, but to iterate through an arrayList..
for (String s : arrayList)
if (s.equals(value))
// ...
String can be replaced for int, ect..
Related
I'm a high schooler in apcs and I'm trying to practice these for the test. The code should return whether a new object was created. Also, the moveUp method doesn't allow me to call it using the scoreboard list (e.g. "scoreboard.move(int x)". Please explain why I'm wrong, but don't solve it.
public boolean newScore(String name, int score)
{
/* Implement your answer to part (b) here */
for (int ind = 0; ind < scoreboard.size(); ind++) {
Player player = scoreboard.get(ind);
if (player.getName().equalsIgnoreCase(name)) {
player.updateScore(score);
moveUp(scoreboard.indexOf(player));
return true;
} else {
Player p = new Player(name, score);
scoreboard.add(p);
p.updateScore(score);
moveUp(scoreboard.indexOf(p));
return false;
}
}
}
I managed to figure out how to print the array for my connect four program but I cannot get the board to update with my code, I looked at it and ran it the code works in theory but however the array won't take the new inputs
Ive tried running it through with a for loop but that turned out wrong and I was thinking about putting the drop method in the print board method but I feel that that would result in an error
public class Connect4 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// DON'T MODIFY THE MAIN METHOD UNLESS FOR DEBUGGING
//MAKE SURE YOU GET RID OF YOUR MODIFICATIONS HERE BEFORE
SUBMISSION
String[][] board = createEmptyBoard();
Scanner input = new Scanner(System.in);
boolean bl = true;
printPattern(board);
while(bl) {
int player1 = 1 , player2 = 2 , userInput;
System.out.println("Please drop a RED disk at the column between 0
and 6:");
userInput = input.nextInt();
dropDisk(board, userInput , player1);
printPattern(board);
System.out.println("Please drop a YELLOW disk at the column
between 0 and 6:");
userInput = input.nextInt();
dropDisk(board, userInput , player2);
printPattern(board);
String win = checkWinner(board);
/*
Write code to announce if there is winner and end the game
*/
}
}
public static String[][] createEmptyBoard() {
/* This method prints the first empty pattern for the game
DON'T MODIFY THIS METHOD
*/
String[][] f = new String[7][15];
for (int i =0;i<f.length;i++) {
for (int j =0;j<f[i].length;j++) {
if (j% 2 == 0) f[i][j] ="|";
else f[i][j] = " ";
if (i==6) f[i][j]= "-";
}
}
return f;
} // end of createEmptyBoard
public static void printPattern(String[][] brd) {
for (int i = 0; i < 7; i++){
System.out.println(brd[i][0] + brd[i][1]+ brd[i][2]+ brd[i][3]+
brd[i][4]+ brd[i][5]+ brd[i][6]+ brd[i][7]+ brd[i][8]+ brd[i][9]+
brd[i][10]+ brd[i][11]+ brd[i][12]+ brd[i][13]+ brd[i][14]);
}
} // end of printPattern
public static void dropDisk(String[][] brd, int position, int
player) {
if (player == 1){
brd[6][position] = "R";
if(brd[6][position] == "R"){
brd[6][position] = brd[6 - 1][position];
}
}
else if (player == 2){
brd[6][position] = "Y";
if(brd[6][position] == "Y"){
brd[6][position] = brd[6 - 1][position];
}
}
/*Write your code to drop the disk at the position the user entered
depending on which player*/
} // end of dropDisk
The logic of dropDisk seems to be not finished yet.
It sets the brd[6][position] to R or Y, just to immediately after that set it to the current value of brd[5][position].
And this should always be null.
In Java, objects are passed into methods by value. This means that when you pass a parameter into a function, the JVM makes a copy of that object which can be modified in the method.
In this case, when you pass brd into dropDisk, it is copied, and you make changes to the copy inside dropDisk. But once dropDisk ends, that copy is discarded. No changes are made to the board from your main method. This is because your board is an array of Strings, and Strings are immutable, meaning that they cannot be changed after instantiation.
If you wanted the board from your main method to update, consider returning brd in dropDisk.
I'm programming a game of cards in Java and everything is going well, but I've come up with an unforeseen reason why I think I can not think of what to use and I want to know what idea to follow. I go:
My game:
My game consists of 6 players, I am always the Player 1 and the other players the computer, therefore I have done with 6 JLabel in a JFrame, each Jlabel means the card that throws jug1 ... jug6, and in the code I take the order of which player wins the hand with an array of integers equal to [3,4,5,6,1,2] assuming player 3 was won by hand.
My problem:
Taking the above arrangement as a reference [3,4,5,6,1,2], it means that in the next hand players [3,4,5,6] must show their card before Player 1, and After Player 1 shows his card, he must show Player 2.
I know how to show the cards of the first four players, but how can I make my program wait for me to click on my selected card and then continue with the last card of Player 2, my main question is how to receive that click Of Player 1 between players, before or after.
Here a fragment:
public void Tirar(JLabel [] label_cartas_en_mesa) //director function
{
cartas_en_mesa = new Vector<Baraja>();
for ( int i =0; i < 6; i++ )
{
switch( orden_de_tiro [i] )
{
case 1: { Tirar_Jugador1(label_cartas_en_mesa, i); break; }
case 2: { Tirar_Jugador2(label_cartas_en_mesa, i); break; }
case 3: { Tirar_Jugador3(label_cartas_en_mesa, i); break; }
case 4: { Tirar_Jugador4(label_cartas_en_mesa, i); break; }
case 5: { Tirar_Jugador5(label_cartas_en_mesa, i); break; }
case 6: { Tirar_Jugador6(label_cartas_en_mesa, i); break; }
default:break;
}
}
}
public void Tirar_Jugador1(JLabel [] label_cartas_en_mesa, int pos)
{ //decision_jug1 = true when I clicked a card and then break a loop.
while(decision_jug1==false) //My wrong idea to wait, I think..
{ }
label_cartas_en_mesa[pos].setIcon( new ImageIcon( Jug1_Barajas.get(pos_baraja_jug1).getImagen() ) );
cartas_en_mesa.add( Jug1_Barajas.get(pos_baraja_jug1) );
Jug1_Barajas.remove(pos_baraja_jug1);
decision_jug1 = false;
}
public void Tirar_Jugador2(JLabel [] label_cartas_en_mesa, int pos)
{
label_cartas_en_mesa[ pos ].setIcon( new ImageIcon( Jug2_Barajas.get(0).getImagen()));
cartas_en_mesa.add( Jug2_Barajas.get(0) );
Jug2_Barajas.remove(0);
}
public void Tirar_Jugador3(JLabel [] label_cartas_en_mesa, int pos)
{
label_cartas_en_mesa[ pos ].setIcon( new ImageIcon( Jug3_Barajas.get(0).getImagen()));
cartas_en_mesa.add( Jug3_Barajas.get(0) );
Jug3_Barajas.remove(0);
}
public void Tirar_Jugador4(JLabel [] label_cartas_en_mesa, int pos)
{
label_cartas_en_mesa[ pos ].setIcon( new ImageIcon( Jug4_Barajas.get(0).getImagen()));
cartas_en_mesa.add( Jug4_Barajas.get(0) );
Jug4_Barajas.remove(0);
}
public void Tirar_Jugador5(JLabel [] label_cartas_en_mesa, int pos)
{
label_cartas_en_mesa[ pos ].setIcon( new ImageIcon( Jug5_Barajas.get(0).getImagen()));
cartas_en_mesa.add( Jug5_Barajas.get(0) );
Jug5_Barajas.remove(0);
}
public void Tirar_Jugador6(JLabel [] label_cartas_en_mesa, int pos)
{
label_cartas_en_mesa[ pos ].setIcon( new ImageIcon( Jug6_Barajas.get(0).getImagen()));
cartas_en_mesa.add( Jug6_Barajas.get(0) );
Jug6_Barajas.remove(0);
}
regards,
Alex
you can have an array of players, all of them including you.
the player may have several members and methods, the 2 methods i want to focus on are play() and isHuman(), in your Game class? there is a method playHand(int) which will control the process:
assume the players array (or list) is
//it contains 6 objects, one of them is You.
List<Player> players = new ArrayList<Player>();
players.add(player1);// add all 6 players...
//make sure when u add human to set isHuman(true)...
and we need to have a method that we will call when it's the Human (you) turn in game, assume it's notifiyHumanPlayer(int)
we also need a local member (class scope) variable the points to the current player.
private int CURRENT_PLAYER = 0;
so your code may look like this:
the method that starts the hand (the round)
private void playHand(int startingPlayerIndex){
for(int i=startingPlayerIndex; i<players.size();i++){
CURRENT_PLAYER = i;
if(!players.get(i).isHuman()){
//not human
notifiyPlayer(i);
players.get(i).play();
}else{
//human
notifiyPlayer(i);
//no call to play();...
break;
}
}//for loop
//when loop ends, all players were done, do what you do at end of each hand...
calculateHandWinner();
}
Shows a simple indicator (arrow) or play some sound...
private void notifiyPlayer(int myIndex){
//it may show an arrow or indeicator on/next player icon, to show which who's playing now
showTurnIndecator(myIndex);
}
when it's your turn, just the onClick of any card you have
private void humanPlayerOnClick(){
//this is the onClick() of the human (when human clicks on any of the cards)
//write the code for drawing a card from human's hand
// now we need to see if human was last player, or not,
if(CURRENT_PLAYER+1 >= players.size()){
//all players were done, do what you do at end of each hand...
calculateHandWinner();
}else{
//still more players after human in the array
playHand(CURRENT_PLAYER+1); // same loop but it will start from the player next to human.
}
}
private void calculateHandWinner(){
//do your logic here ...
//re arrange players list...
playHand(0);//start next hand from first player...
}
not sure if this will suite your current structure you may take something useful out of it.
I am using a genetic algorithm and I'm trying to re-create individuals in a population (after removing them at the end of the generation). The issue is that the 'crossover' function creates two individuals and the 'mutate' and 'createRandomIndividual' function create one individual. How could I incorporate that in the loop?
List<Individual> population = new ArrayList<Individual>();
private void replaceIndividuals(int individualsTurnover) {
//individualTurnover = number of individuals I need to re-generate
boolean even = individualsTurnover % 2 == 0;
for (int i=0; i<individualsTurnover/2; i++){
replaceIndividuals();
}
if (!even)
mutate();
}
private void replaceIndividuals() {
int random = generator.nextInt(10);
if (random < 1) {
// generates one individual via mutation
mutate();
}
else if (random < 2) {
// generates one individual randomly
createRandomIndividual();
}
else {
//generates two individuals by crossing-over individuals from a pool of parents
crossover();
}
}
Currently too many individuals are being created. The number of individuals creates should be = 'individualTurnover'.
This might solve your problem. I have changed the method signature slightly
public class Test
{
private void replaceIndividuals(int individualsTurnover) {
//individualTurnover = number of individuals I need to re-generate
while(individualsTurnover > 1)
{
individualsTurnover = individualsTurnover - replaceIndividuals();
//I am deducting this count because those many individuals are already created
}
//This is the only possible count > 0
if(individualsTurnover == 1)
{
mutate();
}
}
/**
*
* #return No of individulas created
*/
private int replaceIndividuals() {
int random = generator.nextInt(10);
if (random < 1) {
// generates one individual via mutation
mutate();
retrun 1;
}
else if (random < 2) {
// generates one individual randomly
createRandomIndividual();
return 1;
}
else {
//generates two individuals by crossing-over individuals from a pool of parents
crossover();
return 2;
}
}
}
I'm creating a program in Java that solves the n-puzzle, without using heuristics, simply just with depth-first and breadth-first searches of the state space. I'm struggling a little bit with my implementation of depth-first search. Sometimes it will solve the given puzzle, but other times it seems to give up early.
Here's my DFS class. DepthFirstSearch() is passed a PuzzleBoard, which is initially generated by shuffling a solved board (to ensure that the board is in a solvable state).
public class DepthFirst {
static HashSet<PuzzleBoard> usedStates = new HashSet<PuzzleBoard>();
public static void DepthFirstSearch(PuzzleBoard currentBoard)
{
// If the current state is the goal, stop.
if (PuzzleSolver.isGoal(currentBoard)) {
System.out.println("Solved!");
System.exit(0);
}
// If we haven't encountered the state before,
// attempt to find a solution from that point.
if (!usedStates.contains(currentBoard)) {
usedStates.add(currentBoard);
PuzzleSolver.print(currentBoard);
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != 0) {
System.out.println("Moving left");
DepthFirstSearch(PuzzleSolver.moveLeft(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != PuzzleSolver.n-1) {
System.out.println("Moving down");
DepthFirstSearch(PuzzleSolver.moveDown(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != PuzzleSolver.n-1) {
System.out.println("Moving right");
DepthFirstSearch(PuzzleSolver.moveRight(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != 0) {
System.out.println("Moving up");
DepthFirstSearch(PuzzleSolver.moveUp(currentBoard));
}
return;
} else {
// Move up a level in the recursive calls
return;
}
}
}
I can assert that my moveUp(), moveLeft(), moveRight(), and moveDown() methods and logic work correctly, so the problem must lie somewhere else.
Here's my PuzzleBoard object class with the hashCode and equals methods:
static class PuzzleBoard {
short[][] state;
/**
* Default constructor for a board of size n
* #param n Size of the board
*/
public PuzzleBoard(short n) {
state = PuzzleSolver.getGoalState(n);
}
public PuzzleBoard(short n, short[][] initialState) {
state = initialState;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(state);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PuzzleBoard other = (PuzzleBoard) obj;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (state[i][j] != other.state[i][j])
return false;
}
}
return true;
}
}
As previously stated, sometimes the search works properly and finds a path to the solution, but other times it stops before it finds a solution and before it runs out of memory.
Here is a snippet of the output, beginning a few moves before the search stops searching.
...
Moving down
6 1 3
5 8 2
0 7 4
Moving right
6 1 3
5 8 2
7 0 4
Moving left
Moving right
Moving up
6 1 3
5 0 2
7 8 4
Moving left
Moving down
Moving right
Moving up
Moving up
Moving right
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
...
I truncated it early for brevity, but it ends up just moving up and down dozens of times and never hits the solved state.
Can anyone shed light on what I'm doing wrong?
Edit: Here is MoveUp(). The rest of the move methods are implemented in the same way.
/**
* Move the blank space up
* #return The new state of the board after the move
*/
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
I have had many problems with hashset in the past best thing to try is not to store object in hashset but try to encode your object into string.
Here is a way to do it:-
StringBuffer encode(PuzzleBoard b) {
StringBuffer buff = new StringBuffer();
for(int i=0;i<b.n;i++) {
for(int j=0;j<b.n;j++) {
// "," is used as separator
buff.append(","+b.state[i][j]);
}
}
return buff;
}
Make two changes in the code:-
if(!usedStates.contains(encode(currentBoard))) {
usedStates.add(encode(currentBoard));
......
}
Note:- Here no need to write your own hashcode function & also no need to implement equals function as java has done it for you in StringBuffer.
I got one of the problems in your implementation:-
In th following code:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Here you are using the reference of same array as newState from currentState.state so when you make changes to newState your currentState.state will also change which will affect DFS when the call returns. To prevent that you should initialize a new array. Heres what to be done:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = new short[n][n];
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
newState[i][j] = currentState.state[i][j];
}
}
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Do this change for all moveup,movedown....
Moreover I donot think your hashset is working properly because if it was then you would always find your new state in hashset and your program would stop. As in equals you comparing the state arrays with same reference hence will always get true. Please try and use my encode function as hash.