Recursive Backtracking for puzzle solver in java - java

Just get my hand on coding and it is very addicted. So I try new challenge in making puzzle solver. I am getting so close to finish it but get stuck.
There are 2 main methods: puzzleSolver and check
I have tested check method with all cases and it is working very well.
So the only problem is solve method and I dont know whats wrong with it.
Please look at my code and help me out.
Very appreciate.
I will explain the rules below.
RULES:
1.No 3 consecutive values (1 and 2) in each row and column.
2.Each row and column contains the same amount of values.
If grid[6][6]. Each row and column will have 3 of 1s and 3 of 2s.
But cannot have 3 of 1s or 2s next each other.
Example:
grid[2][2]
0 1
1 0
Solution:
2 1
1 2
grid[2][2]
1 1
0 0
Unsolvable
It violated rule number 2.
grid[4][4]
[0, 2, 2, 1]
[0, 2, 1, 2]
[2, 1, 0, 1]
[2, 0, 0, 0]
solution:
[1, 2, 2, 1]
[1, 2, 1, 2]
[2, 1, 2, 1]
[2, 1, 1, 2]
grid[4][4]
[0, 2, 2, 2] <- violated rule number 2
[0, 2, 1, 2]
[2, 1, 0, 1]
[2, 0, 0, 0]
Unsolvable
grid[6][6]
[0, 0, 1, 1, 1, 0] <- violated rule #1
[0, 0, 0, 1, 0, 0]
[2, 2, 2, 0, 0, 0] <-violated rule #1
[0, 0, 0, 1, 0, 0]
[0, 1, 2, 0, 0, 0]
[0, 2, 0, 1, 0, 0]
Unsolvable
This is my input grid:
public static void main(String[] args) {
int[][] grid = { { 0, 1 }, { 1, 0 } };
int[][] grid1 = { { 0, 2, 2, 1 }, { 0, 2, 1, 2 }, { 2, 1, 0, 1 }, { 2, 0, 0, 0 } };
int[][] grid2 = { { 0, 2, 2, 0 }, { 0, 0, 0, 0 }, { 0, 2, 0, 0 }, { 0, 0, 0, 1 } };
int[][] grid3 = { { 0, 0, 1, 0, 2, 2 }, { 0, 0, 2, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 2, 0, 0 },
{ 2, 0, 1, 0, 0, 0 }, { 0, 0, 2, 1, 2, 0 } };
It works in some cases but not all and I dont know why
OUTPUT
Fail to find solution
[0, 2, 2, 0]
[0, 0, 0, 0]
[0, 2, 0, 0]
[0, 0, 0, 1]
false
Solution should have:
1, 2, 2, 1
2, 1, 1, 2
1, 2, 1, 2
2, 1, 2, 1
Here is my code
Solve method will run all row and column and uses check method to decide which value to be placed
public static boolean puzzleSolve(int[][] grid) {
for (int row = 0; row < grid.length; row++) {
// column start from 0 and increasing as going down
for (int col = 0; col < grid.length; col++) {
// start at 0, 0
if (grid[row][col] == 0) { // if value =0, will be replaced with n
for (int n = 1; n < 3; n++) { // n =1 or n=2
grid[row][col] = n; // place n=1 then check condition
if (check(grid)) {
grid[row][col] = n;// if true, replace 0 with n
if (solve(grid)) { // check whole grid if violated rules
return true;
}
}
}
// System.out.println("No solution");
return false; // fail in replacing
}
}
}
// print out solved grid if succeed
System.out.println("solution: ");
for (int i = 0; i < grid.length; i++) {
System.out.println(Arrays.toString(grid[i]));
}
return true; // success
}
//end code
I have check method to detect any violations and it work well in any cases.
I know there is something wrong in solve method but cannot find it.

In, pseudocode, your solution reads like:
for each cell with value zero
for each allowed value
place value in cell
check if it's a solution
Walkthrough what happens if you have all zeroes in you cells. The first cell will be given value 1, then 2, neither of which solve the whole grid (because there are still zeroes). So it moves the second cell and so on throughout the grid, leaving each cell with value 2. It obviously won't find a solution in that situation.
Your first issue here is that you actually aren't doing any recursion or backtracking.
A correct solution will likely look like:
solve (grid, position):
if position is past end and grid is solved
yah!
else
for each allowed value
place value in position on grid
call solve(grid, next position)
That's recursive (because it calls itself) and backtracking because if it can't find a solution it returns to a previous position (above it in the call stack) and tries a new value.
So an actual solution might look something like:
private void findSolutions(int[][] grid, int col, int row) {
if (row == grid.length && isSolved(grid)) {
printSolution(grid);
} else {
for (int v = 1; v <= 2; v++) {
grid[row][col] = v;
if (col == grid[row].length) {
findSolutions(grid, 0, row + 1);
} else {
findSolutions(grid, col + 1, row + 1);
}
}
}
}

Related

When building array program in Java, it does not return the last number of the array when following the array.length - 1 method

I am writing a small program to take an input array, nums and create a new array that is double the size and returns the last number from the previous array as the last and only different number in the new array.
When I try to return this number using the nums.length - 1 formula to get the end of the array, it returns the number in the middle of the new array. Below is my program.
public int[] makeLast(int[] nums) {
int lengonewarr = nums.length;
int officiallength = lengonewarr * 2;
int [] makezero = new int [officiallength];
makezero [nums.length-1] = nums[nums.length-1];
return(makezero);
}
These are the outputs I should be making:
makeLast([4, 5, 6]) → [0, 0, 0, 0, 0, 6]
makeLast([1, 2]) → [0, 0, 0, 2]
makeLast([3]) → [0, 3]
But I instead get something like:
makeLast([1, 2, 3, 4]) → [0, 0, 0, 0, 0, 0, 0, 4] (My output) [0, 0, 0, 4, 0, 0, 0, 0]
makeLast([2, 4]) → [0, 0, 0, 4] (My output) [0, 4, 0, 0]
Any advice is greatly appreciated.
the array makezero's length is officiallength, not nums.length, just replace the first nums.length by makezero.length or officiallength.
makezero [makezero.length -1] = nums[nums.length-1];
BTW: It's better to name the variable with camelCase style, which will make the code more readable. Like makeZero or officialLength
I modified your and here it is:
public int[] makeLast(int[] nums) {
int lengonewarr = nums.length;
int officiallength = lengonewarr * 2;
int [] makezero = new int [officiallength];
makezero [makezero.length-1] = nums[nums.length-1];
return(makezero);
}
As the array makezero is double size, the length of lengonewarr is always in the middle of makezero.

Longest Plateau Solution: the length and location of the longest continuous sequence of equal values

Here is a full program description with test cases and below it is my solution:
Given an array of integers int A[], find the length and location of the longest contiguous sequence of equal values for which the values of the elements just before and just after this sequence are smaller.
You should just print these two numbers (first is the length and second is the starting index of the plateau).
To complete the definition, we can consider there are imaginary index positions at A[-1] and A[A.length] where A[-1] < A[0] and A[A.length] < A[A.length-1]. Therefore, the plateau can start/end at both ends of array A. This condition guarantees the existence of a plateau. A plateau can be of length 1.
Example 1:
java LongestPlateau 1 2 2 2 2 1
With these command-line arguments, the program should print:
4
1
Example 2:
java LongestPlateau 1 2 2 2 2 3
With these command-line arguments, the program should print:
1
5
Example 3:
java LongestPlateau 3 2 2 2 1 2 1 1 1 2 2 0 1 1 1 1 0
With these command-line arguments, the program should print:
4
12
Here is my Solution:
public class LongestPlateau {
private static int[] parseInputArray(String[] args) {
int[] value = new int[args.length+1];
for(int i = 0 ; i < args.length; i++){
if (i == args.length-1) value[i] = 0; // this imaginary last value of the array ensures that if the plateau is the last value of the array, then it outputs the correct answer
value[i] = Integer.parseInt(args[i]);
}
return value;
}
public static void printLargestPlateau(int[] values) {
int biggestStartIndex = -1;
int biggestLength = 0;
int currentIndex = 1;
int currentPlateauStartIndex = 1;
int currentLength = 1;
boolean plateauStarted = false;
while (currentIndex < values.length) {
if(isStartOfPlateau(currentIndex, values)){
currentLength = 1;
plateauStarted = true;
currentPlateauStartIndex = currentIndex;
} else if (isEndOfPlateau(currentIndex, values)) {
if(plateauStarted && currentLength > biggestLength){
biggestLength = currentLength;
biggestStartIndex = currentPlateauStartIndex;
}
plateauStarted = false;
currentLength = 1;
} else {
currentLength++;
}
currentIndex++;
}
System.out.println(biggestLength +"\n"+biggestStartIndex);
}
private static boolean isStartOfPlateau(int index, int[] values){
if(index <= 0){
return false;
}
return values[index-1] < values[index];
}
private static boolean isEndOfPlateau(int index, int[] values){
if(index <= 0){
return false;
}
return values[index - 1] > values[index];
}
public static void main(String[] args) {
int[] values = parseInputArray(args);
printLargestPlateau(values);
}
}
As I mentioned in the comments, existing code fails to detect plateaus at the start and the end of the input data, and the following implementation fixes this issue.
static void printLargestPlateau(int ... arr) {
int start = -1, maxStart = -1;
int length = 0, maxLength = -1;
boolean onPlateau = false;
if (arr.length > 0) {
start = 0;
length = 1;
onPlateau = true;
for (int i = 1; i < arr.length; i++) {
if (arr[i] == arr[i - 1]) {
if (onPlateau) {
length++;
}
} else if (arr[i] < arr[i - 1]) {
if (length > maxLength) {
maxLength = length;
maxStart = start;
}
onPlateau = false;
} else { // possible start of new plateau
onPlateau = true;
start = i;
length = 1;
}
}
// check possible plateau at the end
if (length > maxLength) {
maxLength = length;
maxStart = start;
}
}
System.out.println(maxLength);
System.out.println(maxStart);
}
Tests:
int[][] tests = {
{},
{1},
{1, 1},
{1, 2},
{1, 1, 2},
{1, 2, 2},
{1, 2, 1},
{1, 2, 3},
{1, 2, 2, 2, 3, 3, 1, 1, 1, 1},
{1, 2, 2, 2, 2, 1},
{1, 2, 2, 2, 2, 3},
{3, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 0, 1, 1, 1, 1, 0},
{3, 3, 3, 3, 1, 1, 0, 2, 2, 2, 2, 2, 2}
};
for (int[] arr : tests) {
System.out.println(Arrays.toString(arr));
printLargestPlateau(arr);
System.out.println("-".repeat(arr.length * 3));
}
Output:
[]
-1
-1
[1]
1
0
---
[1, 1]
2
0
------
[1, 2]
1
1
------
[1, 1, 2]
1
2
---------
[1, 2, 2]
2
1
---------
[1, 2, 1]
1
1
---------
[1, 2, 3]
1
2
---------
[1, 2, 2, 2, 3, 3, 1, 1, 1, 1]
2
4
------------------------------
[1, 2, 2, 2, 2, 1]
4
1
------------------
[1, 2, 2, 2, 2, 3]
1
5
------------------
[3, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 0, 1, 1, 1, 1, 0]
4
12
---------------------------------------------------
[3, 3, 3, 3, 1, 1, 0, 2, 2, 2, 2, 2, 2]
6
7
---------------------------------------

How do I count repeated occurrences of an element in a list?

Say I have an arraylist = [1, 1, 1, 1, 1, 5, 5, 6, 3, 5, 6 2, 5, 1 , 1, 1, 1, 1, 4, 2, 4, 2, 5 ,2 ,6 ,3,5, 2, 5, 1 , 1, 1, 1, 1, 1, 4, 1, 5, 2,]
I would like to find all the start indexes of a sequence of x.
The sequence length must be > 2
For example x = 1
My expected output is this:
start at element 0, interval of size 5.
start at element 13, interval of size 5.
start at element 29, interval of size 6.
I am new to programming in java and I don't know what the logic would be.
I was thinking of using a for loop and looping through each element in the array and using a counter when the element i == 1. My problem is I'm not sure how to stop counting and resume counting between intervals.
public void count() {
int count = 0;
for(Integer number: ArrayList) {
if (number == 1 ) {
count++;
}
if (number != 1 ) {
break;
}
}
}
As you can see my attempts are pretty bad. I'm missing something crucial and just can't see it.
Please check sliding window approach:
https://medium.com/outco/how-to-solve-sliding-window-problems-28d67601a66
In general, you should use 2 pointers in the array,
The first one will indecte the beginning of the sequence, the second one will indecte about the length or the sequence.
You start moving with that start index untill you getting to you value, then moving with the second index untill reaching to a different number.
Then you record you result bye saving Pair of start index and length inside an ArrayList or any structure, and setting the startIndex =endindex+1
You can visit leetcode / geeksforgeeks for more related questions and topics
Try this
import java.util.*;
public class Main
{
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
List<Integer> numbers = new ArrayList<Integer>();
numbers.addAll(Arrays.asList(1, 1, 1, 1, 1, 5, 5, 6, 3, 5, 6, 2, 5, 1, 1, 1, 1, 1, 4, 2, 4, 2, 5 ,2 ,6 ,3,5, 2, 5, 1, 1, 1, 1, 1, 1, 4, 1, 5, 2));
int startIndex = -1;
int count = 0;
System.out.print("Enter a number to count: ");
int x = scan.nextInt();
numbers.add(x-1);
for(int i = 0; i < numbers.size(); i++){
if(numbers.get(i) == x){
if(count == 0)
startIndex = i;
count++;
} else{
if(count > 2)
System.out.printf("start at index %d, interval of size %d \n", startIndex, count);
count = 0;
}
}
}
}
Output:
Enter a number to count: 1
start at index 0, interval of size 5
start at index 13, interval of size 5
start at index 29, interval of size 6
I am new to programming in java
...but this is not related to java, is it?
I don't know what the logic would be.
That's what you need to solve before trying to implement it.
Hint: Can you implement something slightly different? Change the input to number occurrences of 1s in a list, so your output would be [5, 5, 6, 1].
Hint 2: sometimes it's easier to add extra number (terminator) to original list, so let say if -1 cannot be there, add -1 to the end, so once you find -1, you know you are at the end...

