関数でゲームロジックを整理しよう
プログラムを作っていると、同じような処理を繰り返し書いてしまうことがよくあります。特にゲームのロジックなどでは、
攻撃や防御など似たような計算や判定を複数の場所で使い回したくなるかもしれません。
同じ処理が何度も出てくると、バグが発生したときの修正が大変で、作り終わってからの手直しに時間がかかる原因となります。
そこでおすすめなのが「関数化」です。関数は「ある処理をひとまとまりにしたもの」であり、
コードを分割して整理しやすくする上で強力なツールです。繰り返し使う処理を関数化し、バグを見つけやすく、修正もしやすいプログラムを書く練習をしましょう。
なぜ関数で整理すると良いのか
関数を使うと以下のようなメリットがあります。
- 重複コードをなくせる
同じ処理を複数箇所に書かずに済むので、修正が必要になったときは関数の中身だけを直せば良いです。 - バグが見つけやすい
処理がひとまとまりになっているので、どこに問題があるかを特定しやすくなります。 - 読みやすいコードになる
関数化されていれば、処理の流れを関数名から把握できます。コード全体の構造が見通しやすくなるのです。 - テストがしやすい
関数単位で動作をチェックできるため、小規模でテストを書きやすくなります。
サンプル:数当てゲームを関数で作る
ここでは、簡単な「数当てゲーム」を例に関数化の手法を見てみましょう。以下のような機能を持つゲームを考えます。
- コンピュータが1~10の乱数を生成する
- プレイヤーが数字を入力して当てる
- 正解なら勝利、ハズレなら再度入力を促す
このゲームを関数化しないと、ランダム生成や判定処理、入力を繰り返す処理などを毎回書くかもしれません。試しに、まずは関数を使わずに書いた例を見てみます。
import random
answer = random.randint(1, 10)
print("数当てゲームを始めます。1~10の数字を当ててください。")
while True:
guess = input("あなたの予想は? ")
if not guess.isdigit():
print("数字を入力してください。")
continue
guess_num = int(guess)
if guess_num == answer:
print("正解です!")
break
else:
print("ハズレです。もう一度試してください。")
このコードはシンプルですが、もしゲームのルールが変わったり、あるいは「もう一度挑戦しますか?」のような追加機能が必要になったとき、
各所に散らばった処理をあちこち編集しなくてはなりません。たとえば、答えの判定部分を変えたり、入力チェックを厳しくしたりといった変更をする際、
修正箇所が複数だとミスもしやすくなります。
関数を定義してみる
では、これらの処理を関数にして整理してみましょう。数当てゲームでは主に以下のような機能を関数として分割できそうです。
- ランダムな答えを生成する関数
- ユーザー入力を処理し、整数を返す関数
- 答えを判定する関数
- メインのゲーム進行を管理する関数
さっそくコード例を見てみます。
import random
def generate_answer(min_num=1, max_num=10):
"""min_numからmax_numまでの乱数を返す関数"""
return random.randint(min_num, max_num)
def get_player_guess():
"""ユーザーに数字を入力させて、整数に変換して返す関数"""
while True:
guess = input("あなたの予想は? ")
if guess.isdigit():
return int(guess)
else:
print("数字を入力してください。")
def check_guess(guess, answer):
"""ユーザーの予想(guess)と正解(answer)を比較し、結果を返す関数"""
if guess == answer:
print("正解です!")
return True
else:
print("ハズレです。もう一度試してください。")
return False
def play_guessing_game():
"""メインのゲーム進行を管理する関数"""
print("数当てゲームを始めます。1~10の数字を当ててください。")
answer = generate_answer()
while True:
guess = get_player_guess()
result = check_guess(guess, answer)
if result: # 当たりならTrue
break
# メイン処理
if __name__ == "__main__":
play_guessing_game()
これで、数字を当てるゲームの処理がそれぞれ独立した関数になりました。こうしておくと、下記のような拡張や修正がしやすくなります。
- ゲームの難易度を変更
「1~10」ではなく「1~100」に変更したい場合は、generate_answer()
のデフォルト引数を変えるだけで済みます。 - 入力チェック方法の変更
get_player_guess()
の関数内を変更すれば、数字以外にも特殊な入力や終了コマンドなどにも対応しやすくなります。 - 判定のロジック変更
たとえば「ハズレでも近かったらヒントを出す」といった機能を追加する場合は、check_guess()
内だけを修正できます。
このように関数を活用しておくことで、プログラムの規模が大きくなっても部品ごとに責任を分担できるのです。
関数化したプログラムのテスト
ゲームロジックを関数化すると、単体テストが書きやすくなります。Pythonには標準ライブラリとして
unittest
があるほか、pytest
という外部ライブラリを使う方法もあります。たとえば以下は
check_guess()
をテストする簡単なunittest
の例です。
import unittest
from guessing_game import check_guess
class TestGuessingGame(unittest.TestCase):
def test_check_correct(self):
# 正解の場合Trueが返る
self.assertTrue(check_guess(5, 5))
def test_check_incorrect(self):
# ハズレの場合Falseが返る
self.assertFalse(check_guess(3, 5))
if __name__ == "__main__":
unittest.main()
関数単位でテストが書けるので、ゲーム全体を起動しなくても部分的に動作確認ができます。
こうした小さなテストを積み重ねることで、バグ発生時にどの関数が原因なのかを特定しやすくなるメリットがあります。
まとめ
ゲームなどのコードを開発していると、機能の追加やルール変更が発生しがちです。繰り返し使う処理を早めに関数化しておけば、
コードを整理しやすく、バグの修正も局所化できるため作業効率が大きく向上します。特にゲームロジックのように「結果がすぐにわかる」処理では、
検証やデバッグがしやすい一方で、細かな変更が続く場合も多いです。そうした場合こそ関数を導入する価値があります。
初心者のうちは、コードの量をなるべく減らしてシンプルに書きたいという気持ちがあるかもしれませんが、長期的に見れば
「意味のあるまとまりを関数に分割」しておくことが、プログラミングを続ける上で大きな助けになります。ぜひ日頃から関数化を意識して
コードを書いてみてください。
以上が関数でゲームロジックを整理する際の基礎的な考え方と実装例です。分割と再利用の考え方を身につけることで、
より複雑なゲームやアプリケーションもスムーズに開発しやすくなるでしょう。ぜひ実際にコードを書きながら練習してみてください。