what-is-word-cli
Version:
CLI game where your task is to unscramble words by given definition
189 lines • 7.79 kB
JavaScript
import React, { useContext, useEffect } from 'react';
import { Text, Box, useInput } from 'ink';
import Gradient from 'ink-gradient';
import TextInput from 'ink-text-input';
import { Alert, StatusMessage } from '@inkjs/ui';
import * as R from 'remeda';
import { listenKeys } from 'nanostores';
import { useStore } from '@nanostores/react';
import delay from 'delay';
import { manager as appManager, $roundItem, $suite } from '../store.js';
import { useScreenSize } from '../hooks/useScreenSize.js';
import { $newLines, $definitionHeight, actions as roundActions, $panelHeight } from '../store/round.js';
import { $status, actions as statusActions, manager as statusManager, statuses } from '../store/status.js';
import { $score, $userInput, $gameRounds, manager as gameManager, scoreActions, $lastUserAnswer } from '../store/game.js';
import { getId, getSuiteBySettings } from '../helpers.js';
import { SettingsContext } from '../app.js';
export default function Game() {
const definitionHeight = useStore($definitionHeight);
const escapingCharsPanelHeight = useStore($panelHeight);
const newLines = useStore($newLines);
useStore($status);
const roundItem = useStore($roundItem);
const suite = useStore($suite);
const gameRounds = useStore($gameRounds);
const score = useStore($score);
const userInput = useStore($userInput);
const lastUserAnswer = useStore($lastUserAnswer);
const {
settings
} = useContext(SettingsContext);
const {
width,
height
} = useScreenSize();
useEffect(() => {
listenKeys($roundItem, ['definition'], value => {
roundActions.calculateDefinitionHeight(value.definition);
});
const unbindDefintionHeightListener = $definitionHeight.subscribe(value => {
roundActions.setNewLines(height - value - 9);
roundActions.setPanelHeight(height - value - 6);
});
const unbindFinishedListener = $status.subscribe(value => {
if (value === statuses.finished) {
appManager.displayNextResult();
}
});
appManager.displayNextResult();
return () => {
unbindDefintionHeightListener();
unbindFinishedListener();
clearInterval($roundItem.get().intervalId);
console.clear();
};
}, [height]);
const startNewRound = () => {
appManager.setupNextRound();
statusActions.setRunning();
roundActions.setNewLines(process.stdout.rows - definitionHeight - 9);
const intervalId = setInterval(async () => {
const newLines = roundActions.decrement();
appManager.setRoundTemplate();
if (newLines < 0) {
clearInterval(intervalId);
gameManager.setErrored();
statusActions.setDisplayingResult();
await delay(600);
if ($suite.get().length === $gameRounds.get().length) {
statusActions.setFinished();
} else {
startNewRound();
}
}
}, 1000);
appManager.setIntervalId(intervalId);
return intervalId;
};
useInput((input, _key) => {
if (input === 'y') {
roundActions.setPanelHeight(process.stdout.rows - definitionHeight - 5);
appManager.setSuite(getSuiteBySettings(settings).items);
const intervalId = startNewRound();
appManager.setIntervalId(intervalId);
statusActions.setRunning();
}
}, {
isActive: statusManager.isPaused()
});
const lastGameRound = R.last(gameRounds);
return statusManager.isRunning() || statusManager.isDisplayingResult() ? /*#__PURE__*/React.createElement(Box, {
width: width,
height: height,
flexDirection: "column",
alignItems: "center"
}, /*#__PURE__*/React.createElement(Box, {
alignSelf: "flex-end",
marginBottom: 1
}, /*#__PURE__*/React.createElement(Box, {
alignSelf: "flex-end",
borderStyle: "single"
}, /*#__PURE__*/React.createElement(Text, null, "Trial ", $gameRounds.get().length), /*#__PURE__*/React.createElement(Text, null, "\xA0of"), /*#__PURE__*/React.createElement(Text, null, "\xA0", $suite.get().length)), /*#__PURE__*/React.createElement(Box, {
alignSelf: "flex-end",
borderStyle: "single"
}, /*#__PURE__*/React.createElement(Text, null, "Score: ", score))), /*#__PURE__*/React.createElement(Box, {
flexDirection: "column",
marginBottom: 1
}, /*#__PURE__*/React.createElement(Box, {
height: definitionHeight,
alignItems: "center",
justifyContent: "center"
}, /*#__PURE__*/React.createElement(Text, {
color: "#89d"
}, roundItem.definition))), statusManager.isDisplayingResult() ? R.isDefined(lastGameRound) && /*#__PURE__*/React.createElement(Box, {
flexDirection: "column",
height: escapingCharsPanelHeight,
justifyContent: "center",
alignItems: "center"
}, /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Alert, {
variant: lastGameRound.status === 'success' ? 'success' : 'error'
}, lastGameRound.message))) : /*#__PURE__*/React.createElement(Box, {
flexDirection: "column",
height: escapingCharsPanelHeight,
alignItems: "center"
}, /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Text, null, R.times(roundItem.word.length, () => '-'))), /*#__PURE__*/React.createElement(Box, {
flexDirection: "column"
}, /*#__PURE__*/React.createElement(Box, {
height: newLines
}), roundItem.template.map(chars => /*#__PURE__*/React.createElement(Text, {
key: getId()
}, chars.join(''))))), /*#__PURE__*/React.createElement(Box, {
marginTop: 1,
alignItems: "center",
justifyContent: "center"
}, /*#__PURE__*/React.createElement(Text, null, "Answer:\xA0"), /*#__PURE__*/React.createElement(Box, {
borderStyle: "single",
borderColor: "#e90",
borderTop: false,
borderLeft: false,
borderRight: false
}, !statusManager.isPaused() && /*#__PURE__*/React.createElement(TextInput, {
placeholder: "What is it?",
value: userInput,
onChange: value => {
gameManager.setInput(value);
},
onSubmit: async value => {
if (value === roundItem.word) {
clearInterval(roundItem.intervalId);
gameManager.setSucceeded(value);
gameManager.resetInput();
scoreActions.increment();
statusActions.setDisplayingResult();
await delay(600);
if (suite.length === $gameRounds.get().length) {
statusActions.setFinished();
return;
}
startNewRound();
} else {
gameManager.registerUserAnswer(userInput);
gameManager.resetInput();
}
}
})), /*#__PURE__*/React.createElement(Box, {
paddingLeft: 2,
flexDirection: "row",
justifyContent: "space-around"
}, R.isEmpty(lastUserAnswer) ? /*#__PURE__*/React.createElement(Text, {
color: "green"
}) : /*#__PURE__*/React.createElement(StatusMessage, {
variant: "error"
}, lastUserAnswer)))) : /*#__PURE__*/React.createElement(Box, {
width: width,
height: height,
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
paddingX: 2
}, /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Gradient, {
name: "teen"
}, /*#__PURE__*/React.createElement(Text, null, "WHAT-IS-WORD"))), /*#__PURE__*/React.createElement(Box, {
marginTop: 3
}, /*#__PURE__*/React.createElement(Text, null, "Try to unscramble words by given definition and provide a correct word.")), /*#__PURE__*/React.createElement(Box, {
paddingBottom: 3
}, /*#__PURE__*/React.createElement(Text, null, "You must be in time before the scrambled word reaches dashed borders.")), /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Text, null, "Are you ready? Press", ' ', /*#__PURE__*/React.createElement(Text, {
bold: true,
color: "cyan"
}, "y"), ' ', "to start.")));
}