kopia lustrzana https://github.com/lynn/hello-wordl
merged main
commit
666fd89421
16
README.md
16
README.md
|
@ -1,27 +1,41 @@
|
|||
# hello wordl
|
||||
|
||||
It's [Wordle](https://www.powerlanguage.co.uk/wordle/) but you can play forever!
|
||||
|
||||
Play it [**here**](https://hellowordl.net/).
|
||||
|
||||
## Introduction
|
||||
Wordle is a word game similar to the TV show [Lingo](https://en.wikipedia.org/wiki/Lingo_(British_game_show)).
|
||||
|
||||
Wordle is a word game similar to the TV show [Lingo](<https://en.wikipedia.org/wiki/Lingo_(British_game_show)>).
|
||||
|
||||
You get 6 tries to guess a 5-letter target word. After each guess, the letters light up in various colors as clues. Green means a letter is correct in this spot; yellow means a letter is _elsewhere_ in the target word; gray means a letter is not in the target word at all.
|
||||
|
||||
Click _About_ inside the game to learn by example.
|
||||
|
||||
## History
|
||||
|
||||
In 2021, Josh "powerlanguage" Wardle created _Wordle_, a version of the Lingo word game that you can play once a day. The target word is the same for everyone each day, and you can share results to Twitter and compare with your friends. This made Wordle [go absolutely viral](https://www.nytimes.com/2022/01/03/technology/wordle-word-game-creator.html) around January 2022.
|
||||
|
||||
I liked this game a lot, but wanted to play more than once a day, so I created my own version of it, where the words are random but you can play as much as like. I called it _hello wordl_, which is a sort of [bad programming joke](https://en.wikipedia.org/wiki/%22Hello,_World!%22_program).
|
||||
|
||||
## But playing once a day is the point!
|
||||
|
||||
Don't get me wrong: I, too, think this is the most brilliant aspect of Wordle, and I don't aim to dethrone or improve on the "real" game.
|
||||
|
||||
## My word contained two of the same letter!
|
||||
|
||||
This can happen in Wordle too, and I give clues exactly the same way Wordle does. I think the game would be too easy if I got rid of double letters, so I won't.
|
||||
|
||||
## Where are the words coming from?
|
||||
|
||||
To generate target words, I have been manually curating the top 25,000 or so entries of [Peter Norvig's English word frequency list](http://norvig.com/mayzner.html) to get rid of obscure words, plurals, conjugated verbs, inappropriate language, and British spellings (sorry). If you get dealt a strange target word, please open an issue on this here GitHub repository.
|
||||
|
||||
To check guesses, I use some variation of the _Official Tournament and Club Word List_ used in North American Scrabble tournaments. (I'm not a native English speaker, but my English tends mostly American.)
|
||||
|
||||
## For developers
|
||||
|
||||
You're very welcome to create your own Wordle offshoot/remix based on _hello wordl_. To get started, you can [fork the code](https://docs.github.com/en/get-started/quickstart/fork-a-repo) on GitHub.
|
||||
|
||||
To run the code locally, first install [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#using-a-node-version-manager-to-install-nodejs-and-npm). Then, in this directory, open a terminal and run `npm install` followed by `npm run start`. _hello wordl_ will be running at http://localhost:3000/. Any changes you make to the source code will be reflected there. Have fun!
|
||||
|
||||
Finally, `npm run deploy` will deploy your code to the `gh-pages` branch of your fork, so that everyone can play your version at https://yourname.github.io/hello-wordl (or the name of your fork if you renamed it).
|
||||
|
|
|
@ -33,13 +33,13 @@ export function About() {
|
|||
<b>W</b> and <b>O</b> aren't in the target word at all.
|
||||
</p>
|
||||
<p>
|
||||
<b className="green-bg">R</b> is correct! The third letter is{" "}
|
||||
<b className="green-bg">R</b>
|
||||
<b className={"green-bg"}>R</b> is correct! The third letter is{" "}
|
||||
<b className={"green-bg"}>R</b>
|
||||
.<br />
|
||||
<strong>(There may still be a second R in the word.)</strong>
|
||||
</p>
|
||||
<p>
|
||||
<b className="yellow-bg">D</b> occurs <em>elsewhere</em> in the target
|
||||
<b className={"yellow-bg"}>D</b> occurs <em>elsewhere</em> in the target
|
||||
word.
|
||||
<br />
|
||||
<strong>(Perhaps more than once. 🤔)</strong>
|
||||
|
@ -78,7 +78,8 @@ export function About() {
|
|||
<p>
|
||||
This game will be free and ad-free forever,
|
||||
<br />
|
||||
but you can <a href="https://ko-fi.com/chordbug">buy me a coffee</a> if you'd like.
|
||||
but you can <a href="https://ko-fi.com/chordbug">buy me a coffee</a> if
|
||||
you'd like.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
|
26
src/App.css
26
src/App.css
|
@ -26,6 +26,19 @@ body {
|
|||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
.Row-letter-color {
|
||||
margin: 2px;
|
||||
border: 2px solid rgba(128, 128, 128, 0.8);
|
||||
flex: 1;
|
||||
max-width: 40px;
|
||||
height: 40px;
|
||||
font-size: 28px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.Row-annotation {
|
||||
margin-inline-start: 16px;
|
||||
|
@ -217,13 +230,14 @@ a:active {
|
|||
height: 18px;
|
||||
}
|
||||
|
||||
.Settings-setting input[type=range] {
|
||||
.Settings-setting input[type="range"] {
|
||||
width: 50px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.Settings-setting label {
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: 8px;
|
||||
}
|
||||
|
||||
.top-right {
|
||||
|
@ -240,3 +254,13 @@ a:active {
|
|||
.top-right a + a {
|
||||
margin-inline-start: 8px;
|
||||
}
|
||||
|
||||
.App-container.color-blind .letter-correct,
|
||||
.App-container.color-blind .App-about b.green-bg {
|
||||
background-color: #f5793a;
|
||||
}
|
||||
|
||||
.App-container.color-blind .letter-elsewhere,
|
||||
.App-container.color-blind .App-about b.yellow-bg {
|
||||
background-color: #85c0f9;
|
||||
}
|
||||
|
|
46
src/App.tsx
46
src/App.tsx
|
@ -35,6 +35,12 @@ function App() {
|
|||
const [dark, setDark] = useSetting<boolean>("dark", prefersDark);
|
||||
const [difficulty, setDifficulty] = useSetting<number>("difficulty", 2);
|
||||
const [titleFormat, setTitleFormat] = useState<string>("inherit");
|
||||
const [colorBlind, setColorBlind] = useSetting<boolean>("colorblind", false);
|
||||
const [keyboard, setKeyboard] = useSetting<string>(
|
||||
"keyboard",
|
||||
"qwertyuiop-asdfghjkl-BzxcvbnmE"
|
||||
);
|
||||
const [enterLeft, setEnterLeft] = useSetting<boolean>("enter-left", false);
|
||||
|
||||
useEffect(() => {
|
||||
switch (difficulty) {
|
||||
|
@ -77,7 +83,7 @@ function App() {
|
|||
);
|
||||
|
||||
return (
|
||||
<div className="App-container">
|
||||
<div className={"App-container" + (colorBlind ? " color-blind" : "")}>
|
||||
<h1>
|
||||
<span
|
||||
style={{
|
||||
|
@ -132,6 +138,15 @@ function App() {
|
|||
/>
|
||||
<label htmlFor="dark-setting">Dark theme</label>
|
||||
</div>
|
||||
<div className="Settings-setting">
|
||||
<input
|
||||
id="colorblind-setting"
|
||||
type="checkbox"
|
||||
checked={colorBlind}
|
||||
onChange={() => setColorBlind((x: boolean) => !x)}
|
||||
/>
|
||||
<label htmlFor="colorblind-setting">Color blind mode</label>
|
||||
</div>
|
||||
<div className="Settings-setting">
|
||||
<input
|
||||
id="difficulty-setting"
|
||||
|
@ -147,6 +162,7 @@ function App() {
|
|||
<strong>
|
||||
{["Baby", "Easy", "Normal", "Hard", "Ultra Hard"][difficulty]}
|
||||
</strong>
|
||||
<strong>{["Normal", "Hard", "Ultra Hard"][difficulty]}</strong>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 14,
|
||||
|
@ -167,12 +183,40 @@ function App() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="Settings-setting">
|
||||
<label htmlFor="keyboard-setting">Keyboard layout:</label>
|
||||
<select
|
||||
name="keyboard-setting"
|
||||
id="keyboard-setting"
|
||||
value={keyboard}
|
||||
onChange={(e) => setKeyboard(e.target.value)}
|
||||
>
|
||||
<option value="qwertyuiop-asdfghjkl-BzxcvbnmE">QWERTY</option>
|
||||
<option value="azertyuiop-qsdfghjklm-BzxcvbnE">AZERTY</option>
|
||||
<option value="qwertzuiop-asdfghjkl-ByxcvbnmE">QWERTZ</option>
|
||||
<option value="BpyfgcrlE-aoeuidhtns-qjkxbmwvz">Dvorak</option>
|
||||
<option value="qwfpgjluy-arstdhneio-BzxcvbkmE">Colemak</option>
|
||||
</select>
|
||||
<input
|
||||
style={{ marginLeft: 20 }}
|
||||
id="enter-left-setting"
|
||||
type="checkbox"
|
||||
checked={enterLeft}
|
||||
onChange={() => setEnterLeft((x: boolean) => !x)}
|
||||
/>
|
||||
<label htmlFor="enter-left-setting">"Enter" on left side</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Game
|
||||
maxGuesses={maxGuesses}
|
||||
hidden={page !== "game"}
|
||||
difficulty={difficulty}
|
||||
colorBlind={colorBlind}
|
||||
keyboardLayout={keyboard.replaceAll(
|
||||
/[BE]/g,
|
||||
(x) => (enterLeft ? "EB" : "BE")["BE".indexOf(x)]
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
13
src/Game.tsx
13
src/Game.tsx
|
@ -25,6 +25,8 @@ interface GameProps {
|
|||
maxGuesses: number;
|
||||
hidden: boolean;
|
||||
difficulty: Difficulty;
|
||||
colorBlind: boolean;
|
||||
keyboardLayout: string;
|
||||
}
|
||||
|
||||
const easyTargets = targetList.slice(0, targetList.indexOf("revel") + 1); // Slightly more frequent word on the list
|
||||
|
@ -284,7 +286,11 @@ function Game(props: GameProps) {
|
|||
>
|
||||
{hint || `\u00a0`}
|
||||
</p>
|
||||
<Keyboard letterInfo={letterInfo} onKey={onKey} />
|
||||
<Keyboard
|
||||
layout={props.keyboardLayout}
|
||||
letterInfo={letterInfo}
|
||||
onKey={onKey}
|
||||
/>
|
||||
{gameState !== GameState.Playing && (
|
||||
<p>
|
||||
<button
|
||||
|
@ -299,13 +305,16 @@ function Game(props: GameProps) {
|
|||
</button>{" "}
|
||||
<button
|
||||
onClick={() => {
|
||||
const emoji = props.colorBlind
|
||||
? ["⬛", "🟦", "🟧"]
|
||||
: ["⬛", "🟨", "🟩"];
|
||||
share(
|
||||
getChallengeUrl(target),
|
||||
"Result copied to clipboard!",
|
||||
guesses
|
||||
.map((guess) =>
|
||||
clue(guess, target)
|
||||
.map((c) => ["⬛", "🟨", "🟩"][c.clue ?? 0])
|
||||
.map((c) => emoji[c.clue ?? 0])
|
||||
.join("")
|
||||
)
|
||||
.join("\n")
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import { Clue, clueClass } from "./clue";
|
||||
|
||||
interface KeyboardProps {
|
||||
layout: string;
|
||||
letterInfo: Map<string, Clue>;
|
||||
onKey: (key: string) => void;
|
||||
}
|
||||
|
||||
export function Keyboard(props: KeyboardProps) {
|
||||
const keyboard = [
|
||||
"q w e r t y u i o p".split(" "),
|
||||
"a s d f g h j k l".split(" "),
|
||||
"Backspace z x c v b n m Enter".split(" "),
|
||||
];
|
||||
const keyboard = props.layout
|
||||
.split("-")
|
||||
.map((row) =>
|
||||
row
|
||||
.split("")
|
||||
.map((key) => key.replace("B", "Backspace").replace("E", "Enter"))
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="Game-keyboard" aria-hidden="true">
|
||||
|
|
|
@ -16981,7 +16981,7 @@
|
|||
"gauntlet",
|
||||
"crag",
|
||||
"rodeo",
|
||||
"squaw",
|
||||
"*****",
|
||||
"proliferate",
|
||||
"evangelistic",
|
||||
"tannin",
|
||||
|
|
Ładowanie…
Reference in New Issue