I'm trying to create a maze with Union Find, but am unable to remove walls.
This is what I have got so far.
private void createMaze (int cells, Graphics g) {
s = new int[cells*cells]; //No unions yet setting all to -1
for(int i = 0; i < cells*cells; ++i){
s[i] = -1;
}
g.setColor(Color.yellow);
random = new Random();
while(breaker){
g.setColor(Color.yellow);
int innerWall = random.nextInt(4)+0;
int randomCellX = random.nextInt(cells-1)+0;
int randomCellY = random.nextInt(cells)+0;
if(randomCellX==cells&&innerWall==2||
randomCellX==0&&innerWall==0||
randomCellY==cells-1&&innerWall==3||
randomCellY==0&&innerWall==1){
continue;
}
else{
int location = randomCellX+(randomCellY*cells);
int neighbour = 0;
if(innerWall==0){
neighbour =location-1;
}
else if(innerWall==1){
neighbour =location-cells;
}
else if(innerWall==2){
neighbour =location+1;
}
else if(innerWall==3){
neighbour =location+cells;
}
int locationRoot =find(location);
int neighbourRoot =find(neighbour);
if(locationRoot==neighbourRoot){
breaker = checkIfDone(s);
}
union(location,neighbour);
drawWall(randomCellX,randomCellY,innerWall,g);
}
}
}
If I remove the
if(randomCellX==cells&&innerWall==2||
randomCellX==0&&innerWall==0||
randomCellY==cells-1&&innerWall==3||
randomCellY==0&&innerWall==1){
continue;
}
It removes the lines fine,but when it is added the walls are not removed. The method is called but doesn't do anything.
It seems some logical mistake have been done obviously. But can not spot specifically as you haven't given the explanation of the logic you have done. Only can help showing the path where the problem might be happening.
Since you can not reach the else block anyway, it is obvious that one or more of these conditions in if are always true.
(randomCellX == cells && innerWall == 2)
(randomCellX == 0 && innerWall == 0)
(randomCellY == cells - 1 && innerWall == 3)
(randomCellY == 0 && innerWall == 1)
That's why you are getting true for the if condition and continuing the loop without doing anything. Ensure the conditions are okay.
If these conditions are right, the next suspect might be these lines:
int innerWall = random.nextInt(4)+0;
int randomCellX = random.nextInt(cells-1)+0;
int randomCellY = random.nextInt(cells)+0;
Check whether these random values range are exactly what you want or not. For example: you are taking random values for randomCellX from 0 to cells-2, but for randomCellY the range is 0 to cells-1.
Related
currently my program is only always giving me 4, how can I determine how many steps the ant took to cover the whole board? The ant can walk up down left right, but can't walk off the board, and then do this simulation 4 times.
public static void main(String args[]) {
int[][] grid = new int[8][8];
int count = 0;
int x = 0;
int y = 0; // arrays are 0 based
while(true)
{
int random = (int)Math.random()*4+1;
if (random == 1)
{
x--; // move left
}
else if (random == 2)
{
x++; // move right
}
else if (random == 3)
{
y--; // move down
}
else if (random == 4)
{
y++; // move up
}
if(x < 0 || y < 0 || x >= grid.length || y >= grid[x].length) break;
count++;
grid[x][y]++;
}
System.out.println("Number of Steps in this simulation: " + count); // number of moves before it fell
}
}
The problem is this expression:
int random = (int)Math.random()*4+1;
Through the explicit cast, only Math.random() ist casted to int. But since Math.random() returns a dobule < 1, it is casted to 0 and thus random is always 1 and the method always returns 0.
The problem can be fixed by casting Math.random() * 4:
int random = (int) (Math.random() * 4) + 1;
The parenthesis enforce that the value of Math.random() * 4 (which will be a value in the interval [0, 3)) will be casted to int.
Two remarks on your code:
I would recommend introducing an enum Direction with four values (one for each direction) and choose a random Direction by calling Direction.values()[(int) (Math.random() * 4)];
I would recommend to use a switch instead of the if-else-if cascade.
Ideone demo
The program will exit the while(true) loop once one of the 4 conditions is true. My suggestion is to move these conditions in your if(random == value) checks like this:
if( random == 1 )
{
x--;
if (x < 0 )
{
x++;
}
}
Now to exit your while(true) loop you need to have an extra condition. I would suggest to think about your board in terms of 0's and 1's. Everytime the ant cross a cell, you set the grid[x][y] = 1.
int stepsTaken = 0;
int cellsToCover = grid.length * grid[0].length ;
int coveredCells = 0;
while(true)
{
//your code here
if( random == 1 )
{
stepsTaken++;
x--;
if (x < 0 )
{
x++;
}
}
// the other if's with "stepsTaken" incremented too.
if ( grid[x][y] == 0 )
{
grid[x][y] = 1;
coveredCells++;
}
if (coveredCells == cellsToCover )
break;
}
But please notice the many ifs statements inside a while(true) loop. If you have to fill a board of 10 rows x 10 columns it would take too much until the board is filled. Instead I would suggest you to use some more efficient algorithms like backtracking, dynamic programming etc.
Edit : Added step counter.
I am trying to save the method outOfBounds which is called inside the lengthOfColor method more than once to a local variable, so that less processing power is used. I provided the lengthOfColor method in which I want to store the variable, and I also provided the outOfBounds method. As you can see the outOfBounds method is a boolean and I am not sure how to store it with integer parameters.
private Integer[] lengthOfColor(int col, boolean color, int pattern, int row) {
int x = 0;
int y = 0;
if (pattern == 1) {
// vertical pattern
y = 1;
} else if (pattern == 2) {
// horizontal pattern
x = 1;
} else if (pattern == 3) {
// diagonal slope left pattern
x = 1;
y = 1;
} else {
// diagonal slope right pattern
x = 1;
y = -1;
}
// length = how many neighbor slots are of same color
// possible equals number of slots, that you can play off of.
// whichSide = left or right if horizontal and top or bottom if vertical.
int length = 0;
int possible = 0;
Integer[] whichSide = new Integer[]{1, -1};
for (int side : whichSide) {
int i = 1;
boolean complete = false;
//while complete is false continue the loop
while (!complete) {
//mainX == horizontal pattern distance
//mainY == vertical pattern distance
int mainX = x * i * side;
int mainY = y * i * side;
//if still inbounds and if the same slot is filled and it matches the color, increment length
if (!outOfBounds(col, mainX, mainY, row) && getIsFilled(col, mainX, mainY, row) &&
checkColor(col, mainX, mainY, row) == color)
{
length++;
}
//if still inbounds and if the same slot is empty, increment possible number of spots and change complete to true
else if (!outOfBounds(col, mainX, mainY, row) && !getIsFilled(col, mainX, mainY, row) &&
getLowestEmptyIndex(myGame.getColumn(col + mainX)) == getLowestEmptyIndex(myGame.getColumn(col)) + mainY - row)
{
possible++;
complete = true;
}
//finish the statement to avoid a infinite loop if neither conditions are met.
else
{
complete = true;
}
// If not complete, then check one slot further.
i = i + 1;
}
}
return new Integer[] {length, possible};
}
private boolean outOfBounds(int col, int x , int y, int row)
{
int currentX = col;
int currentY = getLowestEmptyIndex(myGame.getColumn(col)) - row;
return currentX + x >= myGame.getColumnCount() || currentY + y >= myGame.getRowCount() || currentX + x < 0 || currentY + y < 0;
}
I see that mainX and mainY change values so there isn't any real optimization that can be done outside of the for and while loop besides creating a boolean value that holds the result of outOfBounds before the if check is called which would reduce the number of operations you need to do. To be honest, the optimization is so insignificant that it wouldn't really matter but would be good coding practice I suppose (JIT might optimize for you as well depending on your code). More importantly the method reduces the extra lines of code you need to type and does not necessarily mean that there is less computing.
So something like this before any outOfBounds call but inside the while loop,
boolean outOfBounds = outOfBounds(col, mainX, mainY, row);
and change your current if(!outOfBounds(col, mainX, mainY, row) && ....) into if (!outOfBounds && ...)
Also the #1 rule to optimization is to not optimize until you are done with your project and notice a significant performance dip. In which case you would start with the biggest bottleneck until the optimal performance is gained. Of course this does not mean coding in an incorrect way which would of course create unnecessary performance losses. In those cases it would also be wise to consider whether or not you are looking at the problem the right way rather than micro-optimizing.
Here's a snippet of what I would do to micro-optimize the code shown.
private Integer[] lengthOfColor(int col, boolean color, int pattern, int row) { // consider changing Integer[] into
// int[] if you don't need a boxed integer. It will increase performance
int x = 0;
int y = 0;
// length = how many neighbor slots are of same color
// possible equals number of slots, that you can play off of.
// whichSide = left or right if horizontal and top or bottom if vertical.
int length = 0;
int possible = 0;
switch (pattern) { // switch may be a tad faster but insignificant. More importantly it provides clarity.
case 1:
y = 1;
break;
case 2:
x = 1;
break;
case 3:
x = 1;
y = 1;
break;
default:
x = 1;
y = -1;
break;
}
//int[] whichSide = new int[]{1, -1}; // changed to int[] because you don't need a boxed primitive from what is
// shown
// nevermind, this line isn't needed and you will be able to avoid an instantiation.
for (int i = 1; i != -3; i-=2) {
int count = 1;
int mainX; // bring this to a higher scope. (honestly this is micro optimization but a habit of mine if this is
// can be considered in scope)
int mainY;
boolean outOfBounds = false;
//boolean complete = false; // removed as its unnecessary to break out of the while loop.
//while complete is false continue the loop
while (true) {
//mainX == horizontal pattern distance
//mainY == vertical pattern distance
mainX = x * count * i;
mainY = y * count * i;
outOfBounds = outOfBounds(col, mainX, mainY, row);
//if still inbounds and if the same slot is filled and it matches the color, increment length
if (!outOfBounds && getIsFilled(col, mainX, mainY, row) &&
checkColor(col, mainX, mainY, row) == color) {
length++;
}
//if still inbounds and if the same slot is empty, increment possible number of spots and change complete to
// true
else if (!outOfBounds && !getIsFilled(col, mainX, mainY, row) &&
getLowestEmptyIndex(myGame.getColumn(col + mainX)) == getLowestEmptyIndex(myGame.getColumn(col)) + mainY -
row) {
possible++;
break;
}
//finish the statement to avoid a infinite loop if neither conditions are met.
else {
break;
}
// If not complete, then check one slot further.
count++;
}
}
return new Integer[]{length, possible}; // once again consider whether or not you need a boxed integer
}
private boolean outOfBounds(int col, int x, int y, int row) {
//int currentX = col; this is an unnecessary line
int currentY = getLowestEmptyIndex(myGame.getColumn(col)) - row;
return col + x >= myGame.getColumnCount() || currentY + y >= myGame.getRowCount() || col + x < 0 ||
currentY + y < 0;
}
I've created a Sudoku solver that will solve a Sudoku as a human might- by checking possibilities + definite values in squares corresponding to the square being checked.
(Source: http://pastebin.com/KVrXUDBF)
However, I would like to create a random Sudoku generator (from a blank grid), and so have decided to use a backtracking algorithm. I understand the concept of backtracking, but am confused about one thing:
How do I know which previous node to return to (and change) once I know a certain solution is not allowed?
Should I simply return to the previous node and cycle through all possibilities? (And then if this yields no correct answers, return to the value before, etc.). This seems like a viable method, but also quite inefficient. Is this the correct way of implementing a backtracking method or is there a better way to go about it?
Thanks in advance.
More can be found about backtracking here: http://en.wikipedia.org/wiki/Backtracking
Sudoku Puzzle can be reduced to graph coloring problem which can be solved using simple backtracking like assigning colors to node (1-9) till the there is no violation that all directly connected nodes have no same color.
Constructing Graph from Sudoku : -
There is an direct edge between two grid points if they are in same
row or column or square.
Backtracking :-
Assign one color (1-9) to node
Check if there is no other directly connected node with same color
If valid color move to next node.
else change the color and recheck.
If all color exhausted backtrack to previous node.
Do recursion till all nodes are color.
Once You are done with it you can start removing numbers from the grid at random till you think the problem is unsolvable if any more numbers are removed.
A simple way to generate random Sudoku is that
1) generate a random completing Sudoku, that is, generate random Sudoku no square is blank.
2) Remove numbers from squares of 1).
3) Solve Sudoku of 2). If there are many solutions, then add a number removed at 2).
If there are still many solutions, then repeat 3).
1) sample source code:
public int[][] generateRandomCompleteSudoku() {
int[][] sudoku = new int[10];
for(int i = 1; i <= 9; i++) {
sudoku[i] = new int[10];
Arrays.fill(sudoku[i], 0);
}
generateRandomCompleteSudoku(sudoku, 1, 1);
return sudoku;
}
private boolean generateRandomCompleteSudoku(int[][] sudoku, int x, int y) {
if(x > 9) {
x = 1;
y++;
}
//sudoku of the argument is completing sudoku.
//so return true
if(y > 9) {
return true;
}
// enumerate the possible numbers of the pos(x,y).
List<Integer> possibleNumbers = new ArrayList<Integer>();
for(int i = 1; i <= 9; i++) {
boolean possible = true;
//check i is a possible number.
//check there isn't i in the raw of y .
for(int j = 1; j <= x - 1; j++) {
if(sudoku[j][y] == i) {
possible = false;
break;
}
}
//check there isn't i in the column of x(omitted).
//check there isn't i in the group of x,y(omitted).
if(possible) {
possibleNumbers.add(i);
}
}
//sudoku is wrong so return false.(There is no solution of sudoku)
if(possibleNumbers.size() <= 0) {
return false;
}
Collections.shuffle(possibleNumbers);// This gives sudoku randomness.
for(Integer possibleNumber : possibleNumbers) {
sudoku[x][y] = possibleNumber;
// a sudoku is generated, so return true
if(generateRandomCompleteSudoku(sudoku, x + 1, y)) {
return true;
}
}
// No sudoku is generated, so return false
return false;
}
For a backtracking solution, the first step is to define the state. So for this problem, I think the most straightforward way is (x,y, blank , num) with x , y is the position of the current state, blank is the number of blank position left, and num is the value you want to fill in that position (from 0 to 9 and 0 means blank).
And the return type should be boolean, which determine whether the move is valid or not (which means is there any valid solution for this move).
So, the state transition is column by column, row by row: x, y to x , (y + 1) or x , y to (x + 1), 0.
Similarly, the blank will be from a -> a - 1-> ... 0.
We have a draft solution here:
public boolean move(int x, int y, int blank, int num, int[][]sudoku){
sudoku[x][y] = num;
//checking condition and return if x,y is the last position, code omitted
if(y == sudoku[x].length){
x++;
y = 0;
}else{
y++;
}
for(int i = 1; i < 10; i++){
if(move(x,y,blank,i,sudoku){//Backtrack here
return true;
}
}
if(blank > 0){
if(move(x,y,blank - 1, 0, sudoku){//Backtrack here
return true;
}
}
return false;
}
So when ever there is a false return from the current state, it will backtrack to the last state , and the last state will continue to check for the next num until it find a correct solution (or return false).
I'm trying to implement a binary insert method.
Currently this method is very simple, it takes an argument, in a while loop it searches for an element that is bigger than the argument (in this case a String that is the last name of a person), it breaks once it finds it and shifts the rest of the array to the right. Then the argument is inserted at the position of breaking.
I tried changing it to one that would search for the insert position by borrowing from the binary search algorithm. However, I just can't get it to work.
Could you please let me know what I'm doing wrong? Here's my code:
public void insert(Person person)
{
String lastName = person.getLastName();
int position = -1; // the position from which the array will be shifted to the right and where the argument will be inserted, will be assigned properly below
int lowerBound = 0;
int upperBound = numElems - 1;
int currIt;
if (numElems == 0)
array[0] = person; // if array empty insert at first position
else
{
while (true)
{
currIt = (lowerBound + upperBound) / 2; //the item to compare with
int result2 = 0;
int result1 = array[currIt].getLastName().compareTo(lastName);
if (array[currIt+1] != null) // if the next element is not null, compare the argument to it
result2 = array[currIt+1].getLastName().compareTo(lastName);
if (currIt == 0 && result1 > 0) // this is when the argument is smaller then the first array element
{
position = 0;
break;
}
// if the position to insert is the last one, or we have found a suitable position between a smaller and a bigger element
else if ( (result1 < 0 && (currIt == numElems-1)) || (result1 < 0 && result2 > 0) ) {
position = currIt+1;
break;
}
else
{
if (result1 < 0) // the place to put it should be in the upper half
lowerBound = currIt + 1;
else
upperBound = currIt - 1; //in the lower half
}
}
}
// position has been set to anything else other -1, then we have found our spot, probably a redundant check but useful for debugging
if (position != -1)
{
//shift array to the right and insert element
for (int j = numElems; j > position; j--)
array[j] = array[j-1];
System.out.println("Inserted an element");
array[position] = person;
numElems++;
}
}
Your "probably [] redundant check" prohibits initial inserting. Position is -1 the first time.
Setting position to 0 at the top, should fix the problem.
I am having problems with my full house method. I thought it was as simple as checking for three of a kind and a pair. But with my current code i am getting a full house with only a three of a kind. Code for isFullHouse() isThreeOfAKind() and isPair() is below thanks for all the help!
public boolean isPair() {
Pips[] values = new Pips[5];
int count =0;
//Put each cards numeric value into array
for(int i = 0; i < cards.length; i++){
values[i] = cards[i].getPip();
}
//Loop through the values. Compare each value to all values
//If exactly two matches are made - return true
for(int x = 1; x < values.length; x++){
for(int y = 0; y < x; y++){
if(values[x].equals(values[y])) count++;
}
if (count == 1) return true;
count = 0;
}
return false;
}
public boolean isThreeOfAKind() {
Pips[] values = new Pips[5];
int counter = 0;
for(int i = 0; i < cards.length; i++){
values[i] = cards[i].getPip();
}
//Same process as isPair(), except return true for 3 matches
for(int x = 2; x < values.length; x++){
for(int y = 0; y < x; y++){
if(values[x].equals(values[y]))
counter++;
}
if(counter == 2) return true;
counter = 0;
}
return false;
}
public boolean isFullHouse(){
if(isThreeOfAKind() && isPair())
return true;
return false;
}
Check to make sure that the pair is of a different rank than the three of a kind. Otherwise, your isPair() function will find the same cards as the three of a kind. Maybe like this:
public boolean isFullHouse(){
int three = isThreeOfAKind();
int pair = isPair();
if (three != 0 && pair != 0 && three != pair) {
return true;
}
return false;
}
(I used int, but you could change to use your Pips type if you like.)
Can I suggest a way of making your logic dramatically simpler?
Consider a helper method named partitionByRank():
public class RankSet {
private int count;
private Rank rank;
}
/**
* Groups the hand into counts of cards with same rank, sorting first by
* set size and then rank as secondary criteria
*/
public List<RankSet> partitionByRank() {
//input e.g.: {Kh, Qs, 4s, Kd, Qs}
//output e.g.: {[2, K], [2, Q], [1, 4]}
}
Getting the type of hand is really easy then:
public boolean isFullHouse() {
List<RankSet> sets = partitionByRank();
return sets.length() == 2 && sets.get(0).count == 3 && sets.get(1).count() == 2;
}
public boolean isTrips() {
//...
return sets.length() == 3 && sets.get(0).count = 3;
}
This will also help later on when you inevitably need to check whether one pair is greater than another pair, e.g.
You have to remove the three of a kind cards from the five card hand first. Three of a kind is true implies two of a kind is true. The sets need to be disjoint.
You are missing a third condition: the triple needs to be different cards than the pair. Soo... since you have this shared "cards" array, you probably could "mark" the cards as counted, and reset the counted status for each pass:
//Same process as isPair(), except return true for 3 matches
for(int x = 2; x < values.length; x++){
cards[x].setCounted(true); // by default, count the start card
for(int y = 0; y < x; y++){
// make sure the card isn't already counted:
if(!cards[y].isCounted() && values[x].equals(values[y])) {
counter++;
cards[x].setCounted(true); // count it
}
}
if(counter == 2) return true;
counter = 0;
// reset counted cards
for(int z=0, zlen=values.length; z < zlen; z++) { cards[z].setCounted(false); }
}
because three of a kind has a pair as well (actually would probably be 2 pairs in your code)
one way to do this is to sort the hand by rank, then its just conditionals to detect a boat.
if ( ((c1.rank == c2.rank == c3.rank) && (c4.rank == c5.rank)) ||
(c1.rank == c2.rank) && (c3.rank == c4.rank == c5.rank))
ther emight be an extra ( in there but you get the idea...
You need to make sure the pair is a different two cards than the three of a kind. If the hand is A A A 7 8, then both ThreeOfAKind and isPair return true because you have three aces (and a pair of aces).
Your isPair() method will always return true when there are three cards of a kind because your inner loop always tests the y values only up to x.
so with this data AAA78, when x = 1 y = 0 you will get count == 1 in the inner loop and return true although there are three of a kind. It's better to loop over the entire array and count values when
if(values[x].equals(values[y]) && x != y)
Besides - it's better to use one function in the form of isNOfAKind() which gets the amount of cards as a parameter since these two methods essentially do the same.
Just an idea, wouldn't it be easier to do something like this:
int[] count=new int[13];//size of all ranks
for (i=0;i<5;i++)
count[ card[i].rank ] ++;
So you will have for example: 0 0 0 0 0 3 0 0 0 2 0 0 0 0 for a full house. A straight would look like 5 ones in a row: 0 0 0 0 1 1 1 1 1 0 0 0.
Since the methods are public, I would not like the isPair() method to return true if there is a pair. It should only return true if there is nothing better than one pair.
A better general approach to the problem - this is C#, but converting it to Java should be straightforward:
int[] countOfRank = new int[13];
int[] countOfSuit = new int[4];
for(int i = 0; i < cards.length; i++)
{
countOfRank[cards[i].Rank]++;
countOfSuit[cards[i].Suit]++;
}
for (int i=0; i < countOfSuit.length; i++)
{
isFlush = isFlush || countOfSuit[i] == 5;
}
int[] countOfTuple = new int[5];
int runLength=0;
for (int i=0; i < countOfRank.length; i++)
{
if (countOfRank[i] == 1)
{
runLength++;
isStraight = (isStraight || runLength == 5);
}
else
{
runLength=0;
}
countOfTuple[countOfRank[i]]++;
}
isPair = (countOfTuple[2] == 1 && countOfTuple[3] == 0);
isTwoPair = (countOfTuple[2] == 2);
isFullHouse = (countOfTuple[2] == 1 && countOfTuple[3] == 1);
isThreeOfAKind = (countOfTuple[2] == 0 && countOfTuple[3] == 1);
isFourOfAKind = (countOfTuple[4] == 1);
isStraightFlush = (isStraight && isFlush);
isStraight = (isStraight && !isStraightFlush);
isFlush = (isFlush && !isStraightFlush);
isRoyalFlush = (isStraightFlush && countOfRank[12] == 1);
isStraightFlush = (isStraightFlush && !isRoyalFlush);
If you're only dealing with five-card hands, counting the number of pairs should yield one for a pair, two for two-pair, three for three-of-a-kind (e.g. if one has As, Ad, and Ac, the pairs are As-Ad, As-Ac, and Ad-Ac), four for a full house, and six for four-of-a-kind. This logic will not work with seven card hands, since it would count three for e.g. A-A-K-K-Q-Q-J (which should only count as two-pair, not three-of-a-kind), and six for A-A-A-K-K-K-Q (which should count as a full house, not four-of-a-kind).
According to your code inlined comments (exactly two matches words) maybe you are trying to implement isPair method in such a way that it will return false in case of three of a kind combination. If so, you need change your isPair method to iterate over all items in the array, like this:
//Loop through the values. Compare each value to all values
//If exactly two matches are made - return true
for(int x = 0; x < values.length; x++){
for(int y = 0; y < values.length; y++){
if(y != x && values[x].equals(values[y])) count++;
}
if (count == 1) return true;
count = 0;
}