From c0e7dbe51914f4ed3eb35f0b3cf2ed9505cf7d2a Mon Sep 17 00:00:00 2001 From: assylzhan Date: Wed, 17 Jun 2026 13:42:56 +0900 Subject: [PATCH 1/3] Add option to give up and reveal the answer Add a give-up GameAction. Bind it to Ctrl+Q --- src/components/status-text.tsx | 5 +++-- src/state/reducer.ts | 3 +++ src/ui.tsx | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/status-text.tsx b/src/components/status-text.tsx index f975c051..25155ecc 100644 --- a/src/components/status-text.tsx +++ b/src/components/status-text.tsx @@ -24,10 +24,11 @@ function notesForState(gameState: GameState): [string, string] { `Press '${KEY_NEW_GAME}' for a new game, or '${KEY_QUIT}' to quit.`, ]; } + const giveUpHint = "Press Ctrl+G to give up and reveal the answer."; if (gameState.note) { - return [gameState.note, ""]; + return [gameState.note, giveUpHint]; } - return ["", ""]; + return ["", giveUpHint]; } export const StatusText: React.FC<{ gameState: GameState }> = ({ 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 }, ); From 7a03c6efec0d27b5b14ea44c59b5db0e78f04804 Mon Sep 17 00:00:00 2001 From: assylzhan Date: Thu, 18 Jun 2026 12:03:04 +0900 Subject: [PATCH 2/3] Address review feedback - Shorten give-up hint to "Ctrl+Q to give up" - Delay the hint so it only appears after 15s of play - Keep Ctrl+Q (Ctrl+G conflicts with VS Code's terminal binding) --- src/components/status-text.tsx | 31 +++++++++++++++++++++++-------- src/constants.ts | 2 ++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/components/status-text.tsx b/src/components/status-text.tsx index 25155ecc..5fe842ec 100644 --- a/src/components/status-text.tsx +++ b/src/components/status-text.tsx @@ -1,20 +1,26 @@ 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,24 +28,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 = "Press Ctrl+G to give up and reveal the answer."; + const giveUpHint = "Ctrl+Q to give up"; if (gameState.note) { - return [gameState.note, giveUpHint]; + return [gameState.note, giveUpHint, true]; } - return ["", giveUpHint]; + 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; From 313c6eec3532026ab04e43162c1e4477a6d1db20 Mon Sep 17 00:00:00 2001 From: John Ruble Date: Wed, 17 Jun 2026 23:36:42 -0400 Subject: [PATCH 3/3] format code --- src/components/status-text.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/status-text.tsx b/src/components/status-text.tsx index 5fe842ec..b1e919c4 100644 --- a/src/components/status-text.tsx +++ b/src/components/status-text.tsx @@ -1,10 +1,6 @@ import { Box, Text } from "ink"; import React, { useEffect, useState } from "react"; -import { - GIVE_UP_HINT_DELAY_MS, - KEY_NEW_GAME, - KEY_QUIT, -} from "../constants.js"; +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, boolean] {