1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
import { useEffect, useRef, useState } from "react";
import { fetchPokeApi } from "../api/api";
import css from "../css/Game.module.css";
import OptionsModel from "../models/OptionsModel";
import { PokeApiModel } from "../models/PokeApiModel";
import Card from "./Card";
import GameOver from "./GameOver";
import Victory from "./Victory";
interface GameProps {
opts: OptionsModel,
onReturnToOptions: () => void
}
const Game = ( {opts, onReturnToOptions } : GameProps) => {
const [cards, setCards] = useState<PokeApiModel["results"][number][]>([]);
const [reload, setReload] = useState(true);
const [loadError, setLoadError] = useState(false);
const [gameOver, setGameOver] = useState(false);
const [victory, setVictory] = useState(false);
const setRef = useRef<Set<number>>(new Set());
const scoreRef = useRef<number>(0);
useEffect(() => {
async function getRandomCards() {
try {
setLoadError(false);
setRef.current.clear();
const data = await fetchPokeApi();
const count = data.count - 1;
const set: Set<PokeApiModel["results"][number]> = new Set();
while (set.size < opts.difficulty) {
const randIdx = Math.floor(Math.random() * count);
const pokemon = data.results[randIdx];
pokemon.index = randIdx + 1;
set.add(pokemon);
}
const slides: PokeApiModel["results"] = Array.from(set);
setCards(slides);
} catch (err) {
console.error(err);
setLoadError(true);
} finally {
setReload(false);
}
}
if (reload) {
getRandomCards();
}
}, [opts.difficulty, reload, gameOver]);
function handleCardClick(index: number) {
if (setRef.current.has(index)) {
setGameOver(true);
return;
}
scoreRef.current++;
if (scoreRef.current === opts.difficulty) {
setVictory(true)
return;
}
setRef.current.add(index);
const newCards = [...cards];
let currIdx = newCards.length;
while (0 !== currIdx) {
const randIdx = Math.floor(Math.random() * currIdx);
currIdx -= 1;
const tmp = newCards[currIdx];
newCards[currIdx] = newCards[randIdx];
newCards[randIdx] = tmp;
}
setCards(newCards);
}
return (
<>
{reload && <>Loading...</>}
{loadError && <>An unknown error occurred. Please refresh.</>}
{gameOver &&
<GameOver
onReplayClick = {() => {
setGameOver(false);
scoreRef.current = 0;
setReload(true);
}}
score={scoreRef.current}
maxScore={opts.difficulty} />
}
{victory &&
<Victory
maxScore={opts.difficulty}
onReplayClick = {() => {
setVictory(false);
scoreRef.current = 0;
setReload(true);
onReturnToOptions();
}}
/>
}
{!reload && !loadError && !gameOver && !victory &&
<div className={css.gameContainer}>
{cards.map(card => (
<Card
key={card.index}
index={card.index}
cardName={card.name}
imgUrl={"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/" + card.index + ".png"}
onCardClick={() => {handleCardClick(card.index)}}
/>
))}
</div>
}
</>
);
}
export default Game;
|