8 Puzzle A* java Implemenation [closed] - java

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am told that A* implementation on following 8 puzzle Solver is wrong, can anybody please tell me where it's wrong and how to correct it?
Also: this throws Exception in thread "main" java.lang.OutOfMemoryError: Java heap space even though Build Process Heap size is set to 2048.
Here is Solver.java
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.PriorityQueue;
public class Solver {
private int moves = 0;
private SearchNode finalNode;
private Stack<Board> boards;
public Solver(Board initial) {
if (!initial.isSolvable()) throw new IllegalArgumentException("Unsolvable puzzle");
// this.initial = initial;
PriorityQueue<SearchNode> minPQ = new PriorityQueue<SearchNode>(initial.size() + 10);
Set<Board> previouses = new HashSet<Board>(50);
Board dequeuedBoard = initial;
Board previous = null;
SearchNode dequeuedNode = new SearchNode(initial, 0, null);
Iterable<Board> boards;
while (!dequeuedBoard.isGoal()) {
boards = dequeuedBoard.neighbors();
moves++;
for (Board board : boards) {
if (!board.equals(previous) && !previouses.contains(board)) {
minPQ.add(new SearchNode(board, moves, dequeuedNode));
}
}
previouses.add(previous);
previous = dequeuedBoard;
dequeuedNode = minPQ.poll();
dequeuedBoard = dequeuedNode.current;
}
finalNode = dequeuedNode;
}
// min number of moves to solve initial board
public int moves() {
if (boards != null) return boards.size()-1;
solution();
return boards.size() - 1;
}
public Iterable<Board> solution() {
if (boards != null) return boards;
boards = new Stack<Board>();
SearchNode pointer = finalNode;
while (pointer != null) {
boards.push(pointer.current);
pointer = pointer.previous;
}
return boards;
}
private class SearchNode implements Comparable<SearchNode> {
private final int priority;
private final SearchNode previous;
private final Board current;
public SearchNode(Board current, int moves, SearchNode previous) {
this.current = current;
this.previous = previous;
this.priority = moves + current.manhattan();
}
#Override
public int compareTo(SearchNode that) {
int cmp = this.priority - that.priority;
return Integer.compare(cmp, 0);
}
}
public static void main(String[] args) {
int[][] tiles = {{4, 1, 3},
{0, 2, 6},
{7, 5, 8}};
double start = System.currentTimeMillis();
Board board = new Board(tiles);
Solver solve = new Solver(board);
System.out.printf("# of moves = %d && # of actual moves %d & time passed %f\n, ", solve.moves(), solve.moves, (System.currentTimeMillis() - start) / 1000);
}
}
And Board.java, just in case:
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
public final class Board {
private final int[][] tilesCopy;
private final int N;
// cache
private int hashCode = -1;
private int zeroRow = -1;
private int zeroCol = -1;
private Collection<Board> neighbors;
/*
* Rep Invariant
* tilesCopy.length > 0
* Abstraction Function
* represent single board of 8 puzzle game
* Safety Exposure
* all fields are private and final (except cache variables). In the constructor,
* defensive copy of tiles[][] (array that is received from the client)
* is done.
*/
public Board(int[][] tiles) {
//this.N = tiles.length;
this.N = 3;
this.tilesCopy = new int[N][N];
// defensive copy
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (tiles[i][j] >= 0 && tiles[i][j] < N*N) tilesCopy[i][j] = tiles[i][j];
else {
System.out.printf("Illegal tile value at (%d, %d): "
+ "should be between 0 and N^2 - 1.", i, j);
System.exit(1);
}
}
}
checkRep();
}
public int tileAt(int row, int col) {
if (row < 0 || row > N - 1) throw new IndexOutOfBoundsException
("row should be between 0 and N - 1");
if (col < 0 || col > N - 1) throw new IndexOutOfBoundsException
("col should be between 0 and N - 1");
return tilesCopy[row][col];
}
public int size() {
return N;
}
public int hamming() {
int hamming = 0;
for (int row = 0; row < this.size(); row++) {
for (int col = 0; col < this.size(); col++) {
if (tileAt(row, col) != 0 && tileAt(row, col) != (row*N + col + 1)) hamming++;
}
}
return hamming;
}
// sum of Manhattan distances between tiles and goal
public int manhattan() {
int manhattan = 0;
int expectedRow = 0, expectedCol = 0;
for (int row = 0; row < this.size(); row++) {
for (int col = 0; col < this.size(); col++) {
if (tileAt(row, col) != 0 && tileAt(row, col) != (row*N + col + 1)) {
expectedRow = (tileAt(row, col) - 1) / N;
expectedCol = (tileAt(row, col) - 1) % N;
manhattan += Math.abs(expectedRow - row) + Math.abs(expectedCol - col);
}
}
}
return manhattan;
}
public boolean isGoal() {
if (tileAt(N-1, N-1) != 0) return false; // prune
for (int i = 0; i < this.size(); i++) {
for (int j = 0; j < this.size(); j++) {
if (tileAt(i, j) != 0 && tileAt(i, j) != (i*N + j + 1)) return false;
}
}
return true;
}
// change i && j' s name
public boolean isSolvable() {
int inversions = 0;
for (int i = 0; i < this.size() * this.size(); i++) {
int currentRow = i / this.size();
int currentCol = i % this.size();
if (tileAt(currentRow, currentCol) == 0) {
this.zeroRow = currentRow;
this.zeroCol = currentCol;
}
for (int j = i; j < this.size() * this.size(); j++) {
int row = j / this.size();
int col = j % this.size();
if (tileAt(row, col) != 0 && tileAt(row, col) < tileAt(currentRow, currentCol)) {
inversions++;
}
}
}
if (tilesCopy.length % 2 != 0 && inversions % 2 != 0) return false;
if (tilesCopy.length % 2 == 0 && (inversions + this.zeroRow) % 2 == 0) return false;
return true;
}
#Override
public boolean equals(Object y) {
if (!(y instanceof Board)) return false;
Board that = (Board) y;
// why bother checking whole array, if last elements aren't equals
return this.tileAt(N - 1, N - 1) == that.tileAt(N - 1, N - 1) && this.size() == that.size() && Arrays.deepEquals(this.tilesCopy, that.tilesCopy);
}
#Override
public int hashCode() {
if (this.hashCode != -1) return hashCode;
// more optimized version(Arrays.hashCode is too slow)?
this.hashCode = Arrays.deepHashCode(tilesCopy);
return this.hashCode;
}
public Collection<Board> neighbors() {
if (neighbors != null) return neighbors;
if (this.zeroRow == -1 && this.zeroCol == -1) findZeroTile();
neighbors = new HashSet<>();
if (zeroRow - 1 >= 0) generateNeighbor(zeroRow - 1, true);
if (zeroCol - 1 >= 0) generateNeighbor(zeroCol - 1, false);
if (zeroRow + 1 < this.size()) generateNeighbor(zeroRow + 1, true);
if (zeroCol + 1 < this.size()) generateNeighbor(zeroCol + 1, false);
return neighbors;
}
private void findZeroTile() {
outerloop:
for (int i = 0; i < this.size(); i++) {
for (int j = 0; j < this.size(); j++) {
if (tileAt(i, j) == 0) {
this.zeroRow = i; // index starting from 0
this.zeroCol = j;
break outerloop;
}
}
}
}
private void generateNeighbor(int toPosition, boolean isRow) {
int[][] copy = Arrays.copyOf(this.tilesCopy, tilesCopy.length);
if (isRow) swapEntries(copy, zeroRow, zeroCol, toPosition, zeroCol);
else swapEntries(copy, zeroRow, zeroCol, zeroRow, toPosition);
neighbors.add(new Board(copy));
}
private void swapEntries(int[][] array, int fromRow, int fromCol, int toRow, int toCol) {
int i = array[fromRow][fromCol];
array[fromRow][fromCol] = array[toRow][toCol];
array[toRow][toCol] = i;
}
public String toString() {
StringBuilder s = new StringBuilder(4 * N * N); // optimization?
// s.append(N + "\n");
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
s.append(String.format("%2d ", tileAt(i, j)));
}
s.append("\n");
}
return s.toString();
}
private void checkRep() {
assert tilesCopy.length > 0;
}
}