Base Negation given an inDigits

I have the following problem:
Given an input in base (the input is given as an array of its digits in that base), write the negation of the number in "base's"-complement notatation in outDigits.
The "base's complement" notation of a number is a generalization of "two's complement": if we treat (-x) as an unsigned number in base and add it to x, we should get 0 (modulo base^digit-size). I cannot call other function (even Math.pow)
I keep getting an error with my tests. My code:
public static void baseNegate(int base, int[] inDigits, int[] outDigits) {
outDigits[0] = 1;
for (int i = outDigits.length - 1; i >= 0; i--) {
outDigits[i] += base - (1 + inDigits[i]);
if (i < outDigits.length - 1) {
outDigits[i + 1] = outDigits[i] / base;
}
outDigits[i] %= base;
}
}
I cannot find the error in my calculations, please help.
my test:
------------------------------------ Negate number 365 in base 10 ------------------------------------
Test case have FAILED.
Base: 10
Input number: [5, 6, 3]
Expected: [5, 3, 6]
Output: [5, 0, 0]
-------------------------------- Negate number b1010110011 in base 2 --------------------------------
Test case have FAILED.
Base: 2
Input number: [1, 1, 0, 0, 1, 1, 0, 1, 0, 1]
Expected: [1, 0, 1, 1, 0, 0, 1, 0, 1, 0]
Output: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-------------------------------------- Negate 0x7AF0 in base 16 --------------------------------------
Test case have FAILED.
Base: 16
Input number: [0, 15, 10, 7]
Expected: [0, 1, 5, 8]
Output: [0, 1, 0, 0]
Your problem is that you may seem to be trying to do the negation of the complement while calculating the complement and it is complicating your solution.
You could try to simplify your solution by splitting it into two phases:
First compute the complement.
Second add the +1 to the computed complement.
The following method is a working version of this:
public static void baseNegate(int base, int[] inDigits, int[] outDigits) {
// Compute the complement of the digits
for (int i = outDigits.length - 1; i >= 0; i--)
outDigits[i] = base - (1 + inDigits[i]);
// Negate the complement by adding +1 to the computed number (collection of digits)
for (int i = 0; i < outDigits.length; i++) {
if (outDigits[i] == base - 1) {
// Max out digit. Set it to zero and try with the higher order next.
outDigits[i] = 0;
} else {
// Digit that has room for +1. Finally add the 1 and DONE!
outDigits[i]++;
break;
}
}
}
This approach is clearer, better performing and the code is self explanatory; but I added comments in the code to follow the logic used.
Complete code on GitHub
Hope this helps.
Since the "expected" values show that index 0 is the lowest order digit, it means that for number 123₁₀ the array would be [3, 2, 1], i.e. the digits are in reverse order of what you'd expect as a human. To a computer, it makes sense that value at index i is the value that must be multiplied by baseⁱ.
That means you need the i loop to iterate up, not down, so you can track the carry-over. Otherwise you code works fine:
public static void baseNegate(int base, int[] inDigits, int[] outDigits) {
outDigits[0] = 1;
for (int i = 0; i < outDigits.length; i++) { // <== reversed iteration
outDigits[i] += base - (1 + inDigits[i]);
if (i < outDigits.length - 1) {
outDigits[i + 1] = outDigits[i] / base;
}
outDigits[i] %= base;
}
}
Personally, writing it like this makes more sense, especially since it doesn't rely on outDigits array to be pre-initialized to all 0's:
public static void baseNegate(int base, int[] inDigits, int[] outDigits) {
int carry = 0;
for (int i = 0; i < outDigits.length; i++) {
outDigits[i] = (base - inDigits[i] - carry) % base;
carry = (inDigits[i] + outDigits[i] + carry) / base;
}
}
For better performance, you don't want to use % and /, so something like this might be better:
public static void baseNegate(int base, int[] inDigits, int[] outDigits) {
boolean carry = false;
for (int i = 0; i < outDigits.length; i++) {
if (carry) {
outDigits[i] = base - inDigits[i] - 1;
} else if (inDigits[i] != 0) {
outDigits[i] = base - inDigits[i];
carry = true;
}
}
}
Test
All 3 will give the same result:
public static void main(String[] args) {
test(10, 5,6,3);
test(2, 1,1,0,0,1,1,0,1,0,1);
test(16, 0,15,10,7);
test(8, 0,0,0); // 0 -> 0 (000)
test(8, 1,0,0); // 1 -> -1 (777)
test(8, 7,7,3); // 255 -> -255 (104)
test(8, 0,0,4); // -256 -> -256 (004)
}
static void test(int base, int... inDigits) {
int[] outDigits = new int[inDigits.length];
baseNegate(base, inDigits, outDigits);
System.out.printf("%d: %s -> %s%n", base, Arrays.toString(inDigits),
Arrays.toString(outDigits));
}
Output
10: [5, 6, 3] -> [5, 3, 6]
2: [1, 1, 0, 0, 1, 1, 0, 1, 0, 1] -> [1, 0, 1, 1, 0, 0, 1, 0, 1, 0]
16: [0, 15, 10, 7] -> [0, 1, 5, 8]
8: [0, 0, 0] -> [0, 0, 0]
8: [1, 0, 0] -> [7, 7, 7]
8: [7, 7, 3] -> [1, 0, 4]
8: [0, 0, 4] -> [0, 0, 4]
I think there's a problem around here:
if (i < outDigits.length - 1) {
outDigits[i + 1] = outDigits[i] / base;
}
Let's say you're using base 10. Since a digit can only be 0 through 9, dividing by 10 would mean the result of this calculation is always 0. I don't think you intended this.

