Compare commits

..

No commits in common. "da4a87eb8603c8fa34442b5b43f8e20010681c27" and "947ed37974c2e239a7c9565c4ed44c5a6022c8a5" have entirely different histories.

10 changed files with 68 additions and 1247 deletions

View file

@ -5,9 +5,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt"
"github.com/PuerkitoBio/goquery" "github.com/PuerkitoBio/goquery"
"github.com/bitfield/script"
gonanoid "github.com/matoous/go-nanoid" gonanoid "github.com/matoous/go-nanoid"
"log" "log"
"math/rand/v2" "math/rand/v2"
@ -19,8 +17,6 @@ import (
"time" "time"
) )
const maxWordLength = 7
var validWordRegex = regexp.MustCompile(`^[a-z]+$`) var validWordRegex = regexp.MustCompile(`^[a-z]+$`)
type wordList struct { type wordList struct {
@ -50,7 +46,7 @@ func main() {
return return
} }
if len(w) >= 4 && len(w) <= maxWordLength { if len(w) >= 4 && len(w) <= 6 {
wordSet[word] = true wordSet[word] = true
} }
}); err != nil { }); err != nil {
@ -85,7 +81,7 @@ func main() {
pattern[i] = i pattern[i] = i
} }
for x := 12; x < r.IntN(8)+16; x++ { for x := 4; x < r.IntN(8)+4; x++ {
r.Shuffle(len(pattern), func(i, j int) { r.Shuffle(len(pattern), func(i, j int) {
pattern[i], pattern[j] = pattern[j], pattern[i] pattern[i], pattern[j] = pattern[j], pattern[i]
}) })
@ -113,7 +109,7 @@ func scanSuitableWords(dictDir string, withWord func(word string)) error {
return err return err
} }
if err := scanSuitableWordsFromEnGB(filepath.Join(dictDir, "en_GB.dic"), filepath.Join(dictDir, "en_GB.aff"), withWord); err != nil { if err := scanSuitableWordsFromEnGB(filepath.Join(dictDir, "en_GB.dic"), withWord); err != nil {
return err return err
} }
@ -153,14 +149,35 @@ func scanSuitableWordsFromOxford3000(dictFile string, withWord func(word string)
return scanner.Err() return scanner.Err()
} }
func scanSuitableWordsFromEnGB(dictFile, affFile string, withWord func(word string)) error { func scanSuitableWordsFromEnGB(dictFile string, withWord func(word string)) error {
words, err := script.Exec(fmt.Sprintf("unmunch '%v' '%v'", dictFile, affFile)).String() f, err := os.Open(dictFile)
if err != nil { if err != nil {
return err return err
} }
defer f.Close()
for _, word := range strings.Split(words, "\n") { scanner := bufio.NewScanner(f)
withWord(word) for scanner.Scan() {
isSuitable := true
breakpoint := len(scanner.Text())
for i, r := range scanner.Text() {
if r == '/' {
breakpoint = i
break
} }
return nil
if r < 'a' || r > 'z' {
isSuitable = false
break
}
}
if isSuitable {
word := scanner.Text()[:breakpoint]
withWord(word)
} else {
}
}
return scanner.Err()
} }

View file

@ -2,12 +2,8 @@ oxford-word-list.htm
Taken from https://www.oxfordwordlist.com/pages/report.asp Taken from https://www.oxfordwordlist.com/pages/report.asp
en_GB.dic en_GB.dic
en_GB.aff
This is a Hunspell dictionary taken from this location: This is a Hunspell dictionary taken from this location:
https://archive.netbsd.org/pub/pkgsrc-archive/distfiles/2019Q4/hunspell-dictionaries/en_GB-20061130/en_GB.zip https://archive.netbsd.org/pub/pkgsrc-archive/distfiles/2019Q4/hunspell-dictionaries/en_GB-20061130/en_GB.zip
The possible set of words is produced by running it through "unmunch" as per this Stack Overflow answer:
https://stackoverflow.com/questions/42566916/how-to-obtain-all-possible-words-from-given-hunspell-dictionary
The_Oxford_3000.txt The_Oxford_3000.txt
https://github.com/sapbmw/The-Oxford-3000/blob/master/The_Oxford_3000.txt https://github.com/sapbmw/The-Oxford-3000/blob/master/The_Oxford_3000.txt

File diff suppressed because it is too large Load diff

4
go.mod
View file

@ -5,10 +5,6 @@ go 1.23.3
require ( require (
github.com/PuerkitoBio/goquery v1.10.2 // indirect github.com/PuerkitoBio/goquery v1.10.2 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/bitfield/script v0.24.0 // indirect
github.com/itchyny/gojq v0.12.13 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/matoous/go-nanoid v1.5.1 // indirect github.com/matoous/go-nanoid v1.5.1 // indirect
golang.org/x/net v0.35.0 // indirect golang.org/x/net v0.35.0 // indirect
mvdan.cc/sh/v3 v3.7.0 // indirect
) )