The problem you have is at line
int[][] copy = Arrays.copyOf(this.tilesCopy, tilesCopy.length);
You assume here to have copied the matrix. But actually you've copied the array with references to arrays in the 2nd dimension.
In other words
copy == this.tolesCopy // false
copy[0] == this.tilesCopy[0] // true
copy[1] == this.tilesCopy[1] // true
copy[2] == this.tilesCopy[2] // true
what leads to have the same matrix changed multiple times, and even to an invalid/unsolvable state.
The easiest fix I see in your code would be to change the generateNeighbor method
private void generateNeighbor(int toPosition, boolean isRow) {
Board board = new Board(this.tilesCopy);
if (isRow) swapEntries(board.tilesCopy, zeroRow, zeroCol, toPosition, zeroCol);
else swapEntries(board.tilesCopy, zeroRow, zeroCol, zeroRow, toPosition);
neighbors.add(board);
}
Although the overal idea looks good. There are multiple other things that can be improved. I suggest you to have a look at this implementation

Related

What's Wrong With this minimax algorithm

I have no idea what the problem is .I printed the moveVal all the time it prints 0 and its going in a horizontal order.
The I have been editing a changing the code by using Google and YouTube but, there was no good
static class Move {
int row, col;
}
private boolean equals(JButton a, JButton b, JButton c){
return a.getText().equals(b.getText()) && b.getText().equals(c.getText()) && !a.getText().equals("");
}
private boolean isGameOver() {
for (int i = 0; i < 3; i++) {
if (equals(board[i][0], board[i][1], board[i][2])) {
return true;
}
}
for (int i = 0; i < 3; i++) {
if (equals(board[0][i], board[1][i], board[2][i])) {
return true;
}
}
if (equals(board[0][0], board[1][1], board[2][2])) {
return true;
}
else if (equals(board[2][0], board[1][1], board[0][2])) {
return true;
}
int openSpots = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j].getText().equals("")) {
openSpots++;
}
}
}
return openSpots == 0;
}
private int evaluate(JButton[][] b) {
for (int row = 0; row < 3; row++)
{
if (b[row][0] == b[row][1] &&
b[row][1] == b[row][2])
{
if (b[row][0].getText().equals(ai))
return 20;
else if (b[row][0].getText().equals(human))
return -10;
}
}
for (int col = 0; col < 3; col++)
{
if (b[0][col] == b[1][col] &&
b[1][col] == b[2][col])
{
if (b[0][col].getText().equals(ai))
return 20;
else if (b[0][col].getText().equals(human))
return -10;
}
}
if (b[0][0] == b[1][1] && b[1][1] == b[2][2])
{
if (b[0][0].getText().equals(ai))
return 20;
else if (b[0][0].getText().equals(human))
return -10;
}
if (b[0][2] == b[1][1] && b[1][1] == b[2][0])
{
if (b[0][2].getText().equals(ai))
return 20;
else if (b[0][2].getText().equals(human))
return -10;
}
return 0;
}
private int minimax(JButton[][] position, int depth, boolean isMax) {
if (isGameOver() || depth == 0){
return evaluate(position);
}
else if (isMax)
{
int best = -1000000000;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (position[i][j].getText().equals(""))
{
position[i][j].setText(ai);
JButton[][] position1 = position;
best = Math.max(best, minimax(position1, depth - 1, false));
System.out.println(best);
position[i][j].setText("");
}
}
}
return best;
}
else
{
int best1 = 1000000000;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (position[i][j].getText().equals(""))
{
position[i][j].setText(human);
JButton[][] position1 = position;
best1 = Math.min(best1, minimax(position1, depth - 1, true));
position[i][j].setText("");
}
}
}
return best1;
}
}
private void BestMove(JButton[][] board) {
int bestVal = -1000000000;
Move bestMove = new Move();
bestMove.row = -1;
bestMove.col = -1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (board[i][j].getText().equals(""))
{
board[i][j].setText(ai);
int moveVal = minimax(board, 3, false);
board[i][j].setText("");
if (moveVal > bestVal)
{
bestVal = moveVal;
bestMove.row = i;
bestMove.col = j;
}
}
}
}
board[bestMove.row][bestMove.col].setText(ai);
playersTurn = true;
CheckWinner();
}
Any ideas & please help is needed
past 3 days I have been debugging I know this code is not the best in fact this code might be the worst you have ever seen.
Blockquote
You have only 3 possible evaluations:
20, if the AI wins
-10, if the human wins
0, in all other cases
As you only look at 4 turns (ai, human, ai, human), it's impossible to find a winning position, so the evaluation is always 0.
There is no obvious issue with your implementation of the minimax, however your evaluation function is too simple.
You can, for example:
Give more points to playing in a position that creates a row of 2
Give more points to playing in a position that creates multiple rows of 2
Give less points to a position that is already blocked
However, there is only so much you can do. This game is obviously solved, and a perfect player can always get a draw playing either sides.

