Need help with backtracking algorithm for generating Sudoku board - javascript

I have written an algorithm for generating a Sudoku board but it is failing. I have written it based on this though it does differ as I had written a lot of my code before I stumbled upon this.
The Code
I have a multidimensional array set up for holding the values called matrix. matrix consists of 9 arrays which are the rows and each of these hold the 9 columns. So to get the value at row 4 column 7 I would use
matrix[3][6];
The function for solving all the squares:
var populateMatrix = function() {
var possibles = generatePossibleNumbersArray();
var found = false;
for(var i=0; i< matrix.length; i++) {
for(var j=0; j< matrix[i].length; j++) {
while(possibles[i][j].length > 0) {
var rnd = Math.floor(Math.random() * possibles[i][j].length);
var num = possibles[i][j].splice(rnd, 1)[0];
if(isValid(i, j, num)) {
matrix[i][j] = num;
found = true;
break;
} else {
found = false;
continue;
}
}
if(!found) {
possibles[i][j] = [1,2,3,4,5,6,7,8,9];
j -= 2;
}
}
}
}
The generatePossibleNumbersArray() is just a helper function for creating a multidimensional array exactly like matrix except it is initialised to hold an array of integers 1-9 for each cell. During the populateMatrix() function these possible numbers get whittled down for each cell.
The Problem
It fails before completing the matrix every time because j ends up being -1. This is because as more cells get solved it becomes harder for the algorithm to find a value for a cell so it backtracks. But it eventually ends up backtracking all the way back until j == -1.
I really thought this algorithm would work and I've spent all day trying to get my head around this but I'm stumped so any light anyone could shed on this would be very much appreciated.
I thought 'I know, I'll write a javascript function for solving Sudoku. How hard can it be?'. How wrong I was.
[SOLUTION]
Based on a comment by #Steve314 (which he's now deleted!) I added matrix[i][j] = undefined into the if(!found) { ... and the algorithm now works and is lightening fast.
If anyone is interested, here is the complete code.

Backtracking algorithms usually restore the state if a branch fails and do the next possible move. So if the random filling of a field creates a failed branch just write back what was originally there.

Related

Why does my JavaScript solution to problem 2 (project euler) show infinity on the console?

let arr=[0,1];
let sum=0;
for(let i=2;i<4000000;i++) {
arr.push(arr[i-1]+arr[i-2]);
}
for (let i=0;i<arr.length;i++) {
if (arr[i]%2==0) {
sum+=arr[i];
}
}
console.log(sum);
By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms.
My solution to this question is wrong and I can't figure out why at all. I am not that experienced so please if anyone can explain in a simple way why my code is wrong. What can I do to fix it??
Note: I haven't hadn't included code in this answer because I figure the point of what you're doing is to learn to code these things. (Now you've gotten most of the way there, I did add a solution at the end.)
The problem is that your sums quickly go beyond the range of what JavaScript's number type can represent, reaching the point where they just are represented by Infinity. The number type only has 53 effective significant bits in which to hold numbers. You're exceeding that:
let seen4M = false;
let seenInfinity = false;
let arr=[0,1];
let sum=0;
for(let i=2;i<4000000;i++) {
const num = arr[i-1]+arr[i-2];
if (!seen4M && num > 4_000_000) {
console.log(`Too big: ${num}`);
seen4M = true;
} else if (!seenInfinity && !isFinite(num)) {
console.log(`Overflowed just after ${arr[i-1]}`);
seenInfinity = true;
}
arr.push(num);
}
for (let i=0;i<arr.length;i++) {
if (arr[i]%2==0) {
sum+=arr[i];
}
}
console.log(sum);
You're doing four million (minus two) loops, but the question asks you to consider the Fibonacci numbers whose values are less than or equal to four million (4M), which is a very different thing and is reached much more quickly. So instead of (nearly) 4M loops, stop when your code determines that the next number is > 4M.
Also note that there's no reason to use an array for this, and doing so will consume a lot of memory unnecessarily. Instead, just remember the penultimate and ultimate values, and shuffle them in the loop. Maintain sum in the first loop rather than using a second one.
In a comment you showed that you'd solved it using an array but couldn't see how to solve it without using an array. Here's how to do that (see comments):
// The penultimate (second-to-last) Fibonacci number we've done
let pen = 0;
// The ultimate (last) Fibonacci number we've done
let ult = 1;
// The sum so far
let sum = 0;
// A variable for each number as we go
let num;
// Create the next number and keep looping if it's less than or
// equal to four million
while ((num = pen + ult) <= 4_000_000) {
// We have a new number (`num`), count it if appropriate
if (num % 2 == 0) {
sum += num;
}
// Now that we have a new number, shuffle the last two:
// our ultimate number is our penultimate number, and
// our ultimate number is the new one
pen = ult;
ult = num;
}
console.log(sum);

socket Merchant problem, how can I solve it just sorting the array and counting the number of pairs flooring the numbers?

