次の DEMO を見に行く
Python

【Python】じゃんけんアプリを作ってみた(初心者プログラミング)

takahide

おはようございます。タカヒデです。

本日はPythonで「じゃんけんアプリ」を作ってみました。

STEP形式で解説しているので、「まずは何かを作ってみたい」という初心者の方の参考になれば幸いです。

こんな人にオススメ
  • プログラミング初心者
  • 何から始めればよいか分からない
  • まずは簡単なゲームを作って興味を持ってみたい

ぜひ実際にコードを打ちながら作成してみてください。

「じゃんけんアプリ」完成イメージ

まずは、「じゃんけんアプリ」完成後の最終的なコードと完成イメージです。

import random
import tkinter as tk

# ============================
# 定数
# ============================
HANDS = ["グー", "チョキ", "パー"]  # じゃんけんの手
RULES = {                         # 左が右に勝つ対応表
    ("グー", "チョキ"): "win",
    ("チョキ", "パー"): "win",
    ("パー", "グー"): "win",
}
RESULT_TEXT = {                   # 判定→表示文の対応
    "win":  "結果:あなたの勝ち",
    "lose": "結果:あなたの負け",
    "draw": "結果:あいこ",
}

class JankenApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("じゃんけんアプリ")
        self.geometry("380x420")
        self.resizable(False, False)

        # タイトル
        tk.Label(self, text="じゃんけんしよう!", font=("Yu Gothic UI", 18, "bold")).pack(pady=(16, 8))

        # 区切り線
        tk.Frame(self, height=1, bg="#ccc").pack(fill="x", padx=16, pady=10)

        # 表示用の変数(あなた/コンピュータ/結果)
        self.player_var = tk.StringVar(value="あなた:-")
        self.cpu_var    = tk.StringVar(value="コンピュータ:-")
        self.result_var = tk.StringVar(value="結果:-")

        # 表示エリア
        frame_status = tk.Frame(self)
        frame_status.pack(pady=(4, 8))
        tk.Label(frame_status, textvariable=self.player_var, font=("Yu Gothic UI", 12)).grid(row=0, column=0, padx=8, pady=4)
        tk.Label(frame_status, textvariable=self.cpu_var,    font=("Yu Gothic UI", 12)).grid(row=1, column=0, padx=8, pady=4)
        tk.Label(self, textvariable=self.result_var, font=("Yu Gothic UI", 16, "bold")).pack(pady=(8, 12))

        # ボタン群
        btn_frame = tk.Frame(self)
        btn_frame.pack(pady=8)
        tk.Button(btn_frame, text="グー",   width=10, height=2, command=lambda: self.play("グー")).grid(row=0, column=0, padx=6, pady=6)
        tk.Button(btn_frame, text="チョキ", width=10, height=2, command=lambda: self.play("チョキ")).grid(row=0, column=1, padx=6, pady=6)
        tk.Button(btn_frame, text="パー",   width=10, height=2, command=lambda: self.play("パー")).grid(row=0, column=2, padx=6, pady=6)

    # ------------------------------
    # ロジック
    # ------------------------------
    def play(self, player_hand: str):
        cpu_hand = random.choice(HANDS)  # 定数からランダムに選ぶ
        self.player_var.set(f"あなた:{player_hand}")
        self.cpu_var.set(f"コンピュータ:{cpu_hand}")

        result = self.judge(player_hand, cpu_hand)
        self.show_result(result)

    def judge(self, p: str, c: str) -> str:
        if p == c:
            return "draw"
        return "win" if (p, c) in RULES else "lose"

    def show_result(self, result: str):
        self.result_var.set(RESULT_TEXT[result])

if __name__ == "__main__":
    app = JankenApp()
    app.mainloop()

こんなゲームが作れます。

STEP1:ウィンドウの表示

まずは、じゃんけんを動かすための土台となる「アプリのウィンドウ」を表示します。
ここでは最小限のコードで、ウィンドウの作成から表示までを確認します。

import tkinter as tk

class JankenApp(tk.Tk):
    def __init__(self):
        super().__init__()
        # ウィンドウの基本設定
        self.title("じゃんけんアプリ")
        self.geometry("380x420")     # 幅x高さ(ピクセル)
        self.resizable(False, False) # 横・縦のリサイズを禁止

        # タイトルラベル(画面上部の見出し)
        title = tk.Label(self, text="じゃんけんしよう!", font=("Yu Gothic UI", 18, "bold"))
        title.pack(pady=(16, 8))

