Compare commits

..

24 Commits

Author SHA1 Message Date
ThePendulum
59dd7c793a 1.30.8 2025-02-18 22:13:26 +01:00
ThePendulum
a9f733227c Added weekly points back-up, writing points to dedicated directory. 2025-02-18 22:13:24 +01:00
ThePendulum
19feb9a55f 1.30.7 2024-09-04 22:28:02 +02:00
ThePendulum
df3c682ff6 Separated wordle and hardle score. 2024-09-04 22:28:00 +02:00
ThePendulum
aca9a4b597 1.30.6 2024-09-04 22:26:16 +02:00
ThePendulum
e4055ad99c Another fix for missing definition breaking mash. 2024-09-04 22:26:14 +02:00
ThePendulum
5dcb928c35 1.30.5 2024-08-24 18:01:10 +02:00
ThePendulum
8c7995340e Fixed missing definition breaking mash. 2024-08-24 18:01:08 +02:00
ThePendulum
84025d6a8b 1.30.4 2024-08-15 22:32:02 +02:00
ThePendulum
84b158cf21 Fixed crash when target is missing from message. 2024-08-15 22:32:00 +02:00
ThePendulum
7531a69904 1.30.3 2024-08-14 01:37:10 +02:00
ThePendulum
c402628161 Disable wordle bonus points for small dictionaries. 2024-08-14 01:37:08 +02:00
ThePendulum
e9df99bdcb 1.30.2 2024-07-05 00:40:55 +02:00
ThePendulum
a0f1914ce6 Amended wordle help. 2024-07-05 00:40:52 +02:00
ThePendulum
857f1816f0 1.30.1 2024-07-05 00:36:43 +02:00
ThePendulum
5ac935cc95 Fixed wordle hard hint letter background color. 2024-07-05 00:36:41 +02:00
ThePendulum
af9f15d11d 1.30.0 2024-07-05 00:30:27 +02:00
ThePendulum
7747eabce2 Regenerated dictionary. 2024-07-05 00:30:10 +02:00
ThePendulum
990e18d3da Added hard mode to wordle. 2024-07-05 00:29:40 +02:00
ThePendulum
234bbb2bbc Added word blacklist for lowercase names. Improved definition curation. 2024-07-04 22:55:54 +02:00
ThePendulum
f46d5f008b 1.29.9 2024-06-19 00:23:24 +02:00
ThePendulum
a86ef925ff Re-added morse and a few other 'name' words. Removed raw word list. 2024-06-19 00:23:21 +02:00
ThePendulum
ad26d2635c 1.29.8 2024-06-18 23:34:30 +02:00
ThePendulum
8d98581cd9 Fixed any mention of sponges being interpreted as a pong. 2024-06-18 23:34:27 +02:00
15 changed files with 118 additions and 89703 deletions

View File

@@ -15,6 +15,6 @@
"no-console": 0,
"indent": ["error", "tab"],
"no-tabs": 0,
"max-len": [2, {"code": 400, "tabWidth": 4, "ignoreUrls": true}]
"max-len": 0
}
}

2
.gitignore vendored
View File