The problem I have to solve is this:
There is a large pile of socks that must be paired by color. Given an
array of integers representing the color of each sock, determine how
many pairs of socks with matching colors there are.
Example
There is one pair of color and one of color . There are three odd
socks left, one of each color. The number of pairs is
.
Function Description
Complete the sockMerchant function in the editor below.
sockMerchant has the following parameter(s):
int n: the number of socks in the pile
int ar[n]: the colors of each sock
Returns
int: the number of pairs
My solution in javascript since I know very little of the language was this
function sockMerchant(n, ar) {
// Write your code here
let pairs=0;
let counter;
ar.sort()
for(let i=0; i < n; i++){
if (i == 0){
counter = 1;
}else{
if(ar[i] == ar[i-1]){
counter++;
}else{
pairs= pairs + Math.floor(counter/2);
counter= 1;
}
}
}
return pairs
}
The problem is that hackerranks complains because with this input
10
1 1 3 1 2 1 3 3 3 3
my output is 2 instead of 4. Can somebody tell me why because I can't see where the problem is.
If someone can help me to see where is the issue, I will appreciate it
Thanks in advance
Jenifer
Unfortunately, I couldn't understand the logic of your proposed algorithm, But as an alternative solution, you may have a look at my code.
Here is my javascript code for this problem which works fine.
First, I defined a dictionary (ar_count) and count each number from ar array and update the dictionary for the corresponding key. I defined the key in the form of "key"+ar[i] for easy coding and fast processing of finding the existing key and for counting pairs.
function sockMerchant(n, ar) {
var ar_count={};
for(let i=0; i<ar.length;i++){
if("key"+ar[i] in ar_count){
ar_count["key"+ar[i]]+=1;
}
else{
ar_count["key"+ar[i]]=1;
}
}
//console.log(ar_count);
var pairs=0;
for (var key in ar_count){
paires+=~~(ar_count[key]/2);
}
return pairs;
}

Mathematical Concept In Multi-Dimensional Array Sorting

I have found this code written online(not by me), and was hoping to get an answer on what the mathematical formula or concept is that makes this function work. I am curious as to how this person designed this. First, I will explain the requirements that the function must produce, then I will supply the code, and a link to a working code pen for further hacking. P.S. The problem uses the word "vector", but since this is Javascript, vector just means array.
Function Requirements
Given a vector of vectors of words, ex.
[['quick', 'lazy'], ['brown', 'black', 'grey'], ['fox', 'dog']].
Write a function that prints all combinations of one word from the first vector, one word from the second vector, etc.
The solution may not use recursion. The number of vectors and number of elements within each vector may vary.
Example output: 'quick, brown, dog', 'lazy black fox' etc.
My Current Level Of Understanding
I am already aware that by using the principle of multiplication, to find the number of possible combinations available in this scenario is to just multiply the lengths of each inner vector by each other. For this specific example, we get a total of 12(2x3x2) different possible combinations. Where I fall off however, is inside the 4 nested for loops section of the program.
Whoever wrote the code, clearly understands some concept or formula that I do not. Just two examples, are the "previous" variable used inside the loops, and the strategic placement of where they decide to increment the j variable. It seems to me that they might be aware of some mathematical formula.
Code
Below is the code without comments. If you however go to this codepen, I have included the same code with plenty of comments that explain how the program works, so you don't have to trace everything out from scratch. You can also test the output in the built-in console.
function comboMaker(vector) {
var length = vector.length;
var solutions = 1;
for (var i = 0; i < length; i++) {
solutions *= vector[i].length;
}
var combinations = [];
for (var i = 0; i < solutions; i++) {
combinations[i] = [];
}
var previous = 1;
for (var i = 0; i < length; i++) {
for (var j = 0; j < solutions;) {
var wordCount = vector[i].length;
previous *= vector[i].length;
for (var l = 0; l < wordCount; l++) {
for (var k = 0; k < (solutions/previous); k++) {
combinations[j][i] = vector[i][l];
j++
}
}
}
}
for (var i = 0; i < solutions; i++) {
console.log(combinations[i].join(" "));
}
}
comboMaker([['quick', 'lazy'], ['brown', 'black', 'grey'], ['fox', 'dog']]);
You can consider combination of items as number in mixed radix numeric system.
Radix for every position is equal to number of items in corresponding array (here {2,3,2}). Overall number of combination M is product of all radixes.
You can generate combination either
by making for-loop with counter in range 0..M-1 and separating every digit from this counter and getting corresponding item. Pseudocode
M = ProductOfLengthsOfArrays
for c = 0..M-1
t = c
combination = {}
for i = 0..NumOfArrays-1
d = t %% Array[i].Length //modulo operation
t = t / Array[i].Length //integer division
combination.add(Array[i][d])
output combination
by counting in mixed radix from 0 to M-1
if item is last in the array, get first item and increment the next array
else get the next item in the same array
A cooperation of .reduce() and .map() allows us to come up with a very efficient single liner answer for this question.
var data = [['quick', 'lazy'], ['brown', 'black', 'grey'], ['fox', 'dog'],['jumps','runs']],
result = data.reduce((p,c) => p.reduce((r,fw) => r.concat(c.map(sw => fw + " " + sw)),[]));
console.log(result);

I'm having trouble with this exercise on hacker rank please look