How do I take a string, convert said string to bianary, and then take each 1 or 0 and add it as a value in an array

I am doing some tests with grids in java, and how to generate them with 1s and 0s, 1s being [+] and 0s being [ ].
(TLDR):
I want to be able to take in words(s), convert that to bianary, and add each individual 1 and 0 to an array
The way I have the grids set up is:
// code that tells method how to generate the grid
int[] GRIDCODE3x3_1 = new int[]{
0, 1, 0,
1, 1, 1,
0, 1, 0
};
public void fillGridSpec(int[] x) {
System.out.println("\n");
int count = 0;
String gridLine = " ";
for(int p = 0; p < gridHeight; p++) {
gridLine = " ";
String[] gridArray = new String[gridWidth];
for(int q = 0; q < gridWidth; q++) {
if(x[count] == 1) {
gridArray[q] = "[+] ";
count++;
} else {
gridArray[q] = "[ ] ";
count++;
}
gridLine += gridArray[q];
}
System.out.println(gridLine);
}
}
Output would be:
[ ] [+] [ ]
[+] [+] [+]
[ ] [+] [ ]
With that out of the way I want to give an example of what I want it to do.
Lets say the string is a
The bianary for this is 01100001, what I need this to turn into is 0,1,1,0,0,0,0,1 so the output is
[ ] [+] [+] [ ] [ ] [ ] [ ] [+]
but I also need it to be repeatable, as in if the String is Hello World
(bianary):
01001000 01100101 01101100 01101100 01101111 00100000 01010111 01101111 01110010 01101100 01100100
(the amount of commas here is redundant so I'll take it you know what I need to convert this to, and how the output works)
If you need any clarification with what I am asking, ask it in the comments and I will get back to you as soon as possible.
I am not sure what you want according to your subject is as follows:
String str = "Hello World";
for (int i = 0; i < str.length(); i++) {
String binStr = String.format("%8s", Integer.toBinaryString(str.charAt(i))).replace(' ', '0');
int[] intArray = new int[binStr.length()];
for (int j = 0; j < binStr.length(); j++) {
intArray[j] = Integer.valueOf(String.valueOf(binStr.charAt(j)));
// This also works
//intArray[j] = Character.getNumericValue(binStr.charAt(j));
}
System.out.println(Arrays.toString(intArray));
}
Console output
[0, 1, 0, 0, 1, 0, 0, 0]
[0, 1, 1, 0, 0, 1, 0, 1]
[0, 1, 1, 0, 1, 1, 0, 0]
[0, 1, 1, 0, 1, 1, 0, 0]
[0, 1, 1, 0, 1, 1, 1, 1]
[0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 1, 0, 1, 1, 1]
[0, 1, 1, 0, 1, 1, 1, 1]
[0, 1, 1, 1, 0, 0, 1, 0]
[0, 1, 1, 0, 1, 1, 0, 0]
[0, 1, 1, 0, 0, 1, 0, 0]
Still not sure what you asking, but
String a = "01001000";
StringBuilder buf = new StringBuilder();
for (char c: a.toCharArray()) {
buf.append("[");
if (c == '1') {
buf.append("+");
}
buf.append("] ");
}
System.out.println(buf);
edit
If the input is a char, it can be converted to a binary String like
String a = Integer.toBinaryString('a');
System.out.println(a);
StringBuilder buf = new StringBuilder();
for (char c: a.toCharArray()) {
buf.append("[");
if (c == '1') {
buf.append("+");
}
else {
buf.append(" ");
}
buf.append("] ");
}
System.out.println(buf);

Categories