8 Queens Java Recursion [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I am practicing for my final for my AP Computer Science class. Anyways, I have just learned recursion and I need help simplifying several methods into one for the 8 queens problem.
I am needing to combine the rowOne-rowEight methods into one method in itself. The program works and prints all 92 solutions, but it just needs simplified..
public class NonAttacking
{
private static int [][] board = new int[8][8];
private static int count = 0;
public void rowOne(int y)
{
int x = 0;
if(onBoard(x, y) != -1)
{
if(validMove(x, y) == 0) //if the move is valid (0) then it puts a 1 at those coordinates and moves on to the next method (RowTwo)
{
board[x][y] = 1;
rowTwo(0);
}
board[x][y] = 0;
rowOne(y + 1);
}
}
public void rowTwo(int col)
{
int x = 1;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowThree(0);
}
board[x][col] = 0;
rowTwo(col + 1);
}
}
public void rowThree(int col)
{
int x = 2;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowFour(0);
}
board[x][col] = 0;
rowThree(col + 1);
}
}
public void rowFour(int col)
{
int x = 3;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowFive(0);
}
board[x][col] = 0;
rowFour(col + 1);
}
}
public void rowFive(int col)
{
int x = 4;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowSix(0);
}
board[x][col] = 0;
rowFive(col + 1);
}
}
public void rowSix(int col)
{
int row = 5;
if(onBoard(row, col) != -1)
{
if(validMove(row, col) == 0)
{
board[row][col] = 1;
rowSeven(0);
}
board[row][col] = 0;
rowSix(col + 1);
}
}
public void rowSeven(int col)
{
int row = 6;
if(onBoard(row, col) != -1)
{
if(validMove(row, col) == 0)
{
board[row][col] = 1;
rowEight(0);
}
board[row][col] = 0;
rowSeven(col + 1);
}
}
public void rowEight(int col)
{
int row = 7;
if(onBoard(row, col) != -1)
{
if(validMove(row, col) == 0)
{
board[row][col] = 1;
count++;
System.out.println(toString());
}
board[row][col] = 0;
rowEight(col + 1);
}
}
public static int validMove(int row, int col)
{
for (int i = 0; i < 8; i++)
{
if(onBoard(row, i) == 1) //checks side to side
{
return -1;
}
if(onBoard(i, col) == 1) //checks up and down
{
return -1;
}
}
//Check Diagonally
for(int i = 0; i < 8; i++)
{
if(onBoard(row - i, col - i) == 1) //checks up and left
{
return -1;
}
if(onBoard(row - i, col + i) == 1) //checks up and right
{
return -1;
}
if(onBoard(row + i, col - i) == 1) //checks down and left
{
return -1;
}
if(onBoard(row + i, col + i) == 1) //checks down and right
{
return -1;
}
}
return 0; //if it works
}
public static int onBoard(int row, int col)
{
if(row < 0 || col < 0 || row > 7 || col > 7) //checks if it is valid on the board
{
return -1;
}
return board[row][col]; //returns what the value is at the valid point
}
public String toString()
{
System.out.println(print());
String ans = "Solution: ";
ans += count;
return ans;
}
public static String print()
{
String sol = "Solution: " + count;
String result = "\n";
for (int row = 0; row < board.length; row++)
{
for(int column = 0; column < board[row].length; column++)
{
result += board[row][column] + "\t";
}
result += "\n";
}
return result;
}
}
Driver:
`
public class Driver
{
public static void main(String args[])
{
NonAttacking queen = new NonAttacking();
queen.rowOne(0);
System.out.println(queen.print());
}
}
`
If all you are looking to do is replace the 8 methods with one method then the following should do as required, using rowN(0, 0) to begin.
public void rowN(int n, int y)
{
if(onBoard(n, y) != -1)
{
if(validMove(n, y) == 0) //if the move is valid (0) then it puts a 1 at those coordinates and moves on to the next method (RowTwo)
{
board[n][y] = 1;
if(n<7) {
rowN(n+1, 0);
}
else {
count++;
System.out.println(toString());
}
}
board[n][y] = 0;
rowN(n, y + 1);
}
}

