推測ゲームのコンソールアプリの構築
メニューを表示するにはスワイプしてください
この章では、コンソールアプリケーションのスキルをさらに高めるために、エキサイティングな数当てゲームアプリの作成に取り組みます。このインタラクティブなゲームでは、プレイヤーがあらかじめ定められた範囲内でランダムに生成された数を直感で当てることに挑戦します。進行の中で、以下の基本的な概念についても学びます。
- ランダムな数値生成
- 入力値の検証
- ユーザーとの対話
- ゲーム結果のファイル保存
チャレンジ
ワクワクと興味を誘うアプリに挑戦してみましょう。プレイヤーは、あらかじめ定められた範囲内で神秘的に選ばれた数を当てることに招待されます。アプリは各推測に対して即座にフィードバックを返し、試行回数も正確に記録します。
この実践的な例を通じて、CLIアプリの構築スキルを磨き、インタラクティブなプログラム作成の技術を身につけましょう。
完成アプリ
実際の動作を確認しましょう。下記のGIFは、これから作成するエキサイティングな数当てゲームアプリの様子を示しています。
推測ゲームコンソールアプリの構築
2つの道が提示されています。1つ目の選択肢は、サポートなしで自ら旅に出ることを促し、2つ目は成功を確実にするための有益なガイドを提供します。大胆に挑戦する場合も、構造化されたガイドに従う場合も、機能的で魅力的なコンソールアプリを作成するという興味深い体験が待っています。
マスタープラン
- ステップ1: セットアップと初期化
- ステップ2: ゲームパラメータの定義
- ステップ3: ユーティリティ関数の定義
- ステップ4: ゲームロジック
- ステップ5: ゲーム結果の保存
- ステップ6: ゲームの開始
- 結論
- アプリ全体のコード
ステップ1: セットアップと初期化
新しいディレクトリと app.js という名前のファイルを作成し、キャンバスを準備します。このファイル内で、必要なモジュールを呼び出します:
const readline = require('readline');
const fs = require('fs').promises;
Readlineインターフェースの作成:
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
-
readline: コンソールからの入力の読み取りおよび出力への書き込みのためのインターフェースを提供; -
readline.createInterface({ ... }):readline.Interfaceクラスのインスタンスを作成。inputおよびoutputプロパティを持つオブジェクトを受け取る; -
input: process.stdin: 入力ストリームをprocess.stdinに設定し、キーボードからのユーザー入力の読み取りを可能にする; -
output: process.stdout: 出力ストリームをprocess.stdoutに設定し、コンソールにテキストを表示可能にする。
説明: 必要なモジュールをインポート:ユーザーとの対話用に readline、ファイル操作用に fs.promises。その後、入出力を処理するための Readline インターフェース rl を作成。
ステップ2: ゲームパラメータの定義
最小値と最大値の設定:
const minNumber = 1;
const maxNumber = 100;
シークレットナンバーの生成:
const secretNumber =
Math.floor(Math.random() * (maxNumber - minNumber + 1)) + minNumber;
-
Math.random():0(含む)から1(含まない)までのランダムな浮動小数点数を生成; -
maxNumber - minNumber + 1: 可能な数値の範囲を計算。1を加えることで、minNumberとmaxNumberの両方が範囲に含まれる; -
Math.random() * (maxNumber - minNumber + 1):0から計算された範囲までのランダムな数値を生成; -
Math.floor(...): 生成された浮動小数点数を最も近い整数に切り下げ、結果が希望する範囲内の整数となるようにする; -
... + minNumber: 生成された数値の範囲をminNumberから0にシフトさせる。
試行回数カウンターの初期化:
let attempts = 0;
説明: 秘密の数字が生成される範囲(minNumber と maxNumber)を定義。秘密の数字は Math.random() を使ってランダムに生成され、secretNumber に代入。attempts 変数はユーザーの試行回数を記録するために初期化。
ステップ3: ユーティリティ関数の定義
正確なバリデーションのためのユーティリティ関数:
function isValidGuess(guess) {
return !isNaN(guess)
&& guess >= minNumber
&& guess <= maxNumber;
}
-
!isNaN(guess):guessが有効な数値かどうかを確認。isNaN()関数は有効な数値の場合falseを返し、!演算子でtrueに反転; -
guess >= minNumber:guessがminNumber以上であることを検証し、許可された範囲より下でないことを保証; -
guess <= maxNumber:guessがmaxNumber以下であることを検証し、許可された範囲を超えていないことを保証; -
&&: すべての条件を論理積(AND)演算子で結合。すべての条件がtrueの場合のみ、全体の式がtrueになる。
説明: isValidGuess 関数は、ユーザーの推測が指定された範囲(minNumber から maxNumber)内の有効な数値かどうかを確認する。
ステップ 4: ゲームロジック
ゲームのコアメカニクスは playGame 関数で実装されている:
function playGame() {
rl.question(`Guess a number between ${minNumber} and ${maxNumber}: `, guess => {
if (isValidGuess(guess)) {
attempts++;
const guessNumber = parseInt(guess);
if (guessNumber === secretNumber) {
console.log(`Congratulations! You guessed the number in ${attempts} attempts.`);
saveGameResult(`Player won in ${attempts} attempts.`);
rl.close();
} else if (guessNumber < secretNumber) {
console.log('Try higher.');
playGame();
} else {
console.log('Try lower.');
playGame();
}
} else {
console.log('Please enter a valid number within the specified range.');
playGame();
}
});
}
-
rl.question(\Guess a number between ${minNumber} and ${maxNumber}: `, guess => { ... }): prompts the user to enter a number within the specified range. The user's input is passed to the callback function as theguess` 引数としてコールバック関数に渡される; -
if (isValidGuess(guess)) { ... }: 入力された値がisValidGuess()関数で有効な推測かどうかを確認する; -
attempts++;: プレイヤーが何回推測したかを追跡するためにattemptsカウンターをインクリメントする; -
const guessNumber = parseInt(guess);: ユーザーの入力をparseInt()で文字列から整数に変換する; -
if (guessNumber === secretNumber) { ... }: プレイヤーの推測が秘密の数と一致するかどうかを確認する。一致した場合、成功メッセージを表示し、結果を保存し、readlineインターフェースを閉じてゲームを終了する; -
else if (guessNumber < secretNumber) { ... }: 秘密の数がより大きいことをプレイヤーに伝え、playGame()を再度呼び出してゲームを続行する; -
else { ... }: 秘密の数がより小さいことをプレイヤーに伝え、playGame()を再度呼び出してゲームを続行する; -
else { ... }(バリデーションチェック後): 無効な入力を処理し、許可された範囲内の有効な数値を入力するようプレイヤーに促し、その後playGame()を再度呼び出す。
説明: playGame 関数はゲームループの中核を担います。rl.question を使用してユーザーに推測値を入力させます。推測値が有効な場合、この関数は推測値が秘密の数字と一致するかどうかを確認します。一致しない場合は、ユーザーにフィードバックを提供し、再帰的にゲームループを続行します。
ステップ 5: ゲーム結果の保存
ユーザーのゲーム達成結果を game_results.txt ファイルに保存するロジックを実装します。
async function saveGameResult(result) {
try {
await fs.appendFile('game_results.txt', `${result}\n`);
console.log('Game result saved.');
} catch (err) {
console.log('Failed to save game result.');
}
}
-
async function saveGameResult(result) { ... }:saveGameResult()という名前の非同期関数を定義し、resultパラメータを受け取り、関数本体内でawaitキーワードの使用を可能にします。 -
try { ... } catch (err) { ... }: 非同期ファイル操作中に発生する可能性のあるエラーを処理します。 -
await fs.appendFile('game_results.txt', \${result}\n`);: appends the providedresultfollowed by a newline character to thegame_results.txtfile. Theawait` キーワードはファイル操作が正常に完了するまで実行を一時停止します。 -
console.log('Game result saved.');: ゲーム結果が正常にファイルに書き込まれた際に確認メッセージを表示します。 -
console.log('Failed to save game result.');: ファイル操作が失敗し、catchブロックで例外が捕捉された場合にエラーメッセージを表示します。
説明: saveGameResult 関数は、fs.promises を使用してゲーム結果を game_results.txt ファイルに追記します。結果の保存が成功したか失敗したかについてフィードバックを提供します。
ステップ 6: ゲームの開始
ウェルカムメッセージを作成し、ゲームを開始します:
console.log('Welcome to the Guess the Number game!');
playGame();
説明: ウェルカムメッセージを表示し、playGame 関数を呼び出してゲームループを開始します。
完全なアプリコード
const readline = require("readline");
const fs = require("fs").promises;
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const minNumber = 1;
const maxNumber = 100;
const secretNumber =
Math.floor(Math.random() * (maxNumber - minNumber + 1)) + minNumber;
let attempts = 0;
function isValidGuess(guess) {
return !isNaN(guess) && guess >= minNumber && guess <= maxNumber;
}
function playGame() {
rl.question(
`Guess a number between ${minNumber} and ${maxNumber}: `,
(guess) => {
if (isValidGuess(guess)) {
attempts++;
const guessNumber = parseInt(guess);
if (guessNumber === secretNumber) {
console.log(
`Congratulations! You guessed the number in ${attempts} attempts.`
);
saveGameResult(`Player won in ${attempts} attempts.`);
rl.close();
} else if (guessNumber < secretNumber) {
console.log("Try higher.");
playGame();
} else {
console.log("Try lower.");
playGame();
}
} else {
console.log("Please enter a valid number within the specified range.");
playGame();
}
}
);
}
async function saveGameResult(result) {
try {
await fs.appendFile("game_results.txt", `${result}\n`);
console.log("Game result saved.");
} catch (err) {
console.log("Failed to save game result.");
}
}
console.log("Welcome to the Guess the Number game!");
playGame();
-
1~2行目: 組み込みの
readlineモジュールと、非同期ファイル操作用のfsモジュールのpromisesAPI をインポート。 -
4~7行目: ユーザー入力の読み取りとコンソールへの出力のための readline インターフェース
rlを作成。 -
9~10行目: 推測範囲の最小値と最大値を定義。
-
12~13行目:
Math.random()を使用して指定範囲内のランダムな秘密の数値を生成。 -
14行目: プレイヤーが行った推測回数を記録する
attemptsカウンターを初期化。 -
16~18行目: 入力値が許可された範囲内の数値かどうかを検証する
isValidGuess()関数を定義。 -
20~47行目: 再帰的な
playGame()関数を定義し、以下を実行:- プレイヤーに推測値の入力を促す;
- 入力値の検証;
- 推測値が秘密の数値と一致するかを判定;
- 推測値が小さいか大きいかのフィードバックを提供;
- 必要に応じて自身を再度呼び出してゲームを継続;
- 正解時に結果を保存し、ゲームを終了;
-
49~56行目: ゲーム結果を
saveGameResult()ファイルに保存し、エラー処理も行う非同期関数game_results.txtを定義。 -
58行目: プレイヤーへのウェルカムメッセージを表示。
-
59行目:
playGame()関数を呼び出してゲームを開始。
概要
このプログラムは数当てゲームを作成します。プレイヤーは指定された範囲内でランダムに生成された数値を推測します。ゲームは各推測後にフィードバックを提供し、試行回数を記録し、成功した結果を非同期ファイル操作でテキストファイルに保存します。
フィードバックありがとうございます!
AIに質問する
AIに質問する
何でも質問するか、提案された質問の1つを試してチャットを始めてください