Replace content at multiple indexes in an array Javascript - javascript

I'm trying to make a Hangman game with Javascript, where the user enters a word for another person to guess. The word is sent to a function (makeUnderlines) and is made into an array of underlines and returned to the player with a prompt to enter a letter that they want to guess. The letter and the word is sent to a function that finds the positions of the letters (getPosition) in the word and sends the positions to another function. The function (insertLetters) is supposed replace the underlines with the letter at the positions given. All of this works except that the function doesn't replace anything in the array. It only replaces the first letter if it only occurs once in the word. Any advice to solving this would be greatly appreciated. I would also like to know if there is a way to prevent the user to entering a number in a word or as a guess.
<!DOCTYPE HTML>
<HTML>
<HEAD>
<META CHARSET="UTF-8">
<TITLE>Hangman</TITLE>
</HEAD>
<BODY>
<SCRIPT TYPE="text/javascript">
function makeUnderlines(word) {
for(i = 0; i < word.length; i++){
underlines.push("\"_\"");
}
return underlines;
}
function getPositions(word, letter) {
for(var i=0; i< word.length;i++) {
if (word[i] === letter) positions.push(i);
}
insertLetters(underlines, positions, letter)
}
function insertLetters(underlines, positions, bokstav){
underlines[positions] = letter;
return underlines;
}
let word = prompt("Choose a word for the player!");
underlines = [];
positions = [];
makeUnderlines(word);
for(i = 7; i > 0; i--){
letter = prompt("["+underlines+"]\n Guess a letter. You have " + i + " guesses left");
getPositions(word, letter);
}
</SCRIPT>
</BODY>
</HTML>

One way to start digging into this is by tracing the flow of the application with a debugger. Chrome Dev Tools has a debugger that lets you step line by line to see what the current values of your variables are.
function insertLetters(underlines, positions, bokstav){
underlines[positions] = letter;
return underlines;
}
From looking at insertLetters, positions should be an array of integer index values but it is being directly used as an integer. Maybe try iterating through the values in positions and using those to index underlines.
function insertLetters(underlines, positions, letter){
for (let i = 0; i < positions.length; i++) {
const pos = positions[i];
underlines[pos] = letter;
}
}
And I think the last thing you could do in getPositions is to clear out the positions array with positions = [];.
Overall your code looks quite functional. Take care to try and pass variables to functions directly instead of relying on global variables.

Related

Cannot understand the effect of changing variable positions in for loop

I am fairly new to coding and I am currently learning Javascript. I had this one problem while taking introductory course on CodeCademy.
My line of code looks something like this:
var text = "fewij 9wieopfjerogjerpjf pweijgroireois joerjgoano hnopahf[gjhr0fgjharobihroephg h8h 8pgh8aphvp oehar9tgh034jh f0sheg9h34up hvszoph f9puwahothoishgp34h98p h40thwoipnoi Roman e0jf0erhjg0pehr08gh038htg0a8whje08h430q8ghgv0ejr0v8g34jh098rtju209ghj98dhb98h 8948he088h sdhg9u nu3iqn 9ahs89h";
var myName = "Roman";
var hits = [];
for (i = 0; i < text.length; i++) {
if (text[i] === "R") {
for (i = a; a < (i + myName.length); a++) {
hits.push(text[a]);
}
}
}
if (hits === 0) {
console.log("Your name was not found.");
} else {
console.log(hits);
}
Basically the program is designed to search my name from the jumble of text and then printing out my name in individual letters in form of an array. Like so ['R', 'o', 'm', 'a', 'n']. However, I could not understand why changing the position of variables "a" and "i" in second for loop produces very different results.
If I typed the second for loop like so:
for(a = i; a < (i+myName.length); a++){
hits.push(text[a]);
}
it would yield an array that would not contain the letters from my name. On each run it would put together a random sequence of letters from var text.
Why defining a starting point for second for loop in another order makes the program behave in such different way? Shouldn't it follow the basic mathematical logic like:
i=30; //suppose first letter of my name in var text appears to have this array index
i=a; //now I define a new variable
a=30; //so the new variable should have the same array index as variable i
I cannot wrap my mind around it.
An assignment has a direction -- the value on the right is put into the variable on the left. So
i = a
means take the value of the variable a, and put it into the variable i.
In your code, the variable a was never given a value before the second loop, so i = a gets an error.
Changing it to
a = i
makes it work because i was given a value in the first loop, and this copies that value to the a variable.

Javascript: Page keeps crashing when attempting to load the file?

EDIT: CSS
Javascript
My code is by no means demanding so I'm not sure why this is happening.
It doesn't seem to work on JSFiddle either. Every time I try to load it on the website I get a 404 error.
This only happened after I made a small change in my code:
function runDisplay(data, id) {
var reader = document.getElementById(id);
var index = 0;
if (timer) {
clearInterval(timer);
}
if (data.length) {
timer = setInterval(function() {
reader.innerHTML = data[index++];
var punctuation = [".", ",", ":", ";", "!", "?"];
var word = data[index++];
for (var j = 0; j < punctuation.length; j++) {
if (!(word.indexOf(punctuation[j]) === -1)) {
word = string.replace(punctuation[j], '');
}
index = index % data.length;
}, getTextSpeed()); // change speed dynamically in real time
}
}
function getTextSpeed() {
var speeds = document.getElementById("speed");
return speeds.options[speed.selectedIndex].value;
}
I changed a textSpeed variable to a direct call to the method getTextSpeed in an attempt to get the speed of the text to change dynamically.
Essentially what this class is supposed to display text word-by-word, with font-size and the speed (which must be implemented with setInterval() and clearInterval()) by which the words are displayed being changeable by the user of the webpage.
If a word contains punctuation, then it is removed and the delay between that word and the next is doubled (234 ms instead of 117 ms). If there is more than one character of punctuation (ex: ...) then only one character of punctuation is removed.
Can you help me figure out what's causing this? Is it an error in my implementation? Did I accidentally create an infinite loop somewhere?

JavaScript .join is not working

Here is my code:
board = [];
var rowsNum = 5;
var colsNum = 5;
function printBoard(board) {
for (row in board) {
document.write(" ").join(row);
}
}
function clearAndRestartBoard() {
board = [];
for (i = 0; i < rowsNum; i++) {
board.push("[ ]" * colsNum);
}
}
printBoard(board);
It does not throw an error, but it does not show up in my webpage. Do you know what I am doing wrong?
Just in case, here is the html without the css:
<!DOCTYPE html>
<html>
<head>
<link href="test.css" type="text/css"rel="stylesheet" />
<title> Test! </title>
</head>
<body>
<p id = "script"> <script src = "test.js"> </script> </p>
</body>
</html>
I am very new to JS so thank you so much for any help!
There are several issues there, but the main one is that you never call clearAndRestartBoard, and so board is empty, and so you never output anything.
Here's a list of all of the issues that I see off-the-cuff:
You never call clearAndRestartBoard.
Your code is falling prey to The Horror of Implicit Globals: Declare your variables.
You're using for-in to loop through an array. That's usually not a good idea, though there can be use cases for it; this answer outlines your various options for looping through an array.
"[ ]" * colsNum is NaN because * will convert both of its operands to numbers and then do mathematical multiplication. The string "[ ]" converts to NaN because it cannot be interpreted as a number, and then anything multiplied by NaN is NaN. It isn't colsNum blank arrays. To do that, you'd have to have a second loop creating the row arrays, pushing "[ ]" into them, and pushing those row arrays onto board.
You're using document.write. While that will work for simple experiments, it's not something you want to use in general.
You're calling join on the result of document.write, which I'm fairly certain isn't an array.
I would also suggest that you either use a global board, or always pass it as an argument, but not mix-and-match where one function uses the global and the other uses an argument.
You never output a line break between rows.
Here's a minimal update addressing those:
var board;
var rowsNum = 5;
var colsNum = 5;
function printBoard(board) {
board.forEach(function(row) {
document.write(row.join(""));
document.write("<br>");
});
}
function clearAndRestartBoard() {
var row;
board = [];
for (var r = 0; r < rowsNum; r++) {
row = [];
for (var c = 0; c < colsNum; c++) {
row.push("[ ]"); // If you really wanted the string [ ]
}
board.push(row);
}
}
clearAndRestartBoard();
printBoard(board);

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

Can anyone see what is wrong with my Javascript?

I have written the following:
var pages=["[www.google.co.uk] This is the WWW. ","[www.yahoo.co.uk] This is also the WWW. "];
function findScoresC(s){
var scores=[];
var words=[];
var wordScore;
var indexScore=[];
s=s.toLowerCase();
for(i=0;i<pages.length; i++){
var lowerCaseContents=(pages[i].substring(pages[i].indexOf("]")+1,pages[i].lastIndexOf(" "))).toLowerCase();
words=lowerCaseContents.split(" ");
for(i=0;i<words.length;i++){
if(words[i].match(s)){
wordScore=1;
indexScore[i]=indexScore[i]+1};
scores[i] =indexScore[i]}};
return scores;
}
alert(findScoresC("w"));
The function aims to return an array ("scores") where each index of the array is the number of times the string s is found in each index of the "pages" array, excluding what is inside the square brackets - however, only finding the string s once within each word. So ideally, the first index of scores would be 1, because I have called the function with the letter w, and i would only like it to find the first w of "WWW" in the first index of pages - if this makes sense.
I have confused myself pretty epically in getting this far, so I have no idea why the function is returning ",,,," rather than numerical values for each index of scores - any ideas?
Thanks
When your for loop exits, i is equal to words.length, which is one greater than the last index of indexScore. You are assigning nothing at all to scores[i] each time through.
It might be because you have a nested for loop with the same index variable.
var pages=["[www.google.co.uk] This is the WWW. ","[www.yahoo.co.uk] This is also the WWW. ";
function findScoresC(s){
var scores=[];
var words=[];
s=s.toLowerCase();
for(i=0;i<pages.length; i++)
{
scores[i]=0;
var lowerCaseContents=(pages[i].substring(pages[i].indexOf("]")+1,pages[i].lastIndexOf(" "))).toLowerCase();
words=lowerCaseContents.split(" ");
for(j=0;j<words.length;j++)
{
if(words[j].match(s))
{
scores[i] += 1;
}
}
}
return scores;
}
alert(findScoresC("w"));
There were a few things. I replaced "i" with "j" for the inner index. You don't require a semicolon after a closing paren. You should have a semicolon after instructions (a couple were missing).
Probably the main issue (after the "i" issue) was that scores[i] should have been set outside the inner loop. This would have been clearer if the cosing parens had been separated out onto separate lines, instead of like "scores[i] =indexScore[i]}};".
It turned out that the variable indexScore was not required. That allowed me to bring scores[i] inside the inner loop to accumulate word hits directly.
Finally, I would prefer to communicate the pages variable to the function as an argument than to assume that it is available in the global space. I tend to avoid globals if I can.
var pages = [...];
function findScoresC(pages, s)
{
...
}
alert(findScoresC(pages, "w"));
Here's you're function fixed. It returns [1,1] which appears to be what you were going for. My notes are in the code.
var pages=["[www.google.co.uk] This is the WWW. ","[www.yahoo.co.uk] This is also the WWW. "];
function findScoresC(s){
var scores = [],
words = [],
wordScore;
// indexScore = [] <- this doesn't seem necessary
s = s.toLowerCase();
// Make sure to use `var i` and not just `i`; otherwise, you are creating a global variable.
for ( var i=0; i<pages.length; i++ ) {
// Initialize me!
scores.push(0);
var lowerCaseContents = pages[i].substring(
pages[i].indexOf("]") + 1, pages[i].lastIndexOf(" ")
).toLowerCase();
words = lowerCaseContents.split(" ");
// You were using `i` for this loop as well. No can do.
for ( var j=0; j<words.length; j++) {
if ( words[j].match(s) ) {
// wordScore = 1; <- I don't know what you're using this for
scores[i]++;
}
}
};
return scores;
}
console.log(findScoresC("w"));
here's a small function that counts how many times substring "subStr" occurs in "str", not counting [...]
function substrCount(str, subStr) {
var str = str.replace(/\[.+?\]/g, "");
var del = str.toLowerCase().split(subStr.toLowerCase()).join("");
return (str.length - del.length) / subStr.length;
}
the rest is obvious ;)
// edit: this is how you apply this function to an array
var someArray = ["whatever", "something", "else" ];
var counter = [];
for(var i = 0; i < someArray; i++)
counter[i] = substrCount(someArray[i], "something");
// or, to count only one match, i.e. just to test if a substring is present
counter[i] = substrCount(someArray[i], "something") > 0;

Categories

Resources