if __name__ == "__main__":
    app = JankenApp()
    app.mainloop()

手順①:tkinterを読み込む

import tkinter as tk

「tkinter」はPython標準のGUIライブラリです。
ここでは「tkinterをtkという短い名前で使う」ために読み込んでいます。
以降、ラベルやボタンなどは「tk.Label」「tk.Button」のように書きます。

手順②:「JankenApp」クラスの作成

class JankenApp(tk.Tk):
    def __init__(self):
        super().__init__()

「class」はクラスという設計図を作る構文です。
ここでは「JankenApp」というクラスを定義しています。

「(tk.Tk)」は継承と呼ばれる仕組みで、「tkinterが用意するウィンドウ本体の機能」を引き継ぎます。

「def __init__(self):」はコンストラクタと呼ばれ、クラスから実体を作った直後に自動で一度だけ実行される初期設定の関数です。

「super().__init__()」は親クラス(tk.Tk)の初期化を呼び出します。
これによりウィンドウの中身を安全に設定できる状態になります。
ここを忘れるとウィンドウが正しく初期化されず、後の設定が失敗する原因になるため注意しましょう。

手順③:ウィンドウの基本設定

self.title("じゃんけんアプリ")
self.geometry("380x420")
self.resizable(False, False)

「title」はウィンドウ左上のタイトルバーに表示される文字列です。

「geometry」はウィンドウの大きさを「幅x高さ」のピクセル指定で行います。
ここでは幅380px、高さ420pxで指定しています。

「resizable(False, False)」はウィンドウのサイズ変更可否の設定です。
最初はレイアウト崩れを避けるため、横も縦もリサイズ不可にしています。
アプリが完成してから必要に応じて許可しましょう。

手順④:タイトルラベルを配置する

title = tk.Label(self, text="じゃんけんしよう!", font=("Yu Gothic UI", 18, "bold"))
title.pack(pady=(16, 8))

「Label」は文字を表示する部品です。
第1引数に「self」を渡すことで「このウィンドウ上に表示する」という意味になります。

「font」は「フォント名、サイズ、太字など」を指定します。

「pack」は配置方法です。
「pady=(16, 8)」は上下の余白で、上に16px、下に8pxのスペースを空けます。

手順⑤:アプリを起動するエントリーポイント

if __name__ == "__main__":
    app = JankenApp()
    app.mainloop()

「if __name__ == ‘__main__’:」は、このファイルを直接実行した時だけ中の処理を動かすための定型文です。
モジュールとして他のファイルから読み込まれた場合には実行されません。
「app = JankenApp()」で先ほど作成したクラスからアプリの実体を1つ作ります。
「app.mainloop()」はイベントループと呼ばれる処理で、ウィンドウを表示し続け、ボタンが押されたなどの操作を待ち受けます。
これを呼ばないとウィンドウはすぐに閉じてしまうため注意しましょう。

ここまでのSTEP1が完了した時点では以下のアプリができています。

STEP2:ボタンで「手」を選べるようにする

次は、じゃんけんの要である「グー・チョキ・パー」を選ぶボタンをウィンドウに追加します。
ボタンを押すと、自分の出した手が画面に表示されるようにします。

import tkinter as tk

class JankenApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("じゃんけんアプリ")
        self.geometry("380x420")
        self.resizable(False, False)

        # タイトル
        title = tk.Label(self, text="じゃんけんしよう!", font=("Yu Gothic UI", 18, "bold"))
        title.pack(pady=(16, 8))

        # あなたの手を表示するラベル
        self.player_var = tk.StringVar(value="あなた:-")
        player_lbl = tk.Label(self, textvariable=self.player_var, font=("Yu Gothic UI", 12))
        player_lbl.pack(pady=8)

        # ボタンフレーム(ボタンを横に並べる枠)
        btn_frame = tk.Frame(self)
        btn_frame.pack(pady=8)

        # グー・チョキ・パーのボタン
        btn_rock = tk.Button(btn_frame, text="グー", width=10, height=2,
                             command=lambda: self.play("グー"))
        btn_scissors = tk.Button(btn_frame, text="チョキ", width=10, height=2,
                                 command=lambda: self.play("チョキ"))
        btn_paper = tk.Button(btn_frame, text="パー", width=10, height=2,
                              command=lambda: self.play("パー"))

        btn_rock.grid(row=0, column=0, padx=6, pady=6)
        btn_scissors.grid(row=0, column=1, padx=6, pady=6)
        btn_paper.grid(row=0, column=2, padx=6, pady=6)

    def play(self, player_hand):
        self.player_var.set(f"あなた:{player_hand}")

if __name__ == "__main__":
    app = JankenApp()
    app.mainloop()

手順①:プレイヤーの手を表示する変数を作る

self.player_var = tk.StringVar(value="あなた:-")
player_lbl = tk.Label(self, textvariable=self.player_var, font=("Yu Gothic UI", 12))
player_lbl.pack(pady=8)

ここでは「あなたが出した手」を動的に表示するための仕組みを作ります。
「StringVar」はtkinterが提供する「文字列をリアルタイムに更新できる変数」です。
値を変えると自動的にラベルの表示も変わります。
最初の値として「あなた:-」と表示しておき、まだ何も選んでいない状態を表します。

「textvariable=self.player_var」とすることで、ラベルの中身をこの変数に紐づけます。以降、プログラムから「self.player_var.set(‘あなた:グー’)」のように値を変更すれば、画面表示も自動で切り替わります。

手順②:ボタンを並べるためのフレームを作る

btn_frame = tk.Frame(self)
btn_frame.pack(pady=8)

「Frame」はボタンやラベルなどをまとめるための箱のようなものです。
ウィンドウに直接部品を置いていくと、複雑になるにつれて配置が崩れやすくなるため、「Frame」で領域を分けて管理します。
「pack(pady=8)」で上下に8ピクセルの余白を取り、見た目を整えています。

手順③:「グー」「チョキ」「パー」ボタンを作る

btn_rock = tk.Button(btn_frame, text="グー", width=10, height=2,
                     command=lambda: self.play("グー"))

「Button」はボタンを作る部品です。
ここではボタンを押したときに「self.play(‘グー’)」という関数を実行するように設定しています。
「command=」の右側に関数を指定しますが、引数を渡す場合は「lambda」を使います。
「lambda」は「その場で小さな関数を定義する」書き方で、ここでは「ボタンが押されたらplay関数に“グー”を渡す」という意味になります。

手順④:ボタンを横に並べて配置する

btn_rock.grid(row=0, column=0, padx=6, pady=6)
btn_scissors.grid(row=0, column=1, padx=6, pady=6)
btn_paper.grid(row=0, column=2, padx=6, pady=6)

ここでは「grid」配置を使っています。「grid」は行と列を指定して、表のように部品を並べる方法です。
「row=0, column=0」は左、「row=0, column=1」は中央、「row=0, column=2」は右、というように並びます。
「padx」「pady」はボタンの周りの余白で、部品がくっつかないように適度にスペースを空けます。
これにより3つのボタンがきれいに横一列に整列します。

手順⑤:ボタンが押されたときに手を表示する

def play(self, player_hand):
    self.player_var.set(f"あなた:{player_hand}")

「def play(self, player_hand):」で関数「play」を定義しています。
この関数はボタンを押したときに呼び出されます。
「player_hand」は引数(ひきすう)で、ボタン側から渡された手(グー・チョキ・パー)が入ります。
「self.player_var.set()」で、表示用変数を更新します。
これにより、ボタンを押すたびに「あなた:グー」「あなた:チョキ」「あなた:パー」と切り替わります。

ここまでのSTEP2が完了した時点では以下のアプリができています。

STEP3:コンピュータの手と勝敗結果を表示する

今回は、コンピュータの手をランダムに決め、あなたの手との勝敗を判定して結果を表示します。
ここまでで「じゃんけんアプリ」が使えるものが完成します。

import random
import tkinter as tk

# 勝敗ルール:左が勝つ組み合わせをまとめた表
RULES = {
    ("グー", "チョキ"): "win",
    ("チョキ", "パー"): "win",
    ("パー", "グー"): "win",
}

class JankenApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("じゃんけんアプリ")
        self.geometry("380x420")
        self.resizable(False, False)

        # タイトル
        title = tk.Label(self, text="じゃんけんしよう!", font=("Yu Gothic UI", 18, "bold"))
        title.pack(pady=(16, 8))

        # 区切り線(細い横線)
        tk.Frame(self, height=1, bg="#ccc").pack(fill="x", padx=16, pady=10)

        # 表示用の変数を用意(あなた・コンピュータ・結果)
        self.player_var = tk.StringVar(value="あなた:-")
        self.cpu_var    = tk.StringVar(value="コンピュータ:-")
        self.result_var = tk.StringVar(value="結果:-")

        # 「あなた」「コンピュータ」の表示
        frame_status = tk.Frame(self)
        frame_status.pack(pady=(4, 8))
        player_lbl = tk.Label(frame_status, textvariable=self.player_var, font=("Yu Gothic UI", 12))
        cpu_lbl    = tk.Label(frame_status, textvariable=self.cpu_var,    font=("Yu Gothic UI", 12))
        player_lbl.grid(row=0, column=0, padx=8, pady=4)
        cpu_lbl.grid(row=1, column=0, padx=8, pady=4)

        # 勝敗結果の大きめラベル
        result_lbl = tk.Label(self, textvariable=self.result_var, font=("Yu Gothic UI", 16, "bold"))
        result_lbl.pack(pady=(8, 12))

        # ボタンフレーム(横並び)
        btn_frame = tk.Frame(self)
        btn_frame.pack(pady=8)

        # 3つの手のボタン
        tk.Button(btn_frame, text="グー",   width=10, height=2, command=lambda: self.play("グー")).grid(row=0, column=0, padx=6, pady=6)
        tk.Button(btn_frame, text="チョキ", width=10, height=2, command=lambda: self.play("チョキ")).grid(row=0, column=1, padx=6, pady=6)
        tk.Button(btn_frame, text="パー",   width=10, height=2, command=lambda: self.play("パー")).grid(row=0, column=2, padx=6, pady=6)

    # じゃんけんのメイン処理
    def play(self, player_hand: str):
        # コンピュータの手をランダムに選ぶ
        cpu_hand = random.choice(["グー", "チョキ", "パー"])

        # 画面表示を更新
        self.player_var.set(f"あなた:{player_hand}")
        self.cpu_var.set(f"コンピュータ:{cpu_hand}")

        # 勝敗を判定して結果ラベルに表示
        result = self.judge(player_hand, cpu_hand)
        if result == "win":
            self.result_var.set("結果:あなたの勝ち")
        elif result == "lose":
            self.result_var.set("結果:あなたの負け")
        else:
            self.result_var.set("結果:あいこ")

    # 勝敗判定(同じ手なら引き分け、RULESにあれば勝ち、なければ負け)
    def judge(self, p: str, c: str) -> str:
        if p == c:
            return "draw"
        if (p, c) in RULES:
            return "win"
        return "lose"

if __name__ == "__main__":
    app = JankenApp()
    app.mainloop()

手順①:randomを読み込む

import random

「random」は乱数を扱う標準モジュールです。
ここでは「コンピュータの手を毎回ランダムに選ぶ」ために使います。

手順②:勝敗ルール表を用意する

RULES = {
    ("グー", "チョキ"): "win",
    ("チョキ", "パー"): "win",
    ("パー", "グー"): "win",
}

「辞書(ディクショナリ)」という「対応表」を作っています。
キーが「勝つ組み合わせ(自分の手, 相手の手)」、値が「win」です。
例えば「(“グー”,”チョキ”)」がキーになっていれば「グーはチョキに勝つ」と読み取れます。

手順③:表示用の変数を3つ作る

# 区切り線(細い横線)
tk.Frame(self, height=1, bg="#ccc").pack(fill="x", padx=16, pady=10)

# 表示用の変数を用意(あなた・コンピュータ・結果)
self.player_var = tk.StringVar(value="あなた:-")
self.cpu_var    = tk.StringVar(value="コンピュータ:-")
self.result_var = tk.StringVar(value="結果:-")

「tk.Frame」で見やすくするための横線を入れます。

「StringVar」は「文字列を画面と連動させるための変数」です。
値を変えるとラベルの表示が自動で更新されます。
最初は「まだ選んでいない状態」を表すために「-」を表示しておきます。

手順④:ラベルを配置して表示する

# 「あなた」「コンピュータ」の表示
frame_status = tk.Frame(self)
frame_status.pack(pady=(4, 8))
player_lbl = tk.Label(frame_status, textvariable=self.player_var, font=("Yu Gothic UI", 12))
cpu_lbl    = tk.Label(frame_status, textvariable=self.cpu_var,    font=("Yu Gothic UI", 12))
player_lbl.grid(row=0, column=0, padx=8, pady=4)
cpu_lbl.grid(row=1, column=0, padx=8, pady=4)

# 勝敗結果の大きめラベル
result_lbl = tk.Label(self, textvariable=self.result_var, font=("Yu Gothic UI", 16, "bold"))
result_lbl.pack(pady=(8, 12))

「Label」は文字を表示する部品です。
「textvariable」に先ほどの表示用変数を渡すことで、後から「.set」で更新すると自動で画面も変わります。

「grid」は行・列の座標で並べる配置方法、「pack」は縦に積む配置方法です。
ここでは状態表示は「grid」で整列し、結果ラベルは中央に大きく配置するため「pack」を使っています。

手順⑤:グー・チョキ・パーのボタンを修正

