UNPKG

tmemory

Version:

A terminal-based Memory card game built with React Ink. Features multiple grid sizes, AI opponent, and high scores.

79 lines (78 loc) 3.85 kB
import { Box, Text, useInput } from 'ink'; import Gradient from 'ink-gradient'; import React, { useEffect } from 'react'; import { GameLayout } from '../../components/layout/GameLayout.js'; import { COLORS } from '../../constants/colors.js'; import { findAIMove } from '../../context/GameContext/actions.js'; import { useGame } from '../../context/GameContext/index.js'; import { GameControls } from './components/GameControls.js'; import { GameGrid } from './components/GameGrid.js'; import { GameStatus } from './components/GameStatus.js'; export const GameScreen = () => { const { state, dispatch } = useGame(); // Handle switching players after no match useEffect(() => { if (state.flippedIndices.length === 2) { const [first, second] = state.flippedIndices; // Ensure indices are valid if (typeof first !== 'number' || typeof second !== 'number') return; const firstCard = state.grid[first]; const secondCard = state.grid[second]; const isMatch = firstCard && secondCard && firstCard.value === secondCard.value; if (!isMatch) { // Wait a moment before switching players const timer = setTimeout(() => { dispatch({ type: 'SWITCH_PLAYER' }); }, 1000); return () => clearTimeout(timer); } } }, [state.flippedIndices]); // Handle AI turns useEffect(() => { if (state.currentPlayer === 'ai' && state.flippedIndices.length === 0) { // Add a small delay before AI moves const timer = setTimeout(() => { const [first, second] = findAIMove(state.grid, state.matchedIndices, state.flippedIndices); dispatch({ type: 'FLIP_CARD', payload: first }); // Add delay between first and second card setTimeout(() => { dispatch({ type: 'FLIP_CARD', payload: second }); }, 500); }, 1000); return () => clearTimeout(timer); } }, [state.currentPlayer, state.flippedIndices.length]); useInput((input, key) => { if (state.currentPlayer === 'ai') return; if (key.leftArrow) { dispatch({ type: 'SET_SELECTED_INDEX', payload: Math.max(0, state.selectedIndex - 1) }); } else if (key.rightArrow) { dispatch({ type: 'SET_SELECTED_INDEX', payload: Math.min(state.grid.length - 1, state.selectedIndex + 1) }); } else if (key.upArrow) { dispatch({ type: 'SET_SELECTED_INDEX', payload: Math.max(0, state.selectedIndex - state.gridDimension.cols) }); } else if (key.downArrow) { dispatch({ type: 'SET_SELECTED_INDEX', payload: Math.min(state.grid.length - 1, state.selectedIndex + state.gridDimension.cols) }); } else if (input === ' ' || input === 'enter') { dispatch({ type: 'FLIP_CARD', payload: state.selectedIndex }); } }); return (React.createElement(GameLayout, null, React.createElement(Box, { flexDirection: "column", borderStyle: "singleDouble", paddingX: 1, width: '100%' }, React.createElement(Box, { justifyContent: "space-between" }, React.createElement(Gradient, { name: "cristal" }, React.createElement(Text, null, "tMemory")), React.createElement(Text, { color: COLORS.info }, "[", state.gameMode === 'single' ? 'Single Player' : state.gameMode === 'vs-player' ? 'P1 vs P2' : 'vs AI', "]")), React.createElement(GameStatus, null), React.createElement(GameGrid, null), React.createElement(GameControls, null)))); };