console-fun
Version:
Some stuff in the console: utils, printing, games and other fun
177 lines (158 loc) • 5.67 kB
JavaScript
import readline from "readline";
import figureSet from "figures";
import ansiEscapes from "ansi-escapes";
import stringWidth from "string-width";
import chalk from "chalk";
import { coloreme } from "coloreme";
const randPos = (yMin = 0) => {
const randY = Math.floor(Math.random() * process.stdout.rows);
return [
Math.floor(Math.random() * process.stdout.columns),
randY > yMin
? randY
: Math.floor(yMin + Math.random() * process.stdout.rows),
];
};
const fallingStarsGame = () => {
let interval;
process.stdout.write(ansiEscapes.eraseScreen);
const [x, y] = randPos();
process.stdout.write(ansiEscapes.cursorTo(x, y));
let userScore = 0;
let starCount = 0;
let paused = true;
let finished = false;
let firstIter = true;
const howManyPrint = Math.floor(
(process.stdout.rows * process.stdout.columns) / 70,
);
const takenNumbers = [];
readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);
process.stdin.on("keypress", (_chunk, key) => {
if (key && key.name == "s") {
if (interval != null) {
clearInterval(interval);
}
fallingStarsGame();
} else if (key && key.name == "c") {
process.exit(0);
}
if (finished) {
return;
}
if (key && key.name == "y") {
paused = false;
} else if (key && key.name == "p") {
paused = !paused;
} else if (key.name === "space") {
if (!paused && !takenNumbers.includes(starCount) && starCount % 9 === 0) {
// process.stdout.write(ansiEscapes.cursorTo(15, 0));
// process.stdout.write(ansiEscapes.eraseLine);
userScore++;
const scoreText = chalk.bgYellow.black(
`SCORE: ${userScore.toString()}`,
);
const startingLeftPosition =
process.stdout.columns - stringWidth(scoreText);
process.stdout.write(ansiEscapes.cursorTo(startingLeftPosition, 0));
process.stdout.write(scoreText);
takenNumbers.push(starCount);
}
}
});
const drawnPositions = [];
process.stdout.write(ansiEscapes.cursorTo(0, 0));
const redYellow = coloreme.redYellow.inverse;
process.stdout.write(chalk.bgGreen.hex(redYellow.c)("stars-watcher"));
const scoreText = chalk.bgYellow.black(`SCORE: ${userScore.toString()}`);
const startingLeftPosition = process.stdout.columns - stringWidth(scoreText);
process.stdout.write(ansiEscapes.cursorTo(startingLeftPosition, 0));
process.stdout.write(scoreText);
interval = setInterval(async () => {
if (paused) {
const halfColumns = process.stdout.columns / 2;
let y0 = process.stdout.rows / 2 - 6;
process.stdout.write(ansiEscapes.cursorTo(0, 1));
process.stdout.write(ansiEscapes.eraseDown);
const instructions = [
`Watch appearing stars`,
`Press ${chalk.bold("[space]")} on every 9th, 18th... star's appearance`,
];
let cnt = 0;
instructions.map((instruction, i) => {
process.stdout.write(ansiEscapes.cursorNextLine);
const instructionWidth = stringWidth(instruction);
process.stdout.write(
ansiEscapes.cursorTo(
halfColumns - Math.floor(instructionWidth / 2),
y0 + i,
),
);
process.stdout.write(instruction);
process.stdout.write(ansiEscapes.cursorNextLine);
cnt++;
});
const prompt = `Are you ready? Press 'y' to start a round`;
const promptWidth = stringWidth(prompt);
process.stdout.write(
ansiEscapes.cursorTo(
halfColumns - Math.floor(promptWidth / 2),
y0 + cnt + 1,
),
);
process.stdout.write(prompt);
firstIter = true;
return;
}
if (firstIter) {
process.stdout.write(ansiEscapes.cursorTo(0, 1));
process.stdout.write(ansiEscapes.eraseDown);
firstIter = false;
} else {
for (let i in drawnPositions) {
process.stdout.write(ansiEscapes.cursorTo(...drawnPositions[i]));
process.stdout.write(figureSet.star);
}
}
process.stdout.write(ansiEscapes.cursorTo(0, 1));
process.stdout.write(ansiEscapes.eraseDown);
for (let i in drawnPositions) {
process.stdout.write(ansiEscapes.cursorTo(...drawnPositions[i]));
process.stdout.write(figureSet.star);
}
const [x, y] = randPos();
drawnPositions.push([x, y]);
process.stdout.write(ansiEscapes.cursorTo(x, y));
process.stdout.write(figureSet.star);
starCount++;
if (starCount >= howManyPrint) {
clearInterval(interval);
finished = true;
}
if (finished) {
process.stdout.write(ansiEscapes.cursorTo(0, 1));
process.stdout.write(ansiEscapes.eraseDown);
const status = `GAME OVER`;
let x0 = Math.floor(process.stdout.columns / 2 - stringWidth(status) / 2);
let y0 = process.stdout.rows / 2 - 4;
process.stdout.write(
ansiEscapes.cursorTo(
process.stdout.columns / 2 - 4,
process.stdout.rows / 2 - 3,
),
);
process.stdout.write(status);
process.stdout.write(ansiEscapes.cursorNextLine);
const scoreStr = `SCORE: ${userScore.toString()}`;
x0 = process.stdout.columns / 2 - stringWidth(scoreStr) / 2;
process.stdout.write(ansiEscapes.cursorTo(x0, y0 + 2));
process.stdout.write(scoreStr);
const startGameStr = `Press ${chalk.bold("s")} to start a new round`;
x0 = process.stdout.columns / 2 - stringWidth(startGameStr) / 2;
process.stdout.write(ansiEscapes.cursorTo(x0, y0 + 5));
process.stdout.write(startGameStr);
}
}, 1000);
};
export { fallingStarsGame };