I am trying to make a hangman game and in the beginning the game asks the user for the word. Once it has the word it fills the word letters one by one in an array using a for loop. Unfortunately the last array element is always undefined for some reason.
Code(JS):
for(i=0;i<word.length;i++)
{
if(i == word.length - 1)
{
wordLettersLeft = word.length;
$("#cEText").removeAttr("style");
$(".characterEnter").removeAttr("style");
$("#gBtn").text("Lopeta");
gameStarted = true;
pcArrayLength = pcArray.length;
lives = 4;
alert("Peli alkaa! Sinulla on " + lives + " yritystä jäljellä.");
alert("Vihje: " + hint);
alert("Sinulla on vielä " + wordLettersLeft + " arvattavaa kirjainta jäljellä.");
}
else
{
pcArray.push(word[i]);
}
}
This has a very simple reason: you are not adding the last letter to your pcArray. Let's assume our word is 'bird' (because bird is a word). Your code would go through the letters b, i and r and push those to your array, so far so good. But when it hits the d, it is at position word.length-1 - because the array length starts at 1 but the index starts at 0. Your if statement prevents it from pushing the last letter to the word. There are two solutions:
First, you could simply remove the else statement:
for(i=0;i<word.length;i++){
if(i == word.length - 1){
wordLettersLeft = word.length;
$("#cEText").removeAttr("style");
$(".characterEnter").removeAttr("style");
$("#gBtn").text("Lopeta");
gameStarted = true;
pcArrayLength = pcArray.length;
lives = 4;
alert("Peli alkaa! Sinulla on " + lives + " yritystä jäljellä.");
alert("Vihje: " + hint);
alert("Sinulla on vielä " + wordLettersLeft + " arvattavaa kirjainta jäljellä.");
}
pcArray.push(word[i]);
}
That will push every letter every time! However, There is a more efficient way:
for(i=0;i<word.length;i++)
pcArray.push(word[i]);
wordLettersLeft = word.length;
$("#cEText").removeAttr("style");
$(".characterEnter").removeAttr("style");
$("#gBtn").text("Lopeta");
gameStarted = true;
pcArrayLength = pcArray.length;
lives = 4;
alert("Peli alkaa! Sinulla on " + lives + " yritystä jäljellä.");
alert("Vihje: " + hint);
alert("Sinulla on vielä " + wordLettersLeft + " arvattavaa kirjainta jäljellä.");
This way you will only execute your initial code once instead of checking the if every time. You know your loop will only run for as long as there are letters, so why even bother with the if?
As #Shilly mentions in the comments, you can forego the for loop altogether by doing this:
pcArray = word.split('');
Let's say someone's inputing the word "Test". For i === 3 which is the last iteration, you enter the if clause and you're missing out on the else clause, which is where you're doing:
pcArray.push(word[i]);
What you want is to do this anyway, regardless of whether you're in the if or the else, so you can just drop the else clause and do it anyway.
The last step of your loop does not execute pcArray.push(word[i]);. So obvioulsy, the last value is missing.
But if you want to convert a string into an array, just do this :
var pcArray = word.split('');
Related
Coding linting with JS to iterate through a text.
I have a few iterations that count a specific conditions, for example
sentences
are set to be added upon when there is '.' or '!'.
However, when I created a function that would print one string with information about number of sentences, overused words and so on, it shows up as undefined... Here's a piece of code
console.log(betterWords.length);
let counter = 0;
for (let i = 0; i < betterWords.length; i++){
if (betterWords[i] === 'really' || betterWords[i] === 'very' || betterWords[i] === 'basically'){
counter++
}
}
console.log('You used overused words ' + counter + ' times.');
let sentences = 0;
betterWords.forEach (word => {
if (word[word.length-1] === '.' || word[word.length-1] === '!'){
sentences++
}
});
console.log('There are ' + sentences + ' sentences');
numberOfWords = betterWords.length;
const printFunction = (betterWords, counter, sentences) => {
return('The number of words in text is ' + numberOfWords + ' There are ' + sentences + ' and overused words are used ' + counter + ' times.');
};
console.log(printFunction());
Output
182
You used overused words 8 times.
There are 12 sentences
The number of words in text is 182 There are undefined and overused words are used undefined times. I am mentioning sentences as one example here. One can see that numberOfWords give a proper output
As one can see once sentences return 12, the other time it's undefined.
I have a question regarding the message I'd like to display based on some values.
I have 4 categories that have some values and I need to display the message if they show high risk. The message is based on the number of risks which can be from 1 to 4 factors hence two messages where I'm using "factor IS" and "factors ARE".
My problem is I cannot make those factors bold after I add 'and' in my else statement. The beginning of the sentence is bold but not the last risk which comes after 'and'.
I'm adding 'and' before the last item of my array as I don't want comma (I found the code on: Array to Comma separated string and for last tag use the 'and' instead of comma in jquery).
Thanks for your help and suggestions!
function displayMessage() {
var getRiskFactors = calculateRisk();
var getRiskFactorsLength = getRiskFactors.length;
for (var i=0; i < getRiskFactorsLength; i++ ) {
if(getRiskFactorsLength === 1) {
var message = "Your main risk factor is your <b>" + getRiskFactors[0] + "</b>";
} else {
//this joins items from the array with comma if there's
//more than one factor.
//it also adds "AND" before the last item in the array
// instead of comma
var message = "Your main risk factors are your " + [getRiskFactors.slice(0, -1).join(", "), getRiskFactors.slice(-1)[0]].join(getRiskFactors.length < 2 ? "" : " and " + "</b>");
}
}
return message;
}
You are not starting and closing the bold tag
let getRiskFactors = [ 1,2,3,4 ];
var output = "Your main risk factors are your " + [ "<b>" + getRiskFactors.slice(0, -1).join(", "), getRiskFactors.slice(-1)[0]].join(getRiskFactors.length < 2 ? "" : "</b> and <b>") + "</b>";
document.body.innerHTML = output;
console.log(output);
You've misplaced your start <b> tag in the else clause and you are always adding a closing </b> tag after each and.
Just enclose the whole thing like this:
else {
var message = "Your main risk factors are your <b>" + [getRiskFactors.slice(0, -1).join(", "), getRiskFactors.slice(-1)[0]].join(getRiskFactors.length < 2 ? "" : " and ") + "</b>";
}
There is a balance between writing concise code and debuggable/readable code. This is a good illustration of trying to be too clever. I tried to make your code a little more readable.
In my experience I have found errors arise when using concatenation of strings and the ?: operator on the same line. Try the following code and edit as necessary.
var getRiskFactors = calculateRisk();
var getRiskFactorsLength = getRiskFactors.length;
for (var i=0; i < getRiskFactorsLength; i++ ) {
if(getRiskFactorsLength === 1) {
var message = "Your main risk factor is your <b>";
message+= getRiskFactors[0] + "</b>";
} else {
//this joins items from the array with comma if there's
//more than one factor.
//it also adds "AND" before the last item in the array
// instead of comma
var message = "Your main risk factors are your ";
var arraypart1 = getRiskFactors.slice(0, -1).join(", ");
var arraypart2 = getRiskFactors.slice(-1)[0];
var computation = getRiskFactors.length < 2 ? "" : " and ";
var joinedarray = [];
joinedarray.push(arraypart1);
joinedarray.push(arraypart2);
message += joinedarray.join(compution) + "</b>";
}
}
return message;
I wrote a script with the purpose of sequencing the Fibonacci Sequence (or any two numbers that would add to make the next, and then those two, etc.). When you press a button, the function (called fibonacci) adds the two values together, pushes the new value into an array (called sequence), and then displays the most recent value in the array. I set it up with a setInterval (called recursion), so it continues to add more values to the array, and display more numbers. I was experimenting with the function, and thought to try two strings instead of two numbers. It worked as expected, however it slowed down significantly, crashing the browser within the span of five seconds. I was wondering what the difference would be, performance-wise, between numbers and strings.
My jsfiddle is here: https://jsfiddle.net/MCBlastoise/yrr7fL4z/54/
And here is my code:
var sequence = [0, 1];
var i = 2;
function recursion() {
recur = setInterval(fibonacci, 1);
}
function fibonacci() {
var current = document.getElementById("text");
var a = sequence[i-2] + sequence[i-1];
sequence.push(a);
if (current.innerHTML === "") {
current.innerHTML = sequence[0] + ", " + sequence[1] + ", " + sequence[2];
}
else {
current.innerHTML = current.innerHTML + ", " + sequence[i];
}
i++;
};
function exactValue(position) {
var current = document.getElementById("text");
if (isNaN(position) === false && position % 1 === 0 && position >= 1) {
if (position === 1) {
current.innerHTML = sequence[0];
}
else if (position === 2) {
current.innerHTML = sequence[1];
}
else {
while (i !== position) {
var a = sequence[i-2] + sequence[i-1];
sequence.push(a);
i++;
}
if (i === position) {
current.innerHTML = "The value at position " + position + " is " + a + ".";
}
}
}
}
function checkValue(value) {
var current = document.getElementById("text");
if (isNaN(value) === false) {
if (value === 0) {
current.innerHTML = "The value provided appears at position " + 1 + ".";
}
else if (value === 1) {
current.innerHTML = "The value provided appears at position " + 2 + ".";
}
else {
while(a !== value && a !== Infinity) {
var a = sequence[i-2] + sequence[i-1];
sequence.push(a);
i++;
}
if (a === value) {
current.innerHTML = "The value provided appears at position " + i + ".";
return true;
}
if (a === Infinity) {
current.innerHTML = "The value provided does not appear in this sequence.";
return false;
}
}
}
}
function clear() {
document.getElementById("text").innerHTML = "";
}
<div onclick="recursion(), clear()" style="cursor:pointer; background-color:black; width:30px; height:30px"></div>
<p id="text"></p>
When you change the elements of the sequence array to be strings, the + operator in the following line will perform a completely different operation:
var a = sequence[i-2] + sequence[i-1];
Instead of an arithmetic addition, this will be a string concatenation operation. This will involve a lot more memory and CPU time:
Addition of two numbers:
Time: constant, since an addition is performed as a CPU instruction, limited to the 64-bit float range.
Memory: one 64-bit float, since that is how numbers are represented in JavaScript.
Concatenation of two strings:
Time: linear in terms of the length of the input strings: each character from both strings needs to be copied to a new memory location
Memory: doubles, as the final string occupies the same memory as the two input strings together
The memory impact will probably be the factor that kills the script: after only 20 iterations (i.e. calls to fibonacci) the string value of a will have a length of over 10 000 characters, which will continue to almost double each next iteration. After 30 iterations, a will have more than a million characters. If you have enough patience to wait for the string copying of those megabytes to grow to gigabytes you'll find your PC's memory (the part available to the JavaScript box) has been eaten completely, probably before the 40th iteration.
Well, loading numbers into memory and adding them can usually be compiled to just a few native CPU instructions, while concatenating Strings usually includes a lot of function calls through the whole language to produce a result. And I'm not sure how JavaScript handles strings internally, but growing a string could mean allocating a whole new byte array for each one.
I am new to javascript and am having an issue with displaying the guessed letters in my Hangman game. When the user clicks on the "guess" button, the checkinput() method should start, and this should run:
//loop through word and if guess equals the character of the inputted work, replace - with letter.
for (i = 0; i < input.length; i++) {
//if user's guess is matched against one of the letters of the word, this will execute.
if (guess == input.substring(i, i + 1)) {
placeholder = placeholder.substring(0, i) + guess + placeholder.substring(i + 1, placeholder.length);
spguess.innerHTML = placeholder;
//if guessed letter is wrong, push into wrongg array
} else if (guess != input.substring(i, i + 1)){
wrongg.push(guess);
console.log(wrongg);
}
}
}
The else if part is where I am having issues. I would like to be able to console.log the guessed letters(incorrect letters that don't match the inputted word). Could you point me in the right direction? https://jsfiddle.net/gdbn47or/ is the jsfiddle
You're having problems i think because you have your wrongg.push inside the cycle, so even when the guess is right for the forth letter, it will still enter the wrongg array 3 or even more times, what you should do is for each cycle you should have a boolean (found), then change your if to:
if (guess == input.substring(i, i + 1)) {
placeholder = placeholder.substring(0, i) + guess + placeholder.substring(i + 1, placeholder.length);
spguess.innerHTML = placeholder;
found = true;
}
Then only do the else if part after the for cycle if the found boolean is false
I am trying to convert a string to words, and then print these using javascript and html5 canvas. The string can be any length, but I am using 50 as a max value of words (separated by a space). Right now I have the following to create the array:
var wordArray = kstring.split(" ", 50);
for(var k = 0; k < wordArray.length; k++)
{
if(typeof wordArray[k] == 'undefined')
wordArray[k] = " .";
}
and then print using:
ctx.fillText(wordArray[0] + " " + wordArray[1] + " " + wordArray[2] + " " + wordArray[3] + " " + wordArray[4], leftOffset, txtHeight);
ctx.fillText(wordArray[5] + " " + wordArray[6] + " " + wordArray[7] + " " + wordArray[8] + " " + wordArray[9], leftOffset, txtHeight+20);
etc.
However, when the text prints, any undefined values print as "undefined" instead of " ." It seems that I am going about checking for the undefined value the wrong way, but I'm not sure what else to try.
Additionally, if anyone has any better suggestions for how to achieve this goal (convert a string to words and then print 5 words at a time). Please feel free to suggest some better options.
Thanks
There won't be any undefined values in the array returned by .split(). You're getting undefined because your print code has hardcoded indexes higher than the highest index in the array.
Sorry, I don't have time right now to test this, or explain it beyond mentioning that .slice() creates a new array extracting a range from the source array, and .join() is (obviously) the opposite of .split(), but maybe you could try something like this:
var wordArray = kstring.split(" ", 50),
i, h, l
wordsPerLine = 5,
lineHeight = 20;
for (i=0, h=0, l=wordArray.length; i < l; i+=wordsPerLine, h+=lineHeight) {
ctx.fillText( wordArray.slice(i, Math.min(l, i+wordsPerLine)).join(" "),
leftOffset, txtHeight + h);
}