> ## Content Index
> Fetch the complete content index at: https://www.geekjp.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# 【pygame】pythonでヒット＆ブローゲーム作る　#05　正誤判定、ログの表示【簡単】
- URL: https://www.geekjp.com/2019-11-22-052748/
- Published: 2019-11-21T20:27:48.000Z
- Updated: 2019-11-21T20:27:48.000Z
- Description: python プログラミング 入門シリーズです。 pythonとpygameを使ってとても簡単なゲームを作ってみます。 前回は、画面構成を整えてみました。 今回は、プレイヤーの数字の入力を実装していきます。 もっと良い画面構成や、入力法もあるかと思いますが、初心者の考えたもんですので、大目に見てください。
- Author: 工学じじい
- Tags: ゲームプログラミング, 技術, Pygame, Python, #Import 2026-07-19 20:21, #Import 2026-07-19 20:24

- [【pygame】pythonでヒット＆ブローゲーム作る #05 正誤判定、ログの表示【簡単】](#pygamepythonでヒットブローゲーム作る05正誤判定ログの表示簡単)
  - [前回までのまとめ](#前回までのまとめ)
  - [出題と正誤判定](#出題と正誤判定)
    - [正誤判定](#正誤判定)
    - [ログの表示](#ログの表示)
  - [今回のまとめ](#今回のまとめ)
  - [次回](#次回)

### 前回までのまとめ

[【簡単？】初心者がpython３とpygameでヒット＆ブローゲーム作ってみる【習作？】 - 工学じじいの縁側日記](https://www.geekjp.com/2019-11-16-184245/)  
[【簡単？】初心者がpython３とpygameでヒット＆ブローゲーム作ってみる #02【習作？】 - 工学じじいの縁側日記](https://www.geekjp.com/2019-11-17-133208/)  
[【簡単？】初心者がpython３とpygameでヒット＆ブローゲーム作ってみる #03 画面作るよ【習作？】 - 工学じじいの縁側日記](https://www.geekjp.com/2019-11-19-015433/)  
[【pygame】pythonでヒット＆ブローゲーム作る #04 数字の入力【簡単】 - 工学じじいの縁側日記](https://www.geekjp.com/2019-11-19-170123/)

  
前回は、数字の入力までを行えるようになりました。  
今回は、出題の処理と、正誤判定、ログの判定をやっていきたいと思います。  
出題と正誤判定は、テキストバージョンの関数をそのまま使います。

それでは、作っていくー(笑)

### 出題と正誤判定

初めにも書きましたが、出題と正誤判定はテキスト版のゲームで使用したものをそのまま使います。（使えます）

[【簡単？】初心者がpython３とpygameでヒット＆ブローゲーム作ってみる【習作？】 - 工学じじいの縁側日記](https://www.geekjp.com/2019-11-16-184245/)  

```python
def has_not_duplicates(seq):
    return len(seq) == len(set(seq))

def judgement(yin, ans):
    h=0
    b=0
    for i in range(len(yin)):
        if yin[i] == ans[i]:
            h += 1
        else:
            if yin[i] in ans:
                b += 1
    return([h, b])

def make_question():
    nums = list(range(10))
    return(random.sample(nums, 4))

```

これらの関数を適切なタイミングで呼び出していきます。

まず出題ですが、ゲームスタートボタンを押したときに、問題が初期化されれば都合がよさそうです。また、このときに、プレイヤーの入力した数字が初期化されると、これまた都合がいいです。  
すなわち、

```python
    players_input = []  # プレイヤーの入力した数字
    question = []  # 出題された数字
（省略）
if gamebuttonrect.collidepoint(event.pos):
    if gamescene == 0: #gamesceneが０の時（タイトル画面の時）
        question = make_question()  # 問題を作成
        players_input = [-1, -1, -1, -1]  # プレイヤーの入力を初期化
        gamescene = 1  # 状態を「ゲーム中」へ変更

```

これで、スタートボタンを押したときに、出題(question)とプレイヤーの入力(players\_input)が初期化されます。  
この辺は画面に現れないので、各自print文でquestionとplayers\_inputを表示してみるなど試してみてください。  
  
#### 正誤判定

スタートボタンが押され、状態が「ゲーム中」になると（gamescnene==1)、プレイヤーは、４桁の数字を入力して、ヒット数、ブロー数をかくにんして、それをヒントに正解になるまで繰り返し数字を入力します。

入力は、前回作成した通り、４桁の数字をを数字ボタンでを順にクリックすることで入力できます。  
プレイヤーは、４桁の数字の入力が終わったら「Judgement」ボタンを押すことで、ヒット数、ブロー数の判定ができます  
このとき、４ヒットが獲得できれば、クリアです。

これらの機能を実装していきます。

４桁の数字が入力されて「judgement」ボタンが押されたときの動作を考えてみます。  
「judgement」ボタンが押されたときの状態は以下の３つが考えられます。

- 「judgement」ボタンが押されたときの状態
1. 数字が４桁入力されていない（エラー）
2. 数字に重複がある（エラー）
3. 数字が正しく入力されていて、正解である
4. 数字が正しく入力されているが、正解はしていない

これらの時の表示メッセージを切り替えてみます。  
「数字が正しく入力されているが、正解はしていない」ときは、ヒット数、ブロー数のログを画面右のスペースに表示します。

まずは、エラーと正解のメッセージの処理を実装していきます。

タイトルの表示の時と同じように、メッセージ用のフォントを用意します。お好みでいいですが、このフォントで、入力数字が正しくないときのエラーと、数字が重複しているエラー、クリアおめでとう（Congratulations)の３種類のメッセージを表示します。  
別に３つとも別のフォントで表示できますが、その時はその都度別フォントを読み込んでください。

また、エラー状態とクリア状態を表す状態変数 input\_statusを準備しておきます。

```python
input_status = 0 # 1 入力エラー 2 重複エラー 3 正解

gamemessage = []
    mes_font = pygame.font.SysFont("yumincho", 40)
    gamemessage.append(mes_font.render("エラー：数字が正しくない", True, (255, 0, 0)))
    gamemessage.append(mes_font.render("エラー：数字が重複", True, (255, 0, 0)))
    gamemessage.append(mes_font.render("CONGRATULATIONS", True, (255, 0, 0)))

```

これでエラー表示の準備ができました。  
次に、実際にエラーの検知と正解の判定をしていきます。  
不正入力エラーと数字の重複エラーの検知、正誤判定のタイミングはすべて「judgement」ボタンを押したときです。

それぞれの条件は、

- 不正入力エラー
  - players\_inputのどこかの桁に初期値-1が残っている
- 数字重複エラー
  - players\_inputの数字に重複がある
  - 関数has\_duplicates(players\_input)で判定
- 正解か不正解か
  - 関数judgement(players\_input, question)で判定
  - 戻り値が\[4, 0\]の時が正解

正誤判定、重複判定は、テキストバージョンのものがそのまま使えます。

```python
if gamebuttonrect.collidepoint(event.pos):
# judgementボタンが押されたときに
    if gamescene == 0:
        question = make_question()  # 問題の作成
        # print(question)  # デバッグ用に答えを表示
        players_input = [-1, -1, -1, -1]
        gamescene = 1  # ゲーム状態の初期化
        input_status = 0  # エラー状態もリセットする
    elif gamescene == 1:
        if -1 in players_input:  # 入力に初期値が残っている
            input_status = 1  # 不正入力エラー
        elif has_duplicates(players_input):  # Trueの時は数字が重複
            input_status = 2  # 数字重複エラー
        else:  # エラー以外の時は正誤判定をする
            judge = judgement(players_input, question)
　　　 # judgeに判定結果が返される[Hit数, Blow数]
            if judge[0] == 4: # ヒット数が４なら正解
                input_status = 3   # Congratularions状態に遷移 
                gamescene = 2  # ゲームオーバー状態へ遷移

```

これで、エラー判定、正誤判定ができます。

まとめると

| gamescene | input\_status | 状態         |
| --------- | ------------- | ---------- |
| 0         | \-            | タイトル画面     |
| 1         | 0             | 通常の入力状態    |
| 1         | 1             | 不正入力エラー    |
| 1         | 2             | 数字重複エラー    |
| 2         | 3             | 正解でゲームオーバー |

この条件で適切なメッセージを表示します。

```python
   while running:
        screen.fill((100, 100, 100))  # 背景色で塗る
        if gamescene == 0:
            screen.blit(title, titlepos)
            screen.blit(gamebutton[0], gamebuttonrect)
        elif gamescene == 1:
            for i in range(4): # 入力された数字を表示する領域
                if players_input[i] == -1:
                    screen.blit(qimagelist[10], qbuttonrect[i])
                else:
                    screen.blit(qimagelist[players_input[i]], qbuttonrect[i])
            for i in range(5): # 入力のためのボタンとなる画像０～４
                screen.blit(imagelist[i], buttonrect[i])
            for i in range(5, 10): # 入力のためのボタンとなる画像５～９
                screen.blit(imagelist[i], buttonrect[i])
            screen.blit(gamebutton[1], gamebuttonrect)
            pygame.draw.rect(screen, (255, 0, 0), qbuttonrect[input_pos], 3)
            if input_status > 0:
                screen.blit(gamemessage[input_status-1], (80, 30))
　　　　 #エラーメッセージを表示
        elif gamescene == 2:
            screen.blit(gamemessage[input_status - 1], (100, 100))
            # 「Congratulations」表示
            screen.blit(gamebutton[2], gamebuttonrect)
        else:
            print("error")

```

実行してみます。

![f:id:gomta777:20191122045323p:plain](https://www.geekjp.com/content/files/images/import/hatena/2019/11/20191122045323.png "f:id:gomta777:20191122045323p:plain")

図 エラーと正解メッセージの表示

「judgement」ボタンを押したときの反応を貼っておきます。

#### ログの表示

次に、正解を導くために肝心なヒット数、ブロー数のログを表示していきます。これがないと、正解を予測できませんね(笑)

ログ表示用のフォント（20pt)と現在まで答えた手数を表す変数turnを用意します。

```python
    anslog = []
    log_font = pygame.font.SysFont("yumincho", 20)
    turn = 1  # 現在まで答えた手数（judgementボタンの押下数）

```

これを使って、judgementボタンを押すたびにログメッセージをanslogに追加してゆき、turnを＋１します。

```python
if (event.type == pygame.MOUSEBUTTONUP) and (event.button == 1):
    if gamebuttonrect.collidepoint(event.pos):
        if gamescene == 0:
            question = make_question()
            print(question)
            players_input = [-1, -1, -1, -1]
            gamescene = 1
            input_status = 0
        elif gamescene == 1:
            if -1 in players_input:
                input_status = 1
            elif has_duplicates(players_input):
                input_status = 2
            else:
                judge = judgement(players_input, question)
                # ここから追加部分
                anslog.append("%02d 回目 " % turn + str(players_input) + \
                "  " + str(judge[0]) + " HIT  " + str(judge[1]) + " BLOW")
                turn += 1
                # ここまで追加部分
                if judge[0] == 4:
                    input_status = 3
                    gamescene = 2
        elif gamescene == 2:
            gamescene = 0
        else:
            gamescene = -1

```

あとは適切なタイミングでログメッセージを表示してあげればよいです。

```python
        #（省略）
        elif gamescene == 1:
            for i in range(4): # 入力された数字を表示する領域
                if players_input[i] == -1:
                    screen.blit(qimagelist[10], qbuttonrect[i])
                else:
                    screen.blit(qimagelist[players_input[i]], qbuttonrect[i])

            for i in range(5): # 入力のためのボタンとなる画像０～４
                screen.blit(imagelist[i], buttonrect[i])
            for i in range(5, 10): # 入力のためのボタンとなる画像５～９
                screen.blit(imagelist[i], buttonrect[i])
            screen.blit(gamebutton[1], gamebuttonrect)
            pygame.draw.rect(screen, (255, 0, 0), qbuttonrect[input_pos], 3)
            if input_status > 0:
                screen.blit(gamemessage[input_status-1], (80, 30))
            # ここから追加部分
            for i in range(len(anslog)):
                text = log_font.render(anslog[i], True, (255, 255, 255))
                screen.blit(text, (560, 30 * i + 100 - 3))
            # ここまで追加部分
        elif gamescene == 2:
        #（省略）

```

![f:id:gomta777:20191122051930p:plain](https://www.geekjp.com/content/files/images/import/hatena/2019/11/20191122051930.png "f:id:gomta777:20191122051930p:plain")

図 ログの表示

### 今回のまとめ

今回は、「judgement」ボタンを押したときの反応を中心に進めてきました。「judgement」ボタンを押したときのエラー表示、正解の表示、入力ログの表示を実装しました。  
実は、今回の実装にはちょっとした問題があります。

![f:id:gomta777:20191122052229p:plain](https://www.geekjp.com/content/files/images/import/hatena/2019/11/20191122052229.png "f:id:gomta777:20191122052229p:plain")

図 表示のバグ

ログの表示を、ただ座標をずらして繰り返しで表示しているので、画面の外にどんどんはみ出ていってしまいます。また、１６回ぐらいまでは表示できますが、わりと１５，６回で正解するのは、難しいかもしれません。何か工夫が必要ですよね。  
  
### 次回

今回のソースコード一式はgithubにもあります。  
[https://github.com/gomta777/hitandblow/](https://github.com/gomta777/hitandblow/?ref=geekjp.com)  
のjudgementが今回のものです。

次回は、ログの表示を工夫してみます。

よかったら、ブログ村↓のクリックお願いします。