wordle

2022.05.08

Helper for Wordle game in JavaScript

#va#JavaScript
use client /components/post/reExport styled-components react-icons/ri react-icons/md , pos: null, notPos: 1 }, { char: , pos: 2, notPos: null } ], charArr: [ ], noCharsArr: [ ], vocabArr: [ ], charsNum: 5, ...args } let arr = [] arr = arrOfStrOfCertainLength(vocabArr, charsNum) arr = arrOfStrWithChars(arr, charArr) arr = arrOfStrWithoutChars(arr, noCharsArr) arr = arrOfStrWithCharsAtPos(arr, charObjArr) arr = arrOfStrWithoutCharsAtPos(arr, charObjArr) return arr // helper functions function arrOfStrOfCertainLength(arr, length) { return arr.filter(str => str && str.length === length) } function arrOfStrWithChars(arr, charsArr) { return arr.filter(str => { const areAllCharsInside = charsArr.every(char => str.includes(char)) return areAllCharsInside }) } function arrOfStrWithoutChars(arr, charsArr) { return arr.filter(str => { const isCharsInside = charsArr.some(char => str.includes(char)) return !isCharsInside }) } function isCharAtPosition(str, char, pos) { return str.split( )[pos] === char } function arrOfStrWithCharsAtPos(arr, charObjArr) { return arr.filter(str => charObjArr.every(o => { if (isNaN(o.pos)) return true return isCharAtPosition(str, o.char, o.pos) })) } function arrOfStrWithoutCharsAtPos(arr, charObjArr) { return arr.filter(str => charObjArr.every(o => { if (isNaN(o.notPos)) return true return !isCharAtPosition(str, o.char, o.notPos) })) } } function Component() { const [excludeLettersInputState, setExcludeLettersInputState] = React.useState([ ]) const [charsNumInputState, setCharsNumInputState] = React.useState(5) const [lettersNumState, setLettersNumState] = React.useState(0) const [possibleWordsState, setPossibleWordsState] = React.useState([]) const [loadingState, setLoadingState] = React.useState(false) const ref = React.useRef() // React.useEffect(() => { search() }, []) async function formArgsFromDom() { const container = ref.current const charObjArr = [] container.querySelectorAll( ).forEach(el => { charObjArr.push({ char: el.value }) }) container.querySelectorAll( ).forEach((el, i) => { charObjArr[i].pos = parseInt(el.value) - 1 }) container.querySelectorAll( ).forEach((el, i) => { charObjArr[i].notPos = parseInt(el.value) - 1 }) const charArr = Array.from(container.querySelectorAll( )).map(el => el.value) const charsNum = parseInt(container.querySelector( ).value) const noCharsArr = container.querySelector( ).value.split( ) let ruWords = [] const getRuWordsPromise = fetch( ) .then(res => res.json()) .then(data => { ruWords = data }) let enWords = [] const getEnWordsPromise = fetch( ) .then(res => res.json()) .then(data => { enWords = data }) // just to have 1.5s loading... alert const delayPromise = new Promise(resolve => { setTimeout(() => { resolve( ) }, 1500) }) setLoadingState(true) return Promise.all([getRuWordsPromise, getEnWordsPromise, delayPromise]) .then((resultArr) => { const lang = container.querySelector( ).value const vocabArr = (lang === ) ? enWords : ruWords return { charObjArr, charsNum, noCharsArr, charArr, vocabArr } }) .finally(() => { setLoadingState(false) }) } async function search() { const argsForNextFunction = await formArgsFromDom() const possibleWords = listOfPossibleWords(argsForNextFunction) setPossibleWordsState(possibleWords) } return ( <div ref={ref}> <RadioButtons /> <FlexContainer> <LetterPosDiv char= /> <LetterPosDiv char= /> {Array(lettersNumState) .fill( ) .map((val, i) => ( <LetterPosDiv key={i} /> ))} <div style={{ justifyContent: }}> <Plus onClick={() => setLettersNumState(lettersNumState + 1)} /> <Minus onClick={() => setLettersNumState(lettersNumState - 1 < 0 ? 0 : lettersNumState - 1)} /> </div> <div className= > <input className= type= spellCheck= required value={excludeLettersInputState} onChange={e => setExcludeLettersInputState(e.target.value)} /> <span className= >Letters to exclude</span> </div> <div className= > <input className= type= value={charsNumInputState} spellCheck= required onChange={e => setCharsNumInputState(e.target.value)} /> <span className= >Number of letters</span> </div> <button onClick={search}>{loadingState ? }</button> <div id= > {possibleWordsState.length === 0 ? : } found possibleWordsContainer > { } {word}{ } </span> ))} </div> </FlexContainer> </div> ) } function RadioButtons() { const [langState, setLangState] = React.useState( ) return ( <Div> <label> <input type= defaultChecked onChange={e => setLangState(e.target.value)} /> <span>en</span> </label> <label> <input type= onChange={e => setLangState(e.target.value)} /> <span>ru</span> </label> </Div> ) } const Div = styled.div function LetterPosDiv(props) { const [letterInputState, setLetterInputState] = React.useState(props.char) const [posInputState, setPosInputState] = React.useState(props.pos) const [notPosInputState, setNotPosInputState] = React.useState(props.notPos) return ( <div> <div className= > <input className= type= maxLength={1} spellCheck= autoCapitalize= required value={letterInputState} onChange={e => setLetterInputState(e.target.value)} /> <span className= >Letter</span> </div> <div className= > <input className= type= spellCheck= autoCapitalize= required value={posInputState} onChange={e => setPosInputState(e.target.value)} /> <span className= >At</span> </div> <div className= > <input className= type= spellCheck= autoCapitalize= required value={notPosInputState} onChange={e => setNotPosInputState(e.target.value)} /> <span className= >Not at</span> </div> </div> ) } const FlexContainer = styled.div ] { letter-spacing: normal; } svg { height: 24px; cursor: pointer; &:hover { transform: scale(1.5); transition: transform .3s; } } , date: , tags: [ JavaScript https://antonarbus.com/imgs/wordle.png Helper for Wordle game in JavaScript } <Lnk path= >EN</Lnk> & <Lnk path= >RU</Lnk> games. </p> <Component /> <H>Files structure</H> <p>We have huge files with words arrays and we do not want to include them into our project via <code>import</code>, because it makes the bundle bigger and will take <i>webpack</i> ages to produce a production build.</p> <p>We put our files into <code>public</code> folder instead of <code>src</code> and access data via <Code>{ }</Code> function.</p> <LazyImg src= /> <H>Logic</H> <Code block jsx>{ , pos: null, notPos: 1 }, { char: , pos: 2, notPos: null }, ], charArr: [ ], noCharsArr: [ ], vocabArr: [ ], charsNum: 5, ...args, } let arr = [] arr = arrOfStrOfCertainLength(vocabArr, charsNum) arr = arrOfStrWithChars(arr, charArr) arr = arrOfStrWithoutChars(arr, noCharsArr) arr = arrOfStrWithCharsAtPos(arr, charObjArr) arr = arrOfStrWithoutCharsAtPos(arr, charObjArr) return arr // helper functions function arrOfStrOfCertainLength(arr, length) { return arr.filter(str => str && str.length === length) } function arrOfStrWithChars(arr, charsArr) { return arr.filter(str => { const areAllCharsInside = charsArr.every(char => str.includes(char)) return areAllCharsInside }) } function arrOfStrWithoutChars(arr, charsArr) { return arr.filter(str => { const isCharsInside = charsArr.some(char => str.includes(char)) return !isCharsInside }) } function isCharAtPosition(str, char, pos) { return str.split( )[pos] === char } function arrOfStrWithCharsAtPos(arr, charObjArr) { return arr.filter(str => charObjArr.every(o => { if (isNaN(o.pos)) return true return isCharAtPosition(str, o.char, o.pos) })) } function arrOfStrWithoutCharsAtPos(arr, charObjArr) { return arr.filter(str => charObjArr.every(o => { if (isNaN(o.notPos)) return true return !isCharAtPosition(str, o.char, o.notPos) })) } } import styled from import React from import { RiAddLine as Plus } from import { MdRemove as Minus } from function Component() { const [excludeLettersInputState, setExcludeLettersInputState] = React.useState([ ]) const [charsNumInputState, setCharsNumInputState] = React.useState(5) const [lettersNumState, setLettersNumState] = React.useState(0) const [possibleWordsState, setPossibleWordsState] = React.useState([]) const [loadingState, setLoadingState] = React.useState(false) const ref = React.useRef() // React.useEffect(() => { search() }, []) async function formArgsFromDom() { const container = ref.current const charObjArr = [] container.querySelectorAll( ).forEach(el => { charObjArr.push({ char: el.value }) }) container.querySelectorAll( ).forEach((el, i) => { charObjArr[i].pos = parseInt(el.value) - 1 }) container.querySelectorAll( ).forEach((el, i) => { charObjArr[i].notPos = parseInt(el.value) - 1 }) const charArr = Array.from(container.querySelectorAll( )).map(el => el.value) const charsNum = parseInt(container.querySelector( ).value) const noCharsArr = container.querySelector( ).value.split( ) let ruWords = [] const getRuWordsPromise = fetch( ) .then(res => res.json()) .then(data => { ruWords = data }) let enWords = [] const getEnWordsPromise = fetch( ) .then(res => res.json()) .then(data => { enWords = data }) // just to have 1.5s loading... alert const delayPromise = new Promise(resolve => { setTimeout(() => { resolve( ) }, 1500) }) setLoadingState(true) return Promise.all([getRuWordsPromise, getEnWordsPromise, delayPromise]) .then((resultArr) => { const lang = container.querySelector( ).value const vocabArr = (lang === ) ? enWords : ruWords return { charObjArr, charsNum, noCharsArr, charArr, vocabArr } }) .finally(() => { setLoadingState(false) }) } async function search() { const argsForNextFunction = await formArgsFromDom() const possibleWords = listOfPossibleWords(argsForNextFunction) setPossibleWordsState(possibleWords) } return ( <div ref={ref}> <RadioButtons /> <FlexContainer> <LetterPosDiv char= /> <LetterPosDiv char= /> {Array(lettersNumState).fill( ).map((val, i) => <LetterPosDiv key={i}/>)} <div style={{ justifyContent: }}> <Plus onClick={() => setLettersNumState(lettersNumState + 1)} /> <Minus onClick={() => setLettersNumState((lettersNumState - 1 < 0) ? 0 : lettersNumState - 1)} /> </div> <div className= > <input className= spellCheck= required value={excludeLettersInputState} onChange={e => setExcludeLettersInputState(e.target.value)}/> <span className= >Letters to exclude</span> </div> <div className= > <input className= value={charsNumInputState} spellCheck= required onChange={e => setCharsNumInputState(e.target.value)}/> <span className= >Number of letters</span> </div> <button onClick={search}>{loadingState ? }</button> <div id= >{(possibleWordsState.length === 0) ? \${possibleWordsState.length} word\${possibleWordsState.length === 1 ? }</div> <div id= >{possibleWordsState.map(word => (<span key={word} className= > {word} </span>))}</div> </FlexContainer> </div> ) } function RadioButtons() { const [langState, setLangState] = React.useState( ) return ( <Div> <label> <input type= defaultChecked onChange={e => setLangState(e.target.value)} /> <span>en</span> </label> <label> <input type= onChange={e => setLangState(e.target.value)} /> <span>ru</span> </label> </Div> ) } const Div = styled.div\ function LetterPosDiv(props) { const [letterInputState, setLetterInputState] = React.useState(props.char) const [posInputState, setPosInputState] = React.useState(props.pos) const [notPosInputState, setNotPosInputState] = React.useState(props.notPos) return ( <div> <div className= > <input className= type= maxLength={1} spellCheck= autoCapitalize= required value={letterInputState} onChange={e => setLetterInputState(e.target.value)} /> <span className= >Letter</span> </div> <div className= > <input className= type= spellCheck= autoCapitalize= required value={posInputState} onChange={e => setPosInputState(e.target.value)} /> <span className= >At</span> </div> <div className= > <input className= type= spellCheck= autoCapitalize= required value={notPosInputState} onChange={e => setNotPosInputState(e.target.value)} /> <span className= >Not at</span> </div> </div> ) } const FlexContainer = styled.div\ ] { letter-spacing: normal; } svg { height: 24px; cursor: pointer; &:hover { transform: scale(1.5); transition: transform .3s; } } \