タイトル画像
琴葉茜

前回、無事にじゃんけんが出来るようになったし、次は「今まで何回勝てた」とか戦績を管理できるようにしようか

琴葉葵

戦績の管理をするなら単純に変数を使えば良いんだよね

琴葉茜

そうだね!今回は「勝ち(win_count)」「負け(lose_count)」「あいこ(draw_count)」の3種類の変数を用意すればOK

# 勝敗を管理する変数(変数「win_rules」を設定してる場所の下あたりに配置)
win_count = 0
lose_count = 0
draw_count = 0
琴葉葵

オッケー!もう慣れたもんですよ

琴葉茜

じゃあ次は戦績を表示するためにlayoutを変更しよう

layout = [
    [eg.Text("じゃんけんの手を選ぼう!")],
    [col1, col2, col3],
    [eg.Text("プレイヤーの手"),
     eg.Image(None, size=(100, 100),key="player_hand"),
     eg.Text("vs"),
     eg.Image(None, size=(100, 100), key="cpu_hand"),
     eg.Text("CPUの手")],
    [eg.Text("", key="result")],
    [eg.Text("勝ち: 0", key="win_score"),
     eg.Text("負け: 0", key="lose_score"),
     eg.Text("あいこ: 0", key="draw_score")] # この3行を追加
]
琴葉葵

配列に途中から要素を追加すると「,」を忘れがちになるから気をつけないとね

琴葉茜

次はそれぞれのテキストが更新されるように「.update()」を追加しよう

琴葉茜

今回は各戦績の画面表示の更新を「じゃんけんの判定後」に行いたいから、「eg.popup(check_hands(player, cpu))」の次の行に追加してね

window["win_score"].update(f"勝ち: {win_count}")
window["lose_score"].update(f"負け: {lose_count}")
window["draw_score"].update(f"あいこ: {draw_count}")
琴葉葵

画面の更新もできるようにしたし、次はさっきの変数の値の更新だね!
だとしたら、関数「check_hands()」を書き換えるのかな?

琴葉茜

そうだね!だけど、ここで注意しないといけないことがあるんだ

琴葉葵

そうなの?そのまま「win_count += 1」って感じにすれば良いんじゃないの??

琴葉茜

その他の関数定義」でも説明したけど、関数内でグローバル変数は更新できないってのは覚えてるかな?

琴葉葵

そういえばそうだった...!!
でも、returnで返してる内容は直接ポップアップに使っちゃってるからどうしよう!?

琴葉茜

そうなんだよね、だから今回は関数「check_hands()」内でグローバル変数を更新できるように「global」を使うよ

def check_hands(player_hand, cpu_hand):
    global win_count, lose_count, draw_count
    if player_hand == cpu_hand:
        draw_count += 1
        return "あいこだよ"
    elif win_rules[player_hand] == cpu_hand:
        win_count += 1
        return "勝ち!!"
    else:
        lose_count += 1
        return "負け..."
琴葉茜

関数内で変数の前にこれを付けてあげることで、その変数をグローバル変数として扱えるようになるんだ

琴葉葵

おおー、なんかズルい

琴葉茜

まぁ裏技的なものでバグの原因になりやすいから多用しすぎないでね

琴葉葵

りょうかい!!じゃあ早速動かしてみるね

解説画像1
琴葉葵

うまくいってそう!(なぜか全然勝てなかったけど...)

琴葉茜

良い感じだね!だけど今の結果は不服そうだし、いつでもリセットできる機能があったら欲しくない??

琴葉葵

欲しい!!

琴葉茜

じゃあまずは、リセットボタンをlayoutの最後に追加しよう

layout = [
    [eg.Text("じゃんけんの手を選ぼう!")],
    [col1, col2, col3],
    [eg.Text("プレイヤーの手"),
     eg.Image(None, size=(100, 100),key="player_hand"),
     eg.Text("vs"),
     eg.Image(None, size=(100, 100), key="cpu_hand"),
     eg.Text("CPUの手")],
    [eg.Text("", key="result")],
    [eg.Text("勝ち: 0", key="win_score"),
     eg.Text("負け: 0", key="lose_score"),
     eg.Text("あいこ: 0", key="draw_score")],
    [eg.Button("リセット")] # これを追加
]
琴葉茜

次にリセットボタンが押された時の処理を作ろう
それぞれの変数を「0」にして、各オブジェクトの表示も初期状態に戻すよ

