Skip to content

Conversation

@sean-b765
Copy link

My code is commented so hopefully you can understand it, I wanted to contribute as I recently had this issue in my own rendition of a wordle clone

Addresses this issue: #10

After my changes:
fix

@sean-b765
Copy link
Author

My formatter must have caused the massive diff.
heres the code I changed

function submitGuess() {
	const activeTiles = [...getActiveTiles()]
	if (activeTiles.length !== WORD_LENGTH) {
		showAlert('Not enough letters')
		shakeTiles(activeTiles)
		return
	}

	const guess = activeTiles.reduce((word, tile) => {
		return word + tile.dataset.letter
	}, '')

	if (!dictionary.includes(guess)) {
		showAlert('Not in word list')
		shakeTiles(activeTiles)
		return
	}

	stopInteraction()

	// My algorithm for determining classname of the letter
	let matchingChars = ''
	const classDictionary = { 1: '', 2: '', 3: '', 4: '', 5: '' }

	for (let i = 0; i < targetWord.length; i++) {
		const letter = guess[i]

		console.log(matchingChars)

		const rgx = new RegExp(`${letter}`, 'g')
		// Need to know the total appearances of the letter in the word
		const totalAppearances = (targetWord.match(rgx) || []).length
		// Also need to know all prior appearances of the letter in the word,
		//  so we don't mistakenly tell the user that a duplicate letter exists
		const priorAppearances = (matchingChars.match(rgx) || []).length

		// Letter not in word
		if (!targetWord.includes(letter)) {
			classDictionary[i + 1] = 'wrong'
			continue
		}

		// The letter is correct
		if (targetWord[i] === guess[i]) {
			classDictionary[i + 1] = 'correct'

			matchingChars = matchingChars + letter
			continue
		}

		// The letter is included in the word somewhere...

		// Look ahead... If there is a correct appearance further in the word, we need to know
		let futureCorrectAppearances = 0
		for (let j = i; j < targetWord.length; j++) {
			if (targetWord[j] === guess[j] && targetWord[j] === letter)
				futureCorrectAppearances++
		}

		console.log(
			`There are already ${futureCorrectAppearances} correct ahead of [${i}]: "${letter}"`
		)
		console.log(
			`There are already ${priorAppearances} which come before [${i}]: "${letter}"`
		)

		console.log(futureCorrectAppearances, priorAppearances, totalAppearances)

		// If there are already too many future / prior / future+prior appearances,
		//  there can not be another instance of this letter, so we must continue
		if (futureCorrectAppearances >= totalAppearances) {
			classDictionary[i + 1] = 'wrong'
			continue
		}
		if (priorAppearances >= totalAppearances) {
			classDictionary[i + 1] = 'wrong'
			continue
		}
		if (priorAppearances + futureCorrectAppearances >= totalAppearances) {
			classDictionary[i + 1] = 'wrong'
			continue
		}

		classDictionary[i + 1] = 'wrong-location'

		matchingChars = matchingChars + letter
	}

	activeTiles.forEach((value, index, array) => {
		flipTile(value, index, array, guess, classDictionary[index + 1])
	})
}

function flipTile(tile, index, array, guess, className) {
	const letter = tile.dataset.letter
	const key = keyboard.querySelector(`[data-key="${letter}"i]`)
	setTimeout(() => {
		tile.classList.add('flip')
	}, (index * FLIP_ANIMATION_DURATION) / 2)

	tile.addEventListener(
		'transitionend',
		() => {
			tile.classList.remove('flip')

			tile.dataset.state = className
			key.classList.add(className)

			if (index === array.length - 1) {
				tile.addEventListener(
					'transitionend',
					() => {
						startInteraction()
						checkWinLose(guess, array)
					},
					{ once: true }
				)
			}
		},
		{ once: true }
	)
}

@MrAmericanMike
Copy link

Thanks for providing a better method. This was really needed in the code.
I worked out a different solution but creating an object with the letters on the target word as "keys" and a number representing the amount on them. But yes, this does the job too I guess.

@cyberabi
Copy link

The current code in master still doesn't properly resolve a case where the player enters more of a given letter than there are in the word. For example, guessing "EERIE" when the word is "QUEER." Here's my fix for it:

...
  stopInteraction()
  flips = mapTiles(guess)
  activeTiles.forEach((...params) => flipTile(...params, guess, flips))
}

function mapTiles(guess) {

  // Pass 1: Number of times each letter occurs in target word
  var targetMap = [...targetWord].reduce((res, char) => (res[char] = (res[char] || 0) + 1, res), {})

  // Pass 2: All of the correct guesses (and build five letter map)
  var map2 = ""
  for (var i = 0; i < guess.length; i++) {
    var c = guess.charAt(i)
    if (c === targetWord.charAt(i)) {
      map2 += "c"
      targetMap[c] -= 1
    } else {
      map2 += "i"
    }
  }

  // Pass 3: Letters in the word, but in incorrect positions
  var map3 = ""
  for (var i = 0; i < map2.length; i++) {
    var f = map2.charAt(i)
    if (f === 'i') {
      var c = guess.charAt(i)
      if (targetMap.hasOwnProperty(c) && (targetMap[c] > 0)) {
        targetMap[c] -= 1
        f = 'p'
      }
    }
    map3 += f
  }

  return map3
}

function flipTile(tile, index, array, guess, flips) {
  const letter = tile.dataset.letter
  const key = keyboard.querySelector(`[data-key="${letter}"i]`)
  const status = flips.charAt(index)

  setTimeout(() => {
    tile.classList.add("flip")
  }, (index * FLIP_ANIMATION_DURATION) / 2)

  tile.addEventListener(
    "transitionend",
    () => {
      tile.classList.remove("flip")
      if (status === 'c') {
        tile.dataset.state = "correct"
        key.classList.add("correct")
      } else if (status === 'p') {
        tile.dataset.state = "wrong-location"
        key.classList.add("wrong-location")
      } else {
        tile.dataset.state = "wrong"
        key.classList.add("wrong")
      }
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants