【Python】レッスン3-S1:丁半賭博ゲームを作ろう
一つ前のLessonでは無名関数について学習しました。
今回はLessonで学習した内容を応用して丁半賭博ゲームを作成しましょう。
Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数とスコープ編
・Lesson3-1:関数の基本を理解しよう
・Lesson3-2:関数の戻り値とデフォルト引数を理解しよう
・Lesson3-3:スコープの概念を理解しよう
・Lesson3-4:関数を使いこなそう
・Lesson3-5:無名関数を理解しよう
・練習問題3-1:丁半賭博ゲームを作ろう ◁今回はココ
・練習問題3-2:石取りゲームを作ろう
Lesson4:データ構造編
Lesson5:オブジェクト指向編
次のステップ:Python基礎習得者にお勧めの道5選(実務or副業)
Pythonのゲームコード一覧は こちらをクリック
Pythonでのゲームアプリ開発は こちらをクリック
丁半(サイコロ)ゲームを作ろう|関数×条件分岐の実践
サイコロを使った丁半賭博ゲームを作成しましょう。
このゲームでは、プレイヤーが掛け金を決めてサイコロの結果(丁(偶数)か半(奇数)か)を予測し、勝敗を決めます。
プレイヤーが勝てば掛け金を得て、負ければ掛け金を失います。また、所持金が無くなった時点でゲームが終了します。
条件分岐、例外処理、関数、そして無名関数(lambda)を用いて、コードを完成させましょう。
要件と仕様|関数編の実装方針
以下の要件に従ってコードを完成させてください。
- 初期所持金は1000円とする。
- サイコロを2個振り、合計の偶奇で勝敗を決める。
- 掛け金は所持金の範囲内の正の整数。非数や範囲外は例外処理でエラーメッセージを出し再入力させる。
- 丁/半の選択と続行確認は数値入力(実行結果例に準ずる)。無効入力は再入力させる。
- 勝てば掛け金分だけ所持金を増やし、負ければ掛け金分だけ減らす。
- 所持金が0円になったら終了。所持金が残っている場合はプレイヤーの選択で継続可。
- 終了時に最終所持金とゲーム終了メッセージを表示する。
ただし、以下のような実行結果となるコードを書くこと。
丁半賭博ゲームを始めます! プレイヤーの所持金: 1000円 いくらかけますか? ⇒ 500 丁か半か?(丁:0,半:1) ⇒ 1 サイコロの目: 3, 4 ⇒ 半 あなたの勝ち!賞金は500円 プレイヤーの所持金: 1500円 続けますか?(はい:0,いいえ:1) ⇒ 1 最終所持金は1500円でした。 丁半賭博ゲームを終わります。
【ヒント】難しいと感じる人だけ見よう
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
- ヒント1【コードの構成を見る】
-
正解のコードは上から順に以下のような構成となっています。
1:掛け金を入力する関数
・サイコロに使う標準モジュールを最初に読み込む。
・関数は所持金を受け取り、掛け金を返すかたちにする。
・無限ループで入力を繰り返し、正しい値が来たら抜ける。
・文字入力を整数に変換する処理でエラーが起きたら、分岐して再入力を促す。
・金額が1以上かつ所持金以下かどうかを条件でチェックし、範囲外はメッセージを出してやり直す。2:丁か半かを選択する関数
・入力は「0か1か」の二択であることを明示して案内する。
・文字列の入力を整数に変換してから判定する。
・0または1以外ならメッセージを出して再入力を促す。
・数字以外が入ったときのエラーを補足し、プログラムが止まらないようにする。
・正しい値が入ったら、その値を返してループを抜ける。3:サイコロを振る関数
・サイコロ1個分の出目は「1〜6(両端を含む)」の整数から等確率で選ぶ。
・2個分の出目を独立に用意し、それぞれ別の変数に入れるイメージ。
・戻り値は2つの数を一度に返す(後で同時に受け取りやすくするため)。
・ここで作った2つの数は、後で合計して偶奇を判定する材料になる。4:続けるかどうかを確認する関数
・有効な入力は「0(続ける)」「1(やめる)」の二択であることを前提にする。
・数字以外の入力が来る可能性を考え、例外処理で受け止めて再入力させる。
・0でも1でもない場合は、メッセージを出してループを継続する。
・正しい値が得られたら、その値を返して処理を終了する。
・返された値は後のメイン処理でゲーム継続/終了の判定に用いる。5:ゲーム本体の導入
・メイン処理は専用の関数名でまとめ、最初に開始メッセージを表示する。
・プレイヤーの初期所持金を明示的に設定して、ゲーム状態を初期化する。
・偶奇判定と「0/1 → 丁/半」の変換は、短い無名関数として関数の冒頭に置く。
・小さなユーティリティは「使う場所の近く」に置くと読みやすい。
・ここで用意したユーティリティは後続の勝敗判定や表示で使われる。6:1ターン分のゲームループ
・ループの最初で「今の所持金」を見せると、次の判断(掛け金や継続)がしやすい。
・勝敗は「予想ラベル」と「結果ラベル」が一致するかどうかの比較で決める。
・サイコロの合計の偶奇を判定してから、文字ラベル(丁/半)に変換して表示する。
・所持金の増減は勝ち負けの直後に反映し、0以下ならすぐ終了する。
・継続確認は数値入力で行い、「やめる」の選択ならbreak
でループを抜けるイメージを持つ。7:ゲーム終了処理
・ループの外で最終所持金を表示すると、途中終了でも重複を避けられる。
・所持金の数値は埋め込み表示を使うと読みやすい。
・終了メッセージは簡潔で一貫した文言にする(実行結果例に合わせる)。
・「終了時に必ず表示する」ことを意識して、位置をループの後に置く。8:ゲームエントリポイント
・「このファイルを直接動かしたときだけ処理を実行する」ための条件を書く。
・メインの処理は専用の関数名にまとめ、そこを呼び出す形にする。
・他のファイルから読み込んだときに勝手にゲームが始まらないようにするのが目的。
・テストや再利用を見据えた標準的な書き方であることを意識する。
- ヒント2【穴埋め問題にする】
-
以下のコードをコピーし、コメントに従ってコードを完成させて下さい。
import random # 掛け金を入力する関数 '''(穴埋め)get_bet 関数の定義(引数: money を受け取り、掛け金を返す)''' while True: try: bet = int(input("いくらかけますか? ⇒ ")) if 0 < bet <= money: return bet else: print("無効な入力です!所持金以内の正しい金額を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。") # 丁か半かを選択する関数 '''(穴埋め)get_choice 関数の定義(丁/半の選択を数値で受け取り、0か1のみを返す)''' while True: try: choice = int(input("丁か半か?(丁:0,半:1) ⇒ ")) if choice in (0, 1): return choice else: print("無効な入力です!0か1を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。") # サイコロを振る関数 def roll_dice(): dice1 = random.'''(穴埋め)'''(1, 6) dice2 = random.randint(1, 6) return dice1, dice2 # 続けるかどうかを確認する関数 '''(穴埋め)ask_continue 関数の定義(続行確認を数値で受け取り、0か1のみを返す)''' while True: try: continue_game = int(input("続けますか?(はい:0,いいえ:1) ⇒ ")) if continue_game in (0, 1): return continue_game else: print("無効な入力です!0か1を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。") # メインのゲーム関数 def cho_han_game(): print("丁半賭博ゲームを始めます!") money = '''(穴埋め)''' # 初期所持金 '''(穴埋め)無名関数 is_even の定義(n が偶数なら True を返す)''' '''(穴埋め)無名関数 choice_to_label の定義(0→'丁', 1→'半' に変換する)''' '''(穴埋め)ゲームのメインループ(所持金が正の間 繰り返す)''' print(f"プレイヤーの所持金: {money}円") # 掛け金を取得 bet = get_bet(money) # 丁か半かの選択 choice = get_choice() choice_label = choice_to_label(choice) # サイコロを振る dice1, dice2 = roll_dice() dice_sum = dice1 + dice2 outcome_label = '丁' if is_even(dice_sum) else '半' print(f"サイコロの目: {dice1}, {dice2} ⇒ {outcome_label}") # 勝敗判定 if outcome_label == choice_label: print(f"あなたの勝ち!賞金は{bet}円") money += bet else: print(f"あなたの負け!{bet}円没収!") money -= bet # 所持金が尽きたら終了 if money <= 0: break # 続けるかどうかを確認 if ask_continue() == 1: break print(f"最終所持金は{money}円でした。") print("丁半賭博ゲームを終わります。") # ゲームを実行 if __name__ == "__main__": '''(穴埋め)'''()
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
当サイトではテキストベースのゲームコードを多数紹介していますが、それだけでなく 画面上で遊べるゲームアプリ の作り方を紹介たコースも用意してあります。
Pythonの実践力強化にもなりますので、ぜひ挑戦して下さい^^
解答と解説|丁半賭博ゲームのサンプルコード
この問題の一つの正解例とそのコードの解説を以下に示します。
解答例|丁半賭博ゲームプログラム
例えば以下のようなプログラムが考えられます。
- 正解コード
-
import random # 掛け金を入力する関数 def get_bet(money): while True: try: bet = int(input("いくらかけますか? ⇒ ")) if 0 < bet <= money: return bet else: print("無効な入力です!所持金以内の正しい金額を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。") # 丁か半かを選択する関数 def get_choice(): while True: try: choice = int(input("丁か半か?(丁:0,半:1) ⇒ ")) if choice in (0, 1): return choice else: print("無効な入力です!0か1を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。") # サイコロを振る関数 def roll_dice(): dice1 = random.randint(1, 6) dice2 = random.randint(1, 6) return dice1, dice2 # 続けるかどうかを確認する関数 def ask_continue(): while True: try: continue_game = int(input("続けますか?(はい:0,いいえ:1) ⇒ ")) if continue_game in (0, 1): return continue_game else: print("無効な入力です!0か1を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。") # メインのゲーム関数 def cho_han_game(): print("丁半賭博ゲームを始めます!") money = 1000 # 初期所持金 is_even = lambda n: n % 2 == 0 choice_to_label = lambda c: '丁' if c == 0 else '半' while money > 0: print(f"プレイヤーの所持金: {money}円") # 掛け金を取得 bet = get_bet(money) # 丁か半かの選択 choice = get_choice() choice_label = choice_to_label(choice) # サイコロを振る dice1, dice2 = roll_dice() dice_sum = dice1 + dice2 outcome_label = '丁' if is_even(dice_sum) else '半' print(f"サイコロの目: {dice1}, {dice2} ⇒ {outcome_label}") # 勝敗判定 if outcome_label == choice_label: print(f"あなたの勝ち!賞金は{bet}円") money += bet else: print(f"あなたの負け!{bet}円没収!") money -= bet # 所持金が尽きたら終了 if money <= 0: break # 続けるかどうかを確認 if ask_continue() == 1: break print(f"最終所持金は{money}円でした。") print("丁半賭博ゲームを終わります。") # ゲームを実行 if __name__ == "__main__": cho_han_game()
解答例の解説|丁半賭博ゲームの考え方
解答例の詳細解説は以下の通りです。
- 詳細解説
-
掛け金を入力する関数
import random # 掛け金を入力する関数 def get_bet(money): while True: try: bet = int(input("いくらかけますか? ⇒ ")) if 0 < bet <= money: return bet else: print("無効な入力です!所持金以内の正しい金額を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。")
最初に、後でサイコロを振るための標準モジュールを読み込みます。
続いて、プレイヤーが入力する掛け金を正しく受け取るための関数を用意しています。
関数は所持金を受け取り、正の整数で所持金以内かどうかを確認します。
数字以外が入力されたり、範囲外の金額が入った場合には、エラーメッセージを表示してもう一度入力してもらいます。
正しい値が入ったときだけその金額を呼び出し元に返します。これにより、ゲームの途中で間違った入力があってもプログラムが止まらず、安心して操作できる設計になります。丁か半かを選択する関数
# 丁か半かを選択する関数 def get_choice(): while True: try: choice = int(input("丁か半か?(丁:0,半:1) ⇒ ")) if choice in (0, 1): return choice else: print("無効な入力です!0か1を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。")
この部分では、プレイヤーに「丁」か「半」かを選んでもらう入力を担当します。
入力は数字で受け付け、あらかじめ決めた番号(丁は0、半は1)のどちらかだけが有効です。
数字以外を入力したり、決められていない値を入れた場合にはエラーメッセージを表示し、正しい入力が得られるまで何度でもやり直してもらいます。
こうすることで、後続の処理が前提としている値(0か1)だけを扱えるようになり、バグや思わぬ動作を防げます。サイコロを振る関数
# サイコロを振る関数 def roll_dice(): dice1 = random.randint(1, 6) dice2 = random.randint(1, 6) return dice1, dice2
この部分は、実際にサイコロを振ったときの出目をプログラムで用意します。
サイコロの目は1〜6の整数で、どの数字も同じ確率で選ばれます。
ここではサイコロを2個振る想定なので、同じ仕組みで2回値を作り、まとめて呼び出し元に返します。
返されるのは2つの整数で、後の処理では合計を計算して丁か半かを判定します。
乱数は毎回結果が変わるため、ゲームらしい予測不能さが生まれます。続けるかどうかを確認する関数
# 続けるかどうかを確認する関数 def ask_continue(): while True: try: continue_game = int(input("続けますか?(はい:0,いいえ:1) ⇒ ")) if continue_game in (0, 1): return continue_game else: print("無効な入力です!0か1を入力してください。") except ValueError: print("無効な入力です!数字を入力してください。")
この部分は、プレイヤーに「続ける」か「やめる」かを尋ねる役割です。
入力は数値で受け付け、決められた選択肢(はい=0、いいえ=1)のどちらかであることを必ず確認します。
数字以外を入力した場合や、用意していない数値が入った場合は、エラーメッセージを表示して再入力を求めます。
正しい値が入ったらそのまま返し、呼び出し側でゲームを続行するか終了するかの判断に使います。
こうしておくと、ゲームの進行が想定外の入力で止まったり、誤った分岐に進んだりすることを防げます。ゲーム本体の導入
# メインのゲーム関数 def cho_han_game(): print("丁半賭博ゲームを始めます!") money = 1000 # 初期所持金 is_even = lambda n: n % 2 == 0 choice_to_label = lambda c: '丁' if c == 0 else '半'
ここではゲーム全体を動かすメイン関数を用意し、最初に開始のメッセージを表示します。
次に、プレイヤーの初期所持金を決めてゲームの状態を初期化します。
あわせて、合計が偶数かどうかを判定する処理と、数値で受け取った選択を「丁/半」の文字に変換する処理を、短い無名関数として関数内の先頭にまとめています。
こうしておくと、後に続く処理から近い場所で必要な道具が揃い、読みやすく保守もしやすくなります。
無名関数は関数を返したり受け取ったりする高度な使い方ではなく、局所的な小さな変換・判定に使うことで、コードの見通しを良くしています。1ターン分のゲームループ
# メインのゲーム関数 def cho_han_game(): print("丁半賭博ゲームを始めます!") money = 1000 # 初期所持金 is_even = lambda n: n % 2 == 0 choice_to_label = lambda c: '丁' if c == 0 else '半' while money > 0: print(f"プレイヤーの所持金: {money}円") # 掛け金を取得 bet = get_bet(money) # 丁か半かの選択 choice = get_choice() choice_label = choice_to_label(choice) # サイコロを振る dice1, dice2 = roll_dice() dice_sum = dice1 + dice2 outcome_label = '丁' if is_even(dice_sum) else '半' print(f"サイコロの目: {dice1}, {dice2} ⇒ {outcome_label}") # 勝敗判定 if outcome_label == choice_label: print(f"あなたの勝ち!賞金は{bet}円") money += bet else: print(f"あなたの負け!{bet}円没収!") money -= bet # 所持金が尽きたら終了 if money <= 0: break # 続けるかどうかを確認 if ask_continue() == 1: break
この部分は、ゲームの「1回分の流れ」をまとめて処理します。
まず現在の所持金を表示し、掛け金を安全に受け取ります。
次に、丁か半かの選択を数値で受け取り、表示用のラベルに変換します。
その後サイコロを2回振り、出目の合計が偶数か奇数かで結果ラベルを決め、出目と結果を表示します。
プレイヤーの予想と結果が一致していれば所持金を増やし、外れていれば減らします。
所持金が尽きたらそこでゲーム終了です。
まだお金が残っている場合は、続けるかどうかを確認し、「やめる」の選択ならこのループを抜けます。
こうして、資金が続く限り同じ手順を繰り返せる仕組みになっています。ゲーム終了処理
print(f"最終所持金は{money}円でした。") print("丁半賭博ゲームを終わります。")
この部分は、メインのループを抜けた後に行う「締め」の処理です。
ゲームが終わる理由は所持金が尽きた場合か、プレイヤーが続行しないと決めた場合のいずれかですが、どちらのケースでも最後に現在の所持金を分かりやすく表示し、ゲーム終了のメッセージを出して処理を終えます。
終了のメッセージは1回だけに統一しておくことで、画面表示が重複せず、読み手にもわかりやすい結果になります。ゲームを起動するエントリポイント
# ゲームを実行 if __name__ == "__main__": cho_han_game()
この部分はファイルを「直接実行した場合」と「ほかのファイルから読み込んだ場合」を区別するための仕組みです。直接実行のときだけメインの関数を呼び出し、ゲームが始まります。
一方で、学習用に他のファイルから関数を再利用したいときや、テストを行いたいときには自動でゲームが起動しないようにできます。
これにより、コードをモジュールとしてもスクリプトとしても扱えるようになり、拡張や保守がしやすくなります。
Pythonのゲームコード一覧は こちらをクリック
Pythonでのゲームアプリ開発は こちらをクリック
- サイト改善アンケート|ご意見をお聞かせください(1分で終わります)
-
本サイトでは、みなさまの学習をよりサポートできるサービスを目指しております。
そのため、みなさまの「プログラミングを学習する理由」などをアンケート形式でお伺いしています。1分だけ、ご協力いただけますと幸いです。
【Python】サイト改善アンケート