@@ -4,5 +4,5 @@ config/*
*.config.js
!ecosystem.config.js
*.sqlite
points*.json
points/*
assets/mash-words.json

View File

@@ -39,7 +39,16 @@ async function init() {
const sortedWords = validWords.reduce((acc, [rawWord, fullDefinition]) => {
const word = rawWord.toLowerCase();
const anagram = word.split('').sort().join('');
const definitions = fullDefinition?.split(/\d+\.\s+/).filter(Boolean).map((definition) => definition.split('.')[0].toLowerCase()) || [];
const definitions = fullDefinition
?.split(/\d+\.\s+/).filter(Boolean).map((definition) => {
const splitIndex = definition.indexOf('.', 16); // split after n characters to avoid splitting on e.g. abbreviated categories at the start of the definition: (Anat.)
if (splitIndex > -1) {
return definition.slice(0, splitIndex).trim().toLowerCase();
}
return definition.toLowerCase();
}) || [];
if (!acc[anagram.length]) {
acc[anagram.length] = {};

View File

@@ -913,6 +913,8 @@
"adolescences": "The state of growing up from childhood to manhood or womanhood; youth, or the period of life between puberty and maturity, generally considered to be, in the male sex, from fourteen to twenty-one. Sometimes used with reference to the lower animals.",
"adolescent": "Growing; advancing from childhood to maturity. Schools, unless discipline were doubly strong, Detain their adolescent charge too long. Cowper.\n\nA youth.",
"adolescents": "Growing; advancing from childhood to maturity. Schools, unless discipline were doubly strong, Detain their adolescent charge too long. Cowper.\n\nA youth.",
"adonis": "1. (Gr. Myth.) A youth beloved by Venus for his beauty. He was killed in the chase by a wild boar. 2. A preëminently beautiful young man; a dandy. 3. (Bot.) A genus of plants of the family Ranunculaceæ, containing the pheasaut's eye (Adonis autumnalis); -- named from Adonis, whose blood was fabled to have stained the flower.",
"adonises": null,
"adopt": "1. To take by choice into relationship, as, child, heir, friend, citizen, etc. ; esp. to take voluntarily (a child of other parents) to be in the place of, or as, one's own child. 2. To take or receive as one's own what is not so naturally; to select and take or approve; as, to adopt the view or policy of another; these resolutions were adopted.",
"adoptable": "Capable of being adopted.",
"adopted": "Taken by adoption; taken up as one's own; as, an adopted son, citizen, country, word. -- A*dopt\"ed*ly, adv.",
@@ -1204,6 +1206,8 @@
"afoul": "In collision; entangled. Totten. To run afoul of, to run against or come into collision with, especially so as to become entangled or to cause injury.",
"afraid": "Impressed with fear or apprehension; in fear; apprehensive. [Afraid comes after the noun it limits.] \"Back they recoiled, afraid.\" Milton. Note: This word expresses a less degree of fear than terrified or frightened. It is followed by of before the object of fear, or by the infinitive, or by a dependent clause; as, to be afraid of death. \"I am afraid to die.\" \"I am afraid he will chastise me.\" \"Be not afraid that I your hand should take.\" Shak. I am afraid is sometimes used colloquially to soften a statement; as, I am afraid I can not help you in this matter. Syn. -- Fearful; timid; timorous; alarmed; anxious.",
"afresh": "Anew; again; once more; newly. They crucify . . . the Son of God afresh. Heb. vi. 6.",
"afro": null,
"afros": null,
"aft": "Near or towards the stern of a vessel; astern; abaft.",
"after": "1. Next; later in time; subsequent; succeeding; as, an after period of life. Marshall. Note: In this sense the word is sometimes needlessly combined with the following noun, by means of a hyphen, as, after-ages, after-act, after-days, after-life. For the most part the words are properly kept separate when after has this meaning. 2. Hinder; nearer the rear. (Naut.) To ward the stern of the ship; -- applied to any object in the rear part of a vessel; as the after cabin, after hatchway. Note: It is often combined with its noun; as, after-bowlines, after- braces, after-sails, after-yards, those on the mainmasts and mizzenmasts. After body (Naut.), the part of a ship abaft the dead flat, or middle part.\n\n1. Behind in place; as, men in line one after another. \"Shut doors after you.\" Shak. 2. Below in rank; next to in order. Shak. Codrus after PhDryden. 3. Later in time; subsequent; as, after supper, after three days. It often precedes a clause. Formerly that was interposed between it and the clause. After I am risen again, I will go before you into Galilee. Matt. xxvi. 32. 4. Subsequent to and in consequence of; as, after what you have said, I shall be careful. 5. Subsequent to and notwithstanding; as, after all our advice, you took that course. 6. Moving toward from behind; following, in search of; in pursuit of. Ye shall not go after other gods. Deut. vi. 14. After whom is the king of Israel come out 1 Sam. xxiv. 14. 7. Denoting the aim or object; concerning; in relation to; as, to look after workmen; to inquire after a friend; to thirst after righteousness. 8. In imitation of; in conformity with; after the manner of; as, to make a thing after a model; a picture after Rubens; the boy takes after his father. To name or call after, to name like and reference to. Our eldest son was named George after his uncle. Goldsmith. 9. According to; in accordance with; in conformity with the nature of; as, he acted after his kind. He shall not judge after the sight of his eyes. Isa. xi. 3. They that are after the flesh do mind the things of the flesh. Rom. viii. 5. 10. According to the direction and influence of; in proportion to; befitting. [Archaic] He takes greatness of kingdoms according to bulk and currency, and not after their intrinsic value. Bacon. After all, when everything has been considered; upon the whole. -- After (with the same noun preceding and following), as, wave after wave, day after day, several or many (waves, etc.) successively. -- One after another, successively. -- To be after, to be in pursuit of in order to reach or get; as, he is after money.\n\nSubsequently in time or place; behind; afterward; as, he follows after. It was about the space of three hours after. Acts. v. 7. Note: After is prefixed to many words, forming compounds, but retaining its usual signification. The prefix may be adverbial, prepositional, or adjectival; as in after- described, after-dinner, after-part. The hyphen is sometimes needlessly used to connect the adjective after with its noun. See Note under After, a., 1.",
"afterbirth": "The placenta and membranes with which the fetus is connected, and which come away after delivery.",
@@ -4925,6 +4929,7 @@
"barkers": "1. An animal that barks; hence, any one who clamors unreasonably. 2. One who stands at the doors of shops to urg [Cant, Eng.] 3. A pistol. [Slang] Dickens. 4. (Zoöl.) The spotted redshank.\n\nOne who strips trees of their bark. BARKER'S MILL Bark\"er's mill`. Etym: [From Dr. Barker, the inventor.] A machine, invented in the 17th century, worked by a form of reaction wheel. The water flows into a vertical tube and gushes from apertures in hollow horizontal arms, causing the machine to revolve on its axis.",
"barking": null,
"barks": "1. To strip the bark from; to peel. 2. To abrade or rub off any outer covering from; as to bark one's heel. 3. To girdle. See Girdle, v. t., 3. 4. To cover or inclose with bark, or as with bark; as, to bark the roof of a hut.\n\n1. To make a short, loud, explosive noise with the vocal organs; -- said of some animals, but especially of dogs. 2. To make a clamor; to make importunate outcries. They bark, and say the Scripture maketh heretics. Tyndale. Where there is the barking of the belly, there no other commands will be heard, much less obeyed. Fuller.\n\nThe short, loud, explosive sound uttered by a dog; a similar sound made by some other animals.\n\n1. Formerly, any small sailing vessel, as a pinnace, fishing smack, etc.; also, a rowing boat; a barge. Now applied poetically to a sailing vessel or boat of any kind. Byron. 2. (Naut.) A three-masted vessel, having her foremast and mainmast squarerigged, and her mizzenmast schooner-rigged.",
"barky": "Covered with, or containing, bark. \"The barky fingers of the elm.\" Shak.",
"barley": "A valuable grain, of the family of grasses, genus Hordeum, used for food, and for making malt, from which are prepared beer, ale, and whisky. Barley bird (Zoöl.), the siskin. -- Barley sugar, sugar boiled till it is brittle (formerly with a decoction of barley) and candied. -- Barley water, a decoction of barley, used in medicine, as a nutritive and demulcent.",
"barmaid": "A girl or woman who attends the customers of a bar, as in a tavern or beershop. A bouncing barmaid. W. Irving.",
"barmaids": "A girl or woman who attends the customers of a bar, as in a tavern or beershop. A bouncing barmaid. W. Irving.",
@@ -11206,6 +11211,7 @@
"chocolates": "1. A paste or cake composed of the roasted seeds of the Theobroma Cacao ground and mixed with other ingredients, usually sugar, and cinnamon or vanilla. 2. The beverage made by dissolving a portion of the paste or cake in boiling water or milk. Chocolate house, a house in which customers may be served with chocolate. -- Chocolate nut. See Cacao.",
"chocolaty": null,
"chocs": null,
"chode": "the old imp. of chide. See Chide.",
"choice": "1. Act of choosing; the voluntary act of selecting or separating from two or more things that which is preferred; the determination of the mind in preferring one thing to another; election. 2. The power or opportunity of choosing; option. Choice there is not, unless the thing which we take be so in our power that we might have refused it. Hooker. 3. Care in selecting; judgment or skill in distinguishing what is to be preferred, and in giving a preference; discrimination. I imagine they [the apothegms of Cæsar] were collected with judgment and choice. Bacon. 4. A sufficient number to choose among. Shak. 5. The thing or person chosen; that which is approved and selected in preference to others; selection. The common wealth is sick of their own choice. Shak. 6. The best part; that which is preferable. The flower and choice Of many provinces from bound to bound. Milton. To make a choice of, to choose; to select; to separate and take in preference. Syn. - See Volition, Option.\n\n1. Worthly of being chosen or preferred; select; superior; precious; valuable. My choicest hours of life are lost. Swift. 2. Preserving or using with care, as valuable; frugal; -- used with of; as, to be choice of time, or of money. 3. Selected with care, and due attention to preference; deliberately chosen. Choice word measured phrase. Wordsworth. Syn. - Select; precious; exquisite; uncommon; rare; chary; careful/",
"choicer": null,
"choices": "1. Act of choosing; the voluntary act of selecting or separating from two or more things that which is preferred; the determination of the mind in preferring one thing to another; election. 2. The power or opportunity of choosing; option. Choice there is not, unless the thing which we take be so in our power that we might have refused it. Hooker. 3. Care in selecting; judgment or skill in distinguishing what is to be preferred, and in giving a preference; discrimination. I imagine they [the apothegms of Cæsar] were collected with judgment and choice. Bacon. 4. A sufficient number to choose among. Shak. 5. The thing or person chosen; that which is approved and selected in preference to others; selection. The common wealth is sick of their own choice. Shak. 6. The best part; that which is preferable. The flower and choice Of many provinces from bound to bound. Milton. To make a choice of, to choose; to select; to separate and take in preference. Syn. - See Volition, Option.\n\n1. Worthly of being chosen or preferred; select; superior; precious; valuable. My choicest hours of life are lost. Swift. 2. Preserving or using with care, as valuable; frugal; -- used with of; as, to be choice of time, or of money. 3. Selected with care, and due attention to preference; deliberately chosen. Choice word measured phrase. Wordsworth. Syn. - Select; precious; exquisite; uncommon; rare; chary; careful/",
@@ -36132,7 +36138,6 @@
"inward": "1. Being or placed within; inner; interior; -- opposed to outward. Milton. 2. Seated in the mind, heart, spirit, or soul. \"Inward beauty.\" Shak. 3. Intimate; domestic; private. [Obs.] All my inward friends abhorred me. Job xix. 19. He had had occasion, by one very inward with him, to know in part the discourse of his life. Sir P. Sidney.\n\n1. That which is inward or within; especially, in the plural, the inner parts or organs of the body; the viscera. Jer. Taylor. Then sacrificing, laid the inwards and their fat. Milton. 2. The mental faculties; -- usually pl. [Obs.] 3. An intimate or familiar friend or acquaintance. [Obs.] \"I was an inward of his.\" Shak.\n\n1. Toward the inside; toward the center or interior; as, to bend a thing inward. 2. Into, or toward, the mind or thoughts; inwardly; as, to turn the attention inward. So much the rather, thou Celestial Light, Shine inward. Milton.",
"inwardly": "1. In the inner parts; internally. Let Benedick, like covered fire, Consume away in sighs, waste inwardly. Shak. 2. Toward the center; inward; as, to curve inwardly. 3. In the heart or mind; mentally; privately; secretas, he inwardly repines. 4. Intimately; thoroughly. [Obs.] I shall desire to know him more inwardly. Beau. & Fl.",
"inwards": "1. Toward the inside; toward the center or interior; as, to bend a thing inward. 2. Into, or toward, the mind or thoughts; inwardly; as, to turn the attention inward. So much the rather, thou Celestial Light, Shine inward. Milton.\n\nSee Inward.",
"ioctl": null,
"iodide": "A binary compound of iodine, or one which may be regarded as binary; as, potassium iodide.",
"iodides": "A binary compound of iodine, or one which may be regarded as binary; as, potassium iodide.",
"iodine": "A nonmetallic element, of the halogen group, occurring always in combination, as in the iodides. When isolated it is in the form of dark gray metallic scales, resembling plumbago, soft but brittle, and emitting a chlorinelike odor. Symbol I. Atomic weight 126.5. If heated, iodine volatilizes in beautiful violet vapors. Note: Iodine was formerly obtained from the ashes of seaweed (kelp or varec), but is now also extracted from certain natural brines. In the free state, iodine, even in very minute quantities, colors starch blue. Iodine and its compounds are largely used in medicine (as in liniments, antisyphilitics, etc.), in photography, in the preparation of aniline dyes, and as an indicator in titration. Iodine green, an artificial green dyestuff, consisting of an iodine derivative of rosaniline; -- called also night green. -- Iodine scarlet, a pigment of an intense scarlet color, consisting of mercuric iodide. -- Iodine yellow, a brilliant yellow pigment, consisting of plumbic iodide.",
@@ -43221,6 +43226,7 @@
"morphs": null,
"morrow": "1. Morning. [Obs.] \"White as morrow's milk.\" Bp. Hall. We loved he by the morwe a sop in wine. Chaucer. 2. The next following day; the day subsequent to any day specified or understood. Lev. vii. 16. Till this stormy night is gone, And the eternal morrow dawn. Crashaw. 3. The day following the present; to-morrow. Good morrow, good morning; -- a form of salutation. -- To morrow. See To-morrow in the Vocabulary.",
"morrows": "1. Morning. [Obs.] \"White as morrow's milk.\" Bp. Hall. We loved he by the morwe a sop in wine. Chaucer. 2. The next following day; the day subsequent to any day specified or understood. Lev. vii. 16. Till this stormy night is gone, And the eternal morrow dawn. Crashaw. 3. The day following the present; to-morrow. Good morrow, good morning; -- a form of salutation. -- To morrow. See To-morrow in the Vocabulary.",
"morse": "The walrus. See Walrus.\n\nA clasp for fastening garments in front. Fairholt.",
"morsel": "1. A little bite or bit of food. Chaucer. Every morsel to a satisfied hunger is only a new labor to a tired digestion. South. 2. A small quantity; a little piece; a fragment.",
"morsels": "1. A little bite or bit of food. Chaucer. Every morsel to a satisfied hunger is only a new labor to a tired digestion. South. 2. A small quantity; a little piece; a fragment.",
"mortal": "1. Subject to death; destined to die; as, man is mortal. 2. Destructive to life; causing or occasioning death; terminating life; exposing to or deserving death; deadly; as, a mortal wound; a mortal sin. 3. Fatally vulnerable; vital. Last of all, against himself he turns his sword, but missing the mortal place, with his poniard finishes the work. Milton. 4. Of or pertaining to the time of death. Safe in the hand of one disposing Power, Or in the natal or the mortal hour. Pope. 5. Affecting as if with power to kill; deathly. The nymph grew pale, and in a mortal fright. Dryden. 6. Human; belonging to man, who is mortal; as, mortal wit or knowledge; mortal power. The voice of God To mortal ear is dreadful. Milton. 7. Very painful or tedious; wearisome; as, a sermon lasting two mortal hours. [Colloq.] Sir W. Scott. Mortal foe, Mortal enemy, an inveterate, desperate, or implacable enemy; a foe bent on one's destruction.\n\nA being subject to death; a human being; man. \"Warn poor mortals left behind.\" Tickell.",
@@ -61727,6 +61733,7 @@
"shirtwaists": null,
"shirty": null,
"shit": null,
"shite": null,
"shitfaced": null,
"shithead": null,
"shitheads": null,
@@ -77539,7 +77546,6 @@
"xor": null,
"xref": null,
"xrefs": null,
"xterm": null,
"xylem": "That portion of a fibrovascular bundle which has developed, or will develop, into wood cells; -- distinguished from phloëm.",
"xylene": "Any of a group of three metameric hydrocarbons of the aromatic series, found in coal and wood tar, and so named because found in crude wood spirit. They are colorless, oily, inflammable liquids, C6H4.(CH3)2, being dimethyl benzenes, and are called respectively orthoxylene, metaxylene, and paraxylene. Called also xylol. Note: Each of these xylenes is the nucleus and prototype of a distinct series of compounds.",
"xylophone": "1. (Mus.) An instrument common among the Russians, Poles, and Tartars, consisting of a series of strips of wood or glass graduated in length to the musical scale, resting on belts of straw, and struck with two small hammers. Called in Germany strohfiedel, or straw fiddle. 2. An instrument to determine the vibrative properties of different kinds of wood. Knight.",

89675
assets/words

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,14 @@
const fs = require('fs').promises;
const words = require('./words.json');
const dictionary = require('./dictionary_old.json');
const wordsBlacklist = require('./words_blacklist.json');
const dictionary = require('./dictionary.json');
// mainly lowercase names
const blacklist = new Set(wordsBlacklist);
async function init() {
const notNameWords = words.filter((word) => word.charAt(0) === word.charAt(0).toLowerCase()); // don't include names for places, products, people, etc.
const notNameWords = words.filter((word) => word.charAt(0) === word.charAt(0).toLowerCase() && !blacklist.has(word)); // don't include names for places, products, people, etc.
const definitions = Object.fromEntries(notNameWords.map((word) => {
const normalizedWord = word.normalize('NFD').replace(/\p{Diacritic}/ug, '').toLowerCase().trim();

View File

@@ -1010,6 +1010,8 @@
"Adolph",
"Adonis",
"Adonises",
"adonis",
"adonises",
"adopt",
"adoptable",
"adopted",
@@ -1340,9 +1342,11 @@
"Afrikaner",
"Afrikaners",
"Afro",
"afro",
"Afrocentric",
"Afrocentrism",
"Afros",
"afros",
"AFT",
"aft",
"after",
@@ -5930,6 +5934,7 @@
"barking",
"Barkley",
"barks",
"barky",
"barley",
"Barlow",
"barmaid",
@@ -13432,6 +13437,7 @@
"chocs",
"Choctaw",
"Choctaws",
"chode",
"choice",
"choicer",
"choices",
@@ -50693,6 +50699,7 @@
"morrow",
"morrows",
"Morse",
"morse",
"morsel",
"morsels",
"Mort",
@@ -71565,6 +71572,7 @@
"shirtwaists",
"shirty",
"shit",
"shite",
"shitfaced",
"shithead",
"shitheads",

View File

@@ -0,0 +1,4 @@
[
"ioctl",
"xterm"
]

View File

@@ -136,7 +136,9 @@ module.exports = {
},
wordle: {
minLength: 3,
defaultLength: 5,
length: 5,
bonusDictionaryThreshold: 1000, // minimum dictionary size to assign bonus points, prevent people from scoring full bonus points from 1-word dictionaries
mode: 'easy',
},
numbers: {
length: 6,

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "schat2-clive",
"version": "1.29.7",
"version": "1.30.8",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "schat2-clive",
"version": "1.29.7",
"version": "1.30.8",
"license": "ISC",
"dependencies": {
"better-sqlite3": "^8.3.0",

View File

@@ -1,6 +1,6 @@
{
"name": "schat2-clive",
"version": "1.29.7",
"version": "1.30.8",
"description": "Game host for SChat 2-powered chat sites",
"main": "src/app.js",
"scripts": {

View File

@@ -35,7 +35,7 @@ function start(length, context, attempt = 0) {
if (answers.some((answer) => answer.word === anagram)) {
if (attempt >= 10) {
context.sendMessage(`Sorry, I did not find a mashable ${length}-letter word`);
context.sendMessage(`Sorry, I did not find a mashable ${length}-letter word`, context.room.id);
return;
}
@@ -81,7 +81,9 @@ function play(rawWord, context, shouted) {
}
if (answer) {
const definition = answer.definitions[0] ? `: ${style.italic(`${answer.definitions[0].slice(0, 100)}${mash.answers[0].definitions[0].length > 100 ? '...' : ''}`)}` : '';
const definition = answer.definitions[0]
? `: ${style.italic(`${answer.definitions[0].slice(0, 100)}${answer.definitions[0].length > 100 ? '...' : ''}`)}`
: '';
context.sendMessage(mash.answers.length === 1
? `${style.bold(style.yellow(word))} is the right answer${definition}, ${style.bold(style.cyan(`${config.usernamePrefix}${context.user.username}`))} now has ${style.bold(`${context.user.points + 1} ${context.user.points === 0 ? 'point' : 'points'}`)}! There were no other options for ${style.bold(mash.anagram)}.`
@@ -153,6 +155,10 @@ function define(word, context) {
}
function sanitizeDefinition(definition, answers) {
if (!definition) {
return 'No definition';
}
return definition.replaceAll(/\w+/g, (word) => {
if (answers.some((answer) => answer.word.includes(word))) {
return '*'.repeat(word.length);

View File

@@ -60,13 +60,13 @@ function getBoard(letters, showLetters, context) {
: style.grey(letter);
}).join(config.platform === 'irc' ? ' ' : ''); // regular space vs em space
return `${prefix}${middle}${suffix}Letters: ${letterBoard}`; // eslint-disable-line no-irregular-whitespace
return `${prefix}${middle}${suffix}${wordle.mode === 'hard' ? ' (Hard)' : ''}Letters: ${letterBoard}`; // eslint-disable-line no-irregular-whitespace
}
return `${prefix}${middle}${suffix}`;
}
function start(length = settings.defaultLength, context) {
function start(length = settings.length, mode = settings.mode, context) {
const wordPool = words[length];
if (length < settings.minLength) {
@@ -85,15 +85,16 @@ function start(length = settings.defaultLength, context) {
wordles.set(context.room.id, {
word: word.word.toUpperCase(),
wordList,
mode,
definitions: word.definitions,
letters: new Map(alphabet.map((letter) => [letter, null])),
guesses: [],
});
if (config.platform === 'irc') {
context.sendMessage(`${getBoard(Array.from({ length }, () => null), false, context)} guess the word with ${config.prefix}w [word]! ${style.bgsilver('X')} not in word; ${style.bgyellow(`X${style.yellow('?')}`)} wrong position; ${style.bggreen(`X${style.green('*')}`)} correct position.`, context.room.id); // eslint-disable-line no-irregular-whitespace
context.sendMessage(`${getBoard(Array.from({ length }, () => null), false, context)}${mode === 'hard' ? ' (Hard)' : ''} guess the word with ${config.prefix}w [word]! ${style.bgsilver('X')} not in word; ${style.bgyellow(`X${style.yellow('?')}`)} wrong position; ${style.bggreen(`X${style.green('*')}`)} correct position.`, context.room.id); // eslint-disable-line no-irregular-whitespace
} else {
context.sendMessage(`${getBoard(Array.from({ length }, () => null), false, context)} guess the word with ${config.prefix}w [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.sendMessage(`${getBoard(Array.from({ length }, () => null), false, context)}${mode === 'hard' ? ' (Hard)' : ''} guess the word with ${config.prefix}w [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()}`);
@@ -122,6 +123,37 @@ function play(guess, context) {
const guessLetters = upperGuess.split('');
const check = guessLetters.map((letter) => [letter, null]);
const prevGuess = wordle.guesses.at(-1)?.[1];
if (wordle.mode === 'hard' && prevGuess) {
const prevLetters = prevGuess.split('');
const valid = prevLetters.every((letter, index) => {
if (wordle.letters.get(letter) === false && !guessLetters.includes(letter)) {
context.sendMessage(`(Hard) Your guess must include the letter ${config.platform === 'irc'
? style.bgyellow(` ${letter} `)
: `${style.grey(style.code('['))}${style.orange(style.bold(style.code(letter)))}${style.grey(style.code(']'))}`
}.`, context.room.id);
return false;
}
if (wordle.letters.get(letter) === true && letter === wordle.word[index] && letter !== guessLetters[index]) {
context.sendMessage(`(Hard) Your guess must include the letter ${config.platform === 'irc'
? style.bggreen(` ${letter} `)
: `${style.grey(style.code('['))}${style.green(style.bold(style.code(letter)))}${style.grey(style.code(']'))}`
} in the correct position.`, context.room.id);
return false;
}
return true;
});
if (!valid) {
return;
}
}
// correct
guessLetters.forEach((letter, index) => {
@@ -153,11 +185,16 @@ function play(guess, context) {
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 assignBonusPoints = wordle.wordList.length > config.wordle.bonusDictionaryThreshold;
const points = assignBonusPoints
? Math.max((wordle.word.length + 1) - wordle.guesses.length, 1)
: 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 in ${wordle.guesses.length} guesses! ${style.bold(style.cyan(`${config.usernamePrefix}${context.user.username}`))} gets ${points} ${points > 1 ? 'points' : 'point'}. ${style.bold(wordle.word)}${definition}`, context.room.id);
context.setPoints(context.user, points, { key: wordle.mode === 'hard' ? 'hardle' : 'wordle' });
context.sendMessage(`${getBoard(check, false, context)} is correct in ${wordle.guesses.length} guesses! ${style.bold(style.cyan(`${config.usernamePrefix}${context.user.username}`))} gets ${points} ${points > 1 ? 'points' : 'point'}${assignBonusPoints ? '. ' : ` (${wordle.word.length}-letter dictionary too small for bonus points). `}${style.bold(wordle.word)}${definition}`, context.room.id);
wordles.delete(context.room.id);
@@ -169,7 +206,10 @@ function play(guess, context) {
function onCommand(args, context) {
const wordle = wordles.get(context.room.id);
const length = Number(args[0]) || settings.defaultLength;
const length = args.map((arg) => Number(arg)).find(Boolean) || settings.length;
const mode = args.find((arg) => arg === 'easy' || arg === 'hard')
|| (context.command === 'hardle' && 'hard')
|| settings.mode;
if (['guess', 'w'].includes(context.command)) {
play(args[0], context);
@@ -189,7 +229,7 @@ function onCommand(args, context) {
}
if (!wordle && context.room.id) {
start(length, context);
start(length, mode, context);
return;
}
@@ -198,8 +238,8 @@ function onCommand(args, context) {
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.`,
commands: ['wordle', 'hardle', 'lingo', 'guess', 'w'],
help: `Guess the ${settings.length}-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. Change the numbers of letters or switch to hard mode with ~wordle [length] [hard] or ~hardle [length].`,
onCommand,
// onMessage,
};

View File

@@ -3,6 +3,7 @@
const config = require('config');
const fs = require('fs').promises;
const logger = require('simple-node-logger').createSimpleLogger();
const { getWeek } = require('date-fns');
const { argv } = require('yargs');
// const timers = require('timers/promises');
@@ -15,14 +16,16 @@ const points = {};
async function initPoints(identifier) {
try {
const pointsFile = await fs.readFile(`./points-${identifier}.json`, 'utf-8');
const pointsFile = await fs.readFile(`./points/points-${identifier}.json`, 'utf-8');
Object.assign(points, JSON.parse(pointsFile));
} catch (error) {
if (error.code === 'ENOENT') {
logger.info('Creating new points file');
await fs.writeFile(`./points-${identifier}.json`, '{}');
await fs.mkdir('./points', { recursive: true });
await fs.writeFile(`./points/points-${identifier}.json`, '{}');
await initPoints(identifier);
}
}
@@ -50,7 +53,8 @@ async function setPoints(identifier, defaultKey, user, value, { mode = 'add', ke
points[gameKey][userKey] = value;
}
await fs.writeFile(`./points-${identifier}.json`, JSON.stringify(points, null, 4));
await fs.writeFile(`./points/points-${identifier}_backup${getWeek(new Date())}.json`, JSON.stringify(points, null, 4)); // weekly back-up
await fs.writeFile(`./points/points-${identifier}.json`, JSON.stringify(points, null, 4));
}
function getPoints(game, rawUsername, { user, room, command }) {
@@ -117,6 +121,11 @@ async function getGames(bot, identifier) {
const sendMessage = (body, roomId, options, recipient) => {
const curatedBody = curateMessageBody(body, game, key, options);
if (!roomId && !recipient) {
logger.error(`Missing room ID or recipient for message: ${body}`);
return;
}
if (config.platform === 'irc') {
bot.client.say(/^#/.test(roomId) ? roomId : recipient, curatedBody);
}

View File

@@ -130,6 +130,8 @@ function handleError(error, socket, domain, data) {
}
}
const pongRegex = /^pong:\d+$/;
async function connect(bot, games) {
const socket = {
ws: { readyState: 0 },
@@ -154,7 +156,7 @@ async function connect(bot, games) {
socket.ws.on('message', async (msgData) => {
const msg = msgData.toString();
if (typeof msg === 'string' && msg.includes('pong')) {
if (typeof msg === 'string' && pongRegex.test(msg)) {
logger.debug(`Received pong ${msg.split(':')[1]}`);
return;
}