How do I get rid of these errors in my code? NumberFormatException: for input string: ""

Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at HelloWorld.main(HelloWorld.java:169)
These errors continue to pop up when I run my code against our sample input. We are given a document with polygons and have to use kruskal's algorithm and build a minimal spanning tree to find the shortest distance to each island without creating a cycle. If anyone can help or give advice on how to get rid of these errors that would be great! I dont understand how there can be a numberformatexception on a string ""....
import java.util.Scanner;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
public class HelloWorld {
static class Point {
int x = 0;
int y = 0;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "(x: " + x + " y: " + y + ")";
}
}
static class Polygon {
int numberOfVertices = 0;
ArrayList<Point> points = new ArrayList<Point>();
public Polygon(int numberOfVertices, ArrayList<Point> points) {
this.numberOfVertices = numberOfVertices;
this.points = points;
}
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < points.size(); i++) {
Point point = this.points.get(i);
stringBuilder.append(point);
}
return stringBuilder.toString();
}
}
static class PQItem implements Comparable<PQItem> {
int node1;
int node2;
double edge;
public PQItem(int node1, int node2, double edge) {
this.node1 = node1;
this.node2 = node2;
this.edge = edge;
}
public int compareTo(PQItem T) {
if (edge - T.edge < 0)
return 1;
else if (edge - T.edge > 0)
return -1;
else
return 0;
}
}
public static void BuildMinimalSpanningTree(int numberOfIslands, ArrayList<Polygon> polygons) {
PriorityQueue q = new PriorityQueue((numberOfIslands * numberOfIslands) / 2);
PQItem Temp;
int[] CheckPad = new int[numberOfIslands];
int FootPrint = 0;
int counter = 0;
double length = 0;
for (int i = 0; i < polygons.size(); i++)
for (int j = 0; j < polygons.size(); j++) {
Temp = new PQItem(i, j, ShortestDistance(polygons.get(i), polygons.get(j)));
}
for (int i = 0; i < polygons.size(); i++)
CheckPad[i] = -1 - i;
while (counter < polygons.size() - 1) {
Temp = (PQItem) q.Remove();
for (int i = 0; i < polygons.size(); i++)
for (int j = 0; j < polygons.size(); j++)
if (CheckPad[Temp.node1] != CheckPad[Temp.node2]) {
if (CheckPad[Temp.node1] < 0 && CheckPad[Temp.node2] < 0) {
CheckPad[Temp.node1] = FootPrint;
CheckPad[Temp.node2] = FootPrint;
FootPrint = FootPrint + 1;
}
else if (CheckPad[Temp.node1] < 0) {
CheckPad[Temp.node1] = CheckPad[Temp.node2];
}
else if (CheckPad[Temp.node2] < 0) {
CheckPad[Temp.node2] = CheckPad[Temp.node1];
}
else {
if (CheckPad[Temp.node1] < CheckPad[Temp.node2]) {
for (i = 0; i < polygons.size(); i++) {
if (CheckPad[i] == CheckPad[Temp.node2])
CheckPad[i] = CheckPad[Temp.node2];
else
for (j = 0; j < polygons.size(); j++)
if (CheckPad[j] == CheckPad[Temp.node2])
CheckPad[j] = CheckPad[Temp.node2];
}
}
System.out.println(Temp.edge);
length += Temp.edge;
counter++;
}
}
}
}
static double ShortestDistance(Polygon polygon1, Polygon polygon2) {
double shortestdistance = 0;
double Temporary = 0;
for (int i = 0; i < polygon1.numberOfVertices; i++)
for (int j = 0; j < polygon2.numberOfVertices; j++) {
Temporary = Math.pow(polygon1.points.get(i).x - polygon2.points.get(j).x, 2)
+ Math.pow(polygon1.points.get(i).y - polygon2.points.get(j).y, 2);
if (Temporary < shortestdistance)
shortestdistance = Temporary;
}
return Math.sqrt(shortestdistance);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Please enter the name of the file");
File file = new File(scanner.nextLine());
try {
Scanner fileScanner = new Scanner(file);
int numberOfIslands = Integer.parseInt(fileScanner.nextLine());
ArrayList<Polygon> polygons = new ArrayList<Polygon>();
while (fileScanner.hasNext()) {
String line = fileScanner.nextLine();
String[] numbers = line.split(" ");
ArrayList<Point> points = new ArrayList<Point>();
// PQItem NewItem = new PQItem(Node1, Node2, edge);
// info.Insert(NewItem);
for (int i = 1; i < numbers.length; i += 2) {
Point point = new Point(Integer.parseInt(numbers[i]), Integer.parseInt(numbers[(i + 1)]));
points.add(point);
}
// build tree
Polygon polygon = new Polygon(points.size(), points);
polygons.add(polygon);
// BuildMinSpanTree(numberOfIslands, polygons);
}
for (int i = 0; i < polygons.size(); i++) {
Polygon polygon = polygons.get(i);
System.out.println(polygon);
}
int minimalInterconnect = 0;
int totalLength = 0;
System.out.printf("The minimal interconnect consists of %d bridges with a total length of %d",
minimalInterconnect, totalLength);
} catch (IOException e) {
System.out.println(e);
}
}
HERE IS THE SAMPLE PROGRAM
3
4 0 0 0 1 1 1 1 0
4 2 0 2 1 3 1 3 0
3 4 0 5 0 5 1
public class PriorityQueue {
private Comparable[] HeapArray;
int Last, Limit;
PriorityQueue
public PriorityQueue(int Capacity) {
HeapArray = new Comparable[Capacity + 1];
Last = 0;
Limit = Capacity;
return;
}
// end constructor
public PriorityQueue() {
HeapArray = new Comparable[101];
Last = 0;
Limit = 100;
return;
}
// end constructor
public void Insert(Comparable PQI) {
if (Last == Limit) {
System.out.println("Priority Queue Overflow!");
System.exit(0);
}
// end if
HeapArray[++Last] = PQI;
this.UpHeap(Last);
return;
}
// end public method Insert
private void UpHeap(int k) {
Comparable V;
V = HeapArray[k];
while (k > 1 && HeapArray[k / 2].compareTo(V) < 0) {
HeapArray[k] = HeapArray[k / 2];
k = k / 2;
}
// end while
HeapArray[k] = V;
return;
}
// end private method UpHeap
public Comparable Remove() {
Comparable PQI;
if (Last == 0) {
System.out.println("Priority Queue Underflow!");
System.exit(0);
}
// end if
PQI = HeapArray[1];
HeapArray[1] = HeapArray[Last--];
this.DownHeap(1);
return PQI;
}
// end public method Remove
private void DownHeap(int k) {
Comparable V;
int j;
V = HeapArray[k];
while (k <= Last / 2) {
j = k + k;
if (j < Last && HeapArray[j].compareTo(HeapArray[j + 1]) < 0)
j++;
// end if
if (V.compareTo(HeapArray[j]) >= 0)
break;
// end if
HeapArray[k] = HeapArray[j];
k = j;
}
// end while
HeapArray[k] = V;
return;
}
// end private method DownHeap
public boolean IsEmpty() {
if (Last == 0)
return true;
else
return false;
// end if
}
// end public method IsEmpty
public boolean IsFull() {
if (Last == Limit)
return true;
else
return false;
// end if
}
// end public method IsFull
public int Length() {
return Last;
}
// end public method Length
}
// end class PriorityQueue
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
This is self explanatory. The input is expected as number however the input entered is String ""
The line that reads input and expects the value to be interger :
int numberOfIslands = Integer.parseInt(fileScanner.nextLine());
Provide correct input.
Also you could change the .nextLine() to nextInt()