if event == "リセット":
    win_count = 0
    lose_count = 0
    draw_count = 0
    window["win_score"].update(f"勝ち: {win_count}")
    window["lose_score"].update(f"負け: {lose_count}")
    window["draw_score"].update(f"あいこ: {draw_count}")
    window["player_hand"].update(data=b"") # 「b""」はバイト列という特別な文字列
    window["cpu_hand"].update(data=b"")
    window["result"].update("")
    eg.popup("スコアをリセットしました!")
琴葉茜

このプログラムを「while True」の中に追加すればOKだよ

解説画像2
琴葉葵

おお!リセットボタンを押したらポップアップ画面が出て、起動した時と同じ状態になった!

琴葉葵

...だけど、ターミナルの方になんかエラーが出てるね

琴葉茜

「player_hand」と「cpu_hand」の画像は「.update(None)」みたいな感じでは消せなくて、無理矢理消そうとしたからなんだよね汗

琴葉葵

じゃあ仕方ないかー
まぁひとまず、これでスコア管理とリセット機能はバッチリだね

琴葉茜

そうだね!だけど、UIのデザインがまだ整ってなかったり、プログラムがごちゃっとしているから次の項目ではその辺りも含めて完成させよう!

この時点での全体のプログラム

import TkEasyGUI as eg
import random

hands = ["グー", "チョキ", "パー"]
hand_images = {
    "グー": "janken_gu.png",
    "チョキ": "janken_choki.png",
    "パー": "janken_pa.png"
}
win_rules = {
    "グー": "チョキ",
    "チョキ": "パー",
    "パー": "グー"
}

# スコア変数
win_count = 0
lose_count = 0
draw_count = 0

def check_hands(player_hand, cpu_hand):
    global win_count, lose_count, draw_count
    if player_hand == cpu_hand:
        draw_count += 1
        return "あいこだよ"
    elif win_rules[player_hand] == cpu_hand:
        win_count += 1
        return "勝ち!!"
    else:
        lose_count += 1
        return "負け..."

# レイアウト(画面構成)
col1 = eg.Column([[eg.Image(hand_images["グー"], size=(100, 100))], [eg.Button("グー")]])
col2 = eg.Column([[eg.Image(hand_images["チョキ"], size=(100, 100))], [eg.Button("チョキ")]])
col3 = eg.Column([[eg.Image(hand_images["パー"], size=(100, 100))], [eg.Button("パー")]])

layout = [
    [eg.Text("じゃんけんの手を選ぼう!")],
    [col1, col2, col3],
    [eg.Text("プレイヤーの手"),
     eg.Image(None, size=(100, 100),key="player_hand"),
     eg.Text("vs"),
     eg.Image(None, size=(100, 100), key="cpu_hand"),
     eg.Text("CPUの手")],
    [eg.Text("", key="result")],
    [eg.Text("勝ち: 0", key="win_score"),
     eg.Text("負け: 0", key="lose_score"),
     eg.Text("あいこ: 0", key="draw_score")],
    [eg.Button("リセット")]
]

# ウィンドウを作成
window = eg.Window("じゃんけんアプリ", layout)

# イベントループ(閉じるまで表示)
while True:
    event, values = window.read()
    if event in ["グー", "チョキ", "パー"]:
        player = event
        cpu = random.choice(hands)
        window["player_hand"].update(hand_images[player])
        window["cpu_hand"].update(hand_images[cpu])

        window["result"].update(f"プレイヤーの手は「{player}」、CPUの手は「{cpu}」です")
        eg.popup(check_hands(player, cpu))
        window["win_score"].update(f"勝ち: {win_count}")
        window["lose_score"].update(f"負け: {lose_count}")
        window["draw_score"].update(f"あいこ: {draw_count}")
    if event == "リセット":
        win_count = 0
        lose_count = 0
        draw_count = 0
        window["win_score"].update(f"勝ち: {win_count}")
        window["lose_score"].update(f"負け: {lose_count}")
        window["draw_score"].update(f"あいこ: {draw_count}")
        window["player_hand"].update(data=b"")
        window["cpu_hand"].update(data=b"")

        window["result"].update("")
        eg.popup("スコアをリセットしました!")
    if event is eg.WINDOW_CLOSED:
        break

# ウィンドウを閉じる
window.close()