recursive backtracking algorithm that counts all solutions - javascript

I'm building a sudoku generator-solver app and currently finishing the hiding algorithm for useless cells.
I have a working backtracking algorithm that returns true when the solution is found, but I need to check if there're any other solutions to prevent a wrong board from creating.
findEmpty function finds the next empty cell inside a sudoku board.
isValid function checks if the parameter passed fits in a current cell.
Provided code returns true if the board is solved.
It does overwrite the passed variable, so to access a solved board I call the variable passed.
If there's at least one extra solution, the function must return false.
If the board cannot be solved, the function must return false.
If there's a solution(only 1), return true
function backTrackSolve(board)
{
let find = findEmpty(board)
if (find[0] == -1)
return true
let row = find[0]
let col = find[1]
for (let i = 1; i < 10; i++)
{
if (isValid(board, { row,col }, i))
{
board[row][col] = i
if (backTrackSolve(board)){
return true
}
}
board[row][col] = 0
}
return false
}

function backTrackSolve(board)
{
let find = findEmpty(board)
if (find[0] == -1){
//count stuff here
return false;
}
let row = find[0]
let col = find[1]
for (let i = 1; i < 10; i++)
{
if (isValid(board, { row,col }, i))
{
board[row][col] = i
if (backTrackSolve(board)){
return true
}
}
board[row][col] = 0
}
return false
}

Related

Return inside for loop return initial value

I have a problem to understand why does RETURN in FOR loop returns me always initial fact value (let fact = 1):
const factorial = function(a) {
let fact=1;
if(a===0){
return 1;
}
else{
for(let i=1; i<=a; i++){
fact*=i;
return fact;** // This return
}
return fact
}
return fact;
};
//Result for all values e.g 1,5,10 is always 1, as in initial let fact =1
And when I remove it, my factorial function works totally fine. I have no idea why does it happen:
const factorial = function(a) {
let fact=1;
if(a===0){
return 1;
}
else{
for(let i=1; i<=a; i++){
fact*=i;
//Nothing
}
return fact
}
return fact;
};
// Code works fine, I receive factorial correctly
I was expecting to return factorial of my initial value. Instead I receive the initial variable value(1).
If I've understood your question correctly, you are wondering why did you get a return value of 1 in the first code regardless of the input value. That is because you had a return statement inside your for loop, which meant that your for loop would only be entered once and then exited with a return value of 1. Essentially, for loop never iterates, which means that you never get to calculate the value of factorial as fact = 1 * 2 * 3 * ..., you only do the initial step, which is fact = 1.
const factorial = function(a) { // <- you have tested this with 1,5 and 10
let fact=1; // <- here you set fact variable to value of 1
if(a===0){ // <- you check if you sent value is equal to 1,
return 1; // since you have used 1, 5 and 10 you will not be returning a value of 1 here
}
else{ // <- you enter this block of code when the value of a≠0
for(let i=1; i<=a; i++){ // <- you set the value of i to 1 and you enter the for loop
fact*=i; // <- you multiple your fact value, which is 1, with a value of i, which is also 1, which means you will get fact=1
return fact; // <- you return a value of fact, which is 1 here!
}
return fact
}
return fact;
};
return operator does not breaking only for loop: it goes deeper and stops whole function.
So, when you left return inside for without any condition, the return stops whole function at the first iteration of that loop (when fact is 1).
That means, that your code:
const factorial = function(a) {
let fact=1;
if(a===0){
return 1;
}
else{
for(let i=1; i<=a; i++){
fact*=i;
return fact; // This return
}
return fact
}
return fact;
};
In fact, is equal to:
const factorial = function(a) {
let fact=1;
if (a === 0){
return 1;
} else {
let i = 1;
fact *= i;
return fact;
}
};
Example of valid condition for return operator inside for loop:
function isAnyStringInside(values) {
for (let i = 0; i < values.length; i += 1) {
if (typeof values[i] === 'string') {
return true;
}
}
return false;
}
isAnyStringInside([1,2,3,4,5,'Hello',2,3,4,5]); // true
isAnyStringInside([1,2,3,4,5,2,3,4,5]); // false

Why does this function not work within the eventListener?

I am just starting with JavaScript and for my first project I am trying to display a working calculator using JS, HTML and CSS. I am just one step away from it finally handling easy operations but for some reason my "solver"-function does not work when hitting the Enter-button.
I already tried out all the functions in a "test.js" console.logging the results and everything worked perfectly. But for some reason it won't work when combining it with the eventListener and trying to display it within the textfield. I also tried simpler functions and displaying only variables in the textfield which works. It is just the solver-function that won't.
I will attach my code - most of you would definitely code a calculator much different and especially much shorter than the way I did it but I am proud I got this far, so please don't judge me too harshly! :D
First the declaration of functions which worked perfectly in the test.js. The solver was originally designed to return the previous 4 functions in a nested way but I thought this might be the problem, so I changed it.
function adds(num1, num2) {
return num1+num2;
};
function subs(num1, num2) {
return num1-num2;
};
function muls(num1, num2) {
return num1*num2;
};
function divis(num1, num2) {
return num1/num2;
};
//Creates an array with string elements.
function createArray(string) {
let array = [];
for(let element of string) {
array.push((element));
}
return array;
};
//Returns an array where numbers are joint within one element (e.g. '1','2' becomes '12').
function joinNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] =numArray[index] + array[i];
}
return numArray;
};
//Returns an array where all elements with numbers in them are changed to proper numbers instead of strings.
function makeNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] = parseInt(array[i]);
}
return numArray;
};
//Calculates the array that is provided and returns a single number as solution.
function operate(array) {
let solution = array[0];
for(let iOp = 1; array.length >= iOp; iOp=iOp+2) {
if(array[iOp] === '+') {
solution = adds(solution, array[iOp+1]);
}
if(array[iOp] === '-') {
solution = subs(solution, array[iOp+1]);
}
if(array[iOp] === '*') {
solution = muls(solution, array[iOp+1]);
}
if(array[iOp] === '/') {
solution = divis(solution, array[iOp+1]);
}
}
return solution;
};
//Takes a string (meant to be the value of a textfield) and returns the solution by calling all previously declared helper functions.
function solver(string) {
let cr = createArray(string);
let jo = joinNums(cr);
let ma = makeNums(jo);
let op = operate(ma);
return op;
};
Now on to the input field and hitting the enter-button:
//This is the enter-button
let enter = document.getElementById("enter");
//This is the textfield where calculations are entered. The textfield is then meant to be changed to display the operations result.
let textfield = document.getElementById("resultLn");
//The eventlistener.
enter.addEventListener("click", () => {
textfield.value = solver(textfield.value);
});
You do not use let statement at the for cycles i operand (at function joinNums, makeNums).
In addition at function operate, you can use switch.
Hi,
Your calculator code works well, If there was a problem, checkout your html.
I test with some operations and it works well. If there any operation doesn't work, please type this operation to help you
//This is the enter-button
let enter = document.getElementById("enter");
//This is the textfield where calculations are entered. The textfield is then meant to be changed to display the operations result.
let textfield = document.getElementById("resultLn");
//The eventlistener.
enter.addEventListener("click", () => {
textfield.value = solver(textfield.value);
});
function adds(num1, num2) {
return num1+num2;
};
function subs(num1, num2) {
return num1-num2;
};
function muls(num1, num2) {
return num1*num2;
};
function divis(num1, num2) {
return num1/num2;
};
//Creates an array with string elements.
function createArray(string) {
let array = [];
for(let element of string) {
array.push((element));
}
return array;
};
//Returns an array where numbers are joint within one element (e.g. '1','2' becomes '12').
function joinNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] =numArray[index] + array[i];
}
return numArray;
};
//Returns an array where all elements with numbers in them are changed to proper numbers instead of strings.
function makeNums(array) {
let numArray = [''];
let index = 0;
for (i=0; i < array.length; i++) {
if (isNaN(parseInt(array[i]))) {
index ++;
numArray.push(array[i]);
index++;
numArray[index]=[''];
continue;
}
numArray[index] = parseInt(array[i]);
}
return numArray;
};
//Calculates the array that is provided and returns a single number as solution.
function operate(array) {
let solution = array[0];
for(let iOp = 1; array.length >= iOp; iOp=iOp+2) {
if(array[iOp] === '+') {
solution = adds(solution, array[iOp+1]);
}
if(array[iOp] === '-') {
solution = subs(solution, array[iOp+1]);
}
if(array[iOp] === '*') {
solution = muls(solution, array[iOp+1]);
}
if(array[iOp] === '/') {
solution = divis(solution, array[iOp+1]);
}
}
return solution;
};
//Takes a string (meant to be the value of a textfield) and returns the solution by calling all previously declared helper functions.
function solver(string) {
let cr = createArray(string);
let jo = joinNums(cr);
let ma = makeNums(jo);
let op = operate(ma);
return op;
};
<input type="text" id="resultLn">
<button id="enter">Enter</button>

Javascript: Testing for perfect squares without using the inbuilt squareroot formula

