Have got a dictionary of words

This commit is contained in:
Leon Mika 2025-01-25 09:45:55 +11:00
parent 5cb44dd17e
commit d9fa154a01
15 changed files with 46459 additions and 39 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
node_modules/ node_modules/
_site/ _site/
build/
.idea/

View file

@ -1,28 +0,0 @@
export class WordSource {
constructor() {
this._words = [
"MUNCH",
"HOUSE",
"MOON"
];
this._currentWord = 0;
}
isWord(word) {
return this._words.filter((x) => x == word).length > 0;
}
getCurrentWord() {
return this._words[this._currentWord];
}
nextWord() {
if (this._currentWord >= this._words.length - 1) {
return false;
}
this._currentWord += 1;
return true;
}
}

72
cmd/prep-words/main.go Normal file
View file

@ -0,0 +1,72 @@
package main
import (
"bufio"
"encoding/json"
"flag"
"log"
"os"
"sort"
)
type wordList struct {
Words map[int][]string `json:"words"`
}
func main() {
dictFile := flag.String("dict", "", "dictionary of word to prep")
flag.Parse()
words := wordList{
Words: make(map[int][]string),
}
if err := scanSuitableWords(*dictFile, func(word string) {
if len(word) >= 4 && len(word) <= 6 {
words.Words[len(word)] = append(words.Words[len(word)], word)
}
}); err != nil {
log.Fatal(err)
}
for _, word := range words.Words {
sort.Strings(word)
}
if err := json.NewEncoder(os.Stdout).Encode(words); err != nil {
log.Fatal(err)
}
}
func scanSuitableWords(dictFile string, withWord func(word string)) error {
f, err := os.Open(dictFile)
if err != nil {
return err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
isSuitable := true
breakpoint := len(scanner.Text())
for i, r := range scanner.Text() {
if r == '/' {
breakpoint = i
break
}
if r < 'a' || r > 'z' {
isSuitable = false
break
}
}
if isSuitable {
word := scanner.Text()[:breakpoint]
withWord(word)
} else {
}
}
return scanner.Err()
}

2
dict/README.md Normal file
View file

@ -0,0 +1,2 @@
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

46281
dict/en_GB.dic Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,12 @@
export default function(cfg) { export default function(cfg) {
cfg.addPassthroughCopy("assets/styles/main.css"); cfg.addPassthroughCopy("site/assets/styles/main.css");
cfg.addPassthroughCopy("assets/scripts/**/*.js"); cfg.addPassthroughCopy("site/assets/scripts/**/*.js");
cfg.addPassthroughCopy("site/assets/data/*");
return {
dir: {
input: "site",
output: "build/site"
}
};
}; };

3
go.mod Normal file
View file

@ -0,0 +1,3 @@
module lmika.dev/lmika/wordle-clone
go 1.23.3

File diff suppressed because one or more lines are too long

View file

@ -7,10 +7,12 @@ import { WordSource } from "../models/words.js";
export default class extends Controller { export default class extends Controller {
static targets = ["row"]; static targets = ["row"];
connect() { async connect() {
this._wordSource = new WordSource(); this._wordSource = new WordSource();
this._gameController = new GameController(this._wordSource); this._gameController = new GameController(this._wordSource);
await this._gameController.start();
this._buildPlayfield(); this._buildPlayfield();
} }

View file

@ -13,29 +13,36 @@ export const MARKERS = {
export class GameController { export class GameController {
constructor(wordSource) { constructor(wordSource) {
this._wordSource = wordSource; this._wordSource = wordSource;
this._currentWord = wordSource.getCurrentWord(); }
async start() {
this._currentWord = await this._wordSource.getCurrentWord();
this._guesses = 5; this._guesses = 5;
console.log("The current word: " + this._currentWord);
} }
wordLength() { wordLength() {
this._checkHasStarted();
return this._currentWord.length; return this._currentWord.length;
} }
guesses() { guesses() {
this._checkHasStarted();
return this._guesses; return this._guesses;
} }
nextWord() { async nextWord() {
if (!this._wordSource.nextWord()) { this._currentWord = await this._wordSource.getCurrentWord();
return false;
}
this._currentWord = this._wordSource.getCurrentWord();
this._guesses = 5; this._guesses = 5;
return true; return true;
} }
checkGuess(guess) { checkGuess(guess) {
this._checkHasStarted();
guess = guess.toLowerCase();
if (guess.length != this._currentWord.length) { if (guess.length != this._currentWord.length) {
throw Error(`Expected length to be ${this._currentWord.length} but was ${guess.length}`); throw Error(`Expected length to be ${this._currentWord.length} but was ${guess.length}`);
} }
@ -100,4 +107,10 @@ export class GameController {
markers: markers markers: markers
}; };
} }
_checkHasStarted() {
if (!this._currentWord) {
throw new Error("call start() first");
}
}
} }

View file

@ -0,0 +1,64 @@
function binSearch(list, word) {
let first = 0;
let last = list.length;
for (;;) {
let ptr = (first + (last - first) / 2) | 0;
if (list[ptr] === word) {
return true;
} else if (last - first <= 1) {
return false;
} else if (list[ptr] > word) {
last = ptr;
} else if (list[ptr] < word) {
first = ptr;
}
}
}
export class WordSource {
constructor() {
this._wordData = null;
this._currentWord = null;
}
isWord(word) {
let list = this._wordData.words[word.length.toString()];
if (!list) {
return false;
}
return binSearch(list, word);
}
async getCurrentWord() {
if (this._currentWord) {
return this._currentWord;
}
let words = await this._fetchAllWordsIfNecessary();
this._currentWord = words.words["4"][7];
return this._currentWord;
}
async nextWord() {
if (this._currentWord >= this._words.length - 1) {
return false;
}
this._currentWord += 1;
return true;
}
async _fetchAllWordsIfNecessary() {
if (this._wordData) {
return this._wordData;
}
let res = await fetch("/assets/data/words.json");
this._wordData = await res.json();
return this._wordData;
}
}