Sudoku - How to use HashSet or Set?

I'm trying to code a method which checks for duplicates on my Sudoku board. Currently, my method getFrontier() always returns true, and I've come to learn that it's because it's only checking for one value rather than an array or values. I use the method 3 times in squareCheck(), rowCheck() and columnCheck(). Is there any way to code the method so it would retain the previous value which was input and then check it against the new value?
My current code:
public class validCheck {
public boolean isSolved(int[][][] board)
{
for(int index = 0; index < board.length;index++)
{
for(int r = 0; r < board[0].length; r++)
{
for(int c = 0; c < board[0].length;c++)
{
if(board[index][r][c] == 0)
return false;
}
}
}
return true;
}
public boolean getFrontier(int value)
{
Set<Integer> reserve = new HashSet<>();
for(int n = 1; n < 10; n++)
{
if(value == n && reserve.contains(n))
return false;
else if(value == n) reserve.add(n);
}
return true;
}
public boolean squareCheck(int[][][] board, int index)
{
for(int r = 0; r < board[0].length; r++)
{
for(int c = 0; c < board[0].length; c++)
{
if(!getFrontier(board[index][r][c]))
{
System.out.println("Square error at ["+index + r + c +"]");
return false;
}
}
}
return true;
}
public boolean isValid(int[][][] board)
{
if(isSolved(board))
{
for(int i = 0; i < board.length; i++)
{
for(int r = 0; r < board[0].length;r++)
{
for(int c = 0; c < board[0].length;c++)
{
if(!rowCheck(board,i,r) || !columnCheck(board,i,c) || !squareCheck(board,i))
{
return false;
}
}
}
}
}
return true;
}
public boolean columnCheck(int[][][] board, int index, int col)
{
int target = 0;
if(index <=2)
{
target = index + 6;
}
else if(index > 2 && index < 6)
{
target = index +3;
index = index - 3;
}
else if (index > 5)
{
target = index;
index = index - 6;
}
while(index <= target)
{
for(int r = 0; r < board[0].length;r++)
{
if(!getFrontier(board[index][r][col]))
{
System.out.println("Column error at " + index + r + col);
return false;
}
}
index = index + 3;
}
return true;
}
public boolean rowCheck(int[][][] board, int index, int row)
{
int target = 0;
if(index <= 2)
{
index = 0;
target = 2;
}
else if (index <= 5)
{
index = 3;
target = 5;
}
else if(index <= 8)
{
index = 6;
target = 8;
}
while(index <= target)
{
for(int c = 0; c < board[0].length; c++)
{
if(!getFrontier(board[index][row][c]))
{
System.out.println("Row error at "+index+row+c);
return false;
}
}
index++;
}
return true;
}
}
Usage:
public static void main(String[] args) {
int[][][] solved = {{{5,3,4},{6,7,2},{1,9,8}},
{{6,7,8},{1,9,5},{3,4,2}},
{{9,1,2},{3,4,8},{5,6,7}},
{{8,5,9},{4,2,6},{7,1,3}},
{{7,6,1},{8,5,3},{9,2,4}},
{{4,2,3},{7,9,1},{8,5,6}},
{{9,6,1},{2,8,7},{3,4,5}},
{{5,3,7},{4,1,9},{2,8,6}},
{{2,8,4},{6,3,5},{1,7,9}}};
validCheck checker = new validCheck();
if(checker.isValid(solved))
System.out.println(true);
else System.out.println(false);
}
Any help will be greatly be appreciated!!!
Here is what I would do to find a valid board config in a 2D sudoku board. I would use a HashSet for a row and another for the column, as long as we never encounter repeats and the values contain 1 to the length of the array we know the board is valid.
int [][] board = {{1,2,3},
{2,3,1},
{3,1,2}
};
HashSet<Integer> rowDuplicates = new HashSet<>();
HashSet<Integer> colDuplicates = new HashSet<>();
boolean invalidBoard = false;
for(int i = 0 ; i < board.length; i++)
{
for(int j = 0; j < board[i].length; j++)
{
if(rowDuplicates.contains(board[i][j]) || colDuplicates.contains(board[j][i]))
{
//this board is not valid
invalidBoard = true;
}
else
{
rowDuplicates.add(board[i][j]);
colDuplicates.add(board[j][i]);
}
}
//now check they contain the correct numbers from 1 to the size of the array
if(colDuplicates.size() == rowDuplicates.size())
{
for(int index = 0; index < colDuplicates.size(); index++)
{
if(!(colDuplicates.contains(index + 1) && rowDuplicates.contains(index + 1)))
{
invalidBoard = true;
break;
}
}
}
else
{
invalidBoard = true;
}
colDuplicates.clear();
rowDuplicates.clear();
}
System.out.println("invalid board: " + invalidBoard);
You should be able to expand this to your 3D array but you can see how much easier it is to use HashSets to verify a valid 2D array Sudoku board.

