hangman-react-game 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,2 +1,2 @@
1
- # Hangman
2
- Simple hangman game that should be portable to a website
1
+ # Hangman
2
+ Simple hangman game that should be portable to a website
@@ -0,0 +1,15 @@
1
+ import * as react from 'react';
2
+
3
+ declare const Game: () => react.JSX.Element;
4
+
5
+ declare const useGame: () => {
6
+ newWord: () => void;
7
+ hasEnded: boolean;
8
+ hasWon: boolean;
9
+ failedAttempts: number;
10
+ guessLetter: (letter: string) => Promise<void>;
11
+ guessedLetters: string[];
12
+ word: string;
13
+ };
14
+
15
+ export { Game, useGame };
package/dist/index.js ADDED
@@ -0,0 +1,223 @@
1
+ // src/hooks/useGame.tsx
2
+ import { useEffect, useState } from "react";
3
+ var MAX_FAILED_ATTEMPTS = 10;
4
+ var wordDictionary = [
5
+ "apple",
6
+ "banana",
7
+ "cherry",
8
+ "date",
9
+ "elderberry",
10
+ "fig",
11
+ "grape",
12
+ "honeydew",
13
+ "kiwi",
14
+ "lemon",
15
+ "mango",
16
+ "nectarine",
17
+ "orange",
18
+ "papaya",
19
+ "quince",
20
+ "raspberry",
21
+ "strawberry",
22
+ "tangerine",
23
+ "ugli",
24
+ "vanilla",
25
+ "watermelon",
26
+ "xigua",
27
+ "yellow",
28
+ "zucchini",
29
+ "abstract",
30
+ "breeze",
31
+ "cactus",
32
+ "dolphin",
33
+ "eagle",
34
+ "forest",
35
+ "giraffe",
36
+ "horizon",
37
+ "island",
38
+ "jungle",
39
+ "kaleidoscope",
40
+ "lighthouse",
41
+ "mountain",
42
+ "nebula",
43
+ "ocean",
44
+ "prairie",
45
+ "quasar",
46
+ "rainbow",
47
+ "sunrise",
48
+ "tornado",
49
+ "universe",
50
+ "volcano",
51
+ "whale",
52
+ "xerox",
53
+ "yacht",
54
+ "zephyr",
55
+ "albatross",
56
+ "butterfly",
57
+ "chameleon",
58
+ "dinosaur",
59
+ "elephant",
60
+ "flamingo",
61
+ "gazelle",
62
+ "hippopotamus",
63
+ "iguana",
64
+ "jellyfish",
65
+ "kangaroo",
66
+ "lion",
67
+ "monkey",
68
+ "narwhal",
69
+ "octopus",
70
+ "penguin",
71
+ "quail",
72
+ "rhinoceros",
73
+ "squirrel",
74
+ "turtle",
75
+ "umbrella",
76
+ "vulture",
77
+ "walrus",
78
+ "xylophone",
79
+ "yak",
80
+ "zebra",
81
+ "astronomy",
82
+ "biology",
83
+ "chemistry",
84
+ "democracy",
85
+ "ecosystem",
86
+ "fossil",
87
+ "genetics",
88
+ "hypothesis",
89
+ "innovation",
90
+ "jurisdiction",
91
+ "kinetic",
92
+ "laboratory",
93
+ "meteorology",
94
+ "neuroscience",
95
+ "observation",
96
+ "physics",
97
+ "quantum",
98
+ "robotics",
99
+ "synthesis",
100
+ "theorem",
101
+ "unicorn",
102
+ "velocity",
103
+ "wavelength",
104
+ "xenon",
105
+ "youth",
106
+ "zenith",
107
+ "bamboozlement",
108
+ "flabbergasted",
109
+ "hypothetical",
110
+ "juxtaposition",
111
+ "labyrinthine",
112
+ "nebulousness",
113
+ "quintessential",
114
+ "sesquipedalian",
115
+ "transcendental",
116
+ "unpredictable",
117
+ "verisimilitude",
118
+ "whippersnapper",
119
+ "xenotransplant",
120
+ "yesteryear",
121
+ "zigzaggedness"
122
+ ];
123
+ var useGame = () => {
124
+ const [word, setWord] = useState("");
125
+ const [guessedLetters, setGuessedLetters] = useState([]);
126
+ const [failedAttempts, setFailedAttempts] = useState(0);
127
+ const [hasEnded, setHasEnded] = useState(false);
128
+ const [hasWon, setHasWon] = useState(false);
129
+ const censorWord = (w) => w.split("").map((x) => (guessedLetters.includes(x) || x === " " ? x : "_") + " ").join("");
130
+ const newWord = () => setWord(wordDictionary[Math.floor(Math.random() * wordDictionary.length)]);
131
+ const guessLetter = async (letter) => {
132
+ if (!hasEnded && letter.length === 1) {
133
+ if (!word.includes(letter))
134
+ setFailedAttempts(failedAttempts + 1);
135
+ setGuessedLetters([...guessedLetters, letter]);
136
+ }
137
+ };
138
+ useEffect(() => newWord(), []);
139
+ useEffect(() => {
140
+ setGuessedLetters([]);
141
+ setFailedAttempts(0);
142
+ setHasEnded(false);
143
+ setHasWon(false);
144
+ }, [word]);
145
+ useEffect(() => {
146
+ if (failedAttempts >= MAX_FAILED_ATTEMPTS)
147
+ setHasEnded(true);
148
+ }, [failedAttempts]);
149
+ useEffect(() => {
150
+ if (word && !censorWord(word).includes("_")) {
151
+ setHasWon(true);
152
+ setHasEnded(true);
153
+ }
154
+ }, [guessedLetters]);
155
+ return {
156
+ newWord,
157
+ hasEnded,
158
+ hasWon,
159
+ failedAttempts,
160
+ guessLetter,
161
+ guessedLetters,
162
+ word: hasEnded ? word : censorWord(word)
163
+ };
164
+ };
165
+ var useGame_default = useGame;
166
+
167
+ // src/components/Hangman.tsx
168
+ import { useEffect as useEffect2 } from "react";
169
+ import { jsx } from "react/jsx-runtime";
170
+ var Hangman = ({ failedAttempts }) => {
171
+ useEffect2(() => {
172
+ }, [failedAttempts]);
173
+ const hangmanParts = [
174
+ // ROD
175
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: "230", x2: "100", y2: "230", stroke: "black" }),
176
+ /* @__PURE__ */ jsx("line", { x1: "60", y1: "20", x2: "60", y2: "230", stroke: "black" }),
177
+ /* @__PURE__ */ jsx("line", { x1: "60", y1: "20", x2: "140", y2: "20", stroke: "black" }),
178
+ /* @__PURE__ */ jsx("line", { x1: "140", y1: "20", x2: "140", y2: "50", stroke: "black" }),
179
+ // HEAD
180
+ /* @__PURE__ */ jsx("circle", { cx: "140", cy: "70", r: "20", stroke: "black" }),
181
+ // BODY
182
+ /* @__PURE__ */ jsx("line", { x1: "140", y1: "90", x2: "140", y2: "150", stroke: "black" }),
183
+ // ARMS
184
+ /* @__PURE__ */ jsx("line", { x1: "140", y1: "120", x2: "120", y2: "100", stroke: "black" }),
185
+ /* @__PURE__ */ jsx("line", { x1: "140", y1: "120", x2: "160", y2: "100", stroke: "black" }),
186
+ // LEGS
187
+ /* @__PURE__ */ jsx("line", { x1: "140", y1: "150", x2: "120", y2: "180", stroke: "black" }),
188
+ /* @__PURE__ */ jsx("line", { x1: "140", y1: "150", x2: "160", y2: "180", stroke: "black" })
189
+ ];
190
+ return /* @__PURE__ */ jsx("svg", { height: "250", width: "200", children: hangmanParts.slice(0, failedAttempts) });
191
+ };
192
+ var Hangman_default = Hangman;
193
+
194
+ // src/components/Game.tsx
195
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
196
+ var Game = () => {
197
+ const {
198
+ newWord,
199
+ hasEnded,
200
+ hasWon,
201
+ failedAttempts,
202
+ guessLetter,
203
+ guessedLetters,
204
+ word
205
+ } = useGame_default();
206
+ return /* @__PURE__ */ jsxs("div", { children: [
207
+ /* @__PURE__ */ jsx2("h1", { children: "Hangman game" }),
208
+ /* @__PURE__ */ jsx2("div", { className: "word", children: /* @__PURE__ */ jsx2("p", { children: word }) }),
209
+ /* @__PURE__ */ jsx2("div", { className: "hangman-illustrtion", children: /* @__PURE__ */ jsx2(Hangman_default, { failedAttempts }) }),
210
+ /* @__PURE__ */ jsx2("div", { className: "guessButtons", children: "abcdefghijklmnopqrstuvwxyz".split("").map((x) => /* @__PURE__ */ jsx2("button", { onClick: () => guessLetter(x), disabled: hasEnded || guessedLetters.includes(x), children: x }, x)) }),
211
+ hasEnded && /* @__PURE__ */ jsxs("div", { className: "game-over", children: [
212
+ hasWon && /* @__PURE__ */ jsx2("h1", { children: "Yay, you won" }),
213
+ !hasWon && /* @__PURE__ */ jsx2("h1", { children: "Too bad, you lose" })
214
+ ] }),
215
+ /* @__PURE__ */ jsx2("button", { onClick: newWord, children: "New word" })
216
+ ] });
217
+ };
218
+ var Game_default = Game;
219
+ export {
220
+ Game_default as Game,
221
+ useGame_default as useGame
222
+ };
223
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useGame.tsx","../src/components/Hangman.tsx","../src/components/Game.tsx"],"sourcesContent":["import {useEffect, useState} from \"react\";\n\nconst MAX_FAILED_ATTEMPTS = 10;\nconst wordDictionary = [\n \"apple\",\n \"banana\",\n \"cherry\",\n \"date\",\n \"elderberry\",\n \"fig\",\n \"grape\",\n \"honeydew\",\n \"kiwi\",\n \"lemon\",\n \"mango\",\n \"nectarine\",\n \"orange\",\n \"papaya\",\n \"quince\",\n \"raspberry\",\n \"strawberry\",\n \"tangerine\",\n \"ugli\",\n \"vanilla\",\n \"watermelon\",\n \"xigua\",\n \"yellow\",\n \"zucchini\",\n \"abstract\",\n \"breeze\",\n \"cactus\",\n \"dolphin\",\n \"eagle\",\n \"forest\",\n \"giraffe\",\n \"horizon\",\n \"island\",\n \"jungle\",\n \"kaleidoscope\",\n \"lighthouse\",\n \"mountain\",\n \"nebula\",\n \"ocean\",\n \"prairie\",\n \"quasar\",\n \"rainbow\",\n \"sunrise\",\n \"tornado\",\n \"universe\",\n \"volcano\",\n \"whale\",\n \"xerox\",\n \"yacht\",\n \"zephyr\",\n \"albatross\",\n \"butterfly\",\n \"chameleon\",\n \"dinosaur\",\n \"elephant\",\n \"flamingo\",\n \"gazelle\",\n \"hippopotamus\",\n \"iguana\",\n \"jellyfish\",\n \"kangaroo\",\n \"lion\",\n \"monkey\",\n \"narwhal\",\n \"octopus\",\n \"penguin\",\n \"quail\",\n \"rhinoceros\",\n \"squirrel\",\n \"turtle\",\n \"umbrella\",\n \"vulture\",\n \"walrus\",\n \"xylophone\",\n \"yak\",\n \"zebra\",\n \"astronomy\",\n \"biology\",\n \"chemistry\",\n \"democracy\",\n \"ecosystem\",\n \"fossil\",\n \"genetics\",\n \"hypothesis\",\n \"innovation\",\n \"jurisdiction\",\n \"kinetic\",\n \"laboratory\",\n \"meteorology\",\n \"neuroscience\",\n \"observation\",\n \"physics\",\n \"quantum\",\n \"robotics\",\n \"synthesis\",\n \"theorem\",\n \"unicorn\",\n \"velocity\",\n \"wavelength\",\n \"xenon\",\n \"youth\",\n \"zenith\",\n \"bamboozlement\",\n \"flabbergasted\",\n \"hypothetical\",\n \"juxtaposition\",\n \"labyrinthine\",\n \"nebulousness\",\n \"quintessential\",\n \"sesquipedalian\",\n \"transcendental\",\n \"unpredictable\",\n \"verisimilitude\",\n \"whippersnapper\",\n \"xenotransplant\",\n \"yesteryear\",\n \"zigzaggedness\"\n];\n\nconst useGame = () => {\n // Should fetch random word from a dictionary (maybe vary by language)\n const [word, setWord] = useState(\"\");\n const [guessedLetters, setGuessedLetters] = useState<string[]>([]);\n const [failedAttempts, setFailedAttempts] = useState<number>(0);\n const [hasEnded, setHasEnded] = useState(false);\n const [hasWon, setHasWon] = useState(false);\n\n const censorWord = (w: string) => w.split(\"\").map(x => (guessedLetters.includes(x) || x === \" \" ? x : \"_\") + \" \").join(\"\");\n const newWord = () => setWord( wordDictionary[Math.floor( Math.random() * wordDictionary.length )]);\n \n const guessLetter = async (letter : string) => {\n if(!hasEnded && letter.length === 1){\n if(!word.includes(letter)) \n setFailedAttempts(failedAttempts+1);\n setGuessedLetters([...guessedLetters, letter]);\n }\n }\n \n useEffect(()=> newWord(), [])\n useEffect(()=> {\n setGuessedLetters([]);\n setFailedAttempts(0);\n setHasEnded(false);\n setHasWon(false);\n }, [word]);\n \n useEffect(()=> {\n if(failedAttempts >= MAX_FAILED_ATTEMPTS)\n setHasEnded(true);\n }, [failedAttempts]);\n \n useEffect(()=> {\n if(word && !censorWord(word).includes(\"_\")) {\n setHasWon(true);\n setHasEnded(true);\n }\n }, [guessedLetters]);\n\n return {\n newWord,\n hasEnded,\n hasWon,\n failedAttempts,\n guessLetter,\n guessedLetters,\n word : hasEnded ? word : censorWord(word)\n };\n}\nexport default useGame;","import { ReactElement, useEffect } from \"react\";\n\ntype HangmanProps = {\n failedAttempts: number\n}\n\nconst Hangman = ({failedAttempts} : HangmanProps) => {\n useEffect(() => {}, [failedAttempts]);\n const hangmanParts : ReactElement[] = [\n // ROD\n <line x1=\"20\" y1=\"230\" x2=\"100\" y2=\"230\" stroke=\"black\" />,\n <line x1=\"60\" y1=\"20\" x2=\"60\" y2=\"230\" stroke=\"black\" />,\n <line x1=\"60\" y1=\"20\" x2=\"140\" y2=\"20\" stroke=\"black\" />,\n <line x1=\"140\" y1=\"20\" x2=\"140\" y2=\"50\" stroke=\"black\" />,\n // HEAD\n <circle cx=\"140\" cy=\"70\" r=\"20\" stroke=\"black\" />,\n // BODY\n <line x1=\"140\" y1=\"90\" x2=\"140\" y2=\"150\" stroke=\"black\" />,\n // ARMS\n <line x1=\"140\" y1=\"120\" x2=\"120\" y2=\"100\" stroke=\"black\" />,\n <line x1=\"140\" y1=\"120\" x2=\"160\" y2=\"100\" stroke=\"black\" />,\n // LEGS\n <line x1=\"140\" y1=\"150\" x2=\"120\" y2=\"180\" stroke=\"black\" />,\n <line x1=\"140\" y1=\"150\" x2=\"160\" y2=\"180\" stroke=\"black\" />\n ];\n return (\n <svg height=\"250\" width=\"200\">\n {hangmanParts.slice(0, failedAttempts)}\n </svg>\n )\n}\nexport default Hangman;","import useGame from \"../hooks/useGame\";\nimport Hangman from \"./Hangman\";\n\nconst Game = () => {\n const {\n newWord,\n hasEnded,\n hasWon,\n failedAttempts,\n guessLetter,\n guessedLetters,\n word \n } = useGame();\n return (\n <div>\n <h1>Hangman game</h1>\n <div className=\"word\">\n <p>{word}</p>\n </div>\n <div className=\"hangman-illustrtion\">\n <Hangman failedAttempts={failedAttempts} />\n </div>\n <div className=\"guessButtons\">\n {\"abcdefghijklmnopqrstuvwxyz\".split(\"\").map(x => (\n <button key={x} onClick={() => guessLetter(x)} disabled={hasEnded || guessedLetters.includes(x)}>{x}</button>\n ))}\n </div>\n {hasEnded && (\n <div className=\"game-over\">\n {hasWon && (<h1>Yay, you won</h1>)}\n {!hasWon && (<h1>Too bad, you lose</h1>)}\n </div>\n )}\n <button onClick={newWord}>New word</button>\n </div>\n )\n};\nexport default Game;"],"mappings":";AAAA,SAAQ,WAAW,gBAAe;AAElC,IAAM,sBAAsB;AAC5B,IAAM,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;A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","names":["useEffect","jsx"]}
package/package.json CHANGED
@@ -1,29 +1,32 @@
1
- {
2
- "name": "hangman-react-game",
3
- "version": "1.0.5",
4
- "type": "module",
5
- "module": "dist/index.js",
6
- "types": "dist/types/index.d.ts",
7
- "exports": {
8
- ".": {
9
- "import": "./dist/index.js",
10
- "types": "./dist/types/index.d.ts"
11
- }
12
- },
13
- "scripts": {
14
- "build": "tsup"
15
- },
16
- "peerDependencies": {
17
- "react": "^19.0.0",
18
- "react-dom": "^19.0.0"
19
- },
20
- "devDependencies": {
21
- "@types/react": "^19.1.13",
22
- "@types/react-dom": "^19.1.9",
23
- "rollup": "^3.29.0",
24
- "tsup": "^8.5.0",
25
- "typescript": "^5.9.2"
26
- },
27
- "author": "Isak Hølleland",
28
- "license": "MIT"
29
- }
1
+ {
2
+ "name": "hangman-react-game",
3
+ "version": "1.0.7",
4
+ "type": "module",
5
+ "module": "dist/index.js",
6
+ "types": "dist/types/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/types/index.d.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup"
18
+ },
19
+ "peerDependencies": {
20
+ "react": "^19.0.0",
21
+ "react-dom": "^19.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/react": "^19.1.13",
25
+ "@types/react-dom": "^19.1.9",
26
+ "rollup": "^3.29.0",
27
+ "tsup": "^8.5.0",
28
+ "typescript": "^5.9.2"
29
+ },
30
+ "author": "Isak Hølleland",
31
+ "license": "MIT"
32
+ }
@@ -1,38 +0,0 @@
1
- import useGame from "../hooks/useGame";
2
- import Hangman from "./Hangman";
3
-
4
- const Game = () => {
5
- const {
6
- newWord,
7
- hasEnded,
8
- hasWon,
9
- failedAttempts,
10
- guessLetter,
11
- guessedLetters,
12
- word
13
- } = useGame();
14
- return (
15
- <div>
16
- <h1>Hangman game</h1>
17
- <div className="word">
18
- <p>{word}</p>
19
- </div>
20
- <div className="hangman-illustrtion">
21
- <Hangman failedAttempts={failedAttempts} />
22
- </div>
23
- <div className="guessButtons">
24
- {"abcdefghijklmnopqrstuvwxyz".split("").map(x => (
25
- <button key={x} onClick={() => guessLetter(x)} disabled={hasEnded || guessedLetters.includes(x)}>{x}</button>
26
- ))}
27
- </div>
28
- {hasEnded && (
29
- <div className="game-over">
30
- {hasWon && (<h1>Yay, you won</h1>)}
31
- {!hasWon && (<h1>Too bad, you lose</h1>)}
32
- </div>
33
- )}
34
- <button onClick={newWord}>New word</button>
35
- </div>
36
- )
37
- };
38
- export default Game;
@@ -1,32 +0,0 @@
1
- import { ReactElement, useEffect } from "react";
2
-
3
- type HangmanProps = {
4
- failedAttempts: number
5
- }
6
-
7
- const Hangman = ({failedAttempts} : HangmanProps) => {
8
- useEffect(() => {}, [failedAttempts]);
9
- const hangmanParts : ReactElement[] = [
10
- // ROD
11
- <line x1="20" y1="230" x2="100" y2="230" stroke="black" />,
12
- <line x1="60" y1="20" x2="60" y2="230" stroke="black" />,
13
- <line x1="60" y1="20" x2="140" y2="20" stroke="black" />,
14
- <line x1="140" y1="20" x2="140" y2="50" stroke="black" />,
15
- // HEAD
16
- <circle cx="140" cy="70" r="20" stroke="black" />,
17
- // BODY
18
- <line x1="140" y1="90" x2="140" y2="150" stroke="black" />,
19
- // ARMS
20
- <line x1="140" y1="120" x2="120" y2="100" stroke="black" />,
21
- <line x1="140" y1="120" x2="160" y2="100" stroke="black" />,
22
- // LEGS
23
- <line x1="140" y1="150" x2="120" y2="180" stroke="black" />,
24
- <line x1="140" y1="150" x2="160" y2="180" stroke="black" />
25
- ];
26
- return (
27
- <svg height="250" width="200">
28
- {hangmanParts.slice(0, failedAttempts)}
29
- </svg>
30
- )
31
- }
32
- export default Hangman;
@@ -1,173 +0,0 @@
1
- import {useEffect, useState} from "react";
2
-
3
- const MAX_FAILED_ATTEMPTS = 10;
4
- const wordDictionary = [
5
- "apple",
6
- "banana",
7
- "cherry",
8
- "date",
9
- "elderberry",
10
- "fig",
11
- "grape",
12
- "honeydew",
13
- "kiwi",
14
- "lemon",
15
- "mango",
16
- "nectarine",
17
- "orange",
18
- "papaya",
19
- "quince",
20
- "raspberry",
21
- "strawberry",
22
- "tangerine",
23
- "ugli",
24
- "vanilla",
25
- "watermelon",
26
- "xigua",
27
- "yellow",
28
- "zucchini",
29
- "abstract",
30
- "breeze",
31
- "cactus",
32
- "dolphin",
33
- "eagle",
34
- "forest",
35
- "giraffe",
36
- "horizon",
37
- "island",
38
- "jungle",
39
- "kaleidoscope",
40
- "lighthouse",
41
- "mountain",
42
- "nebula",
43
- "ocean",
44
- "prairie",
45
- "quasar",
46
- "rainbow",
47
- "sunrise",
48
- "tornado",
49
- "universe",
50
- "volcano",
51
- "whale",
52
- "xerox",
53
- "yacht",
54
- "zephyr",
55
- "albatross",
56
- "butterfly",
57
- "chameleon",
58
- "dinosaur",
59
- "elephant",
60
- "flamingo",
61
- "gazelle",
62
- "hippopotamus",
63
- "iguana",
64
- "jellyfish",
65
- "kangaroo",
66
- "lion",
67
- "monkey",
68
- "narwhal",
69
- "octopus",
70
- "penguin",
71
- "quail",
72
- "rhinoceros",
73
- "squirrel",
74
- "turtle",
75
- "umbrella",
76
- "vulture",
77
- "walrus",
78
- "xylophone",
79
- "yak",
80
- "zebra",
81
- "astronomy",
82
- "biology",
83
- "chemistry",
84
- "democracy",
85
- "ecosystem",
86
- "fossil",
87
- "genetics",
88
- "hypothesis",
89
- "innovation",
90
- "jurisdiction",
91
- "kinetic",
92
- "laboratory",
93
- "meteorology",
94
- "neuroscience",
95
- "observation",
96
- "physics",
97
- "quantum",
98
- "robotics",
99
- "synthesis",
100
- "theorem",
101
- "unicorn",
102
- "velocity",
103
- "wavelength",
104
- "xenon",
105
- "youth",
106
- "zenith",
107
- "bamboozlement",
108
- "flabbergasted",
109
- "hypothetical",
110
- "juxtaposition",
111
- "labyrinthine",
112
- "nebulousness",
113
- "quintessential",
114
- "sesquipedalian",
115
- "transcendental",
116
- "unpredictable",
117
- "verisimilitude",
118
- "whippersnapper",
119
- "xenotransplant",
120
- "yesteryear",
121
- "zigzaggedness"
122
- ];
123
-
124
- const useGame = () => {
125
- // Should fetch random word from a dictionary (maybe vary by language)
126
- const [word, setWord] = useState("");
127
- const [guessedLetters, setGuessedLetters] = useState<string[]>([]);
128
- const [failedAttempts, setFailedAttempts] = useState<number>(0);
129
- const [hasEnded, setHasEnded] = useState(false);
130
- const [hasWon, setHasWon] = useState(false);
131
-
132
- const censorWord = (w: string) => w.split("").map(x => (guessedLetters.includes(x) || x === " " ? x : "_") + " ").join("");
133
- const newWord = () => setWord( wordDictionary[Math.floor( Math.random() * wordDictionary.length )]);
134
-
135
- const guessLetter = async (letter : string) => {
136
- if(!hasEnded && letter.length === 1){
137
- if(!word.includes(letter))
138
- setFailedAttempts(failedAttempts+1);
139
- setGuessedLetters([...guessedLetters, letter]);
140
- }
141
- }
142
-
143
- useEffect(()=> newWord(), [])
144
- useEffect(()=> {
145
- setGuessedLetters([]);
146
- setFailedAttempts(0);
147
- setHasEnded(false);
148
- setHasWon(false);
149
- }, [word]);
150
-
151
- useEffect(()=> {
152
- if(failedAttempts >= MAX_FAILED_ATTEMPTS)
153
- setHasEnded(true);
154
- }, [failedAttempts]);
155
-
156
- useEffect(()=> {
157
- if(word && !censorWord(word).includes("_")) {
158
- setHasWon(true);
159
- setHasEnded(true);
160
- }
161
- }, [guessedLetters]);
162
-
163
- return {
164
- newWord,
165
- hasEnded,
166
- hasWon,
167
- failedAttempts,
168
- guessLetter,
169
- guessedLetters,
170
- word : hasEnded ? word : censorWord(word)
171
- };
172
- }
173
- export default useGame;
package/src/index.tsx DELETED
@@ -1,4 +0,0 @@
1
- import Game from "./components/Game";
2
- import useGame from "./hooks/useGame";
3
-
4
- export {Game, useGame};
package/tsconfig.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "ESNext",
5
- "jsx": "react-jsx",
6
- "declaration": true,
7
- "declarationDir": "dist/types",
8
- "outDir": "dist",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "moduleResolution": "node"
13
- },
14
- "include": ["src"]
15
- }
package/tsup.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from 'tsup';
2
-
3
- export default defineConfig({
4
- entry: ['src/index.tsx'],
5
- format: ['esm'],
6
- dts: true,
7
- sourcemap: true,
8
- clean: true,
9
- external: ['react', 'react-dom'],
10
- });