Solving a 4x4 (simplified one) sudoku in javascript - javascript

I have a problem where I have to code an automatic solution to a given sudoku which is 4x4 which means the numbers go only as far 1 2 3 4. It's a simplified version of a sudoku since I am still new to programming.
I have a given template with random sudoku generated from it and I have to write a code to solve the sudoku automatically.
Here is what I have in the begining as sudoku that i have to solve
sudoku[6] = [[" ","2"," "," "],
[" "," ","2"," "],
[" "," "," ","3"],
["4"," "," "," "]
My idea was to insert "1234" into empty " " and then remove the numbers from "1234" when one of the numbers is already present in the column, row and quadrant. So what I wanted to do is with the use of loops go through all the positions in the tables and the moment I find for example "1" alone i will remove the 1 from "1234".
Here is the beggning of my code, it appears it doesnt work the moment I reach if, can you guys please tell me what I am doing wrong or why isn't it working when i get to my If.
Thank you in advance.
var sudoku = sudoku[6];
// function to put "1234" into empty space ""
var concatenate = function (s)
{
for (i=0; i<s.length; i++)
for (j=0; j<s.length; j++)
if (sudoku[i][j] === " ")
sudoku[i][j] = "1234";
};
concatenate(sudoku);
// function to solve the sudoku automatically.
var solve = function (t)
{
for (i = 0; i<t.length; i++)
for (j=0; j<t.length; j++)
for (k=j; k<(4+j); k++)
if (sudoku[i][j].length === 1) // this is where it seems to bug, in this if im trying to find the position where we only have one number and not "1234"
var s = sudoku[i][j];
if (sudoku[i][k-j] !== ("1" || "2" || "3" || "4")) // here im finding the position of all position in the sudoku where ive got "1234" so i can remove the number found in the previous if.
{
var index = sudoku[i][k-j].indexOf(s);
var string_new = sudoku[i][k-j].substring(0,index) + sudoku[i][k-j].substring(index+1, 4);
sudoku[i][k-j] = string_new;
}
};

There are known algorithms to solve the sudoku problem, you should take a look.
For such a small sudoku like yours, you may choose to implement not taking in account the computational time. (choose the simplest to implement)
For more infos: Sudoku solving algorithms
Reguarding your code, the idea (on paper) is not bad, but I really can't understand what you intended to do with that. For example:
if (sudoku[i][k-j] !== ("1" || "2" || "3" || "4"))
This line has no sense. The expression ("1" || "2" || "3" || "4") will always evaluates "1". So you are writing:
if (sudoku[i][k-j] !== "1")
Moreover sudoku[i][k-j] is a string containing "1234" (or part of it), so you should use indexOf to check the presence of a character.
And what is the use of the internal for?
for (k=j; k<(4+j); k++)
Why are you iterating from j to 4+j? You're always using k-j to access the variable (sudoku[i][k-j]), that is always between j-j and 4+j-j. So why don't:
for (k=0; k<4; k++)
There are more other logic errors in you code...
If you want to implement that idea, you should take your time to think what you are writing, or (better) use a known algorithm.

You should replace this one:
if (sudoku[i][k-j] !== ("1" || "2" || "3" || "4"))
to something like this:
if ( sudoku[i][k-j] !== "1" || sudoku[i][k-j] !== "2" || ...
or you can consider using a switch statement also, but I'm not sure if it's gonna solve the bug that you're struggling with that or not ...

Related

Check length between two characters in a string

So I've been working on this coding challenge for about a day now and I still feel like I haven't scratched the surface even though it's suppose to be Easy. The problem asks us to take a string parameter and if there are exactly 3 characters (not including spaces) in between the letters 'a' and 'b', it should be true.
Example: Input: "maple bread"; Output: false // Because there are > 3 places
Input: "age bad"; Output: true // Exactly three places in between 'a' and 'b'
Here is what I've written, although it is unfinished and most likely in the wrong direction:
function challengeOne(str) {
let places = 0;
for (let i=0; i < str.length; i++) {
if (str[i] != 'a') {
places++
} else if (str[i] === 'b'){
}
}
console.log(places)
}
So my idea was to start counting places after the letter 'a' until it gets to 'b', then it would return the amount of places. I would then start another flow where if 'places' > 3, return false or if 'places' === 3, then return true.
However, attempting the first flow only returns the total count for places that aren't 'a'. I'm using console.log instead of return to test if it works or not.
I'm only looking for a push in the right direction and if there is a method I might be missing or if there are other examples similar to this. I feel like the solution is pretty simple yet I can't seem to grasp it.
Edit:
I took a break from this challenge just so I could look at it from fresh eyes and I was able to solve it quickly! I looked through everyone's suggestions and applied it until I found the solution. Here is the new code that worked:
function challengeOne(str) {
// code goes here
str = str.replace(/ /g, '')
let count = Math.abs(str.lastIndexOf('a')-str.lastIndexOf('b'));
if (count === 3) {
return true
} else return false
}
Thank you for all your input!
Here's a more efficient approach - simply find the indexes of the letter a and b and check whether the absolute value of subtracting the two is 4 (since indexes are 0 indexed):
function challengeOne(str) {
return Math.abs(str.indexOf("a") - str.indexOf("b")) == 4;
}
console.log(challengeOne("age bad"));
console.log(challengeOne("maple bread"));
if there are exactly 3 characters (not including spaces)
Simply remove all spaces via String#replace, then perform the check:
function challengeOne(str) {
return str = str.replace(/ /g, ''), Math.abs(str.indexOf("a") - str.indexOf("b")) == 4;
}
console.log(challengeOne("age bad"));
console.log(challengeOne("maple bread"));
References:
Math#abs
String#indexOf
Here is another approach: This one excludes spaces as in the OP, so the output reflects that. If it is to include spaces, that line could be removed.
function challengeOne(str) {
//strip spaces
str = str.replace(/\s/g, '');
//take just the in between chars
let extract = str.match(/a(.*)b/).pop();
return extract.length == 3
}
console.log(challengeOne('maple bread'));
console.log(challengeOne('age bad'));
You can go recursive:
Check if the string starts with 'a' and ends with 'b' and check the length
Continue by cutting the string either left or right (or both) until there are 3 characters in between or the string is empty.
Examples:
maple bread
aple brea
aple bre
aple br
aple b
ple
le
FALSE
age bad
age ba
age b
TRUE
const check = (x, y, z) => str => {
const exec = s => {
const xb = s.startsWith(x);
const yb = s.endsWith(y);
return ( !s ? false
: xb && yb && s.length === z + 2 ? true
: xb && yb ? exec(s.slice(1, -1))
: xb ? exec(s.slice(0, -1))
: exec(s.slice(1)));
};
return exec(str);
}
const challenge = check('a', 'b', 3);
console.log(`
challenge("maple bread"): ${challenge("maple bread")}
challenge("age bad"): ${challenge("age bad")}
challenge("aabab"): ${challenge("aabab")}
`)
I assume spaces are counted and your examples seem to indicate this, although your question says otherwise. If so, here's a push that should be helpful. You're right, there are JavaScript methods for strings, including one that should help you find the index (location) of the a and b within the given string.
Try here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#instance_methods

Javascript - Find opening and closing bracket positions on a string?

I'm making a calculator for a site project of mine where you can type your entire expression before resolving, for example: 2+3*4 would return 14, 22-4 would return 18, 20+5! would return 140, and so on.
And that works for simple expressions like the ones I showed, but when I add brackets the code breaks.
So a simple expression like (2+3)! that should return 120 actually returns 10 or 2+3!.
my original ideia to make even the basic 2+3! work was to separate the string in math simbols and the rest. so it would separate in this case it would separate it into 2, + and 3!; where it would find the symbol and resolve just that part. And that's why it solves 10 instead of not working.
But after trying to solve I couldn't make the code work except in a extremely specific situation, so I decided to redo the code and post this here in case someone could help me out.
This is the function that I'm currently using to prepare my string for evaluation:
function sepOperFat(){
//2+3! it's working
//1+(2-(2+2)+3)! want that to work in the end
var value = document.calculator.ans.value;
var operandoPos = ['0'];
var operandoInPos = [''];
var paraResolver = [];
for(i = 0; i <= value.length; i++){
//check if value[i] is equal to +, -, ×, ÷, * & /
if(value[i] == '+' || value[i] == '-' || value[i] == '×' || value[i] == '÷' || value[i] == '*' || value[i] == '/'){
operandoPos.push(i);
operandoInPos.push(value[i]);
}
}
paraResolver.push(value.slice(operandoPos[0], operandoPos[1]));
for(var total = 1; total <= operandoPos.length; total++){
paraResolver.push(value.slice(operandoPos[total] + 1, operandoPos[total + 1]));
}
document.calculator.ans.value = '';
for(var total = 0; total <= paraResolver.length - 2; total++){
if(paraResolver[total].includes('!')){
document.calculator.ans.value += "factorial(" + paraResolver[total] + ")";
}else{
document.calculator.ans.value += paraResolver[total];
}
document.calculator.ans.value += operandoInPos[total + 1];
}
}
document.calculator.ans.value is the name of the string where i have the expression.
operandoPos is the position on the string where a symbol is at.
operandoInPos is the symbol (I maybe could have used value.charAt(operandoPos) for that too).
paraResolver is the number that I will be solving (like 3).
factorial( is the name of my function responsible for making the number factorial.
the function doesn't have a return because I still want to solve inside the document.calculator.ans.value.
to resolve the equation I'm using document.calculator.ans.value = Function('"use strict"; return '+ document.calculator.ans.value)(); that activates when I press a button.
And yeah, that's it. I just want a function capable of knowing the difference between (2+3)! and 2+(3)! so it can return factorial(2+3) instead of (2+factorial(3)).
Thank you for your help.
Your biggest problem is going to be that order of operations says parentheses need to be evaluated first. This might mean your code has to change considerably to support whatever comes out of your parentheses parsing.
I don't think you want all of that handled for you, but an approach you can take to sorting out the parenthesis part is something like this:
function parseParentheses(input) {
let openParenCount = 0;
let myOpenParenIndex = 0;
let myEndParenIndex = 0;
const result = [];
for (let i = 0; i < input.length; i++) {
if (input[i] === '(') {
if (openParenCount === 0) {
myOpenParenIndex=i;
// checking if anything exists before this set of parentheses
if (i !== myEndParenIndex) {
result.push(input.substring(myEndParenIndex, i));
}
}
openParenCount++;
}
if (input[i] === ')') {
openParenCount--;
if (openParenCount === 0) {
myEndParenIndex=i+1;
// recurse the contents of the parentheses to search for nested ones
result.push(parseParentheses(input.substring(myOpenParenIndex+1, i)));
}
}
}
// capture anything after the last parentheses
if (input.length > myEndParenIndex) {
result.push(input.substring(myEndParenIndex, input.length));
}
return result;
}
// tests
console.log(JSON.stringify(parseParentheses('1!+20'))) // ["1!+20"]
console.log(JSON.stringify(parseParentheses('1-(2+2)!'))) // ["1-",["2+2"],"!"]
console.log(JSON.stringify(parseParentheses('(1-3)*(2+5)'))) // [["1-3"],"*",["2+5"]]
console.log(JSON.stringify(parseParentheses('1+(2-(3+4))'))) // ["1+",["2-",["3+4"]]]
this will wrap your input in an array, and essentially group anything wrapped in brackets into nested arrays.
I can further explain what's happening here, but you're not likely to want this specific code so much as the general idea of how you might approach unwrapping parenthesis.
It's worth noting, the code I've provided is barely functional and has no error handling, and will behave poorly if something like 1 - (2 + 3 or 1 - )2+3( is provided.

Replace(), replacing a value not specified

I've been learning Javascript via FCC for 6 weeks now, and decided to spend a week learning, and playing around with methods to get really close and comfortable with using them in loops, and with statements. Just playing around with strings, I was trying to replace the string "I like milk", with "I like silk". My code accomplishes this, and I understand it, but I decided to add an || operator, and the outcome bewilders me. If i say if(x[i]=== 'm' || x[i] === 'I', it doesn't replace 'I', but replaces 'm' If i leave it the way it is in my original code, it produces the string 'I lise milk', even though 'k' was never mentioned. What is going on?
let x = 'Hello I like milk';
let y = '';
for(let i = 0; i < x.length; i++) {
if(x[i] === 'm' || 'I') {
y = x.replace(x[i], 's' )
}
}
console.log(y)
ok, there are a couple of gotchas that make your code interesting
x[i] === 'm' || 'I' is always true, because 'I' is truthy - if that's not clear, you can test this with if ('I') { console.log('Merry Christmas') }
your loop produces a new string with one replacement every loop, i.e. it produces the same result as no loop and
y = x.replace(x[x.length - 1], 's')
the replace will replace the first matching character - the last character in your string is k, so the replace will change the first matching k to s
so, the result of your code is
'Hello I lise milk'
Hope that helps clear things up!
btw, the easiest way to replace all ms and Is with an s:
console.log(x.replace(/[mI]/g, 's'))
So you basically are running into an issue with the way your code is flowing.
Let's start with issue one: Why is the m being overwritten but not the y?
So basically you have var x and y that you are updating throughout your loop.
The way your code works is basically: If the letter equals m or I replace it with an s.
The problem you are going to have here however is you never store the value that has since been updated. So when it loops again it is taking the default value of x (which hasn't actually been updated) and is writing it to y. This is going to overwrite the value each time.
We can demo this by simply logging inside of the loop.
let x = 'Hello I like milk';
let y = '';
for(let i = 0; i < x.length; i++) {
if(x[i] === 'm' || x[i] === 'I') {
y = x.replace(x[i], 's' )
console.log(y)
}
}
So if you run the above, you will see two lines being outputted.
Hello s like milk
Hello I like milk
The m is the only one being printed however because the log is after the final update.
So the next issue: Why is replacing that k?
As another commented posted, "I" is always going to be truthy. Truthy basically means the value isn't null, undefined, 0 etc. "I" has a value which means it will always be true.
So is the K being replaced? Well if we run that code, the final letter being checked and replaced is a k. .replace only replaces (by default) the first instance of that letter it comes across. In your case, that K is the first K that is seen.
So to fix it, don't check on "I" check: x[i] === "I"
EDIT: To answer your question about why the last letter matters
So the last letter matters here because you have what basically equates to:
if("I"){}
So that above snippet, contrary to what you may think actually means if this has a value, which because I is a valid character, will always report true. So for your loop, everything is actually being checked, regardless of the character because I is always going to be true.
Here is an easy way to check it:
Lets say I have an array of integers from 1 to 10. I have (pseudo code):
if array value < 10 OR I
Print that value
With the way you are currently thinking, you would expect it to stop printing if the values are less than 10 right? Nope! Once again because I is always truthy and we are saying OR the value I (true) so we are going to always get a print!
Code example:
var x = [0, 1, 2, 3, 4 , 50, 60, 70, 80];
for(var i = 0; i < x.length; i++){
if(x[i] < 10 || "I") {
console.log(x[i]);
}
}
See? Everything prints out! Even though half of the values are over 10 they are still printing out. Why? Because "I" is always true! Now let's edit that a bit to make it a bit more strict in checking:
let x = [0, 1, 2, 3, 4 , 50, 60, 70, 80];
for(var i = 0; i < x.length; i++){
if(x[i] < 10 || x[i] === "I") {
console.log(x[i]);
}
}
See? Much better :)

How to find total possible values from length and characters?

I'm totally not a Math whiz kid here, but have put together a function with the great help of StackOverflow (and a lot of trial and error) that generates a random serial number from a Formula, group of Letters/Numbers, and array (so as to not duplicate values).
So, my current formula is as follows:
$.extend({
generateSerial: function(formula, chrs, checks) {
var formula = formula && formula != "" ? formula : 'XXX-XXX-XXX-XXX-XXX', // Default Formula to use, should change to what's most commonly used!
chrs = chrs && chrs != "" ? chrs : "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", // Default characters to randomize, if not defined!
len = (formula.match(/X/g) || []).length,
indices = [],
rand;
// Get all "-" char indexes
for(var i=0; i < formula.length; i++) {
if (formula[i] === "-") indices.push(i);
}
do {
rand = Array(len).join().split(',').map(function() {
return chrs.charAt(Math.floor(Math.random() * chrs.length));
}).join('');
// Rebuild string!
if (indices && indices.length > 0)
{
for(var x=0; x < indices.length; x++)
rand = rand.insert(indices[x], '-');
}
} while (checks && $.inArray(rand, checks) !== -1);
return rand;
}
});
Ok, so, what I need to be able to do is to find total possible values and make sure that it is possible to generate a unique serial number before actually doing so.
For example:
var num = $.generateSerial('XX', 'AB', new Array('AB', 'BA', 'AA', 'BB'));
This will cause the code to do an infinite loop, since there are no more possibilties here, other than the ones being excluded from the extension. So this will cause browser to crash. What I need to be able to do here is to be able to get the number of possible unique values here and if it is greater than 0, continue, otherwise, don't continue, maybe an alert for an error would be fine.
Also, keep in mind, could also do this in a loop so as to not repeat serials already generated:
var currSerials = [];
for (var x = 0; x < 5; x++)
{
var output = $.generateSerial('XXX-XXX-XXX', '0123456789', currSerials);
currSerials.push(output);
}
But the important thing here, is how to get total possible unique values from within the generateSerial function itself? We have the length, characters, and exclusions array also in here (checks). This would seem more like a math question, and I'm not expert in Math. Could use some help here.
Thanks guys :)
Here is a jsFiddle of it working nicely because there are more possible choices than 16: http://jsfiddle.net/qpw66bwb/1/
And here is a jsFiddle of the problem I am facing: Just click the "Generate Serials" button to see the problem (it continuously loops, never finishes), it wants to create 16 serials, but 16 possible choices are not even possible with 2 characters and only using A and B characters: http://jsfiddle.net/qpw66bwb/2/
I need to catch the loop here and exit out of it, if it is not able to generate a random number somehow. But how?
The number of possible serials is len * chrs.length, assuming all the characters in chrs are different. The serial contains len characters to fill in randomly, and chrs.length is the number of possible characters in each position of that.

Check for empty string is failing in js

After splitting a set of glossary terms with:
lines = text.split(/[\r\n]+/);
I then iterate through the array and parse out each term to properly format them during output. However, a simple check for empty strings has become much more of a headache than I could've ever imagined. Console logging gives me this:
...
"Pushing" "dyspnea: Labored or difficult respiration." //correct
"Pushing" ""
...
Things I have tried in order to find these empty strings:
line === ""
line.length == 0
if(line)
isNaN(line.charCodeAt(0))
typeof line == "undefined"
And various combinations of the list above. On recommendation from a coworker, I checked the line endings of the input text, but it all seemed normal.
I'm sure I'm just doing something really stupid, but the solution has eluded me for far too long. Any help/suggestions would be greatly appreciated!
Edit:
Thanks for the suggestions everyone. Alas, the problem persists...
Also, I forgot to mention, but I have tried both trimming and replacing whitespace in each line after the split, but came up with nothing.
As requested, here is more relevant code.
var text = "";
var end = /\x2E\s\x5B/gm; // ". ["
var lines = [];
var terms = [];
text = document.getElementById("terms").value;
lines = text.split(/[\r\n]+/);
parseText();
function parseText() {
var i = 0;
while(i < lines.length) {
var line = lines[i];
endIndex = lines[i].search(end);
if(line != "" || line != " " || line.length != 0 ) {
parseTerm(lines[i].substring(0, endIndex+1));
}
i++;
}
As the previous answer stated issue is probably whitespace, you can use the trim function to shorten your code:
if (line.trim() == "") {
alert("Blank");
}
maybe string is not a "", but " "?
so check not only zero length, but "white space"
if(st1 == "" || st1 == " " || st1.length == 0 ){
console.log("find empty")
}
Turns out that in my input there was a line with two spaces. I have NO idea why this was causing problems, considering the split was specifically on the pattern described above, but replacing instances of too much whitespace fixed the issue. The new line:
text.replace(/\s\s+/g, " ").split(/[\r\n]+/);

Categories