How to Generate a -complete- sudoku board? algorithm error

I'm trying to generate a complete (ie, each cell filled with a number) Sudoku-like board. It's for something else that has nothing to do with sudokus, so I am not interested in reaching a sudoku with white squares that can be solved, or anything that has to do with sudokus. Don't know if you know what I mean.
I've done this in java:
private int sudokuNumberSelector(int x, int y, int[][] sudoku) {
boolean valid = true;
String validNumbers = new String();
int[] aValidNumbers;
int squarexstart = 0;
int squareystart = 0;
int b = 0; // For random numbers
Random randnum = new Random();
randnum.setSeed(new Date().getTime());
// Check numbers one by one
for(int n = 1; n < 10; n++) {
valid = true;
// Check column
for(int i = 0; i < 9; i++) {
if(sudoku[i][y] == n) {
valid = false;
}
}
// Check file
for(int j = 0; j < 9; j++) {
if(sudoku[x][j] == n) {
valid = false;
}
}
// Check square
switch (x) {
case 0: case 1: case 2: squarexstart = 0; break;
case 3: case 4: case 5: squarexstart = 3; break;
case 6: case 7: case 8: squarexstart = 6; break;
}
switch (y) {
case 0: case 1: case 2: squareystart = 0; break;
case 3: case 4: case 5: squareystart = 3; break;
case 6: case 7: case 8: squareystart = 6; break;
}
for(int i = squarexstart; i < (squarexstart + 3); i++ ) {
for(int j = squareystart; j < (squareystart + 3); j++ ) {
if(sudoku[i][j] == n) {
valid = false;
}
}
}
// If the number is valid, add it to the String
if(valid) {
validNumbers += n;
}
}
if(validNumbers.length() != 0) {
// String to int[]
aValidNumbers = fromPuzzleString(validNumbers);
// By this random number, return the valid number in its position
Log.d(TAG, "NUMBERS: " + validNumbers.length());
// Select a random number from the int[]
b = randnum.nextInt((aValidNumbers.length));
return aValidNumbers[b];
} else {
return 0;
}
}
This method is called from this piece of code:
int[][] sudoku = new int[9][9];
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
sudoku[i][j] = sudokuNumberSelector(i, j, sudoku);
}
}
But it is not as easy as it seemed! When the algorithm has generated a part of the board like this one, and the loop is on the cell on bold:
|||164527389|||
|||983416257|||
|||257938416|||
|||719352648|||
|||3256791**0**0|||
|||000000000|||
|||000000000|||
|||000000000|||
|||000000000|||
There are no numbers to put in this cell, because all the numbers according to the rules of sudoku are already on the column, row or square!
It is a nightmare for me. Is there any way to this to work? If not, i guess I have to redo everything as if I were making a Sudoku game.
The problem is that it is not possible to generate a complete board using random numbers in most cases, you have to use backtracking in cases when it is not possibe to fi the next cell.
I have once written a sudoku game, so here's the piece of code that generates filled board.
This is the Cell class.
public class SudokuCell implements Serializable {
private int value;
private boolean filled;
private HashSet<Integer> tried;
public SudokuCell() {
filled = false;
tried = new HashSet();
}
public boolean isFilled() {
return filled;
}
public int get() {
return value;
}
public void set(final int number) {
filled = true;
value = number;
tried.add(number);
}
public void clear() {
value = 0;
filled = false;
}
public void reset() {
clear();
tried.clear();
}
public void show() {
filled = true;
}
public void hide() {
filled = false;
}
public boolean isTried(final int number) {
return tried.contains(number);
}
public void tryNumber(final int number) {
tried.add(number);
}
public int numberOfTried() {
return tried.size();
}
}
Here's the Field class (it's really handy to keep all data in just one object).
public class SudokuField implements Serializable {
private final int blockSize;
private final int fieldSize;
private SudokuCell[][] field;
public SudokuField(final int blocks) {
blockSize = blocks;
fieldSize = blockSize * blockSize;
field = new SudokuCell[fieldSize][fieldSize];
for (int i = 0; i < fieldSize; ++i) {
for (int j = 0; j < fieldSize; ++j) {
field[i][j] = new SudokuCell();
}
}
}
public int blockSize() {
return blockSize;
}
public int fieldSize() {
return fieldSize;
}
public int variantsPerCell() {
return fieldSize;
}
public int numberOfCells() {
return fieldSize * fieldSize;
}
public void clear(final int row, final int column) {
field[row - 1][column - 1].clear();
}
public void clearAllCells() {
for (int i = 0; i < fieldSize; ++i) {
for (int j = 0; j < fieldSize; ++j) {
field[i][j].clear();
}
}
}
public void reset(final int row, final int column) {
field[row - 1][column - 1].reset();
}
public void resetAllCells() {
for (int i = 0; i < fieldSize; ++i) {
for (int j = 0; j < fieldSize; ++j) {
field[i][j].reset();
}
}
}
public boolean isFilled(final int row, final int column) {
return field[row - 1][column - 1].isFilled();
}
public boolean allCellsFilled() {
for (int i = 0; i < fieldSize; ++i) {
for (int j = 0; j < fieldSize; ++j) {
if (!field[i][j].isFilled()) {
return false;
}
}
}
return true;
}
public int numberOfFilledCells() {
int filled = 0;
for (int i = 1; i <= fieldSize; ++i) {
for (int j = 1; j <= fieldSize; ++j) {
if (isFilled(i, j)) {
++filled;
}
}
}
return filled;
}
public int numberOfHiddenCells() {
return numberOfCells() - numberOfFilledCells();
}
public int get(final int row, final int column) {
return field[row - 1][column - 1].get();
}
public void set(final int number, final int row, final int column) {
field[row - 1][column - 1].set(number);
}
public void hide(final int row, final int column) {
field[row - 1][column - 1].hide();
}
public void show(final int row, final int column) {
field[row - 1][column - 1].show();
}
public void tryNumber(final int number, final int row, final int column) {
field[row - 1][column - 1].tryNumber(number);
}
public boolean numberHasBeenTried(final int number, final int row, final int column) {
return field[row - 1][column - 1].isTried(number);
}
public int numberOfTriedNumbers(final int row, final int column) {
return field[row - 1][column - 1].numberOfTried();
}
public boolean checkNumberBox(final int number, final int row, final int column) {
int r = row, c = column;
if (r % blockSize == 0) {
r -= blockSize - 1;
} else {
r = (r / blockSize) * blockSize + 1;
}
if (c % blockSize == 0) {
c -= blockSize - 1;
} else {
c = (c / blockSize) * blockSize + 1;
}
for (int i = r; i < r + blockSize; ++i) {
for (int j = c; j < c + blockSize; ++j) {
if (field[i - 1][j - 1].isFilled() && (field[i - 1][j - 1].get() == number)) {
return false;
}
}
}
return true;
}
public boolean checkNumberRow(final int number, final int row) {
for (int i = 0; i < fieldSize; ++i) {
if (field[row - 1][i].isFilled() && field[row - 1][i].get() == number) {
return false;
}
}
return true;
}
public boolean checkNumberColumn(final int number, final int column) {
for (int i = 0; i < fieldSize; ++i) {
if (field[i][column - 1].isFilled() && field[i][column - 1].get() == number) {
return false;
}
}
return true;
}
public boolean checkNumberField(final int number, final int row, final int column) {
return (checkNumberBox(number, row, column)
&& checkNumberRow(number, row)
&& checkNumberColumn(number, column));
}
public int numberOfPossibleVariants(final int row, final int column) {
int result = 0;
for (int i = 1; i <= fieldSize; ++i) {
if (checkNumberField(i, row, column)) {
++result;
}
}
return result;
}
public boolean isCorrect() {
for (int i = 0; i < fieldSize; ++i) {
for (int j = 0; j < fieldSize; ++j) {
if (field[i][j].isFilled()) {
int value = field[i][j].get();
field[i][j].hide();
boolean correct = checkNumberField(value, i + 1, j + 1);
field[i][j].show();
if (!correct) {
return false;
}
}
}
}
return true;
}
public Index nextCell(final int row, final int column) {
int r = row, c = column;
if (c < fieldSize) {
++c;
} else {
c = 1;
++r;
}
return new Index(r, c);
}
public Index cellWithMinVariants() {
int r = 1, c = 1, min = 9;
for (int i = 1; i <= fieldSize; ++i) {
for (int j = 1; j <= fieldSize; ++j) {
if (!field[i - 1][j - 1].isFilled()) {
if (numberOfPossibleVariants(i, j) < min) {
min = numberOfPossibleVariants(i, j);
r = i;
c = j;
}
}
}
}
return new Index(r, c);
}
public int getRandomIndex() {
return (int) (Math.random() * 10) % fieldSize + 1;
}
}
And finally the function that fills the game board
private void generateFullField(final int row, final int column) {
if (!field.isFilled(field.fieldSize(), field.fieldSize())) {
while (field.numberOfTriedNumbers(row, column) < field.variantsPerCell()) {
int candidate = 0;
do {
candidate = field.getRandomIndex();
} while (field.numberHasBeenTried(candidate, row, column));
if (field.checkNumberField(candidate, row, column)) {
field.set(candidate, row, column);
Index nextCell = field.nextCell(row, column);
if (nextCell.i <= field.fieldSize()
&& nextCell.j <= field.fieldSize()) {
generateFullField(nextCell.i, nextCell.j);
}
} else {
field.tryNumber(candidate, row, column);
}
}
if (!field.isFilled(field.fieldSize(), field.fieldSize())) {
field.reset(row, column);
}
}
}
The point is that you save the numbers you've already tried for each cell before moving on. If you have to the dead end, you simply need to try another number for the previous cell. If none are possible, erase that cell and step one cell back. Sooner or later you will get it done. (It actuay takes tiny amount of time).
Start out with a solved Sudoko like this:
ABC DEF GHI
329 657 841 A
745 831 296 B
618 249 375 C
193 468 527 D
276 195 483 E
854 372 619 F
432 716 958 G
587 923 164 H
961 584 732 I
And then permutate it by switching columns and switching rows. If you only switch within the following groups ABC, DEF, GHI, the Sudoku is still solved.
A permutated version (switching columns):
BCA DFE IGH
293 675 184 A
457 813 629 B
186 294 537 C
931 486 752 D
762 159 348 E
548 327 961 F
324 761 895 G
875 932 416 H
619 548 273 I
And after some more permutation (switching rows):
BCA DFE IGH
293 675 184 A
186 294 537 C
457 813 629 B
931 486 752 D
548 327 961 F
762 159 348 E
875 932 416 H
619 548 273 I
324 761 895 G
Your problem is you are using Strings. Try a recursive algorithm using integers. This algorithm will be useful for a sudoku of any size. While choosing random numbers within each call does work, it'll take much longer. If you choose a set of random numbers to go through if the next cell doesnt work, then you will not use the same number again. This algorithm will create a unique puzzle every time.
public class Sudoku {
//box size, and game SIZE ==> e.g. size = 3, SIZE = 9
//game will be the game
private int size, SIZE;
private int[][] game;
public Sudoku(int _size) {
size = _size;
SIZE = size*size;
game = generateGame();
}
//This will return the game
private int[][] generateGame() {
//Set everything to -1 so that it cannot be a value
int[][] g = new int[SIZE][SIZE];
for(int i = 0; i < SIZE; i++)
for(int j = 0; j < SIZE; j++)
g[i][j] = -1;
if(createGame(0, 0, g))
return g;
return null;
}
//Create the game
private boolean createGame(int x, int y, int[][] g) {
//An array of integers
Rand r = new Rand(SIZE);
//for every random num in r
for(int NUM = 0; NUM < size; NUM++) {
int num = r.get(NUM);
//if num is valid
if(isValid(x, y, g, num)) {
//next cell coordinates
int nx = (x+1)%SIZE, ny = y;
if(nx == 0) ny++;
//set this cell to num
g[x][y] = num;
//if the next cell is valid return true
if(createGame(nx, ny, g)) return true;
//otherwise return false
g[x][y] = -1;
return false;
}
}
return false;
}
private boolean isValid(int x, int y, int[][] g, int num) {
//Rows&&Cols
for(int i = 0; i < SIZE; i++)
if(g[i][y] == num || g[x][i] == num) return false;
//Box
int bx = x - x%size;, by = y - y%size;
for(int i = bx; i < bx + size; i++) {
for(int j = by; j < by + size; j++) {
if(g[i][j] == num)return false;
}
}
return true;
}
}
public class Rand {
private int rSize;
private int[] r;
public Rand(int _size) {
rSize = _size;
r = new int[size];
for(int i = 0; i < rSize; r++)r[i] = i;
for(int i = 0; i < rSize*5; r++) {
int a = (int)(Math.random()*rSize);
int b = (int)(Math.random()*rSize);
int n = r[a];
r[a] = r[b];
r[b] = n;
}
public void get(int i) {
if(i >= 0 && i < rSize) return r[i]; return -1;
}
}
You're going to have to implement a backtracking algorithm.
For each of the 81 locations, generate the set 1 through 9.
Repeat until solved
Solve one location. Pick one number from the set.
Remove that number from all the sets in the same row, column, and square.
If a conflict arises, backtrack to a known good position, and solve a different location.
You will probably have to use recursive functions so that you can backtrack.
You have at least few ways to do that, but usually you will need recurrence / backtracking. It would be great to have the solver also, just to check if partly filled puzzle has solution (and the unique one - for stoping criteria - if you want the real sudoku).
While performing backtracking / recurrence you will need:
to randomly select available empty cell (you can optimize this step by measuring digidts still free on the given cell, and then sorting)
to randomly select still available digit in that cell
you fill the cell and check if the solution exists, if yes - go further, if not - perform the step back.
Starting points:
- starting with completely empty puzzle
- starting with partially filled puzzle
- starting with solved puzzle (there are a lot of transformations not changing the solution existence, but making the puzzle different - i.e.: reflection, rotation, transposition, segment swapping, columns / rows swapping within segments, permutation, etc.)
I was recently using the Janet Sudoku library which provides solver, generator and puzzle transformation methods.
Janet Sudoku website
Please refer to the below source codes available on the GitHub
Sudoku Solver
Sudoku Generator
Sudoku Transformations
Library usage is pretty simple, ie:
SudokuGenerator g = new SudokuGenerator();
int[][] puzzle = g.generate();
SudokuSolver s = new SudokuSolver(puzzle);
s.solve();
int[][] solvedPuzzle = s.getSolvedBoard();
Best regards,
Just generate some random number between 1 to 9 and see it it fits the given cell[i][j] it promises you a new set of numbers every time as every cell number is generated randomly based on the current system time .
public int sudokuNumberSelector(int i, int j, int[][] sudoku) {
while (true) {
int temp = (int) ((System.currentTimeMillis()) % 9) + 1;//Just getting some random number
while (temp < 10) {
boolean setRow = false, setColomn = false, setBlock = false;
for (int a = 0; a < 9; a++) {
if (sudoku[a][j] == temp) {
setRow = true;
break;
}
}
for (int a = 0; a < 9; a++) {
if (sudoku[i][a] == temp) {
setColomn = true;
break;
}
}
for (int a = i - (i % 3); a < i - (i % 3)+ 3; a++) {
for (int b = j - (j % 3); b < j - (j % 3)+3; b++) {
if (sudoku[a][b] == temp) {
setBlock = true;
a = 3;
b = 3;
}
}
}
if(setRow | setColomn | setBlock == false){
return temp;
}
temp++;
}
}
}

Categories

Resources