Added/implemented wordle game.

This commit is contained in:
ThePendulum 2024-06-03 01:02:30 +02:00
parent 453a3b1b42
commit 5e396a4abe
2 changed files with 183 additions and 0 deletions

View File

@ -27,6 +27,7 @@ module.exports = {
'chat',
'mash',
'trivia',
'wordle',
'letters',
'numbers',
'hunt',
@ -133,6 +134,11 @@ module.exports = {
z: 1,
},
},
wordle: {
minLength: 3,
defaultLength: 5,
highlightRepeat: false, // in wordle, if the I in the guess HINDI is in the wrong place, only the first I is orange
},
numbers: {
length: 6,
timeout: 90,

177
src/games/wordle.js Normal file
View File

@ -0,0 +1,177 @@
'use strict';
const config = require('config');
const crypto = require('crypto');
const style = require('../utils/style');
const words = require('../../assets/mash-words.json');
const settings = { ...config.wordle };
const wordles = new Map();
const alphabet = Array.from({ length: 26 }, (value, index) => String.fromCharCode(65 + index));
function getBoard(letters, showLetters, context) {
const wordle = wordles.get(context.room.id);
const prefix = style.grey(style.code('['));
const middle = letters.map((letter) => {
if (letter === null) {
return style.code(''); // em space, U+2003, charcode 8195
}
if (letter[1] === true) {
return style.green(style.bold(style.code(letter[0].toUpperCase())));
}
if (letter[1] === false) {
return style.orange(style.bold(style.code(letter[0].toUpperCase())));
}
return style.grey(style.bold(style.code(letter[0].toUpperCase())));
}).join(style.grey(style.code('|')));
const suffix = `${style.grey(style.code(']'))}`;
if (showLetters) {
const letterBoard = Array.from(wordle.letters).map(([letter, state]) => {
if (state === true) {
return style.green(style.bold(letter));
}
if (state === false) {
return style.orange(style.bold(letter));
}
return style.grey(letter);
}).join('');
return `${prefix}${middle}${suffix}${letterBoard}`; // eslint-disable-line no-irregular-whitespace
}
return `${prefix}${middle}${suffix}`;
}
function start(length = settings.defaultLength, context) {
const wordPool = words[length];
if (length < settings.minLength) {
context.sendMessage(`Wordle must be at least ${settings.minLength} letters long.`, context.room.id);
return;
}
if (!wordPool) {
context.sendMessage(`No words with ${length} letters available.`, context.room.id);
return;
}
const wordList = Object.values(wordPool).flat();
const word = wordList[crypto.randomInt(wordList.length)];
wordles.set(context.room.id, {
word: word.word.toUpperCase(),
wordList,
definitions: word.definitions,
letters: new Map(alphabet.map((letter) => [letter, null])),
guesses: [],
});
context.sendMessage(`${getBoard(Array.from({ length }, () => null), false, context)} guess the word! ${style.grey(style.bold('X'))} not in word; ${style.orange(style.bold('X'))} wrong position; ${style.green(style.bold('X'))} correct position.`, context.room.id);
context.logger.info(`Wordle started: ${word.word.toUpperCase()}`);
}
function play(guess, context) {
const wordle = wordles.get(context.room.id);
if (!wordle) {
context.sendMessage(`There's no wordle going on. Start one with ${config.prefix}wordle [length]!`, context.room.id);
return;
}
if (!guess || guess.length !== wordle.word.length) {
context.sendMessage(`Your guess needs to be ${wordle.word.length} letters.`, context.room.id);
return;
}
if (!wordle.wordList.some((definition) => definition.word.toLowerCase() === guess.toLowerCase())) {
context.sendMessage(`The word '${guess}' is not in my dictionary.`, context.room.id);
return;
}
const upperGuess = guess.toUpperCase();
const processed = new Set();
const check = upperGuess.split('').map((letter, index) => {
const alreadySeen = settings.highlightRepeat ? false : processed.has(letter);
processed.add(letter);
if (wordle.word[index] === letter) {
wordle.letters.set(letter, true);
return [letter, true];
}
if (wordle.word.includes(letter)) {
wordle.letters.set(letter, false);
return [letter, alreadySeen ? null : false]; // repeating letter in the wrong place is not highlighted
}
wordle.letters.delete(letter);
return [letter, null];
});
wordle.guesses = wordle.guesses.concat([[context.user.username, upperGuess]]);
if (upperGuess === wordle.word) {
const points = Math.max((wordle.word.length + 1) - wordle.guesses.length, 1);
const definition = wordle.definitions[0] ? `: ${style.italic(`${wordle.definitions[0].slice(0, 100)}${wordle.definitions[0].length > 100 ? '...' : ''}`)}` : '';
context.setPoints(context.user, points);
context.sendMessage(`${getBoard(check, false, context)} is correct! ${style.bold(style.cyan(`${config.usernamePrefix}${context.user.username}`))} gets ${points} ${points > 1 ? 'points' : 'point'}. ${style.bold(wordle.word)}${definition}`, context.room.id);
wordles.delete(context.room.id);
return;
}
context.sendMessage(`${getBoard(check, true, context)}`, context.room.id);
}
function onCommand(args, context) {
const wordle = wordles.get(context.room.id);
const length = Number(args[0]) || settings.defaultLength;
if (['guess', 'w'].includes(context.command)) {
play(args[0], context);
return;
}
if (context.subcommand === 'stop') {
if (wordle) {
context.sendMessage(`The game was stopped by ${config.usernamePrefix}${context.user.username}. The word was ${style.bold(wordle.word)}.`, context.room.id);
wordles.delete(context.room.id);
return;
}
context.sendMessage(`The there is no wordle going on, ${config.usernamePrefix}${context.user.username}, start one with ${config.prefix}wordle [length]!`, context.room.id);
return;
}
if (!wordle && context.room.id) {
start(length, context);
return;
}
context.sendMessage(`There is already a ${wordle.word.length}-letter wordle going on, guess with ${config.prefix}w [word]!`, context.room.id);
}
module.exports = {
name: 'Wordle',
commands: ['wordle', 'guess', 'w'],
help: `Guess the ${settings.defaultLength}-letter word on the board. Submit a guess with ${config.prefix}w [word]. If the letter is green, it is in the correct place. If it is yellow, it is part of the word, but not in the correct place. The number of letters in the word is the highest score you can get. You lose 1 point per guess, down to 1 point.`,
onCommand,
// onMessage,
};