0

I’m creating a Hangman game using jQuery. I seem to be having trouble with repeating letters while using indexOf. When I pick a correct letter it only fills in the first slot and won’t fill in the second, even if you click the same letter twice.

Example:

Name: “bob”
Typed character: “b”
Outcome: “b__”
Expected outcome: “b_b”

I tried to convert this over to using a loop, but it become an endless loop.

// Band Names array
var bandNames = ["AJJ", "Bob Dylan", "The Front Bottoms", "The Hotelier"];

var correctLetters = [];
var placeHolder = [];

// creates a random number between 1 and the length of the band array.
var randomNumber = Math.floor(Math.random() * bandNames.length);

// picks a random band based of the length of the randomband array
var selectedBand = bandNames[randomNumber];

// add place holder based on length of band name
for (i = 0; i < selectedBand.length; i++) {
    placeHolder.push("<li></li>");
}

$(document).keypress(function(e) {
  var letterClicked = String.fromCharCode(e.which);

  if (selectedBand.indexOf(letterClicked) > -1) {
    // adds correct letter to the array
    correctLetters.push(letterClicked);

    placeHolder[selectedBand.indexOf(letterClicked)] = letterClicked;
    //  combines the array
    var joinArray = placeHolder.join("");

    // appand 
    $('#current-container').html("").append(joinArray);

    if (joinArray == selectedBand) {
      alert("you win");
      location.reload();
    }
  }
});

How can I find all the characters?

cod3rShea
  • 15
  • 3
  • `indexOf` can have second argument, the `start` index (default is 0), so you can make for ex `let I=str.indexOf(char); while(I!=-1) {... I = str.indexOf(char, I+1) }` something like this – Dominik Matis Aug 25 '19 at 21:18
  • 1
    May I recommend the code in [this answer to the question "How to find indices of all occurrences of one string in another in JavaScript"](https://stackoverflow.com/a/3410557/2694511)? – Spencer D Aug 25 '19 at 21:21
  • @SebastianSimon placeHolder creates an empty place holder, so you know how many letters are in the band name. The code has been updated to reflect it – cod3rShea Aug 25 '19 at 21:43

3 Answers3

0

So here's the thing about String#indexOf(), it returns after the first index found. What you can do instead is to use a Array#forEach() to iterate over the entire string instead of just to the first match. By passing a function that interacts with the value and the index you can use a loop per letter to decide when to update the DOM.

Example usage: Prints out each letter at each index

const letters = 'ababab';

letters
  .split('') // convert to array
  forEach((letter, index) => {
    console.log("letter %s at index %i", letter, index);
  });

Robert Mennell
  • 1,954
  • 11
  • 24
0

indexOf will only return the first index found. What you could instead do is use map to map your placeHolder value to the selectedBand and replace all the values which match the key pressed.

Here is a working example.

var bandNames = ["AJJ", "Bob Dylan", "The Front Bottoms", "The Hotelier"];
var randomNumber = Math.floor(Math.random() * bandNames.length);
var selectedBand = bandNames[randomNumber];

var correctLetters = [];
var placeHolder = [];

for (i = 0; i < selectedBand.length; i++) {
  selectedBand[i] === " " ? placeHolder.push(" ") : placeHolder.push("_");
}

$('#current-container').html(placeHolder);

$(document).keypress(function(e) {
  var letterClicked = String.fromCharCode(e.which);

  selectedBand.split("").map((letter, index) => {
    if (letter.toLowerCase() === letterClicked) {
      placeHolder[index] = selectedBand[index];
    }
  });

  $('#current-container').html(placeHolder);

  if (placeHolder.join("") == selectedBand) {
    setTimeout(() => {
      alert("you win");
    });
    location.reload();
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="current-container">
</div>

Note: I have used setTimeout to display the alert because otherwise the alert displays before the last letter clicked before winning the game is displayed on the screen.

nash11
  • 8,220
  • 3
  • 19
  • 55
0

you can use a map function and get all indexes for each letter that user enter. example:

const getIndexes = (letter, bandName) => bandName.split("").map((currentValue, index) => currentValue.toUpperCase() === letter.toUpperCase() ? index : undefined).filter(x => x !== undefined);
  
const indexes = getIndexes("e", "Green Day");
console.log("indexes", indexes);  
rcoro
  • 326
  • 6
  • 12