// ==UserScript==
// @name NYT Wordle Helper
// @namespace Shuang Luo
// @version 0.2
// @description A helper for New York Times Wordle game
// @author Shuang Luo
// @match https://www.nytimes.com/games/wordle/*
// @grant none
// @downloadURL https://raw.githubusercontent.com/ls8215/nyt_wordle/main/wordle.js
// @updateURL https://raw.githubusercontent.com/ls8215/nyt_wordle/main/wordle.js
// ==/UserScript==
(function() {
'use strict';
// This will store structured guess information
let guesses = [];
let words = [];
// Function to fetch the words from the external file
function fetchWords() {
return fetch('https://raw.githubusercontent.com/ls8215/nyt_wordle/refs/heads/main/words.txt')
.then(response => {
if (!response.ok) {
throw new Error('Status Code: ' + response.statusText);
}
return response.text();
})
.then(data => {
words = data.split('\n').map(word => word.trim());
})
.catch(error => {
console.error('Error loading words:', error);
});
}
// Function to update possible words in the message div
function updatePossibleWords(possibleWords) {
const possibleWordsElement = document.getElementById('possibleWords');
if (possibleWordsElement) {
if (possibleWords.length === 0) {
possibleWordsElement.innerText = 'No suggestions available.';
} else {
possibleWordsElement.innerText = possibleWords.join(', ');
}
}
}
// Function to check if a letter aleady exists in the guesses array. if so, return true
function checkIfLetterExists(letter) {
return guesses.some(guess => guess.letter === letter);
}
// Function to check each of the five board divs and display their content with styling
function checkBoardContent() {
const boardContent = [];
for (let i = 1; i <= 5; i++) {
const boardDiv = document.querySelector(`#wordle-app-game > div.Board-module_boardContainer__TBHNL > div > div:nth-child(${i})`);
if (boardDiv && boardDiv.innerText.trim() !== '') {
const letters = Array.from(boardDiv.querySelectorAll('[data-state]'));
let structuredGuess = {
guess: '',
status: []
};
// Process each letter and build the guess structure
letters.forEach((letterDiv, index) => {
const letter = letterDiv.innerText;
const state = letterDiv.getAttribute('data-state');
if (
(state === 'absent' && !checkIfLetterExists(letter)) ||
state === 'present' ||
state === 'correct'
) {
guesses.push({ letter, state, position: index });
}
let status = '';
if (state === 'present') {
status = 'present';
} else if (state === 'correct') {
status = 'correct';
} else {
status = 'absent';
}
structuredGuess.guess += letter;
structuredGuess.status.push({ letter, status, position: index });
});
// Display the guess with letter colors (if applicable)
let styledGuess = `Guess ${i}: `;
structuredGuess.status.forEach(({ letter, status }) => {
let color = '';
if (status === 'present') {
color = 'orange';
} else if (status === 'correct') {
color = 'green';
} else {
color = 'gray';
}
styledGuess += `${letter}`;
});
boardContent.push(styledGuess);
}
}
const boardContentElement = document.getElementById('boardContent');
if (boardContentElement) {
if (boardContent.length === 0) {
boardContentElement.innerText = 'No guesses made yet.';
} else {
// Join the board guesses with line breaks and display them
boardContentElement.innerHTML = boardContent.join('
');
}
}
}
// Function to filter possible words based on the guesses
function filterPossibleWords() {
if (guesses.length === 0) {
return;
}
let validWords = words.filter(word => {
return guesses.every(guess => {
const letter = guess.letter.toLowerCase();
const position = guess.position;
if (guess.state === 'correct' && word[position] !== letter) {
return false;
}
if (guess.state === 'present') {
if (!word.includes(letter)) {
return false;
}
if (word[position] === letter) {
return false;
}
}
if (guess.state === 'absent' && word.includes(letter)) {
return false;
}
return true;
});
});
updatePossibleWords(validWords);
}
// Function to initialize the script
function initialize() {
// Check if the game board is available
const wordleApp = document.querySelector('#wordle-app-game');
if (!wordleApp) {
console.log('Wordle game not found, script not running.');
return;
}
// Create a div to display the helper message
const messageDiv = document.createElement('div');
messageDiv.style.position = 'absolute';
messageDiv.style.top = '80px';
messageDiv.style.right = '20px';
messageDiv.style.padding = '10px';
messageDiv.style.backgroundColor = 'rgba(0,0,0,0.7)';
messageDiv.style.color = 'white';
messageDiv.style.fontSize = '16px';
messageDiv.style.zIndex = '9999';
messageDiv.style.maxWidth = '300px';
messageDiv.style.wordWrap = 'break-word';
const title = document.createElement('h2');
title.style.fontSize = '24px';
title.style.margin = '20';
title.innerText = "NYT Wordle Helper";
const possibleWordsTitle = document.createElement('h5');
possibleWordsTitle.style.fontSize = '18px';
possibleWordsTitle.style.fontWeight = 'bold';
possibleWordsTitle.style.marginBottom = '5px';
possibleWordsTitle.style.marginTop = '15px';
possibleWordsTitle.innerText = "Possible words are:";
const possibleWords = document.createElement('span');
possibleWords.id = 'possibleWords';
possibleWords.innerText = "Loading...";
const boardContentTitle = document.createElement('h5');
boardContentTitle.style.fontSize = '18px';
boardContentTitle.style.fontWeight = 'bold';
boardContentTitle.style.marginBottom = '5px';
boardContentTitle.style.marginTop = '15px';
boardContentTitle.innerText = "Current guesses:";
const boardContent = document.createElement('span');
boardContent.id = 'boardContent';
boardContent.innerText = "Make your first guess. If you have done so, click enter.";
// Create Filter button
const filterButton = document.createElement('button');
filterButton.id = 'filterButton';
filterButton.innerText = "Filter Words";
filterButton.style.backgroundColor = '#4CAF50';
filterButton.style.color = 'white';
filterButton.style.padding = '10px';
filterButton.style.border = 'none';
filterButton.style.cursor = 'pointer';
filterButton.style.fontSize = '14px';
filterButton.style.marginTop = '10px'; // Add some space between text and button
// Append all elements to the messageDiv
messageDiv.appendChild(title);
messageDiv.appendChild(possibleWordsTitle);
messageDiv.appendChild(possibleWords);
messageDiv.appendChild(document.createElement('br'));
messageDiv.appendChild(boardContentTitle);
messageDiv.appendChild(boardContent);
messageDiv.appendChild(document.createElement('br'));
messageDiv.appendChild(filterButton);
// Append messageDiv to the body
document.body.appendChild(messageDiv);
// Initialize guesses array
guesses = [];
// Start fetching the words from the external file
fetchWords();
// Function to check the board content and update the guesses array
checkBoardContent();
// Listen for keydown events on the document to update the board content and filter words
document.addEventListener('keydown', (event) => {
checkBoardContent();
if (event.key === 'Enter') {
checkBoardContent();
}
})
// Listen for Filter button
filterButton.addEventListener('click', () => {
checkBoardContent();
filterPossibleWords();
});
}
// Wait for Wordle game to load and then initialize the script
const observer = new MutationObserver(() => {
const wordleApp = document.querySelector('#wordle-app-game');
if (wordleApp) {
observer.disconnect();
initialize();
}
});
// Start observing the body for changes to detect when Wordle game is loaded
observer.observe(document.body, { childList: true, subtree: true });
})();