dynamic closure functions for a game in javascript - javascript

Im working on a simple html/javascript multiplication game, in which I have a multiplication table with some inputs that represet the results of the products. in that game, you need to answer as fast as you can on as many questions as you can. to make it easy on the players, ive assign an event to the enter key to move to the next input when it is pressed.
Here is the javascript code for highlighting the rows and the enter key event:
for (var i=0; i<boardInputArray.length; i++) {
boardInputArray[i].onkeydown = (function(nextBox) {
return function(e) {
if(e.keyCode == 13) {
if(nextBox==boardInputArray.length) {boardInputArray[0].focus();boardInputArray[0].select();}
else {boardInputArray[nextBox].focus();boardInputArray[nextBox].select();}
var gameCompleted = true;
for(var c=0;c<boardInputArray.length;c++) {
if(boardInputArray[c].value == '') {gameCompleted = false;}
}
if(gameCompleted) validateGame();
}
}
})(i+1);
}
I dont want to post the entire code here, because it is very long. If you would like to see the game in action, go to:
http://www.webdesk.co.il/articles/javascript/multiplication-table-game.php
Here's the problem: I would like that each time the Enter key is pressed, it will check if the following input is empty or not. in case its not empty - skip to the next one and so on until it finds an empty input. That way, the player can go back to the question he didnt answer and not go through all the ones he did answer. makes sense?

You can probably improve this code, but it does take care of moving to the next empty box.
for (var i=0; i<boardInputArray.length; i++) {
boardInputArray[i].onkeydown = (function(currentBox) {
return function(e) {
if(e.keyCode == 13) {
var gameCompleted = true;
if(boardInputArray[currentBox].value == '')
gameCompleted = false;
for (
var c = (currentBox + 1) % boardInputArray.length;
c != currentBox;
c = (c + 1) % boardInputArray.length
)
{
if(boardInputArray[c].value == '')
{
gameCompleted = false;
boardInputArray[c].focus();
boardInputArray[c].select();
break;
}
}
if(gameCompleted) validateGame();
}
}
})(i);
}
Notes:
I've made the anonymous function a function of currentBox instead of nextBox (i instead of i + 1).
The loop goes through all the boxes except the current box, by starting at the next box, wrapping around and ending at the previous box or when it encounters a blank box.

Related

Creating Simple Hangman Game in js and Can't get if statement read correctly

In the code below, I can not get the code to execute if the players guess of a letter is not in the secret word chosen. I have it set so when the submit button is hit, we first check to see if the letter guessed is in the puzzle word, if it is the letter is turned over, then I am trying to say if it is not in the word take a life away from the player. I've tried several ways but can not get the program to read the second if statement correctly.
submit.addEventListener('click', function(){
console.log("clicked");
usedLetters.innerHTML += playersLetter.value + ' '
for(i=0; i<checkWord.length; i++){
console.log(wordLife)
if(playersLetter.value == (checkWord[i])){
console.log('in if#1')
console.log(playersLetter.value)
var answerLetter = document.getElementsByClassName('letter')[i]
answerLetter.innerHTML = playersLetter.value
wordLife--
}
}
function scoreLetter(value){// To check if the letter is actually in the word
for(let i = 0; i < checkWord.length; i++){
if(value == (checkWord[i])){
return true
}else {
return false
}
}
}
console.log('read function')
if(scoreLetter(playersLetter.value) == false){
console.log('in 2nd if')
playerLife--
console.log(playerLife)
}
})
Your scoreLetter function is wrong, you are only checking the first letter and returning false if the value in not in the first position.
Try this ... to check if the letter is in the array
function scoreLetter(value){
return (checkWord.indexOf(value) === -1) ? false : true;
}

Simple arithmetic challenge function with limited attempts

Recently began studying Javascript, trying to read out of Javascript: The Definitive Guide and Eloquent Javascript, while going off on my own to experiment with things in order to really etch them in my memory. I thought a good way to get my head around arithmetic operations and conditional statements, I'd build a series of little games based around each Math operator, and began with addition.
function beginAdditionChallenge() {
var x = Math.ceiling(Math.random()*100);
alert(x);
for (var i = 0; i < 3; i++) {
var a = Number(prompt("Provide the first addend.", ""));
var b = Number(prompt("Provide the second addend.", ""));
if (a + b === x) {
alert("Well done!");
break;
}
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
else {
alert("Fail.");
}
}
}
function initChallenge() {
var button = document.getElementById("challengeButton");
button.addEventListener("click", beginAdditionChallenge);
}
window.addEventListener("load", initChallenge);
You can see the whole thing thus far on JSFiddle, here. The idea is that clicking the button generates a random number between 1 and 100, displays it to the user, then prompts them to provide two addends, giving them 3 attempts. If the sum of these addends is equal to the RNG number, it congratulates the user and ends the program. If they do not provide suitable addends, the loop prompts them to try again, until they've hit 3 attempts, at which point the program snarks at them and ends.
I know the event listener is not the failure point here, as when I change beginAdditionChallenge to simply display a test alert, it works, but I don't know what exactly is wrong with the loop I've created.
You did it correctly. However, Math.ceiling isn't a function and should be Math.ceil. In addition, your code (in jsfiddle) should be set to wrap in head. Why? Because right now you call initChallenge when the page loads. However, in your jsfiddle example, the code runs onLoad so the load event never gets called. Essentially, you're adding a load event after the page has loaded.
http://jsfiddle.net/rNn32/
Edit: In addition, you have a for loop that goes up to three. Therefore
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
should be
else if (a + b !== x && i < 2) {
alert("Please try again.");
}
because when i === 2, the user's last chance has ended.
Everything is fine. Just change:-
var x = Math.ceiling(Math.random()*100);
to:-
var x = Math.ceil(Math.random()*100);

JavaScript Battleship Array splice

I'm making a battleship game in JavaScript and I stumbled upon a problem
var targetString = target.replace(/\s+/g, '');
for(var i = 0; i !== inputArray.length; i++) {
for(var j = 0; j !== boats[i].usedPositions.length; j++) {
if(targetString === boats[i].usedPositions[j].toString()) {
hit = true;
boats[i].hits[j] = 1;
console.log(boats[i].hits);
currentBoat = boats[i];
boats[i].usedPositions.splice(j,1);
break;
}
}
}
if(hit && stop == false) {
alert ("Hit!");
if(allEquals(currentBoat.hits, 1) && hit) {
alert("Boat with length " + currentBoat.hits.length + " has sunken!");
sunkenBoat++;
}
}
The first piece of code checks if the entered coordinate matches a coordinate of the boats (all of these are stored in usedPositions). To prevent that the player can hit that boat again, I want to take the hit coordiante out of that array using splice. But when I do this, it doesn't alert me when a boat has sunken (second piece of code). When the line with splice in is removed, it does give the alert. Can anyone help me? Full code is found here.
splice moves the subsequent array elements down to fill the space. Your logic doesn't look like it's expecting things to move like that.
Instead of splice, you probably just want to assign some other value to that array location, e.g.:
boats[i].usedPositions[j] = " "; // Where " " is assumed not to represent a boat

Seeing if input matches array if not alert

var tagAllowed = true;
var allowedTags =["Person","People","Dance","Word"];
if(tagAllowed === true) {
for(var i=0;i<allowedTags.length;i++){
var aTags = allowedTags[i];
if(input.val().toLowerCase() === aTags.toLowerCase()) {
tagged.append('<span unselectable="on" class="tagged '+colorize+'" title="Click To Delete">'+inputVal.trim()+'</span>');
tagSize = $('.tagged').length;
var ele = $('.tagged').last(),
subtract = parseInt(ele.outerWidth(true),10);
input.width(input.width() - subtract);
tagged.width(tagged.width() + subtract);
input.css('marginLeft','5px');
input.val("");
input.css('color','#000');
} else {
errorMess.children('span').remove();
errorMess.prepend('<span>'+errorProcess+'<span>');
errorMess.slideDown();
}
}
The following code works in a way, if the input.val() does not match it will show the custom alert errorMess and well even if the word matches it still shows the custom alert. I am wondering if maybe I am doing something wrong in my conditional. As I don't need the custom alert to appear if the words match.
If any suggestions please post. I know this isn't the best example with just a code, but I hope all of you get what I am trying to say. I just don't want the custom alert to appear if the two words match together.
You have the if-statement inside the for-loop. The input value will never equal more than one of the tags in the array. You could use a for-loop to set a boolean. Then the if-statement could follow the for-loop.
boolean isAllowedTag = false;
for(var i=0;i<allowedTags.length;i++){
var aTags = allowedTags[i];
if(input.val().toLowerCase() === aTags.toLowerCase()) {
isAllowedTag = true;
break;
}
}
if (isAllowedTag) {
// ...
} else {
errorMess.children('span').remove();
errorMess.prepend('<span>'+errorProcess+'<span>');
errorMess.slideDown();
}
}
add a break; after your input.css('color, '#000'); line. also, you should really change those last 3 lines to: input.val("").css({marginLeft:'5px', color:'#000'});. Making calls to .css() is slow, so it's better to do as much as you can in one call.

Autocorrection acts weird on duplicated fields

I have a form that users can duplicate, so they can submit multiple forms in one times. This works fine. However, i noticed that users don't use it the right way. For example, i ask for initials and people fill out their front name. PHP checks all fields and auto-corrects them if necessary, but this turns John into J.O.H.N.
Anyway a good way would be to autocorrectfields. This works on the initial form, but goes wrong on the duplicated forms. Especially initials acts weird. My knowledge of jQuery and Javascript is very limited, so after puzzling for weeks i still don't know how to solve it. Suggestions are welcome.
Fiddle: http://jsfiddle.net/QUxyy/15/
JS
// Lowercase
$(".lowercase").keyup(function(e)
{
$(".lowercase").val(($(".lowercase").val()).toLowerCase());
if (/[a-z]/g.test(this.value))
{
this.value = this.value.replace(/[^a-z ]/g, '');
}
});
// Initials
$(".initials").focus(function() {
var current = $(".initials").val();
$(".initials").keyup(function(e) {
var key = String.fromCharCode(e.keyCode);
if (key >= 'A' && key <= 'Z') {
current += key + ".";
this.value = current;
}
else {
current = "";
}
});
$(".initials").blur(function() {
var i = $(".initials").val();
var last = i[i.length - 1];
if (last != "." && i.length !== 0){
this.value += ".";
}
});
});
// Capitalize
$(".cap").keyup(function(e)
{
function convertToUpper() {
return arguments[0].toUpperCase();
}
val = this.value.toLowerCase().replace(/\b[a-z]/g, convertToUpper);
this.value = val;
});
Click for full code and preview
In your callback event handlers function for .voorletters use 'this', e.g:
SEE DEMO
$(document).on("keydown", ".voorletters", function(e) {
var i = $(this).val();
if (e.keyCode == 8 && i.charAt(i.length - 1) == ".") {
$(this).val(i.slice(0, -1));
current = $(this).val();
}
})
And you should do it for all your call back function as .initials, .lowercase, etc...

Categories

Resources