tmemory
Version:
A terminal-based Memory card game built with React Ink. Features multiple grid sizes, AI opponent, and high scores.
104 lines (103 loc) • 5.38 kB
JavaScript
import { Box, Text, useApp, useInput } from 'ink';
import BigText from 'ink-big-text';
import Gradient from 'ink-gradient';
import React, { useState } from 'react';
import { submitScore } from '../../api/scoreApi.js';
import { GameLayout } from "../../components/layout/GameLayout.js";
import { COLORS } from "../../constants/colors.js";
import { useGame } from "../../context/GameContext/index.js";
import { useHighScores } from "../../context/HighScoreContext/index.js";
import { formatTime } from "../../utils/time.js";
import { FinalScore } from "./components/FinalScore.js";
import { Leaderboard } from "./components/Leaderboard.js";
import { PlayerNameInput } from "./components/PlayerNameInput.js";
import { WinnerDisplay } from "./components/WinnerDisplay.js";
export const GameOver = () => {
const { exit } = useApp();
const { state, dispatch } = useGame();
const [nameSubmitted, setNameSubmitted] = useState(false);
const [scoreChecked, setScoreChecked] = useState(false);
useInput((input) => {
if (nameSubmitted && input === 'n') {
dispatch({ type: 'SET_GAME_STATE', payload: 'welcome' });
}
else if (nameSubmitted && input === 'q') {
exit();
}
else if (input.toLowerCase() === 'l') {
dispatch({ type: 'SET_GAME_STATE', payload: 'leaderboard' });
}
});
const { getHighScore, isNewHighScore, saveHighScore, getDeviceId } = useHighScores();
// Check high scores
React.useEffect(() => {
const timeElapsed = endTime - startTime;
const isNew = isNewHighScore(timeElapsed, gridDimension, gameMode);
if (isNew) {
dispatch({ type: 'SET_IS_NEW_RECORD', payload: true });
}
dispatch({ type: 'SET_SHOULD_TRACK_SCORE', payload: true });
setScoreChecked(true);
}, []);
// Handle player name submission
const handleNameSubmit = async (playerName) => {
const timeElapsed = endTime - startTime;
const date = new Date().toISOString();
const scoreData = {
time: timeElapsed,
rows: gridDimension.rows,
cols: gridDimension.cols,
gameMode,
date,
playerName,
deviceId: getDeviceId(),
};
// Save the high score locally
saveHighScore(scoreData);
// Submit the score remotely via API
try {
const response = await submitScore(scoreData);
console.log('Score submitted:', response.score);
}
catch (error) {
console.error('Score submission error:', error);
}
setNameSubmitted(true);
};
const { endTime, startTime, scores, gameMode, gridDimension, winner, shouldTrackScore, isNewRecord, } = state;
const timeElapsed = endTime - startTime;
const currentHighScore = getHighScore(gameMode, gridDimension);
return (React.createElement(GameLayout, null,
React.createElement(Box, { flexDirection: "column", alignItems: "center", padding: 1 },
React.createElement(Box, { flexDirection: "column", alignItems: "center", height: 4 },
React.createElement(Gradient, { name: "mind" },
React.createElement(BigText, { text: "Game Over" }))),
React.createElement(WinnerDisplay, { winner: winner }),
React.createElement(FinalScore, { scores: scores, gameMode: gameMode }),
React.createElement(Box, { flexDirection: "column", alignItems: "center" },
React.createElement(Text, { color: COLORS.info },
"Time: ",
React.createElement(Text, { bold: true }, formatTime(timeElapsed))),
shouldTrackScore &&
(isNewRecord ? (React.createElement(Text, { color: COLORS.gold, bold: true },
"\u2605 New Record",
gameMode === 'vs-player' ? ` by ${winner}` : '',
"! \u2605")) : (currentHighScore && (React.createElement(Text, { color: COLORS.dim },
"Best: ",
React.createElement(Text, { bold: true }, formatTime(currentHighScore.time))))))),
scoreChecked && (React.createElement(PlayerNameInput, { isNewRecord: isNewRecord, onNameSubmit: handleNameSubmit })),
nameSubmitted && (React.createElement(Leaderboard, { gameMode: gameMode, gridDimension: gridDimension })),
React.createElement(Text, { color: COLORS.dim },
"Press ",
React.createElement(Text, { color: COLORS.ai, bold: true }, "L"),
" to view leaderboard"),
React.createElement(Box, { flexDirection: "column", alignItems: "center", marginY: 1 },
React.createElement(Text, { color: COLORS.dim }, nameSubmitted ? (React.createElement(React.Fragment, null,
"Press ",
React.createElement(Text, { color: COLORS.p1, bold: true }, "N"),
" for new game")) : (React.createElement(React.Fragment, null, "Enter your name to continue"))),
nameSubmitted && (React.createElement(Text, { color: COLORS.dim },
"Press ",
React.createElement(Text, { color: COLORS.ai, bold: true }, "Q"),
" to quit"))))));
};