diff --git a/src/components/status-text.tsx b/src/components/status-text.tsx index f975c051..b1e919c4 100644 --- a/src/components/status-text.tsx +++ b/src/components/status-text.tsx @@ -1,20 +1,22 @@ import { Box, Text } from "ink"; -import React from "react"; -import { KEY_NEW_GAME, KEY_QUIT } from "../constants.js"; +import React, { useEffect, useState } from "react"; +import { GIVE_UP_HINT_DELAY_MS, KEY_NEW_GAME, KEY_QUIT } from "../constants.js"; import { GameState } from "../types.js"; -function notesForState(gameState: GameState): [string, string] { +function notesForState(gameState: GameState): [string, string, boolean] { switch (gameState.status) { case "win": return [ `🏆 You win! 🏆`, `Press '${KEY_NEW_GAME}' for a new game, or '${KEY_QUIT}' to quit.`, + false, ]; case "loss": if (gameState.gameBoards.length == 1) { return [ `The word was ${gameState.gameBoards[0].solution}. Better luck next time.`, `Press '${KEY_NEW_GAME}' for a new game, or '${KEY_QUIT}' to quit.`, + false, ]; } return [ @@ -22,23 +24,33 @@ function notesForState(gameState: GameState): [string, string] { .map((b) => b.solution) .join(",")}. Better luck next time.`, `Press '${KEY_NEW_GAME}' for a new game, or '${KEY_QUIT}' to quit.`, + false, ]; } + const giveUpHint = "Ctrl+Q to give up"; if (gameState.note) { - return [gameState.note, ""]; + return [gameState.note, giveUpHint, true]; } - return ["", ""]; + return ["", giveUpHint, true]; } export const StatusText: React.FC<{ gameState: GameState }> = ({ gameState, }) => { - const [note1, note2] = notesForState(gameState); + const [note1, note2, note2IsGiveUpHint] = notesForState(gameState); + + const [hintReady, setHintReady] = useState(false); + useEffect(() => { + const timer = setTimeout(() => setHintReady(true), GIVE_UP_HINT_DELAY_MS); + return () => clearTimeout(timer); + }, []); + + const showNote2 = !note2IsGiveUpHint || hintReady; return ( {note1} - {note2} + {showNote2 ? note2 : ""} ); }; diff --git a/src/constants.ts b/src/constants.ts index f410c1a1..f4c49a99 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,3 +2,5 @@ export const WORD_LEN = 5; export const KEY_NEW_GAME = "N"; export const KEY_QUIT = "Q"; + +export const GIVE_UP_HINT_DELAY_MS = 15000; diff --git a/src/state/reducer.ts b/src/state/reducer.ts index d2ac8ff1..be922bad 100644 --- a/src/state/reducer.ts +++ b/src/state/reducer.ts @@ -30,6 +30,9 @@ export function reducer(state: GameState, action: GameAction): GameState { if (rowIsFull(state)) { return handleSubmission(state); } + break; + case "give-up": + return { ...state, status: "loss" }; } } else { if (action.action == "input-letter" && action.letter == KEY_NEW_GAME) { diff --git a/src/ui.tsx b/src/ui.tsx index f7fcb78d..fb613c37 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -13,7 +13,8 @@ import { useStdoutDimensions } from "./use-stdout-dimensions.js"; export type GameAction = | { action: "input-letter"; letter: string } | { action: "submit-guess" } - | { action: "backspace" }; + | { action: "backspace" } + | { action: "give-up" }; const App: FC<{ initialState?: GameState; @@ -52,6 +53,9 @@ const App: FC<{ if (key.backspace || key.delete) { dispatch({ action: "backspace" }); } + if (key.ctrl && input == "q") { + dispatch({ action: "give-up" }); + } }, { isActive: gameState.exitPlease != true }, );