Added/implemented wordle game.
This commit is contained in:
parent
453a3b1b42
commit
5e396a4abe
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
Loading…
Reference in New Issue