I am new to javascript and taking some tests on codewars, I am writing a code that checks for perfect numbers i.e. if a number has a squareroot that is a whole number it should return true. Here is my code and it only works for 0 and 1, from here it returns false even for numbers that are perfect squares. I need to understand why my code is not working and i cannot see where my problem is.
var isSquare = function(n){
for ( var i=0; i>=0; i++){
var product= i*i;
if( product === n )
return true;
else if(product !==n)
return false;
}
}
Your return false is running every time the input n is not equal to the tested product. That is, on the first iteration, it will return false if n is not 0. You should probably only return false if n is smaller than the tested product, and leave out the iteration condition because the test is being done in the loop body:
var isSquare = function(n) {
for (var i = 0;; i++) {
var product = i * i;
if (product === n) return true;
else if (product > n) return false;
}
}
console.log(isSquare(9));
console.log(isSquare(10));
Your problem is with else if since you don't need else if, move the return outside the loop, it will keep checking until your loop get false, and you need also to rewrite your boolean expression
var isSquare = function(n){
for ( var i=0; i<n; i++){
var product= i*i;
if( product === n )
return true;
}
return false;
}
console.log(isSquare(9))
console.log(isSquare(4))
console.log(isSquare(12))

Javascript How to identify if all elements of one array are present in another

I need to create a function to check if all the letters in the second string of a two string array are present in the first string. The function I wrote seems to work for most of the examples I tried with it but ["hello" , "hey"] returns true despite there not being a y in hello and I don't understand why.
Here's my code:
function mutation(arr) {
arr[0] =arr[0].toUpperCase().split("");
arr[1] =arr[1].toUpperCase().split("");
for(i=0;i<arr[1].length;i++){
if(arr[0].indexOf(arr[1][i])>=0){
return true;
} else {return false;}}}
mutation(["hello", "Hey"]);
You are returning true even if one character is matched ,Try below code it checks if all characters are present or not
function mutation(arr) {
arr[0] = arr[0].toUpperCase().split("");
arr[1] = arr[1].toUpperCase().split("");
var count = 0;
for (i = 0; i < arr[1].length; i++) {
if (arr[0].indexOf(arr[1][i]) >= 0) {
count++;
}
}
return count === arr[1].length
}
mutation(["hello", "Hey"]);
here is one more efficient solution, it works only for lowercase letters.
(function(){
function charCode(str, i){
return str.charCodeAt(i) - 97;
}
function isMutation(a,b){
const aArr = new Uint8Array(26);
const bArr = new Uint8Array(26);
let i=0;
let index = 0;
while(i<a.length){
++aArr[charCode(a, i)];
++i;
}
i = 0;
while(i<b.length){
++bArr[charCode(b, i)];
++i;
}
i = 0;
while(i < 26){
if(!(aArr[i]===0 && bArr[i]===0 || aArr[i]>0 && bArr[i]>0)){
return false
}
++i;
}
return true;
}
console.assert(isMutation('hello', 'oleh') === true);
console.assert(isMutation('hello', 'hey') === false);
})();
you can also compare sum of uniq chars in the both arrays, but in this case you have to add each letters only once.
I would recommend using one of the code solutions suggested by user georg at Remove Duplicates from JavaScript Array.
For example, the function below could be used to sort each array (arr[0] and arr[1]) and remove duplicates.
Credit to user georg at the link above.
function uniq(a) {
return a.sort().filter(function(item, pos, ary) {
return !pos || item != ary[pos - 1];
})
}
Once you have sorted/removed duplicates, you can test to see if the two returned strings are equal or not.
Hello => EHLO, and Hey => EHY
EHLO !== EHY

Recursion without overun

