I am working on a little personal Sudoku and trying to expand it.
So far I got the "Solve" part working, using a recursive backtracking method, which returns true whenever it manages to solve the recursion.
Now I am trying to build a unique solution board generator, and I've found quite a bit of info online about how it can be implemented.
However, I am struggling on the first step, which is my boolean recursive backtracking algorithm into a recursive algorithm that keeps a count of a possible solutions. This is essential to check whether my generated board is unique.
On a larger note, I've realized that I've struggled with this problem before when implementing some recursive sorts: How to transform a boolean recursive function into a recursive function that returns some kind of count (int/long), without losing the functionality? Is there any sort of guidelines or technique to follow?
Attached is the working code so far.
import java.util.Scanner;
public class Sudoku {
int[][] board;
public Sudoku(){}
public Sudoku(int n){
this.board=new int[n][n];
}
/* Creates an NxN game.board in a two-dimensional array*/
public static int[][] createBoard(int n)
{
int[][] board = new int[n][n];
for (int i=0; i<board.length; i++)
for (int j=0; j<board[i].length; j++)
board[i][j]=0;
return board;
}
/* prints the game.board*/
public static void printBoard(int[][] b)
{
int buffer=(int)Math.sqrt(b.length);
// fitting the bottom line into any size of game.board
String btm=new String(new char[buffer*buffer*3+buffer+1]).replace("\0", "_");
for (int i=0; i<b.length; i++)
{
if (i%buffer==0)
System.out.println(btm);
for (int j=0; j<b[i].length; j++)
{
if (j%buffer==0)
System.out.print("|");
if (b[i][j]==0)
System.out.print(" _ ");
else
System.out.print(" " + b[i][j] + " ");
}
System.out.println("|");
}
System.out.println(btm);
}
/* returns true if a number can be inserted in a row, otherwise returns false. */
public static boolean checkLegalRow(int[][] b, int row, int num)
{
for (int i=0; i<b.length; i++)
{
if (b[row][i]==num)
return false;
}
return true;
}
/* returns true if a number can be inserted in a column, otherwise returns false.*/
public static boolean checkLegalCol(int[][] b, int col, int num)
{
for (int i=0; i<b.length; i++)
{
if (b[i][col]==num)
return false;
}
return true;
}
/*returns true if number can be inserted in its local box.*/
public static boolean checkLegalBox(int[][] b, int row, int col, int num)
{
int buffer=(int)Math.sqrt(b.length);
for (int i=0, adjRow=row-(row%buffer); i<buffer; i++, adjRow++)
{
for (int j=0, adjCol=col-(col%buffer); j<buffer; j++, adjCol++)
{
if (b[adjRow][adjCol]==num)
return false;
}
}
return true;
}
/*allows user input for a sudoku game.board*/
public static void fillInBoardConsole(int[][] b)
{
Scanner sc = new Scanner(System.in);
System.out.print("Please enter a row: ");
int r=sc.nextInt();
System.out.print("Please enter a column: ");
int c=sc.nextInt();
System.out.print("Please enter a number from 1 to "+b.length+": ");
int num=sc.nextInt();
while (num>b.length || num<1)
{
System.out.print("Please enter a number from 1 to "+b.length+": ");
num=sc.nextInt();
}
b[r][c]=num;
sc.close();
}
/* returns true if all the conditions for sudoku legal move are met: there is no
* number on the same row, column, box, and the cell isn't taken*/
public static boolean legalMove(int[][] b, int row, int col, int num)
{
return checkLegalRow(b,row,num) && checkLegalCol(b,col,num) && checkLegalBox(b,row,col,num) && b[row][col]==0;
}
/* returns true if the initial board setting is legal*/
public static boolean initialLegal(int[][] b)
{
int num;
for (int i=0; i<b.length; i++)
{
for (int j=0; j<b[i].length; j++)
{
if (b[i][j]!=0)
{
num=b[i][j];
b[i][j]=0;
if (!(checkLegalRow(b,i,num) && checkLegalCol(b,j,num) && checkLegalBox(b,i,j,num)))
{
b[i][j]=num;
return false;
}
else
b[i][j]=num;
}
}
}
return true;
}
/* using backtrack algorithm and recursion to solve the sudoku*/
public static boolean solveBacktrack(int[][] b, int row, int col)
{
/*If the cell is already taken by a number:
* case 1: if its the last cell (rightmost, lowest) is already taken, sudoku solved
* case 2: if its the rightmost cell not on the if it is the rightmost column but not
* the lowest row, go to the leftmost cell in next row
* case 3: if it's a regular cell, go for the next cell*/
if (b[row][col]!=0)
{
if (col==b.length-1)
if (row==b.length-1)
{
//printgame.board(b); // case 1
return true;
}
else
return solveBacktrack(b,row+1,0); // case 2
else
return solveBacktrack(b,row,col+1); // case 3
}
boolean solved=false;
for (int k=1; k<=b.length; k++) //iterates through all numbers from 1 to N
{
// If a certain number is a legal for a cell - use it
if (legalMove(b,row,col,k))
{
b[row][col]=k;
if (col==b.length-1) // if it's the rightmost column
{
if (row==b.length-1) // and the lowest row - the sudoku is solved
{
//printgame.board(b);
return true;
}
else
solved=solveBacktrack(b,row+1,0); // if its not the lowest row - keep solving for next row
}
else // keep solving for the next cell
solved=solveBacktrack(b,row,col+1);
}
if (solved)
return true;
else //if down the recursion sudoku isn't solved-> remove the number (backtrack)
{
b[row][col]=0;
}
}
return solved;
}
/* public static long solveCountSolutions(int[][]b, int row, int col, long counter)
{
}
*/
public static void main(String[] args)
{
Sudoku game = new Sudoku(9);
game.board[0][2]=5;game.board[0][1]=3; game.board[0][0]=1;
game.board[8][2]=4;game.board[8][4]=3;game.board[8][6]=6;
printBoard(game.board);
if (initialLegal(game.board))
System.out.println(solveBacktrack(game.board,0,0));
else
System.out.println("Illegal setting");
printBoard(game.board);
}
}
Such a function could be implemented by not exiting from the recursion when a solution is found, but instead dump that solution to an external structure (if you only need counts, make a counter somewhere outside of the function but visible to it, and increment it once a solution is found), and then continue searching like if you've hit a dead end. Something in line of this (abstract code):
static int solutions=0;
bool recursiveSolver(TYPE data) {
TYPE newData;
while (!nextChoice(data)) {
if (solved(data)) {
// return true; not now, we count instead
solutions++;
}
newData=applyNextChoice(data); // for recursion
if (recursiveSolver(newData)) {
return true; // will never hit, but checking is needed for solver to work
}
}
// all choices checked, no solution
return false;
}
applyNextChoice() is a placeholder for "select next number, put into this cell" in case of sudoku. TYPE is a placeholder for whatever structure that represents an incomplete solution, in your case a combined int[][] b, int row, int col.
Related
I am using an ArrayList to store objects that are "valid" for the purposes of my program and referencing it later in the same class file.
private static ArrayList<TownResource> validResources = new ArrayList<>();
A public method is called, which then calls a private method within the class that makes validResources's size nonzero.
public static boolean detection(int row, int col, TownResource[][] rArray, ResourceEnum[][][] bT, BuildingEnum buildingType) {
int checkTime = 0;
int patternIndex = 0;
try {
for (int i = 1; i < checkTime+1; i++) {
if (compare(row, col, rArray, buildingTemplate[patternIndex], buildingType)) {
for (int j = 0; j < validResources.size(); j++) {
validResources.get(j).setScannedBuilding(buildingType);
}
System.out.println("Size at compare" + validResources.size());
return true;
}
}
}
catch (ArrayIndexOutOfBoundsException e){
//System.out.println("Out of bounds exception?");
}
return false;
}
The compare method is a private method that on one condition, may clear validResources.
private static boolean compare(int row, int col, TownResource[][] rArray, ResourceEnum[][] buildingTemplate, BuildingEnum buildingType) {
for (int r = 0; r < buildingTemplate.length; r++) {
for (int c = 0; c < buildingTemplate[r].length; c++) {
if (match(rArray[row+r][col+c], buildingTemplate[r][c])) {
//System.out.println("Successful comparison at " + (row+r) + ", " + (col+c));
}
else {
validResources.clear();
return false;
}
}
}
return true;
}
match is what sets validResources to be nonzero in size:
private static boolean match(TownResource toBeChecked, ResourceEnum checker) {
if (checker == ResourceEnum.NONE) {
return true;
}
else if (toBeChecked.getResource() == checker) {
validResources.add(toBeChecked);
return true;
}
return false;
}
However, when I know validResources to be nonzero in size(this causes detection to return true which triggers a new method placement), it becomes zero.
public static void placement(TownResource[][] rArray, Building[][] bArray, BuildingEnum building) {
// other parts of method commented out for example
System.out.println(validResources.size());
for (int i = 0; i < validResources.size(); i++) {
System.out.println("Is this statement firing?");
System.out.println(validResources.get(i).getResource());
validResources.get(i).setResource(ResourceEnum.NONE);
}
Have I declared validResources incorrectly? Or is there something else at play?
Thank you.
This was an error in how I executed detection(). This method is called by another method within another class when iterating through a 2D array. The ArrayList validResources becomes nonempty in one check, but gets overwritten by another as a result of the program not calling placement until every object in the 2D array had detection called on it. I changed this to call placement immediately.
I am trying to reverse a stack of type int using recursion. I am able to reverse the first entry, but it shows only zeros when I try to print the supposed reversed stack after the recursion takes place. Here is my code:
//Class to reverse a stack using recursion
class ReverseStack
{
//Global Variables
static int[] stack = new int[5];
static int[] tempStack = new int[5];
private static int size;
//Constructor
public ReverseStack()
{
}
//Functions to for the stack
public static boolean isEmpty()
{
return size == 0;
}
//Function to determine if stack is full
public static boolean isFull()
{
return size == stack.length;
}
//Function to determine size of array
int size()
{
return size;
}
//Function to push entries into stack
public static boolean push(int[] stack, int data)
{
if(isFull())
{
return false;
}
else
{
stack[size] = data;
size++;
return true;
}
}
//Function to remove entries from stack
public static int pop()
{
if(isEmpty())
{
return 0;
}
else
{
size--;
return(stack[size + 1]);
}
}
//Function to print the stack
public static void print(int[] stack)
{
//This prints top to bottom
//Top is the last entry
System.out.println("Top to Bottom");
if(isEmpty())
{
System.out.println("The stack is empty ");
}
else
{
for(int cntr = 0; cntr < size; cntr++)
{
System.out.println(stack[cntr] + " ");
}
}
}
//Function to reverse data recursively
public static void reverseData(int data)
{
//Variables
int tempNum;
int cntr = 4;
int cntr2 = 0;
//Note:
/*
To reverse a stack we need to
1. pass in a number
2. Remove the number
3. Repeat until no numbers are left
4 copy stack
5. print
*/
if(data > stack[cntr - 1])
{
tempStack[cntr2] = data;
cntr--;
cntr2++;
data = stack[cntr - 1];
reverseData(data);
}
}
}
I call this reverseStack function in my program's menu system:
//Function to create a menu system
public static void menu()
{
//Variables
int response;
//Message user
System.out.println("Would you like to: "
+ "\n(1) Reverse a stack using recursion "
+ "\n(2) Draw the Sierpinski Triangle "
+ "\n(3) Draw the Dragon Curve "
+ "\n(4) Recurse through a file/directory system"
+ "\n(5) Recurse through my own recursive function"
+ "\n(6) Quit the program ");
//Save user's response
response = Integer.parseInt(myScanner.nextLine());
//Switch statement for menu options
switch (response)
{
case 1:
{
//Create a new instance of ReverseStack class
ReverseStack rs = new ReverseStack();
//Add data into stack before reversing the stack
rs.push(stack, 10);
rs.push(stack, 20);
rs.push(stack, 30);
rs.push(stack, 40);
rs.push(stack, 50);
//Print stack
rs.print(stack);
//Call function to reverse data set
rs.reverseData(stack[4]);
//Print data set
rs.print(rs.tempStack);
//Return to menu
menu();
break;
}
}
}
Do you know what I may be doing wrong?
Size seems to be always 1 above the index of the last element in the stack, so your pop method should probably be
size--;
return stack[size]; // not stack[size+1]
Also your reverseData function is not working because you are resetting cntr and cntr2 each time the function is called. Those must be global variables.
Maybe try something like
int counter = 0;
public void reverseData (int index) {
if (index > counter) {
int temp = data[index];
data[index] = data[counter];
data[counter] = temp;
counter++;
reverseData(--index);
}
You need to know the next index of your tempStack. Right now it is always 0. So you are only updating the first value and rest are 0s
Change your method
//Function to reverse data recursively
public static void reverseData(int data)
{
//Variables
int tempNum;
int cntr = 4;
int cntr2 = 0;
//Note:
/*
To reverse a stack we need to
1. pass in a number
2. Remove the number
3. Repeat until no numbers are left
4 copy stack
5. print
*/
if(data > stack[cntr - 1])
{
tempStack[cntr2] = data;
cntr--;
cntr2++;
data = stack[cntr - 1];
reverseData(data);
}
}
with this
//Function to reverse data recursively
public static void reverseData(int data, int cntr2)
{
//Variables
int tempNum;
int cntr = 4;
//Note:
/*
To reverse a stack we need to
1. pass in a number
2. Remove the number
3. Repeat until no numbers are left
4 copy stack
5. print
*/
if(data > stack[cntr - 1])
{
tempStack[cntr2] = data;
cntr--;
cntr2++;
data = stack[cntr - 1];
reverseData(data, cntr);
}
}
In your main method, call reverseData(stack[4], 0)
Or create cntr2 as class level variable
If it is a temp stack please not define it as static variable. It is not safe and not good coding behavior.
You used two pointers. The cntr points to the last variable, and the cntr2 points to the first variable. Why not compare them?
For example, keep recursing until the cntr2 less than cntr.
I'm trying to get better at java by making a Sudoku puzzle, however I'm running in to some issues. As it currently stands, if I put any "illegal" input in the Sudoku, it just continues, but I'm trying to make the script ask for a value again if it is "illegal". As seen below in the code, it is when my public boolean "moves" is false I'm trying to start the while loop once again.
public static void main(String[] args) throws Exception {
Sudoku s = new Sudoku("C:\\Users\\caspe\\Downloads\\Sudoku001.sdk");
s.printBoard();
s.errorCheck();
s.getNum();
while(getNum() > 0) {
System.out.println("Next move, please (row , column , value )");
Scanner scanner = new Scanner(System.in);
int row = scanner.nextInt();
int column = scanner.nextInt() ;
int value = scanner.nextInt();
if (s.moves(row, column, value) == false); {
//Try again
}
s.printBoard();
}
}
I still can't figure out an solution after several different attempts, so help is very much appreciated!
This is my getNum method for further understanding:
public static int getNum() {
int getNumb = 0;
for(int j = 0; j < list.size(); j++) {
for (int i=0; i < list.get(j).length(); i++) {
if(list.get(i).charAt(j) == '.') {
getNumb++;
}
}
}
return getNumb;
}
The way you have written your code it is going to print the Sudoku board whether s.move is true or false. The way you would fix that is by add in an else statement to your if statement.
For example:
if(s.moves(row, column, value) == false){
//print error message
}else {
s.printBoard();
}
I am trying to have a method (duplicates) return true if a given array called x (entered by user in another method), contains duplicate values. Otherwise it would return false. Rather then checking the entire array, which is initialized to 100, it will check only the amount of values entered, which is kept track of with a global counter: numElementsInX.
What is the best way to accomplish this?
public static boolean duplicates (int [] x)
I am prompting for user data like so:
public static void readData (int [] x, int i){
Scanner input = new Scanner(System.in);
System.out.println("Please enter integers, enter -999 to stop");
while (i <= 99) {
int temp = input.nextInt();
if(temp == -999){
break;
}
else {
x[i++]=temp;
}
// else
}//end while
printArray(x,i);
}//end readData
public static void printArray(int [] x, int numElementsInX){
int n = numElementsInX;
for (int i = 0; i < n; i++){
System.out.print(x[i] + " ");
}//end for
System.out.println();
}//end printArray
I am sure there is a better way to do this, but this is how I have been taught so far.
Here is a solution that:
Compiles and executes without throwing.
Uses numElementsInX as you requested.
Returns as soon as it finds a duplicate.
This approach tests whether each member of the array has been seen before. If it has, the method can return immediately. If it hasn't, then the member is added to the set seen before.
public static boolean duplicates (int [] x, int numElementsInX ) {
Set<Integer> set = new HashSet<Integer>();
for ( int i = 0; i < numElementsInX; ++i ) {
if ( set.contains( x[i])) {
return true;
}
else {
set.add(x[i]);
}
}
return false;
}
Here's a sample program containing the above code.
this should do it.
public boolean containsDuplicates(Integer[] x) {
return new HashSet<Integer>(Arrays.asList(x)).size() != x.length
}
You dont need numElementsInX as this is the same as x.length
edit after comment from Louis. Arrays.asList does not work with int arrays.
To convert int[] to Integer try this question How to convert int[] to Integer[] in Java?
or do soemthing like this (not tested but from memory)
Integer[] newArray = new Integer[a.length];
System.arraycopy(a, 0, newArray, 0, a.length);
This certainly isn't the most efficient way, but since you don't know about Sets yet, you can use two loops:
public static boolean duplicates (int [] x){
for (int i=0; i<numElementsInX; i++){
for (int j=i+1; j<numElementsInX; j++){
if (x[j]==x[i]) return true;
}
}
return false;
}
"set.add()" returns true if the element is not already present in the set and false otherwise. We could make use of that and get rid of "set.contains()" as in the above solution.
public static boolean duplicates (int[] x, int numElementsInX) {
Set<Integer> myset = new HashSet<>();
for (int i = 0; i < numElementsInX; i++) {
if (!myset.add(x[i])) {
return true;
}
}
return false;
}
For java, return true if the array contains a duplicate value,
boolean containsDuplicates(int[] a) {
HashSet<Integer> hs = new HashSet<>();
for(int i = 0; i<a.length; i++) {
if(!hs.add(a[i])){
return true;
}
}
return false;
}
I'm kind of stumped here.
I'm relatively new to Java/Programming in general. I want to make a program that "books seats" in a 4x4 grid. This multidimensional array will be of the type boolean so that if the seat is not taken, it returns false, but if it is taken it will return true. I want to be able to specify different seats, so like the first two rows will be a different section than the last two rows. Right now I have a method but it just books the entire first two rows as soon as I call that method (as it should, logically speaking). But I want to only be able to book one seat at a time, so that it will end that for loop as soon as one seat is booked. If I select that I want to book another seat, it will move to the next available seat in those rows or columns.
Here is the code so far:
import javax.swing.JOptionPane;
public class Seats{
int maxRows = 4;
int maxCols = 4;
boolean seating[][] = new boolean[maxRows][maxCols];
String bookSeat = null;
public static void main(String []args){
Seats seats = new Seats();
seats.start();
}
public void start(){
bookSeat = JOptionPane.showInputDialog(null, "Book a seat? (y/n)");
if(bookSeat.equals("y")){
bookSeat();
}else{
JOptionPane.showMessageDialog(null, "Okay.");
}
displaySeats(seating);
}
private boolean bookSeat(){
boolean isBooked = false;
for(int row = 0; row <2; row++){
for(int col = 0;col<maxCols;col++){
if (seating[row][col] == false){
seating[row][col] = true;
isBooked = true;
}
}
}
return isBooked;
}
private void displaySeats(boolean[][] anArray){
String seatTaken;
int r=0;
int c=0;
for(int display=0; display<1; display++){
for(r=0;r<anArray.length;r++){
for(c=0;c<anArray.length;c++){
if (seating[r][c]==false){
seatTaken = "O";
}
else{
seatTaken = "X";
}
System.out.print("\t[" + seatTaken + "] \t");
}
System.out.println("");
}
}
}
}
private boolean bookSeat(){
boolean isBooked = false;
for(int row = 0; row <2; row++){
for(int col = 0;col<maxCols;col++){
if (seating[row][col] == false){
seating[row][col] = true;
return true;
}
}
}
return false;
}
I think what you're looking to do is return once you find an open seat and book it -- as shown in the method above. This way the loops won't continue once you book a seat.
Assuming you mean that you want to exit this method as soon as it finds a seat.
private boolean bookSeat()
{
for(int row = 0; row <2; row++)
{
for(int col = 0;col<maxCols;col++)
{
if (seating[row][col] == false)
{
seating[row][col] = true;
return true;
}
}
}
return false;
}