# 3つの手のボタン
tk.Button(btn_frame, text="グー",   width=10, height=2, command=lambda: self.play("グー")).grid(row=0, column=0, padx=6, pady=6)
tk.Button(btn_frame, text="チョキ", width=10, height=2, command=lambda: self.play("チョキ")).grid(row=0, column=1, padx=6, pady=6)
tk.Button(btn_frame, text="パー",   width=10, height=2, command=lambda: self.play("パー")).grid(row=0, column=2, padx

STEP2ではいったん変数に代入してから配置していましたが、ここではあえて変数を使っていません。

理由は、このボタンを後から操作(色を変える・無効化するなど)する予定がないためです。
変数に入れず直接.grid()をつなげることで、コードが短くなり、見た目もすっきりします。

手順⑥:コンピュータの手をランダムに決定する

    # じゃんけんのメイン処理
    def play(self, player_hand: str):
        # コンピュータの手をランダムに選ぶ
        cpu_hand = random.choice(["グー", "チョキ", "パー"])

「random.choice」はリストから要素を1つ無作為に取り出します。
ここでは3つの手から1つ選ばれます。実行のたびに結果が変わるため、対戦らしさが生まれます。

手順⑥:勝敗を判定する関数を作る

def judge(self, p: str, c: str) -> str:
    if p == c:
        return "draw"
    if (p, c) in RULES:
        return "win"
    return "lose"

「judge」関数で勝敗を判定します。
判定の考え方は、まず同じ手なら引き分け。
違う手なら、先ほどの「RULES」に「(自分, 相手)」の組があるかを調べます。
あれば勝ち、なければ負けです。

手順⑦:結果ラベルを更新する

result = self.judge(player_hand, cpu_hand)
if result == "win":
    self.result_var.set("結果:あなたの勝ち")
elif result == "lose":
    self.result_var.set("結果:あなたの負け")
else:
    self.result_var.set("結果:あいこ")

「judge」関数が返す文字列に応じて、表示文を切り替えています。
ラベル更新は毎回必ず行い、古い表示が残らないようにします。

これでSTEP3が完了したので、「じゃんけんアプリ」が完成しました。

STEP4:コードを読みやすく整理(リファクタリング)

最期に、STEP3の機能はそのままに、定数の導入や表示更新の小さな関数化で見通しを良くしましょう。
後から直しやすい形に整えることが目的です。

import random
import tkinter as tk

# ============================
# 定数
# ============================
HANDS = ["グー", "チョキ", "パー"]  # じゃんけんの手
RULES = {                         # 左が右に勝つ対応表
    ("グー", "チョキ"): "win",
    ("チョキ", "パー"): "win",
    ("パー", "グー"): "win",
}
RESULT_TEXT = {                   # 判定→表示文の対応
    "win":  "結果:あなたの勝ち",
    "lose": "結果:あなたの負け",
    "draw": "結果:あいこ",
}

class JankenApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("じゃんけんアプリ")
        self.geometry("380x420")
        self.resizable(False, False)

        # タイトル
        tk.Label(self, text="じゃんけんしよう!", font=("Yu Gothic UI", 18, "bold")).pack(pady=(16, 8))

        # 区切り線
        tk.Frame(self, height=1, bg="#ccc").pack(fill="x", padx=16, pady=10)

        # 表示用の変数(あなた/コンピュータ/結果)
        self.player_var = tk.StringVar(value="あなた:-")
        self.cpu_var    = tk.StringVar(value="コンピュータ:-")
        self.result_var = tk.StringVar(value="結果:-")

        # 表示エリア
        frame_status = tk.Frame(self)
        frame_status.pack(pady=(4, 8))
        tk.Label(frame_status, textvariable=self.player_var, font=("Yu Gothic UI", 12)).grid(row=0, column=0, padx=8, pady=4)
        tk.Label(frame_status, textvariable=self.cpu_var,    font=("Yu Gothic UI", 12)).grid(row=1, column=0, padx=8, pady=4)
        tk.Label(self, textvariable=self.result_var, font=("Yu Gothic UI", 16, "bold")).pack(pady=(8, 12))

        # ボタン群
        btn_frame = tk.Frame(self)
        btn_frame.pack(pady=8)
        tk.Button(btn_frame, text="グー",   width=10, height=2, command=lambda: self.play("グー")).grid(row=0, column=0, padx=6, pady=6)
        tk.Button(btn_frame, text="チョキ", width=10, height=2, command=lambda: self.play("チョキ")).grid(row=0, column=1, padx=6, pady=6)
        tk.Button(btn_frame, text="パー",   width=10, height=2, command=lambda: self.play("パー")).grid(row=0, column=2, padx=6, pady=6)

    # ------------------------------
    # ロジック
    # ------------------------------
    def play(self, player_hand: str):
        cpu_hand = random.choice(HANDS)  # 定数からランダムに選ぶ
        self.player_var.set(f"あなた:{player_hand}")
        self.cpu_var.set(f"コンピュータ:{cpu_hand}")

        result = self.judge(player_hand, cpu_hand)
        self.show_result(result)

    def judge(self, p: str, c: str) -> str:
        if p == c:
            return "draw"
        return "win" if (p, c) in RULES else "lose"

    def show_result(self, result: str):
        self.result_var.set(RESULT_TEXT[result])

if __name__ == "__main__":
    app = JankenApp()
    app.mainloop()

手順①:定数を導入して重複をなくす

HANDS = ["グー", "チョキ", "パー"]
RULES = {
    ("グー", "チョキ"): "win",
    ("チョキ", "パー"): "win",
    ("パー", "グー"): "win",
}
RESULT_TEXT = {
    "win":  "結果:あなたの勝ち",
    "lose": "結果:あなたの負け",
    "draw": "結果:あいこ",
}

「定数」は意味のある固定値をまとめた入れ物です。
今後、手を増やす・絵文字を変えるなどの調整はここだけ直せば全体に反映されます。
コード中の重複や書き換え漏れを防げます。

手順②:表示更新を関数にする

def show_result(self, result: str):
    self.result_var.set(RESULT_TEXT[result])

判定結果に応じた表示文の切り替えを関数にしておくと、表示仕様の変更を1か所で管理できます。

手順③:条件分岐を簡潔に

def judge(self, p: str, c: str) -> str:
    if p == c:
        return "draw"
    return "win" if (p, c) in RULES else "lose"

同じ手は引き分け、それ以外は対応表にあれば勝ち、なければ負け。
処理の流れを短く表現することで、後から読んだときに理解しやすくなります。

手順④:ランダム選択を定数から行う

cpu_hand = random.choice(HANDS)

STEP3ではその場でリストを書いていましたが、定数から選ぶ形に統一しました。
修正箇所が1か所に集約され、保守が楽になります。

今回のリファクタリングは「機能追加なし」です。
STEP3と同じ動きのまま、コードの役割をはっきり分け、変更に強い形に整えています。

完成

以上でPythonで作るじゃんけんアプリの完成です。

ぜひ、コードをコピペするのではなく、実際にコードを打って作ってみてください。

お疲れさまでした。

ABOUT ME
記事URLをコピーしました