8
go.sum
View file

@ -2,13 +2,7 @@ github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9Hq
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU= github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/bitfield/script v0.24.0 h1:ic0Tbx+2AgRtkGGIcUyr+Un60vu4WXvqFrCSumf+T7M=
github.com/bitfield/script v0.24.0/go.mod h1:fv+6x4OzVsRs6qAlc7wiGq8fq1b5orhtQdtW0dwjUHI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/matoous/go-nanoid v1.5.1 h1:aCjdvTyO9LLnTIi0fgdXhOPPvOHjpXN6Ik9DaNjIct4= github.com/matoous/go-nanoid v1.5.1 h1:aCjdvTyO9LLnTIi0fgdXhOPPvOHjpXN6Ik9DaNjIct4=
github.com/matoous/go-nanoid v1.5.1/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U= github.com/matoous/go-nanoid v1.5.1/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@ -77,5 +71,3 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -71,7 +71,7 @@ export default class extends Controller {
} }
} }
async _verifyGuess(rowElem) { _verifyGuess(rowElem) {
let guessedWord = Array.from(rowElem.querySelectorAll("span")).map((x) => x.innerText).join(""); let guessedWord = Array.from(rowElem.querySelectorAll("span")).map((x) => x.innerText).join("");
console.log("The guessed word is: " + guessedWord); console.log("The guessed word is: " + guessedWord);
@ -91,8 +91,7 @@ export default class extends Controller {
})); }));
break; break;
case GUESS_RESULT.MISS: case GUESS_RESULT.MISS:
await this._colorizeRow(rowElem, results, true); this._colorizeRow(rowElem, results);
this._broadcastGuessResults(results);
this._activeRowIndex += 1; this._activeRowIndex += 1;
if (this._activeRowIndex >= this._gameController.guesses()) { if (this._activeRowIndex >= this._gameController.guesses()) {
@ -104,8 +103,7 @@ export default class extends Controller {
break; break;
case GUESS_RESULT.WIN: case GUESS_RESULT.WIN:
await this._colorizeRow(rowElem, results, true); this._colorizeRow(rowElem, results);
this._broadcastGuessResults(results);
this._showWin(); this._showWin();
break; break;
} }
@ -141,7 +139,6 @@ export default class extends Controller {
window.dispatchEvent(new CustomEvent("resetKeyColors")); window.dispatchEvent(new CustomEvent("resetKeyColors"));
let newRows = []; let newRows = [];
let lastGuessResults = null;
for (let r = 0; r < rows; r++) { for (let r = 0; r < rows; r++) {
let currentGuess = null; let currentGuess = null;
let currentGuessResults = null; let currentGuessResults = null;
@ -153,14 +150,12 @@ export default class extends Controller {
newRows.push(this._buildPlayfieldRow(wordLength, currentGuess, currentGuessResults)); newRows.push(this._buildPlayfieldRow(wordLength, currentGuess, currentGuessResults));
if (currentGuessResults) { if (currentGuessResults) {
lastGuessResults = currentGuessResults; window.dispatchEvent(new CustomEvent("guessResults", {
detail: currentGuessResults
}));
} }
} }
if (lastGuessResults != null) {
this._broadcastGuessResults(lastGuessResults);
}
if (wasWin) { if (wasWin) {
this._showWin(); this._showWin();
} else if (currentGuesses.length >= rows) { } else if (currentGuesses.length >= rows) {
@ -190,54 +185,34 @@ export default class extends Controller {
} }
if (currentGuess) { if (currentGuess) {
this._colorizeRow(divElem, currentGuessResults, false); this._colorizeRow(divElem, currentGuessResults);
} }
return divElem; return divElem;
} }
async _colorizeRow(row, results, delayed) { _colorizeRow(row, results) {
let markers = results.markers; let markers = results.markers;
if (delayed) {
row.classList.add("animated-colors");
}
for (let i = 0; i < this._gameController.wordLength(); i++) { for (let i = 0; i < this._gameController.wordLength(); i++) {
this._colorizeCell(row, results, i); switch (markers[i]) {
case MARKERS.RIGHT_POS:
row.children[i].classList.add("right-pos");
break;
case MARKERS.RIGHT_CHAR:
row.children[i].classList.add("right-char");
break;
case MARKERS.MISS:
row.children[i].classList.add("miss");
break;
}
} }
if (delayed) {
return new Promise(resolve => {
row.children[row.children.length - 1].addEventListener("transitionend", () => {
resolve();
});
});
}
return Promise.resolve();
}
_broadcastGuessResults(results) {
window.dispatchEvent(new CustomEvent("guessResults", { window.dispatchEvent(new CustomEvent("guessResults", {
detail: results detail: results
})); }));
} }
_colorizeCell(row, results, cellIndex) {
let markers = results.markers;
switch (markers[cellIndex]) {
case MARKERS.RIGHT_POS:
row.children[cellIndex].classList.add("right-pos");
break;
case MARKERS.RIGHT_CHAR:
row.children[cellIndex].classList.add("right-char");
break;
case MARKERS.MISS:
row.children[cellIndex].classList.add("miss");
break;
}
}
_showHints(row) { _showHints(row) {
let hint = this._gameController.showHint(); let hint = this._gameController.showHint();

View file

@ -26,7 +26,7 @@ class ProgressionState {
let prog = { let prog = {
shuffleId: shuffleId, shuffleId: shuffleId,
wordLength: 4, wordLength: 4,
wordIndex: {"4": 0, "5": 0, "6": 0, "7": 0}, wordIndex: {"4": 0, "5": 0, "6": 0},
currentGuesses: [] currentGuesses: []
}; };
localStorage.setItem('progression', JSON.stringify(prog)); localStorage.setItem('progression', JSON.stringify(prog));
@ -53,7 +53,7 @@ export class GameController {
} }
this._currentWord = await this._wordSource.getCurrentWord(prog); this._currentWord = await this._wordSource.getCurrentWord(prog);
this._guesses = 6; this._guesses = Math.max(this._currentWord.length, 5) + 1;
console.log("The current word: " + this._currentWord); console.log("The current word: " + this._currentWord);
} }
@ -88,17 +88,13 @@ export class GameController {
// Increment the progress // Increment the progress
let prog = this._progressionState.getProgression(); let prog = this._progressionState.getProgression();
prog.wordIndex[prog.wordLength + ""] += 1; prog.wordIndex[prog.wordLength + ""] += 1;
prog.wordLength = (((Math.random() * 23) | 0) / 10 | 0) + 4;
//prog.wordLength = (((Math.random() * 23) | 0) / 10 | 0) + 4;
prog.wordLength = ((Math.random() * 4) | 0) + 4;
prog.currentGuesses = []; prog.currentGuesses = [];
prog.wasWin = false; prog.wasWin = false;
this._progressionState.saveProgression(prog); this._progressionState.saveProgression(prog);
this._currentWord = await this._wordSource.getCurrentWord(prog); this._currentWord = await this._wordSource.getCurrentWord(prog);
//this._guesses = Math.max(this._currentWord.length, 5) + 1; this._guesses = Math.max(this._currentWord.length, 5) + 1;
this._guesses = 6;
return true; return true;
} }
@ -149,6 +145,20 @@ export class GameController {
let misses = {}; let misses = {};
let hits = {}; let hits = {};
if (this._currentWord.length <= 5) {
if (!this._wordSource.isWord(guess)) {
hits = {};
for (let i = 0; i < guess.length; i++) {
hits[guess[i]] = MARKERS.ATTEMPTED;
}
return {
hits: hits,
guessResult: GUESS_RESULT.FOUL,
};
}
}
for (let i = 0; i < guess.length; i++) { for (let i = 0; i < guess.length; i++) {
if (guess[i] == this._currentWord[i]) { if (guess[i] == this._currentWord[i]) {
markers[i] = MARKERS.RIGHT_POS; markers[i] = MARKERS.RIGHT_POS;

View file

@ -152,21 +152,6 @@ div.playfield div.row span {
margin: 5px; margin: 5px;
} }
div.playfield div.row.animated-colors span {
transition-property: background-color, color;
transition-duration: 0.15s;
}
div.playfield div.row.animated-colors span:nth-child(1) { transition-delay: 0s; }
div.playfield div.row.animated-colors span:nth-child(2) { transition-delay: 0.2s; }
div.playfield div.row.animated-colors span:nth-child(3) { transition-delay: 0.4s; }
div.playfield div.row.animated-colors span:nth-child(4) { transition-delay: 0.6s; }
div.playfield div.row.animated-colors span:nth-child(5) { transition-delay: 0.8s; }
div.playfield div.row.animated-colors span:nth-child(6) { transition-delay: 1.0s; }
div.playfield div.row.animated-colors span:nth-child(7) { transition-delay: 1.2s; }
div.playfield div.row.animated-colors span:nth-child(8) { transition-delay: 1.4s; }
div.playfield div.row span.hint { div.playfield div.row span.hint {
color: var(--color-hint); color: var(--color-hint);
} }