2019-01-06 02:27:18 -05:00
|
|
|
<!doctype html>
|
2019-02-10 22:06:01 -05:00
|
|
|
<html manifest="cache.appcache">
|
2019-01-06 02:27:18 -05:00
|
|
|
<head>
|
2019-02-10 23:38:48 -05:00
|
|
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
|
|
|
<meta content="utf-8" http-equiv="encoding">
|
2019-02-11 00:56:46 -05:00
|
|
|
<title>Anagram Mastermind</title>
|
2019-02-10 21:32:17 -05:00
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
2019-01-06 02:27:18 -05:00
|
|
|
<link rel="stylesheet" type="text/css" href="main.css" />
|
2019-02-10 23:02:34 -05:00
|
|
|
<script type="text/javascript" src="../wordlist/typo.js"></script>
|
|
|
|
<script src="../wordlist/wordlist.js"></script>
|
2019-01-06 02:27:18 -05:00
|
|
|
<script src="./mastermind.js"></script>
|
|
|
|
<script >
|
|
|
|
// From https://stackoverflow.com/a/2450976
|
|
|
|
function shuffle(array) {
|
|
|
|
var currentIndex = array.length, temporaryValue, randomIndex;
|
|
|
|
|
|
|
|
// While there remain elements to shuffle...
|
|
|
|
while (0 !== currentIndex) {
|
|
|
|
|
|
|
|
// Pick a remaining element...
|
|
|
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
|
|
|
currentIndex -= 1;
|
|
|
|
|
|
|
|
// And swap it with the current element.
|
|
|
|
temporaryValue = array[currentIndex];
|
|
|
|
array[currentIndex] = array[randomIndex];
|
|
|
|
array[randomIndex] = temporaryValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
function clearElement(element) {
|
|
|
|
// From https://stackoverflow.com/a/3955238
|
|
|
|
while (element.firstChild) {
|
|
|
|
element.removeChild(element.firstChild);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-09 23:18:38 -05:00
|
|
|
class MastermindUI {
|
2019-02-09 20:25:37 -05:00
|
|
|
recolorAvailableLetters() {
|
2019-02-10 17:16:45 -05:00
|
|
|
let idx = this.focusedTextbox;
|
2019-02-10 15:42:26 -05:00
|
|
|
document.querySelectorAll('#available_letters button').forEach(b => {
|
|
|
|
// clear class list
|
|
|
|
while (b.classList.length > 0) {
|
|
|
|
b.classList.remove(b.classList.item(0));
|
|
|
|
}
|
|
|
|
|
2019-02-10 17:16:45 -05:00
|
|
|
let letter = b.innerText;
|
2019-02-10 22:16:16 -05:00
|
|
|
if (letter == '\xA0') {
|
|
|
|
b.classList.add('space');
|
|
|
|
return;
|
|
|
|
}
|
2019-02-10 17:16:45 -05:00
|
|
|
|
|
|
|
let info = this.game.knownInformation[letter];
|
|
|
|
let matchHere = this.game.knownMatches.has(idx);
|
|
|
|
|
|
|
|
let numEntered = 0;
|
|
|
|
let numEnteredAndKnown = 0;
|
|
|
|
for (let i=0; i < this.game.numLetters; i++) {
|
|
|
|
if (i == idx) continue;
|
|
|
|
if (this.letters[i] == letter) {
|
|
|
|
numEntered++;
|
|
|
|
numEnteredAndKnown++;
|
|
|
|
} else if (info.knownMatches.has(i)) {
|
|
|
|
numEnteredAndKnown++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let notHere = false;
|
|
|
|
|
|
|
|
if (matchHere && info.knownMatches.has(idx)) {
|
|
|
|
notHere = false;
|
|
|
|
} else if (matchHere && !info.knownMatches.has(idx)) {
|
|
|
|
notHere = true;
|
|
|
|
} else if (info.knownElsewheres.has(idx)) {
|
|
|
|
notHere = true;
|
|
|
|
} else if (numEntered >= info.max) {
|
|
|
|
notHere = true;
|
|
|
|
} else if (numEnteredAndKnown >= info.max) {
|
|
|
|
notHere = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let cls = 'unknown';
|
|
|
|
if (info.max == 0) {
|
|
|
|
cls = 'unused';
|
|
|
|
} else if (info.knownMatches.size) {
|
2019-02-10 15:42:26 -05:00
|
|
|
cls = 'match';
|
2019-02-10 17:16:45 -05:00
|
|
|
} else if (info.knownElsewheres.size) {
|
2019-02-10 15:42:26 -05:00
|
|
|
cls = 'elsewhere';
|
|
|
|
}
|
2019-02-10 17:16:45 -05:00
|
|
|
|
2019-02-10 15:42:26 -05:00
|
|
|
b.classList.add(cls);
|
2019-02-10 17:16:45 -05:00
|
|
|
if (notHere) b.classList.add('not_here');
|
2019-02-10 15:42:26 -05:00
|
|
|
});
|
2019-02-09 20:25:37 -05:00
|
|
|
}
|
2019-02-10 15:42:26 -05:00
|
|
|
|
2019-01-09 23:18:38 -05:00
|
|
|
shuffleAvailableLetters() {
|
|
|
|
var ui = this;
|
|
|
|
var letters = document.getElementById('available_letters');
|
|
|
|
clearElement(letters);
|
2019-02-10 22:16:16 -05:00
|
|
|
|
|
|
|
var space = document.createElement('button');
|
|
|
|
space.innerText = '\xA0'; //
|
|
|
|
space.addEventListener('click', button => ui.clearCurrent());
|
|
|
|
letters.appendChild(space);
|
|
|
|
|
2019-01-09 23:18:38 -05:00
|
|
|
shuffle(this.game.availableLetters).forEach(function(letter) {
|
|
|
|
var button = document.createElement('button');
|
|
|
|
button.innerText = letter;
|
|
|
|
button.addEventListener('click', button => ui.enterLetter(letter));
|
|
|
|
letters.appendChild(button);
|
|
|
|
});
|
2019-02-10 15:42:26 -05:00
|
|
|
this.recolorAvailableLetters();
|
2019-01-09 23:18:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
setFocusedTextbox(textbox) {
|
|
|
|
this.setFocusedTextboxIndex(this.textboxes.indexOf(textbox));
|
|
|
|
}
|
|
|
|
|
|
|
|
setFocusedTextboxIndex(i) {
|
2019-02-10 18:39:35 -05:00
|
|
|
if (i < 0) i = 0;
|
|
|
|
|
2019-01-09 23:18:38 -05:00
|
|
|
this.focusedTextbox = i;
|
|
|
|
|
|
|
|
while (this.focusedTextbox < this.game.numLetters
|
|
|
|
&& this.locks[this.focusedTextbox].checked) {
|
|
|
|
this.focusedTextbox++;
|
|
|
|
}
|
|
|
|
if (this.focusedTextbox >= this.game.numLetters) {
|
|
|
|
this.focusedTextbox = this.game.numLetters - 1;
|
|
|
|
}
|
|
|
|
|
2019-02-10 20:48:21 -05:00
|
|
|
for (let j = 0; j < this.textboxes.length; j++) {
|
2019-02-13 00:36:33 -05:00
|
|
|
this.textboxes[j].parentNode
|
|
|
|
.classList.toggle('focused', j == this.focusedTextbox);
|
2019-02-10 20:48:21 -05:00
|
|
|
}
|
2019-02-10 16:53:17 -05:00
|
|
|
|
|
|
|
this.recolorAvailableLetters();
|
2019-01-09 23:18:38 -05:00
|
|
|
}
|
|
|
|
|
2019-02-10 18:34:01 -05:00
|
|
|
focusPreviousTextbox() {
|
|
|
|
let i = this.focusedTextbox - 1;
|
|
|
|
|
|
|
|
while (i > 0 && this.locks[i].checked) {
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setFocusedTextboxIndex(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
focusNextTextbox() {
|
|
|
|
let i = this.focusedTextbox + 1;
|
|
|
|
if (i < this.game.numLetters) {
|
|
|
|
this.setFocusedTextboxIndex(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-09 23:18:38 -05:00
|
|
|
enterLetter(letter) {
|
|
|
|
if (!this.game.availableLetters.includes(letter)) {
|
2019-02-13 00:36:33 -05:00
|
|
|
this.textboxes[this.focusedTextbox].innerText = this.letters[this.focusedTextbox];
|
2019-01-09 23:18:38 -05:00
|
|
|
return;
|
|
|
|
}
|
2019-02-10 20:50:37 -05:00
|
|
|
if (this.locks[this.focusedTextbox].checked) {
|
|
|
|
this.focusNextTextbox();
|
|
|
|
return;
|
|
|
|
}
|
2019-01-09 23:18:38 -05:00
|
|
|
|
2019-02-13 00:36:33 -05:00
|
|
|
this.textboxes[this.focusedTextbox].innerText = letter;
|
2019-01-09 23:18:38 -05:00
|
|
|
this.letters[this.focusedTextbox] = letter;
|
|
|
|
this.setFocusedTextboxIndex(this.focusedTextbox + 1);
|
|
|
|
|
|
|
|
if (this.autoSubmit.checked) this.submitWord();
|
|
|
|
}
|
|
|
|
|
|
|
|
textEntered(textbox) {
|
|
|
|
var index = this.textboxes.indexOf(textbox);
|
|
|
|
if (this.locks[index].checked) {
|
2019-02-13 00:36:33 -05:00
|
|
|
textbox.innerText = this.letters[index];
|
2019-01-09 23:18:38 -05:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.setFocusedTextboxIndex(index);
|
2019-02-13 00:36:33 -05:00
|
|
|
this.enterLetter(textbox.innerText.slice(-1).toLowerCase());
|
2019-01-09 23:18:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
clearAll() {
|
|
|
|
for (var i = 0; i < this.game.numLetters; i++) {
|
|
|
|
this.locks[i].checked = false;
|
|
|
|
}
|
2019-01-09 23:19:57 -05:00
|
|
|
this.clearUnlocked();
|
2019-01-09 23:18:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
clearUnlocked() {
|
|
|
|
for (var i = 0; i < this.game.numLetters; i++) {
|
|
|
|
if (!this.locks[i].checked) {
|
2019-02-13 00:36:33 -05:00
|
|
|
this.textboxes[i].innerText = '\xA0';
|
2019-01-09 23:18:38 -05:00
|
|
|
this.letters[i] = '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.setFocusedTextboxIndex(0);
|
|
|
|
}
|
|
|
|
|
2019-02-10 18:34:01 -05:00
|
|
|
clearCurrent() {
|
|
|
|
let i = this.focusedTextbox;
|
|
|
|
if (this.locks[i].checked) return;
|
2019-02-13 00:36:33 -05:00
|
|
|
this.textboxes[i].innerText = '\xA0';
|
2019-02-10 18:34:01 -05:00
|
|
|
this.letters[i] = '';
|
|
|
|
}
|
|
|
|
|
2019-01-09 23:18:38 -05:00
|
|
|
submitWord() {
|
2019-02-10 16:16:30 -05:00
|
|
|
if (this.won) return;
|
2019-01-09 23:18:38 -05:00
|
|
|
if (!this.letters.every(letter => letter != '')) return;
|
|
|
|
var guess = this.letters.join('');
|
|
|
|
var results = this.game.makeGuess(guess);
|
|
|
|
if (results == null) return;
|
|
|
|
|
2019-02-10 20:28:30 -05:00
|
|
|
var resultDisplay = document.createElement('tr');
|
2019-01-09 23:18:38 -05:00
|
|
|
resultDisplay.classList.add('guess');
|
|
|
|
|
|
|
|
for (var i = 0; i < this.game.numLetters; i++) {
|
2019-02-10 20:28:30 -05:00
|
|
|
var letter = document.createElement('td');
|
2019-01-09 23:18:38 -05:00
|
|
|
letter.innerText = this.letters[i];
|
|
|
|
letter.classList.add(results.letters[i].description);
|
|
|
|
resultDisplay.appendChild(letter);
|
|
|
|
}
|
2019-02-13 00:16:57 -05:00
|
|
|
let link = document.createElement('a');
|
|
|
|
link.classList.add('dictionary_link');
|
|
|
|
link.href = 'https://en.wiktionary.org/wiki/' + guess;
|
|
|
|
link.target = '_blank';
|
|
|
|
link.innerText = '🕮';
|
|
|
|
let linkCell = document.createElement('td');
|
|
|
|
linkCell.classList.add('dictionary_link');
|
|
|
|
linkCell.appendChild(link);
|
|
|
|
resultDisplay.appendChild(linkCell);
|
2019-01-09 23:18:38 -05:00
|
|
|
|
2019-02-10 20:28:30 -05:00
|
|
|
var guesses = document.getElementById('guesses');
|
2019-01-09 23:18:38 -05:00
|
|
|
guesses.appendChild(resultDisplay);
|
|
|
|
|
|
|
|
this.clearUnlocked();
|
2019-02-10 15:42:26 -05:00
|
|
|
this.recolorAvailableLetters();
|
2019-02-10 16:16:30 -05:00
|
|
|
|
|
|
|
if (results.correct) {
|
|
|
|
this.won = true;
|
2019-02-10 20:28:30 -05:00
|
|
|
document.getElementById('letters_entry').style.display = 'none';
|
|
|
|
document.getElementById('submit_buttons').style.display = 'none';
|
2019-02-10 16:16:30 -05:00
|
|
|
document.getElementById('endgame').style.display = '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
newGame() {
|
|
|
|
this.initialize(Mastermind.generateRandom());
|
2019-01-09 23:18:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
constructor(game) {
|
2019-02-10 16:16:30 -05:00
|
|
|
var ui = this;
|
|
|
|
document.getElementById('submit')
|
|
|
|
.addEventListener('click', _ => ui.submitWord());
|
|
|
|
document.getElementById('clear')
|
|
|
|
.addEventListener('click', _ => ui.clearAll());
|
2019-02-10 22:40:58 -05:00
|
|
|
document.getElementById('clear_nonlocked')
|
|
|
|
.addEventListener('click', _ => ui.clearUnlocked());
|
2019-02-10 16:16:30 -05:00
|
|
|
document.getElementById('newgame')
|
|
|
|
.addEventListener('click', _ => ui.newGame());
|
2019-02-10 20:48:21 -05:00
|
|
|
document.addEventListener('keyup', event => {
|
|
|
|
if (event.key === "Enter") {
|
|
|
|
ui.submitWord();
|
|
|
|
} else if (event.key === "Backspace") {
|
|
|
|
if (ui.focusedTextbox < ui.game.numLetters - 1
|
|
|
|
|| ui.letters[ui.game.numLetters - 1] == '') {
|
|
|
|
ui.focusPreviousTextbox();
|
|
|
|
}
|
|
|
|
ui.clearCurrent();
|
|
|
|
} else if (event.key === "Clear" || event.key == "Delete") {
|
|
|
|
ui.clearCurrent();
|
|
|
|
} else if (event.key === "ArrowLeft") {
|
|
|
|
ui.focusPreviousTextbox();
|
|
|
|
} else if (event.key === "ArrowRight" || event.key === "Space") {
|
|
|
|
ui.focusNextTextbox();
|
|
|
|
} else if (event.key === "Home") {
|
|
|
|
ui.setFocusedTextboxIndex(0);
|
|
|
|
} else if (event.key === "End") {
|
|
|
|
ui.setFocusedTextboxIndex(ui.game.numLetters - 1);
|
|
|
|
} else if (event.key === "/") {
|
|
|
|
let lock = ui.locks[ui.focusedTextbox];
|
|
|
|
lock.checked = !lock.checked;
|
|
|
|
ui.setFocusedTextboxIndex(ui.focusedTextbox);
|
|
|
|
} else if (event.key === "?") {
|
|
|
|
ui.locks.forEach(lock => lock.checked = false);
|
|
|
|
} else if (ui.game.availableLetters.includes(event.key)) {
|
|
|
|
ui.enterLetter(event.key);
|
|
|
|
}
|
|
|
|
});
|
2019-02-13 01:41:52 -05:00
|
|
|
document.getElementById('copy_permalink')
|
|
|
|
.addEventListener('click', _ => {
|
|
|
|
let permalink = document.getElementById('permalink_input');
|
|
|
|
permalink.focus();
|
|
|
|
let range = document.createRange();
|
|
|
|
range.selectNodeContents(permalink);
|
|
|
|
|
|
|
|
let s = window.getSelection();
|
|
|
|
s.removeAllRanges();
|
|
|
|
s.addRange(range);
|
|
|
|
|
|
|
|
permalink.setSelectionRange(0, permalink.value.length);
|
|
|
|
|
|
|
|
document.execCommand('copy');
|
|
|
|
|
|
|
|
permalink.blur();
|
|
|
|
});
|
2019-02-10 16:16:30 -05:00
|
|
|
|
|
|
|
this.initialize(game);
|
|
|
|
}
|
|
|
|
|
|
|
|
initialize(game) {
|
|
|
|
this.won = false;
|
2019-01-09 23:18:38 -05:00
|
|
|
this.game = game;
|
|
|
|
var ui = this;
|
|
|
|
|
2019-02-10 20:18:51 -05:00
|
|
|
game.getFragment('BE')
|
|
|
|
.catch(_ => game.getFragment('B'))
|
|
|
|
.then(fragment => {
|
2019-02-10 22:05:32 -05:00
|
|
|
document.getElementById('permalink').href = '#' + fragment;
|
2019-02-13 01:41:52 -05:00
|
|
|
document.getElementById('permalink_input').value
|
|
|
|
= window.location.href.split('#')[0] + '#' + fragment;
|
2019-02-10 18:16:07 -05:00
|
|
|
});
|
2019-02-10 16:16:30 -05:00
|
|
|
|
2019-01-09 23:18:38 -05:00
|
|
|
var len = game.numLetters;
|
|
|
|
|
|
|
|
var shuffle = document.getElementById('shuffle');
|
|
|
|
// Clear event listeners. From https://stackoverflow.com/a/19470348
|
|
|
|
var newShuffle = shuffle.cloneNode(true)
|
|
|
|
shuffle.parentNode.replaceChild(newShuffle, shuffle);
|
|
|
|
newShuffle.addEventListener('click', function() {
|
|
|
|
ui.shuffleAvailableLetters();
|
|
|
|
});
|
|
|
|
|
|
|
|
this.autoSubmit = document.getElementById('auto_submit');
|
|
|
|
|
|
|
|
var entry = document.getElementById('letters_entry');
|
|
|
|
clearElement(entry);
|
|
|
|
this.textboxes = new Array(len);
|
|
|
|
this.letters = new Array(len);
|
|
|
|
this.letters.fill('');
|
|
|
|
this.locks = new Array(len);
|
|
|
|
this.focusedTextbox = 0;
|
2019-02-10 22:33:20 -05:00
|
|
|
for (let i=0; i < len; i++) {
|
|
|
|
let t = document.getElementById('letter_entry');
|
|
|
|
let clone = document.importNode(t.content, true);
|
2019-01-09 23:18:38 -05:00
|
|
|
|
2019-02-10 22:33:20 -05:00
|
|
|
let lock_checkbox = clone.querySelector('input.lock');
|
2019-02-10 18:34:01 -05:00
|
|
|
this.locks[i] = lock_checkbox;
|
|
|
|
lock_checkbox.id = 'lock' + i;
|
2019-02-10 22:33:20 -05:00
|
|
|
lock_checkbox.addEventListener('change', e => {
|
|
|
|
if (e.target.checked && ui.letters[i] == ''
|
|
|
|
&& ui.game.knownMatches.has(i)) {
|
|
|
|
let letter = '';
|
|
|
|
Object.values(ui.game.knownInformation).forEach(info => {
|
|
|
|
if (info.knownMatches.has(i)) {
|
|
|
|
letter = info.letter;
|
|
|
|
}
|
|
|
|
});
|
2019-02-13 00:36:33 -05:00
|
|
|
ui.textboxes[i].innerText = letter;
|
2019-02-10 22:33:20 -05:00
|
|
|
ui.letters[i] = letter;
|
|
|
|
}
|
|
|
|
});
|
2019-02-10 18:34:01 -05:00
|
|
|
clone.querySelector('label.lock_label').htmlFor = 'lock' + i;
|
|
|
|
|
2019-02-13 00:36:33 -05:00
|
|
|
let textbox = clone.querySelector('span.letter');
|
2019-01-09 23:18:38 -05:00
|
|
|
this.textboxes[i] = textbox;
|
2019-02-13 00:36:33 -05:00
|
|
|
textbox.parentNode.addEventListener('click', e => {
|
|
|
|
ui.setFocusedTextboxIndex(i);
|
|
|
|
});
|
2019-01-09 23:18:38 -05:00
|
|
|
|
|
|
|
entry.appendChild(clone);
|
|
|
|
}
|
2019-01-06 02:27:18 -05:00
|
|
|
|
2019-02-13 00:36:33 -05:00
|
|
|
ui.setFocusedTextbox(this.focusedTextbox);
|
2019-02-10 16:16:30 -05:00
|
|
|
|
2019-02-10 17:16:45 -05:00
|
|
|
this.shuffleAvailableLetters();
|
|
|
|
|
2019-02-10 16:16:30 -05:00
|
|
|
clearElement(document.getElementById('guesses'));
|
2019-02-10 20:28:30 -05:00
|
|
|
document.getElementById('letters_entry').style.display = '';
|
|
|
|
document.getElementById('submit_buttons').style.display = '';
|
2019-02-10 16:16:30 -05:00
|
|
|
document.getElementById('endgame').style.display = 'none';
|
2019-01-06 02:27:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function loaded() {
|
2019-02-09 20:04:37 -05:00
|
|
|
dictionaryPromise.then(_ =>
|
|
|
|
topWordsPromise
|
2019-02-13 01:41:52 -05:00
|
|
|
.then(_ => {
|
|
|
|
let fragment = window.location.hash.substring(1);
|
|
|
|
history.pushState("", document.title, window.location.pathname + window.location.search);
|
|
|
|
return Mastermind.fromFragment(fragment);
|
|
|
|
})
|
2019-02-10 18:16:07 -05:00
|
|
|
.then(game => {
|
2019-02-10 15:36:30 -05:00
|
|
|
if (game === null) {
|
|
|
|
game = Mastermind.generateRandom();
|
|
|
|
}
|
|
|
|
return new MastermindUI(game);
|
|
|
|
}));
|
2019-01-06 02:27:18 -05:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
<template id="letter_entry">
|
2019-02-10 20:37:54 -05:00
|
|
|
<td class="letter_entry">
|
|
|
|
<input type="checkbox" class="lock" />
|
2019-01-06 02:27:18 -05:00
|
|
|
<div class="lock">
|
|
|
|
<label class="lock_label" />
|
|
|
|
</div>
|
|
|
|
<div class="letter">
|
2019-02-13 00:36:33 -05:00
|
|
|
<span class="letter"> </span>
|
2019-01-06 02:27:18 -05:00
|
|
|
</div>
|
|
|
|
<div class="focus_indicator"></div>
|
2019-02-10 20:37:54 -05:00
|
|
|
</td>
|
2019-01-06 02:27:18 -05:00
|
|
|
</template>
|
|
|
|
</head>
|
|
|
|
<body onload="loaded();">
|
2019-02-13 01:07:13 -05:00
|
|
|
<label id="settings_toggle_label" for="settings_toggle">⚙</label>
|
|
|
|
<input type="checkbox" id="settings_toggle"></input>
|
|
|
|
<div id="settings">
|
|
|
|
<h1>Settings</h1>
|
2019-02-13 01:41:52 -05:00
|
|
|
<a href="#" target="_blank" id="permalink">Permalink</a>
|
|
|
|
to current puzzle:
|
|
|
|
<input contenteditable id="permalink_input" />
|
|
|
|
<button id="copy_permalink">Copy</button>
|
2019-02-13 01:07:13 -05:00
|
|
|
<h1>How to Play</h1>
|
|
|
|
<h2>Gameplay</h2>
|
|
|
|
<p>
|
|
|
|
Anagram Mastermind is a variant of the classic game
|
|
|
|
<a href="https://en.wikipedia.org/wiki/Mastermind_(board_game)"
|
|
|
|
>Mastermind</a> where the secret clue and guesses must all be
|
|
|
|
English words. The computer randomly selects a word and a set
|
|
|
|
of letters that may be used in guesses and tells you how many
|
|
|
|
letters are in the word. In response to each guess, the computer
|
|
|
|
responds with whether each letter was in the correct place, a
|
|
|
|
correct letter but in the wrong place, or an incorrect letter.
|
|
|
|
For example, if the secret word was <q>swept</q> and you guessed
|
|
|
|
<q>trees</q>, the computer would respond as follows:
|
|
|
|
<table class="guesses">
|
|
|
|
<tr class="guess">
|
|
|
|
<td class="elsewhere">t</td>
|
|
|
|
<td class="unused">r</td>
|
|
|
|
<td class="match">e</td>
|
|
|
|
<td class="unused">e</td>
|
|
|
|
<td class="elsewhere">s</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
This indicates that the middle <q>e</q> is the correct letter in the
|
|
|
|
correct position, the secret word has a <q>t</q> and <q>s</q> in it,
|
|
|
|
but not in those positions, and that the secret word does not have
|
|
|
|
an <q>r</q> or another <q>e</q>.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<h2>Interface</h2>
|
|
|
|
<p>
|
|
|
|
You can enter letters in any order; the current letter being edited
|
|
|
|
is highlighted with a yellow border. Clicking/tapping on the position
|
|
|
|
for another letter will select it. In order to aid in entering
|
|
|
|
letters out of order, letters may be frozen by clicking the
|
|
|
|
sun (🌞) above the entry box which will toggle it to a
|
|
|
|
snowflake (❄) to indicate that letter is frozen. If no letter
|
|
|
|
had been entered in that position but a previous guess had revealed
|
|
|
|
the correct letter for that position, it will be copied in
|
|
|
|
automatically.
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
The buttons for entering letters will change color to convey the
|
|
|
|
knowledge from the computer's responses. The colors will match
|
|
|
|
those of the responses, and, additionally, will be slightly grayed
|
|
|
|
out variants of those colors if the next letter to be entered is
|
|
|
|
a position that is definitely not that letter (e.g. if another
|
|
|
|
letter is already known match there).
|
|
|
|
</p>
|
|
|
|
</div>
|
2019-02-10 20:28:30 -05:00
|
|
|
<table id="guesses_and_entry">
|
2019-02-13 00:36:33 -05:00
|
|
|
<tbody id="guesses" class="guesses"></tbody>
|
2019-02-10 20:37:54 -05:00
|
|
|
<tr id="letters_entry"></tr>
|
2019-02-10 20:28:30 -05:00
|
|
|
</table>
|
|
|
|
<div id="submit_buttons">
|
2019-02-10 22:40:58 -05:00
|
|
|
<button id="clear">Clear All</button>
|
|
|
|
<button id="clear_nonlocked">Clear Non-Frozen</button>
|
2019-02-10 20:28:30 -05:00
|
|
|
<button id="submit">Submit Word</button>
|
|
|
|
<label>
|
2019-02-11 00:57:38 -05:00
|
|
|
<input type="checkbox" id="auto_submit" checked />
|
2019-02-10 20:28:30 -05:00
|
|
|
Auto-Submit
|
|
|
|
</label>
|
|
|
|
</div>
|
2019-02-10 16:16:30 -05:00
|
|
|
<div id="endgame">
|
|
|
|
<button id="newgame">New Game</button>
|
|
|
|
</div>
|
2019-01-06 02:27:18 -05:00
|
|
|
<div id="available_letters_display">
|
|
|
|
<button id="shuffle"></button>
|
|
|
|
<div id="available_letters"></div>
|
2019-02-10 22:39:01 -05:00
|
|
|
</div>
|
2019-01-06 02:27:18 -05:00
|
|
|
</body>
|
|
|
|
</html>
|