/*
* Hangman chat plugin
* By bumbadadabum and Zarel. Art by crobat.
*/
import {Utils} from '../../lib/utils';
const maxMistakes = 6;
export class Hangman extends Rooms.RoomGame {
gameNumber: number;
creator: ID;
word: string;
hint: string;
incorrectGuesses: number;
guesses: string[];
letterGuesses: string[];
lastGuesser: string;
wordSoFar: string[];
readonly checkChat = true;
constructor(room: Room, user: User, word: string, hint = '') {
super(room);
this.gameNumber = room.nextGameNumber();
this.gameid = 'hangman' as ID;
this.title = 'Hangman';
this.creator = user.id;
this.word = word;
this.hint = hint;
this.incorrectGuesses = 0;
this.guesses = [];
this.letterGuesses = [];
this.lastGuesser = '';
this.wordSoFar = [];
for (const letter of word) {
if (/[a-zA-Z]/.test(letter)) {
this.wordSoFar.push('_');
} else {
this.wordSoFar.push(letter);
}
}
}
choose(user: User, word: string) {
if (user.id === this.creator) throw new Chat.ErrorMessage("You can't guess in your own hangman game.");
const sanitized = word.replace(/[^A-Za-z ]/g, '');
const normalized = toID(sanitized);
if (normalized.length < 1) {
throw new Chat.ErrorMessage(`Use "/guess [letter]" to guess a letter, or "/guess [phrase]" to guess the entire Hangman phrase.`);
}
if (sanitized.length > 30) throw new Chat.ErrorMessage(`Guesses must be 30 or fewer letters – "${word}" is too long.`);
for (const guessid of this.guesses) {
if (normalized === toID(guessid)) throw new Chat.ErrorMessage(`Your guess "${word}" has already been guessed.`);
}
if (sanitized.length > 1) {
if (!this.guessWord(sanitized, user.name)) {
throw new Chat.ErrorMessage(`Your guess "${sanitized}" is invalid.`);
} else {
this.room.send(`${user.name} guessed "${sanitized}"!`);
}
} else {
if (!this.guessLetter(sanitized, user.name)) {
throw new Chat.ErrorMessage(`Your guess "${sanitized}" is not a valid letter.`);
}
}
}
guessLetter(letter: string, guesser: string) {
letter = letter.toUpperCase();
if (this.guesses.includes(letter)) return false;
if (this.word.toUpperCase().includes(letter)) {
for (let i = 0; i < this.word.length; i++) {
if (this.word[i].toUpperCase() === letter) {
this.wordSoFar[i] = this.word[i];
}
}
if (!this.wordSoFar.includes('_')) {
this.incorrectGuesses = -1;
this.guesses.push(letter);
this.letterGuesses.push(`${letter}1`);
this.lastGuesser = guesser;
this.finish();
return true;
}
this.letterGuesses.push(`${letter}1`);
} else {
this.incorrectGuesses++;
this.letterGuesses.push(`${letter}0`);
}
this.guesses.push(letter);
this.lastGuesser = guesser;
this.update();
return true;
}
guessWord(word: string, guesser: string) {
const ourWord = toID(this.word);
const guessedWord = toID(word);
if (ourWord === guessedWord) {
for (const [i, letter] of this.wordSoFar.entries()) {
if (letter === '_') {
this.wordSoFar[i] = this.word[i];
}
}
this.incorrectGuesses = -1;
this.guesses.push(word);
this.lastGuesser = guesser;
this.finish();
return true;
} else if (ourWord.length === guessedWord.length) {
this.incorrectGuesses++;
this.guesses.push(word);
this.lastGuesser = guesser;
this.update();
return true;
}
return false;
}
hangingMan() {
return `
`;
}
generateWindow() {
let result = 0;
if (this.incorrectGuesses === maxMistakes) {
result = 1;
} else if (!this.wordSoFar.includes('_')) {
result = 2;
}
const color = result === 1 ? 'red' : (result === 2 ? 'green' : 'blue');
const message = `${result === 1 ? 'Too bad! The mon has been hanged.' : (result === 2 ? 'The word has been guessed. Congratulations!' : 'Hangman')}`;
let output = `
${message}
`; output += `| ${this.hangingMan()} | `;
let wordString = this.wordSoFar.join('');
if (result === 1) {
const word = this.word;
wordString = wordString.replace(
/_+/g,
(match, offset) => `${word.substr(offset, match.length)}`
);
}
if (this.hint) output += Utils.html` (Hint: ${this.hint}) `;
output += `${wordString} `; if (this.guesses.length) { if (this.letterGuesses.length) { output += 'Letters: ' + this.letterGuesses.map( g => `${Utils.escapeHTML(g[0])}` ).join(', '); } if (result === 2) { output += Utils.html`Winner: ${this.lastGuesser}`; } else if (this.guesses[this.guesses.length - 1].length === 1) { // last guess was a letter output += Utils.html` – ${this.lastGuesser}`; } else { output += Utils.html` Guessed: ${this.guesses[this.guesses.length - 1]} ` + `– ${this.lastGuesser}`; } } output += ' |