https://www.hackerrank.com/contests/projecteuler/challenges/euler001
Here is the problem I'm confused what the parseInt readline statement
and also the the var n statement mainly..
when i run my code it seems to count up to ten twice probably a simple problem just not seeing it and was hoping I could get it explained so I can keep working on project euler problems
Thanks
function main() {
var t = parseInt(readLine());
var sum = 0;
var arr = [];
for(var a0 = 0; a0 < t; a0++){
var n = parseInt(readLine());
for (var i = 0; i < n; i++)
if (i % 3 === 0 || i % 5 === 0){
arr.push(i);
sum += i;
};
console.log(arr);
};
}
Maybe I'm not following exactly what is your question.
The parseInt is a javascript function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
The readLine() function is defined for you, it will give you "the next line" that was captured from standard in.
All (or most) of the hackerrank problems offer the input for the problem thru standard-in and expect the result from standard-out. So for this problem, hackerrank has created this boilerplate code for reading that input.
process.stdin.on('end', function () {
input_stdin_array = input_stdin.split("\n");
main();
});
There is filling the input_stdin_array array that is used on the readLine() function.
And about the
when i run my code it seems to count up to ten twice
The problem mentions:
First line contains T that denotes the number of test cases. This is followed by T lines, each containing an integer, N.
So you are printing the array T times (for the default test case is 2), so that why you probably see the "up to ten 2 times"
I hope this helped, and probably you could start with a couple of the https://www.hackerrank.com/domains/tutorials/30-days-of-code challenge so you get a better grasp of how to work on the problems.
Regards
Declare the array after the first for loop. You are using the same array for every test case, even though it still contains numbers from the previous test cases. Same for the sum.
for(var a0 = 0; a0 < t; a0++) {
var arr = [];
var sum = 0;

How to sort elements of array in natural order with mixed (letters and numbers) elements

i am trying to create google-form which is used to register students agreements on practice. Every agreement is registered and got agreement number which format is Last to digits of current year-T-number of agreement at this year/M. For example for now it is 17-T-11/M. The number of agreement currently is written by person which is responsible for practice.
Here is code of script below:
function onChange(e)
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
var range = sheet.getDataRange();
var values = range.getValues();
var comboValues = ['16-T-105/M'];
// removing titles from 0 column and 1 line (titles)
for (var i = 1; i <= values.length; i++) {
var v = values[i] && values[i][0];
v && comboValues.push(v)
}
// Sort the values
comboValues.sort(
function(a, b) {
if (b.toLowerCase() < a.toLowerCase()) return -1;
if (b.toLowerCase() > a.toLowerCase()) return 1;
return 0;
}
);
Logger.log(comboValues);
// google-form modification
var form = FormApp.openById('1SHgVIosoE34m9cny9EQySljvgnRpzffdFEZe-kzNOzA');
var items = form.getItems();
for (i = 4; i < items.length; i++) {
Logger.log("ID: " + items[i].getId(), ': ' + items[i].getType());
}
form.getItemById('2087613006').asListItem().setChoiceValues(comboValues);
I got issue which is related with lexicographical order. Person which register agreement choose from list last registered agreement number: i tryed to do that last registered agreement number will always be at list top. As time when i started this everything was fine (it started with number 16-T-105/M), but new year come and soon after 17-T-10/M agreement was registered i got issue, that 17-T-10/M was not on list top. Soon i realised that this happens because script use lexicographical order and "thinks" that 2 is more than 10. So i understood that i somehow will have to change that order and do that 2 is less than 10, 11 is less than 101 and so on.
My question is how to do that? I guess that i need to sort array elements in natural order - but i do not have idea how to do this.
I tryed to google how to do it , but result was not satisfactory - maybe my knowledge of coding is pretty limited (i am PhD student of Psychology, not Informatics) :)
Maybe someone will help how to solve that problem.
Updates:
Link to spreadsheet: https://docs.google.com/spreadsheets/d/1FH5qYTrLUNI2SCrcaqlwgu8lzAylaTkZsiALg0zIpCM/edit#gid=1620956794
Link to google-form (Copy of actual form): https://docs.google.com/forms/d/e/1FAIpQLSerJfkv1dgHexUwxppXNyhb46twOZgvEMOIVXSOJoED3SLmyQ/viewform
You should adjust the sorting method to account of the peculiarities of the data. Here is one way to do this: the function splitConvert processes each string, splitting it by non-word characters and then converting what can be converted to integers (and lowercasing the rest). Then the comparison goes through this array one by one.
comboValues.sort(
function(a, b) {
var as = splitConvert(a);
var bs = splitConvert(b);
for (var i = 0; i < as.length; i++) {
if (bs[i] < as[i]) return -1;
if (bs[i] > as[i]) return 1;
}
return 0;
}
);
function splitConvert(str) {
return str.split(/\W/).map(function(part) {
var x = parseInt(part, 10);
return isNaN(x) ? part.toLowerCase() : x;
});
}
This is not the most performance-oriented solution: the split-parse function will be repeatedly called on the same strings as they are being sorted. If this becomes an issue (I don't really think so), one can optimize by having one run of conversion, creating an array of arrays, and then sorting that.

Categories

Resources