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;
}
}
}
Related
The goal of my task is to generate a presents list(with a max amount price) with presents from another list. The max amount(totalePrijs) cannot exceed 500 AND you can't have the same present more than once in that generated list. The presents chosen are done with a random generator that goes up to 27(amount of presents).
It works perfectly except for the same present more than once part. Which I have yet to figure out. Either I was thinking of making an empty IntegerArray and checking if that Array contained x, if it did than it should restart from the beginning of the while statement otherwise it would add x to that array and continue.
The other way I thought off was changing the if statement to
if (selectedCadeauModel.contains(present.name) && totalePrijs + present.price < 500)
But that just made it loop infinitly I think.
This is the code that executes when clicking on the generate presents button.
selectedCadeauModel.clear();
double totalePrijs = 0;
while (totalePrijs < 500) {
NumberGen ran = new NumberGen();
int x = Integer.parseInt(ran.toString());
Cadeau present = (Cadeau) cadeauModel.elementAt(x);
if (totalePrijs + present.price < 500) {
totalePrijs += present.price;
selectedCadeauModel.addElement(new Cadeau(present.name, present.price));
} else {
break;
}
ftxTotaalPrijs.setValue(totalePrijs);
lstGeneratedPresents.setModel(selectedCadeauModel);
ftxGemiddeldePrijs.setValue(totalePrijs / selectedCadeauModel.size());
}
/
public class Cadeau {
String name;
double price;
public Cadeau(String naam, double prijs) {
name = naam;
price = prijs;
}
/
public class NumberGen {
Random randomGenerator = new Random();
int getal = randomGenerator.nextInt(27);
#Override
public String toString() {
return String.format("%d", getal);
}
}
I have an Ant Colony Simulator. It is a 27 x 27 grid, and there is a Forager Ant class which locates food and the highest pheromone levels. I need to randomly generate the movement within a range.
This is a very large project, so here is only the method in question (if that's enough):
private GridNode locateHighestPherms() {
Random randomNode = new Random();
LinkedList<GridNode> neighborNodeList = gridLocation.getNeighboringNodes(); //a List of Node Objects that keeps track of adjacent nodes
LinkedList<GridNode> randomGridNode = new LinkedList<>(); //random destination Node
for(Iterator<GridNode> gridNodeIterator = neighborNodeList.iterator(); gridNodeIterator.hasNext();) {
GridNode alreadyVisited = gridNodeIterator.next();
if(foragerMoveHistory.contains(alreadyVisited) || !alreadyVisited.isVisible()) {
gridNodeIterator.remove();
}
}
if(neighborNodeList.size() == 0) {
neighborNodeList = gridLocation.getNeighboringNodes();
}
GridNode nodeWithMostPherms = neighborNodeList.get(0);
for(int checkNode = 1; checkNode < neighborNodeList.size(); checkNode++) {
if(nodeWithMostPherms.isVisible() && nodeWithMostPherms.getPheromoneUnit() < neighborNodeList.get(checkNode).getPheromoneUnit()) {
nodeWithMostPherms = neighborNodeList.get(checkNode);
}
}
for (GridNode neighborNode : neighborNodeList) {
if ((neighborNode.getPheromoneUnit() == nodeWithMostPherms.getPheromoneUnit()) && neighborNode.isVisible()) {
randomGridNode.add(neighborNode);
}
}
//DEBUGGING
//System.out.println(randomGridNode.size());
nodeWithMostPherms = randomGridNode.get(randomNode.nextInt(randomGridNode.size()));
//nodeWithMostPherms = randomGridNode.get(RandomInstance.randomNumberGen(1, randomGridNode.size()));
return nodeWithMostPherms;
}
}
Right there ^ the assignment to nodeWithMostPherms is where I need to access the next Random number. However, when I originally tried the code that's commented out, it was crashing because at times I was trying to access zero when the list size was zero.
I will show you my RandomInstance class. It's short and sweet:
import java.util.Random;
public class RandomInstance {
static int randomNumber;
public static int randomNumberGen(int lowRange, int highRange) {
Random numberGenerator = new Random(); //I would prefer not to have this.
randomNumber = numberGenerator.nextInt(highRange - lowRange + 1) + lowRange;
/** EXAMPLE FOR REFERENCE
* setFoodUnitAmount(RandomInstance.randomNumberGen(500, 1000));
*/
return randomNumber;
}
}
The reason I have my own Random class is because there are many instances of random numbers that are generated, and it was suggested to create our own so we don't have a bunch of instances of java.util.Random all over the place.
Does anyone have any suggestions on how I can make this fit my RandomInstance class?
If I try the code that's commented out, it throws an IndexOutOfBoundsException
Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 8, Size: 8
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.get(LinkedList.java:476)
at ForagerObject.locateHighestPherms(ForagerObject.java:121)
Line 121 is the assignment in question mentioned above.
While you can have Random shared, you shouldn't share a multiple field.
public class RandomInstance {
private final Random random = new Random();
public int nextInt(int min, int max) {
return random.nextInt(max - min + 1) + min;
}
}
so when you call it
nodeWithMostPherms = randomGridNode.get(randomInstance.nextInt(1, randomGridNode.size()-1));
or you could use Random directly
nodeWithMostPherms = randomGridNode.get(random.nextInt(randomGridNode.size()-1)+1);
http://www.cstutoringcenter.com/problems/problems.php?id=103
For those who doesn't want to click it, it basically says there's a stepping stone, "-" and soldier "#", soldiers can only move right. If the soldier is behind another soldier, he must wait for the soldier to move first. The ending condition is when all soldiers reaches the end.
The number of ways 2 soldier can move across 5 stepping stones.
1) ##--- #-#-- -##-- -#-#- --##- --#-# ---##
2) ##--- #-#-- -##-- -#-#- -#--# --#-# ---##
3) ##--- #-#-- #--#- -#-#- --##- --#-# ---##
4) ##--- #-#-- #--#- -#-#- -#--# --#-# ---##
5) ##--- #-#-- #--#- #---# -#--# --#-# ---##
I'm using a breadth first search, with 5 stones, it's running within seconds, but with 10 stones, it's taking hours, the time is increasing exponentially with the depth. How can I deal with this?
My Codes:
States.java
import java.util.ArrayList;
public class State {
public int stones;
public Soldiers[] soldiers;
public String currentState ="";
public boolean visited = false;
public State(int stones,int Numsoldiers){
System.out.println(Numsoldiers);
this.stones = stones;
soldiers = new Soldiers[Numsoldiers];
System.out.println("length" + soldiers.length);
initState();
}
public State(int stones,Soldiers[] soldiers){
this.stones = stones;
this.soldiers = soldiers;
paintState();
}
public void initState(){
for(int i=0;i<soldiers.length;i++)
{
soldiers[i] = new Soldiers();
soldiers[i].position =i;
currentState+="#";
}
for(int j=soldiers.length;j<stones;j++)
{
currentState+="-";
}
}
private void paintState(){
for(int j=0;j<stones;j++)
{
currentState+="-";
}
char[] stateChar = currentState.toCharArray();
currentState = "";
for(int i=0;i<soldiers.length;i++){
stateChar[soldiers[i].position] = '#';
}
for(int k=0; k<stateChar.length;k++){
currentState += stateChar[k];
}
}
public void printState(){
System.out.println(currentState);
}
public ArrayList<State> getNextStates(){
ArrayList<State> States = new ArrayList<State>();
for(int i=0;i<soldiers.length;i++){
Soldiers[] newSoldiers = new Soldiers[soldiers.length];
for(int j=0;j<soldiers.length;j++){
newSoldiers[j] = new Soldiers(soldiers[j].position);
}
if(!((newSoldiers[i].position+1)==stones))
{
if((currentState.charAt((newSoldiers[i].position+1))=='-'))
{
newSoldiers[i].move();
States.add(new State(stones,newSoldiers));
}
}
}
if(States.size()==0)
{
TestSoldiers.count++;
}
return States;
}
}
Soldiers.java
public class Soldiers {
int position = 0;
public Soldiers(){
position =0;
}
public Soldiers(int pos){
position = pos;
}
public void move(){
position ++;
}
}
TestSoldiers.java
import java.util.LinkedList;
import java.util.Queue;
public class TestSoldiers {
public static int count=0;
public static void main(String[] args){
TestSoldiers t = new TestSoldiers();
}
public TestSoldiers()
{
State s = new State(10,3);
breadthFirstTraversal(s);
System.out.println(count);
}
public void breadthFirstTraversal(State rootNode){
Queue<State> q = new LinkedList<State>();
q.add(rootNode);
while(!q.isEmpty()){
State n = (State)q.poll();
n.printState();
for(State adj : n.getNextStates()){
q.add(adj);
}
}
}
}
How can I make it so that I will only consider each State once while maintaining the integrity of the total number of ways to end (counts in TestSoldiers.java)?
For those of you who want to modify the parameters, it's the new State(n,k) where n is the number of stones and k is the number of soldiers.
Memoization might come in handy.
The idea would be to run depth-first search to count the number of ways to get from the current state to the end, and store this result, then look up the already-calculated value if ever that state is repeated.
For instance, there are 2 ways to reach the end from -#-#-, so, storing this result when we get there via -##--, we could simply look up 2 when we get there via #--#-.
The simplest (but far from most efficient) way to store these would simply be to have a:
Map<Pair<Integer (Position1), Integer (Position2)>, Integer (Count)>
More generically, you could perhaps make that Pair a List.
A more efficient approach would be to have a bitmap where each bit corresponds to whether or not there's a soldier at some given position. So -#-#- would correspond to 01010, which could simply be stored in an int as 10 in decimal - if there are more than 64 stones (i.e. what would fit into a long), you could use a BitSet.
You might be better using combinatorics to compute the number of paths.
For example, suppose there are 2 soldiers and 5 steps.
Represent the distance the first soldier has moved by y, and the distance the second soldier has moved by x.
You are trying to count the number of monotonic paths from 0,0 to 3,3 such that y is never greater than x.
This is a well known problem and the answer is given by the Catalan numbers. In this case, the answer is given by the Catalan number for n=3, which is 5.
When you have more than 2 soldiers you will need to use multidimensional Catalan numbers. A useful guide and formula can be found on OEIS:
T(m, n) = 0! * 1! * .. * (n-1)! * (m * n)! / ( m! * (m+1)! * .. * (m+n-1)! )
My solution runs 10 positions in less than 1 second. The solution is quick and dirty, but the algorithm is what you should be interested in right?
The idea of my algorithm is:
manage a set of paths to compute. start with the path where both soldiers are at the left most positions.
if the set of paths to compute is not empty pick any path and remove it from the set.
if the path is terminated (both soldiers are at the most right positions) print the path. continue with 2.
extend the path by moving the head soldier if possible and put it into the set.
extend the path by moving the tail soldier if possible and put it into the set.
That's it.
public static void main(String[] args) {
List<Node> nodes = Node.newRootNode(10);
while (!nodes.isEmpty()) {
Node node = nodes.remove(0);
if (node.isLeaf()) node.printPath();
else {
if (node.headSoldierCanMove()) nodes.add(node.moveHeadSoldier());
if (node.tailSoldierCanMove()) nodes.add(node.moveTailSoldier());
}
}
}
static final class Node {
static List<Node> newRootNode(final int maxPos) {
return new ArrayList<Node>() {{
add(new Node(1, 2, maxPos, ""));
}};
}
private final int maxPos;
private final String path;
private int tailPos = 1;
private int headPos = tailPos + 1;
private Node(int tailPos, int headPos, int maxPos, String path) {
this.maxPos = maxPos;
this.tailPos = tailPos;
this.headPos = headPos;
this.path = addPath(path);
}
boolean tailSoldierCanMove() {
return tailPos < headPos - 1;
}
Node moveTailSoldier() {
return new Node(tailPos + 1, headPos, maxPos, path);
}
boolean headSoldierCanMove() {
return headPos < maxPos;
}
Node moveHeadSoldier() {
return new Node(tailPos, headPos + 1, maxPos, path);
}
void printPath() {
System.out.println(path);
}
boolean isLeaf() {
return headPos == maxPos && tailPos == headPos - 1;
}
private String addPath(String prefix) {
StringBuilder builder = new StringBuilder(prefix);
for (int pos = 1; pos <= maxPos; pos++) {
builder.append(tailPos == pos || headPos == pos ? "#" : "-");
}
return builder.append(" ").toString();
}
}
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..
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.