I've been looking for real world examples of recursion. Remember, programming Wizards, I'm and artist and in Photoshop scripting (scriptus modus operandi) it's normally used to loop over all layers and sub layers.
I'm working on a (simple) recursion script to solve a four digit combination lock. You know, start with 1, then try 2, then 3 etc until the solution is found. To make things easy in the example the second digit is correct so we know that we don't have to change that. Also the initial state the numbers start zero, but we know there are no zeroes in the final solution.
The attempt must match the solution AND also add up to 10 in order to
be solved.
This may seem a bit stoppid, but I want to put in a two part condition of the solution, mainly because I can then apply what I've learned and write a brute force suduko solver. But you must crawl before you can ice skate...
var puzzle = [0,2,0,0]; // source
var solution = [1,2,3,4];
var s = superCopy(puzzle); // working array
drawPuzzle(s);
solvePuzzle(s, puzzle);
var total = checkTotal(s, solution);
var solution = checkSolution(s, solution);
function checkTotal(arr, source)
{
var c = 0;
// count the total
for (var i = 0; i < arr.length; i++)
{
c += arr[i];
}
if (c == 10)
{
alert("Total OK")
return true;
}
}
function checkSolution(arr, source)
{
// check the solution
for (var i in arr)
{
if (arr[i] != source[i]) return false
return true;
}
}
function solvePuzzle(arr, source)
{
for (var i = 0; i < arr.length; i++)
{
// check the source
var sourceCell = source[i];
//alert("checking source " + sourceCell)
//if it's a zero we can change it
if (arr[i] == 0)
{
cell = arr[i];
cell+=1;
if (cell > 4) cell = 0;
arr[i] = cell;
}
}
// check the solution
for (var i in arr)
{
// overflow time!
if (arr[i] != source[i]) solvePuzzle(arr, source)
else
{
alert("All done!")
}
}
}
function drawPuzzle(arr)
{
var p = "";
var c = 0;
for (var i = 0; i < arr.length; i++)
{
if (arr[i] == 0) p += "-"
else p += arr[i];
c+=1;
}
alert(p);
}
function superCopy(arr)
{
// returns a true copy of an array
tempArr = new Array();
for (var i = 0; i < arr.length; i++)
{
if (arr[i] == 0) tempArr[i] = 1 // changed, thanks Nostradamnit!
else tempArr[i] = arr[i]
}
return tempArr
}
The script is incomplete. This what I have so far, it falls over with an overflow error. Note solvePuzzle and checkTotal functions are not called because I realised that solvePuzzle needs to call itself and work out the solution...which is when I ran into overflow problems and got a bit confused.
I realise that this type of question runs dangerously close to a "fix my code" venture, so I'm prepared to put a bounty out for it. Thanks.
There are a couple of problems with your code. First up, your checkSolution function stops at the very first number that matches. You probably want it to check every number before returning true, so you should move return true outside the for loop. It only gets there if all numbers match up.
Another flaw is the superCopy function, which as Nostradamnit pointed out has a flawed condition.
Your next problem is in solvePuzzle, where you have this:
if (arr[i] == 0)
{
cell = arr[i];
cell+=1;
if (cell > 4) cell = 0;
arr[i] = cell;
}
The thing is, because arr[i] is 0 and you only add 1, cell will never be 4. So your if is never going to fire. This is where your infinite loop is: it only increments values that are zero with one, so after all zeros became one, it never goes further and you keep checking if "1111" is the solution.
Now the overflow: you shouldn't be calling solvePuzzle for every cell, this grows exponentially:
for (var i in arr)
{
// overflow time!
if (arr[i] != source[i]) solvePuzzle(arr, source)
else
{
alert("All done!")
}
}
Also, you never check the result again, so the looping never ends. You would probably want to change this to this:
if(checkTotal(arr) && checkSolution(arr, source))
{
alert("All done!");
return;
}
solvePuzzle(arr, source);
As a side note (not a bug causing thing): your checkTotal function isn't using the source parameter, so you can probably leave that out. Also, there is a rogue variable called cell in solvePuzzle, which isn't a big deal in this case, but it would be better to put var in front of it so it doesn't become global. Also, there is a sourceCell variable that never gets used.
At first glance, it seems that your superCopy function is flawed. You create an empty array, then compare its 0 index (which doesn't exist) to the input array. Is that where you are getting your "overflow"?
The problem seems to be that you call solvePuzzle(arr, source) multiple times in the same iteration:
for (var i in arr)
{
// overflow time!
if (arr[i] != source[i]) solvePuzzle(arr, source)
else
{
alert("All done!")
}
}
So you iterate over every item in the array, and if it is not equal to the source item, you call solvePuzzle again. But if you have several items that don't match, solvePuzzle will get called multiple times on the same array. And for each call, it gets called again multiple times. Therefore your function calls grow exponentially and result finally in a stack overflow.
What you probably intended to do, is the following:
var areArraysEqual = true;
for (var i in arr)
{
if (arr[i] != source[i]) {
areArraysEqual = false;
break;
}
}
if (areArraysEqual) {
alert("All done!");
} else {
solvePuzzle(arr, source);
}
I haven't looked over your solution yet, but i did write a recursive one for myself to solve the problem. Perhaps it can be of help as a guideline?
var solution = [1,2,3,4];
function checkSolution(arr) {
return solution.every(function(item, index){ return item === arr[index]; });
}
function increment(arr) {
for (var i=0; arr[i] === 9; i++) {
arr[i] = 0;
}
arr[i]++;
return arr;
}
function solvePuzzle(arr) {
if (isNaN(arr[arr.length-1])) {
return null;
}
if (checkSolution(arr)) {
return arr;
}
return solvePuzzle(increment(arr));
}
var solution = solvePuzzle([1,1,1,1]);
console.log(solution); // [1,2,3,4]
Maybe little bit off topic but I have created the easiest recursion example possible in my opinion.
http://jsfiddle.net/33yfS/
var str = "9785";
function rec(a, b)
{
var c=0;
if(b==-1)
return "";
if(a!=str.charAt(b))
return rec(a+1, b);
else
{
return rec(0,b-1)+""+a;
}
}
var ans = rec(0,str.length-1)

Categories

Resources