【ポートフォリオ 01】数当てゲーム(Guess the Number Game)〜標準入出力とループ〜
はじめに
私は現在、未経験からバックエンドエンジニアを目指して学習を進めています。
その一環として、Pythonの基本文法を使いながら、標準入力・出力やループ、例外処理といった実務でも重要な基礎スキルの理解を深めています。
この記事では、学習のアウトプットとして実装した「数当てゲーム(Guess the Number Game)」を紹介します。
このプログラムは、ユーザーの入力を受け取りながら、安全に処理を進める仕組みを意識して設計しました。特に、入力ミスに対応するエラーハンドリングや、コードの再利用性を高める関数化などに取り組みました。
課題概要
本課題は、プログラミング学習サイト「RecursionCS」にて出題された演習問題をもとにしています。
【課題】
ユーザーに対して、2つの整数(最小値 n と最大値 m)を入力してもらいます。
このとき、必ず「最小値が最大値以下」であることを確認してください。
プログラムは、入力された範囲 n から m の中で乱数を生成します(random モジュールの randint 関数を使用)。
その後、ユーザーは生成された乱数を当てるゲームに挑戦します。ユーザーは数字を入力し、正解するまで繰り返し推測を続けるゲームループを作成してください。
さらにゲームの難易度を上げるため、ユーザーの推測回数に制限を設けることも可能です。この場合、最大試行回数を決めて、for 文で回数制限付きのループを実装するか、while 文で正解まで繰り返す方法を選択してください。
開発環境
- 使用PC:MacBook Pro(2019年モデル)
- OS:macOS Sequoia 15.5
- Pythonバージョン:3.9.6(Homebrewでインストール)
※ 現時点では3.12.xなどもありますが、この記事では 3.9.6 で動作確認を行なっています - エディタ:Visual Studio Code(VSCode)
- 実行:ターミナル上で
python3 main.py
コマンドを使用
目的
この課題を通じて、以下のような基本的な構文や処理の理解を深めることを目的としました。
-
標準入力・出力の扱い方の理解
ユーザーからの入力を安全かつ適切に受け取る処理を実装しました。 -
ループ処理と条件分岐の基礎
while や for ループを使って繰り返し処理を行なうロジックを実装しました。 -
乱数生成(random モジュール)の利用方法
ユーザーが予測する対象となる値をランダムに生成しました。 -
例外処理(try-except)による入力バリデーション
ユーザーが不正な入力をした際にもプログラムが止まらず、正しい案内ができるようにしました。 -
関数化によるコードの整理・再利用
共通処理を関数として切り出し、可読性と保守性を意識しました。
ゲームの動作フロー(設計メモ)
※ 筆者による手書きメモ
実装前に、まずゲームの全体フローを紙に書き出しました。
ここから、必要な処理を洗い出してタスクを分解しました。これにより、開発の見通しを立てたうえで実装に着手できたため、手戻りやコードの書き直しを最小限に抑えることができたと思います。
タスク一覧(動作フローに基づく)
1. ゲーム開始前の準備
- 「ゲームスタート」メッセージを表示
- ユーザーに最小値 n の入力を促す
- ユーザーに最大値 m の入力を促す
- n >= m の場合はエラーメッセージを表示して再入力を促す
2. 正解値の設定
- random.randint(n, m) で正解のランダムな数値を生成
3. モード選択と表示
- ゲームモードを選択(1: 回数制限あり / 2: 無制限)
- 範囲と選択モードの確認メッセージを表示
4. 回数制限モード(モード1)
- チャレンジ回数を入力(1~m-n+1の範囲)
- 各試行で数値を入力し、正解かを判定
- 正解なら「おめでとう!」を表示して終了
- 不正解であれば再度入力メッセージを出力
- 回数内に正解できなかった場合、「Game Over」と正解を表示
5. 無制限モード(モード2)
- 正解するまでループして入力を受け付ける
- 不正解であれば再度入力メッセージを出力
実装の方向性
1. ゲーム開始前の準備
- ゲームスタートのメッセージを表示し、ユーザーに最小値(n)と最大値(m)を順に入力してもらう
- 入力は例外処理(try-except)で安全に行ない、不正な入力の場合には再入力を促す
- 最小値が最大値以上の場合はエラーメッセージを出力し、正しい範囲が入力されるまでwhileループで繰り返す
2. 正解値の設定
- random.randint(n, m)を使い、指定された範囲内のランダムな正解値を生成する
3. モード選択と表示
- ゲームモードを
1
(回数制限あり)か2
(無制限)で選択してもらう - 入力が
1
または2
以外の場合は、whileループで再入力を求める - 選択結果と入力範囲をユーザーに案内するメッセージを出力
4. 回数制限モード(モード1)
- 最大試行回数は範囲の幅(m-n+1)以内に制限し、ユーザーに挑戦回数を入力してもらう
- forループで決まった回数だけ繰り返し予想値を入力させ、判定関数で正解かどうかをチェック
- 正解ならメッセージを表示して終了、不正解なら「高すぎる」「低すぎる」「範囲外」などのメッセージを出力
- 回数内に当てられなければ、ゲームオーバーのメッセージと正解値を表示
5. 無制限モード(モード2)
- whileループで正解するまで予想値を受け付け
- 不正解の場合は適切なメッセージを表示し、ユーザーに継続の意思(y/n)を尋ねる
- 「y」ならループを継続、「n」ならゲームオーバーを表示して終了。その他の入力は再入力を促す
例外処理を行なう理由
例外処理(try-except)を導入したのは、ユーザー入力の不正値によるクラッシュを防ぎ、安全な入力処理を実現するためです。
回数制限ではfor
, 回数制限なしではwhile
を使用した理由
whileループは条件次第で繰り返す処理に適しており、入力の妥当性チェックや継続の有無判断など、回数が未定の繰り返しに使用しています。
forループは回数が決まっている処理に適しているため、モード1の試行回数分だけの繰り返しに用いています。
関数を定義した理由
処理を関数に分割することで、再利用や保守を簡単にできるようにするためです。
実装中に気づいた追加タスク
3. モード選択と表示
- 入力モードが正しくないときの処理
4. 回数制限モード(モード1)
- チャレンジ回数を入力(1~m-n+1の範囲)
- 不正解であればヒントを表示する(「Too High」「Too Low」「範囲外」)
- 回数内に正解できなかった場合、正解を出力する
5. 無制限モード(モード2)
- 不正解であればヒントを表示する(「Too High」「Too Low」「範囲外」)
- ユーザーに Continue? (y/n) の入力を促す(いつでも終了できるようにする)
- y なら継続
- n なら「Game Over」と正解を表示し終了
- その他の入力には再入力を促す
実装時に悩んだこと
-
最初に「Enterキーを押してゲームスタート」という部分を何で実装するか
input()で文字列を出力しましたが、目的に対して不要な処理もあったため、最終的にprint()を使用しました。 -
入力内容が整数以外のときの対応: 関数を作って対応
-
正しい内容が入力されるまで続くよう、whileループを使用しました。
def get_integer(prompt):
while True:
try:
return int(input(prompt))
except ValueError:
print("Please enter a valid number.")
実装中のエラー
エラー①
【内容】"int" object is not iterable
【原因】
① inputの冒頭で型指定 int がなかったこと
② rangeを使っていなかったこと
エラー②
【内容】入力値エラーのときにゲームが強制終了になる
【原因】エラーハンドリングがされていなかったこと
学び・気づき
- whileループと例外処理を実装したことで、正しい入力がされるまで繰り返し処理が実装できたこと
- 実装前のタスクの洗い出しの段階で、これで進められると思って取り組んだが、実際に実装していく中で、「こうした方が親切かな」と思い、追加したタスクがあった点は今後気をつけていきたい。最低限必要な処理だけ、設計の段階で確実に洗い出し、追加タスクをできるだけ発生させないようにしていきたい。
- これで大丈夫と考えてしまった見積もりの甘さが、追加タスクを発生させたこと
- 一度実装した後に、共通部分をまとめたことで、再利用性と可読性を改善することができたこと
- 繰り返し使用するメッセージをあらかじめ変数に格納して再利用使用という発想に至った点はナイスだった
-
format()
の使い方を公式ドキュメントと実装を通じて使えるようになった - 実装前に動作フローを紙に書き、処理の全体像を把握できたことで、大きな手戻りなく進めることができた
改善点
- 因数分解を正確に行なうこと
動作フローを整理し、タスクの洗い出しをしている段階で、本当に実現したいことを正確にまとめる - 実装前にできるだけ、共通処理になる部分をまとめ、重複の実装を事前に防ぎ、開発工数を減らすこと
- 可読性の高い変数名を命名できるようにトレーニングを積み重ねること
- 自然な英語表現を書けるようになること
まとめ
今回、RecursionCSの課題の1つである「Guess the Number Game」に取り組んだことで、Pythonの基本文法を組み合わせて実際に動くプログラムを完成させるプロセスを体験することができました。
特に印象に残っているのは、例外処理とループ処理の使い分け、そして関数化による構造的なコードの整理です。単に正解を当てるゲームを作るだけでなく、入力ミスへの対応やヒント表示、ユーザーにとっての使いやすさまで考えた設計を行なったことで、コードの保守性や拡張性を意識する良い練習になりました。
また、実装前に動作フローを紙に書き出して整理したことが、作業の見通しを立てるうえで非常に役立ったと感じています。事前の設計があることで、途中で迷ったり、手戻りが大きくなったりすることを防げました。
さらに、開発途中で気づいたことや後から追加した機能も含めて振り返りを行なうことで、自分の見積もり力や実装力の課題も明確になりました。次回以降は、初期設計の精度をもっと高めることで、より効率的な開発ができるようにしていきたいと思います。
今後もこのようなアウトプットを継続し、実践的なスキルを積み上げていくことで、未経験からのバックエンドエンジニア転職に向けて着実に前進していきます。
最後までお読みいただき、ありがとうございました。
参考URL
Discussion