Moved to an easier dictionary and added invalid word guesses back
All checks were successful
/ publish (push) Successful in 1m19s
All checks were successful
/ publish (push) Successful in 1m19s
Also added a spinner
This commit is contained in:
parent
36b079681c
commit
566f55ed12
|
@ -23,13 +23,11 @@ const maxWordLength = 7
|
||||||
|
|
||||||
var validWordRegex = regexp.MustCompile(`^[a-z]+$`)
|
var validWordRegex = regexp.MustCompile(`^[a-z]+$`)
|
||||||
|
|
||||||
type wordList struct {
|
type dataStruct struct {
|
||||||
Words map[int][]string `json:"words"`
|
VersionID string `json:"versionId"`
|
||||||
}
|
GuessWords map[int][]string `json:"guessWords"`
|
||||||
|
OtherWords map[int][]string `json:"otherWords"`
|
||||||
type shufflePattern struct {
|
ShufflePattern map[int][]int `json:"shufflePattern"`
|
||||||
ID string `json:"id"`
|
|
||||||
Index map[int][]int `json:"index"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -39,49 +37,52 @@ func main() {
|
||||||
|
|
||||||
r := rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), uint64(time.Now().UnixNano())))
|
r := rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), uint64(time.Now().UnixNano())))
|
||||||
|
|
||||||
words := wordList{
|
data := dataStruct{
|
||||||
Words: make(map[int][]string),
|
VersionID: gonanoid.MustID(12),
|
||||||
|
GuessWords: make(map[int][]string),
|
||||||
|
OtherWords: make(map[int][]string),
|
||||||
|
ShufflePattern: make(map[int][]int),
|
||||||
}
|
}
|
||||||
|
|
||||||
wordSet := make(map[string]bool)
|
guessWords := make(map[string]bool)
|
||||||
if err := scanSuitableWords(*dictFile, func(word string) {
|
otherWords := make(map[string]bool)
|
||||||
|
|
||||||
|
if err := scanSuitableWords(*dictFile, func(easy bool, word string) {
|
||||||
w := strings.TrimSpace(word)
|
w := strings.TrimSpace(word)
|
||||||
if !validWordRegex.MatchString(w) {
|
if !validWordRegex.MatchString(w) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(w) >= 4 && len(w) <= maxWordLength {
|
if len(w) >= 4 && len(w) <= maxWordLength {
|
||||||
wordSet[word] = true
|
if easy {
|
||||||
|
guessWords[word] = true
|
||||||
|
} else {
|
||||||
|
otherWords[word] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for w := range wordSet {
|
for w := range guessWords {
|
||||||
words.Words[len(w)] = append(words.Words[len(w)], w)
|
data.GuessWords[len(w)] = append(data.GuessWords[len(w)], w)
|
||||||
|
}
|
||||||
|
for w := range otherWords {
|
||||||
|
data.OtherWords[len(w)] = append(data.OtherWords[len(w)], w)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, word := range words.Words {
|
for k, word := range data.GuessWords {
|
||||||
log.Printf("Found %d words of length %v", len(word), k)
|
log.Printf("Found %d guess words of length %v", len(word), k)
|
||||||
|
sort.Strings(word)
|
||||||
|
}
|
||||||
|
for k, word := range data.OtherWords {
|
||||||
|
log.Printf("Found %d other words of length %v", len(word), k)
|
||||||
sort.Strings(word)
|
sort.Strings(word)
|
||||||
}
|
}
|
||||||
|
|
||||||
var wordData bytes.Buffer
|
for k := range data.GuessWords {
|
||||||
if err := json.NewEncoder(&wordData).Encode(words); err != nil {
|
pattern := make([]int, len(data.GuessWords[k]))
|
||||||
log.Fatal(err)
|
for i := range data.GuessWords[k] {
|
||||||
}
|
|
||||||
if err := os.WriteFile(filepath.Join(*outDir, "words.json"), wordData.Bytes(), 0644); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a shuffle pattern
|
|
||||||
shp := shufflePattern{
|
|
||||||
ID: gonanoid.MustID(12),
|
|
||||||
Index: make(map[int][]int),
|
|
||||||
}
|
|
||||||
for k := range words.Words {
|
|
||||||
pattern := make([]int, len(words.Words[k]))
|
|
||||||
for i := range words.Words[k] {
|
|
||||||
pattern[i] = i
|
pattern[i] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,19 +93,19 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: shuffle
|
// TODO: shuffle
|
||||||
shp.Index[k] = pattern
|
data.ShufflePattern[k] = pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
var patternData bytes.Buffer
|
var wordData bytes.Buffer
|
||||||
if err := json.NewEncoder(&patternData).Encode(shp); err != nil {
|
if err := json.NewEncoder(&wordData).Encode(data); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := os.WriteFile(filepath.Join(*outDir, "shuffle_pattern.json"), patternData.Bytes(), 0644); err != nil {
|
if err := os.WriteFile(filepath.Join(*outDir, "data.json"), wordData.Bytes(), 0644); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanSuitableWords(dictDir string, withWord func(word string)) error {
|
func scanSuitableWords(dictDir string, withWord func(easy bool, word string)) error {
|
||||||
if err := scanSuitableWordsFromWordListHTML(filepath.Join(dictDir, "oxford-word-list.htm"), withWord); err != nil {
|
if err := scanSuitableWordsFromWordListHTML(filepath.Join(dictDir, "oxford-word-list.htm"), withWord); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,7 @@ func scanSuitableWords(dictDir string, withWord func(word string)) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanSuitableWordsFromWordListHTML(dictFile string, withWord func(word string)) error {
|
func scanSuitableWordsFromWordListHTML(dictFile string, withWord func(easy bool, word string)) error {
|
||||||
f, err := os.Open(dictFile)
|
f, err := os.Open(dictFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -133,12 +134,12 @@ func scanSuitableWordsFromWordListHTML(dictFile string, withWord func(word strin
|
||||||
}
|
}
|
||||||
|
|
||||||
dom.Find("table.t tbody tr td.t:nth-child(2)").Each(func(i int, s *goquery.Selection) {
|
dom.Find("table.t tbody tr td.t:nth-child(2)").Each(func(i int, s *goquery.Selection) {
|
||||||
withWord(s.Text())
|
withWord(true, s.Text())
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanSuitableWordsFromOxford3000(dictFile string, withWord func(word string)) error {
|
func scanSuitableWordsFromOxford3000(dictFile string, withWord func(easy bool, word string)) error {
|
||||||
f, err := os.Open(dictFile)
|
f, err := os.Open(dictFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -147,20 +148,20 @@ func scanSuitableWordsFromOxford3000(dictFile string, withWord func(word string)
|
||||||
|
|
||||||
scanner := bufio.NewScanner(f)
|
scanner := bufio.NewScanner(f)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
withWord(scanner.Text())
|
withWord(true, scanner.Text())
|
||||||
}
|
}
|
||||||
|
|
||||||
return scanner.Err()
|
return scanner.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanSuitableWordsFromEnGB(dictFile, affFile string, withWord func(word string)) error {
|
func scanSuitableWordsFromEnGB(dictFile, affFile string, withWord func(easy bool, word string)) error {
|
||||||
words, err := script.Exec(fmt.Sprintf("unmunch '%v' '%v'", dictFile, affFile)).String()
|
words, err := script.Exec(fmt.Sprintf("unmunch '%v' '%v'", dictFile, affFile)).String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, word := range strings.Split(words, "\n") {
|
for _, word := range strings.Split(words, "\n") {
|
||||||
withWord(word)
|
withWord(false, word)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
1
site/assets/data/data.json
Normal file
1
site/assets/data/data.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -5,7 +5,7 @@ import { WordSource } from "../models/words.js";
|
||||||
|
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = ["row", "playfield", "topMessage", "nextPuzzleButtons"];
|
static targets = ["row", "playfield", "topMessage", "nextPuzzleButtons", "loader"];
|
||||||
static outlets = ["overlay"];
|
static outlets = ["overlay"];
|
||||||
|
|
||||||
async connect() {
|
async connect() {
|
||||||
|
@ -15,6 +15,8 @@ export default class extends Controller {
|
||||||
await this._gameController.start();
|
await this._gameController.start();
|
||||||
|
|
||||||
this._buildPlayfield();
|
this._buildPlayfield();
|
||||||
|
|
||||||
|
this.loaderTarget.classList.add("hide");
|
||||||
}
|
}
|
||||||
|
|
||||||
tappedKey(key) {
|
tappedKey(key) {
|
||||||
|
@ -109,11 +111,16 @@ export default class extends Controller {
|
||||||
|
|
||||||
async loadNextPuzzle(ev) {
|
async loadNextPuzzle(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
||||||
|
this.loaderTarget.classList.remove("hide");
|
||||||
|
|
||||||
if (await this._gameController.nextWord()) {
|
if (await this._gameController.nextWord()) {
|
||||||
this._buildPlayfield();
|
this._buildPlayfield();
|
||||||
} else {
|
} else {
|
||||||
this.overlayOutlet.showMessage("No more words available.");
|
this.overlayOutlet.showMessage("No more words available.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.loaderTarget.classList.add("hide");
|
||||||
}
|
}
|
||||||
|
|
||||||
_showWin() {
|
_showWin() {
|
||||||
|
|
|
@ -149,6 +149,18 @@ export class GameController {
|
||||||
let misses = {};
|
let misses = {};
|
||||||
let hits = {};
|
let hits = {};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
|
@ -19,38 +19,38 @@ function binSearch(list, word) {
|
||||||
|
|
||||||
export class WordSource {
|
export class WordSource {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this._dataVersion = null;
|
||||||
this._wordData = null;
|
this._wordData = null;
|
||||||
|
this._otherWords = null;
|
||||||
this._pattern = null;
|
this._pattern = null;
|
||||||
// this._currentWord = null;
|
|
||||||
// this._progressionState=
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isWord(word) {
|
isWord(word) {
|
||||||
let list = this._wordData.words[word.length.toString()];
|
if (!this._wordData || !this._otherWords) {
|
||||||
if (!list) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return binSearch(list, word);
|
return binSearch(this._wordData[word.length.toString()], word) ||
|
||||||
|
binSearch(this._otherWords[word.length.toString()], word);
|
||||||
}
|
}
|
||||||
|
|
||||||
async needToResetProgression(prog) {
|
async needToResetProgression(prog) {
|
||||||
await this._fetchAllWordsIfNecessary();
|
await this._fetchAllWordsIfNecessary();
|
||||||
return !prog || !prog.shuffleId || this._pattern.id !== prog.shuffleId;
|
return !prog || !prog.shuffleId || this._dataVersion !== prog.shuffleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPattenShuffleID() {
|
async getPattenShuffleID() {
|
||||||
return this._pattern.id;
|
return this._dataVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCurrentWord(prog) {
|
async getCurrentWord(prog) {
|
||||||
let words = await this._fetchAllWordsIfNecessary();
|
await this._fetchAllWordsIfNecessary();
|
||||||
|
|
||||||
let wordLengthKey = prog.wordLength + "";
|
let wordLengthKey = prog.wordLength + "";
|
||||||
let wordIndex = prog.wordIndex[wordLengthKey];
|
let wordIndex = prog.wordIndex[wordLengthKey];
|
||||||
let idx = this._pattern.index[wordLengthKey][wordIndex];
|
let idx = this._pattern[wordLengthKey][wordIndex];
|
||||||
|
|
||||||
return words.words[wordLengthKey][idx];
|
return this._wordData[wordLengthKey][idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fetchAllWordsIfNecessary() {
|
async _fetchAllWordsIfNecessary() {
|
||||||
|
@ -58,8 +58,11 @@ export class WordSource {
|
||||||
return this._wordData;
|
return this._wordData;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._wordData = await (await fetch("/assets/data/words.json")).json();
|
let data = await (await fetch("/assets/data/data.json")).json();
|
||||||
this._pattern = await (await fetch("/assets/data/shuffle_pattern.json")).json();
|
|
||||||
return this._wordData;
|
this._dataVersion = data["versionId"];
|
||||||
|
this._wordData = data["guessWords"];
|
||||||
|
this._otherWords = data["otherWords"];
|
||||||
|
this._pattern = data["shufflePattern"];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -217,4 +217,26 @@ div.overlay-message {
|
||||||
|
|
||||||
.hide {
|
.hide {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
margin-top: 6rem;
|
||||||
|
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border: 5px solid #FFF;
|
||||||
|
border-bottom-color: var(--color-no-letter-bg);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
animation: rotation 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotation {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,8 @@
|
||||||
<div data-playfield-target="topMessage"> </div>
|
<div data-playfield-target="topMessage"> </div>
|
||||||
<div data-playfield-target="playfield"></div>
|
<div data-playfield-target="playfield"></div>
|
||||||
|
|
||||||
|
<span data-playfield-target="loader" class="loader"></span>
|
||||||
|
|
||||||
<div data-playfield-target="nextPuzzleButtons" class="hide">
|
<div data-playfield-target="nextPuzzleButtons" class="hide">
|
||||||
<button class="secondary" data-action="playfield#loadDef">Define</button>
|
<button class="secondary" data-action="playfield#loadDef">Define</button>
|
||||||
<button data-action="playfield#loadNextPuzzle">Next Puzzle</button>
|
<button data-action="playfield#loadNextPuzzle">Next Puzzle</button>
|
||||||
|
|
Loading…
Reference in a new issue