> ## 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.

# 【簡単？】初心者がpython３とpygameでヒット＆ブローゲーム作ってみる　#01【習作？】
- URL: https://www.geekjp.com/2019-11-16-184245-2/
- Published: 2019-11-16T09:42:45.000Z
- Updated: 2026-08-04T15:59:53.000Z
- Description: 前回こんなこと言ってましたが、いわゆるヒット＆ブローゲームを作ってみます。今回はプロトタイプとして、テキストベースでコンソール画面で実行できるバージョンを作ってみます。 そして次回以降で、グラフィックを追加してゆき、最終的にビデオゲーム風に仕上げます。（テトリス完成させろよ、という突っ込みお待ちしております）
- Author: 工学じじい
- Tags: ゲームプログラミング, Pygame, Python, #Import 2026-07-19 20:21, #Import 2026-07-19 20:24

- [初心者がpython３とpygameでヒット＆ブローゲーム作ってみる #01](#初心者がpython３とpygameでヒットブローゲーム作ってみる-01)
  - [前回から](#前回から)
  - [ヒット＆ブローゲーム](#ヒットブローゲーム)
    - [ヒット＆ブローの仲間とゲームの実装](#ヒットブローの仲間とゲームの実装)
  - [実装（設計）](#実装設計)
    - [出題](#出題)
    - [判定](#判定)
  - [入力](#入力)
    - [プレイヤーの入力](#プレイヤーの入力)
  - [判定結果の表示](#判定結果の表示)
    - [正解まで繰り返す](#正解まで繰り返す)
  - [入力制限](#入力制限)
    - [入力の重複チェック](#入力の重複チェック)
  - [ちょっとしたゲーム要素を追加](#ちょっとしたゲーム要素を追加)
  - [完成したソースコード一覧](#完成したソースコード一覧)
  - [次回](#次回)

### 前回から

いわゆるヒット＆ブローゲームを作ってみます。今回はプロトタイプとして、テキストベースでコンソール画面で実行できるバージョンを作ってみます。  
そして次回以降で、グラフィックを追加してゆき、最終的にビデオゲーム風に仕上げます。（テトリス完成させろよ、という突っ込みお待ちしております）  
  
### ヒット＆ブローゲーム

ヒット＆ブローゲームを御存知でしょうか？  
結構有名なので、どこかでは見たことあると思います。  
知らない方のためにちょっとだけ説明します。  
簡単に言うと、数字当てゲームです。  
出題者側から４桁（が多分ノーマルルール）のかぶらない数字が出題されます。  
３１２４、９８７６、１５２６など。  
解答者側は、この数字を当てます。

解答者の予想した数字の、

位置があっていた場合はHIT(ヒット）  
数字のみあっていた場合はBLOW（ブロー）

となります。

例えば、「１５２６」が出題されたとしましょう。  
解答者は、４桁の数字とその並びを予想して答えます。  
「１２３４」と答えた場合

| 出題 | １５２６       |
| -- | ---------- |
| 解答 | １２３４       |
| 結果 | １HIT １BLOW |

次に「１２５６」と答えた場合

| 出題 | １５２６       |
| -- | ---------- |
| 解答 | １２５６       |
| 結果 | ２HIT ２BLOW |

これを、なるべく少ない回数で４HIT獲得しよう！というゲームです。

#### ヒット＆ブローの仲間とゲームの実装

ヒットアンドブローゲームは、スターマインドという名前でボードゲームとして発売されてヒットしています。

[https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%9E%E3%82%A4%E3%83%B3%E3%83%89](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%9E%E3%82%A4%E3%83%B3%E3%83%89?ref=geekjp.com)

スターマインドでは、数字の並びではなく、ボールの色を当てるゲームです。（子供のころ友達の家で遊んだことがあるのは内緒です）  
このウィキペデアの「その他」の項にありますが、

「ルールが簡潔であるため、パソコンの黎明期にBASICで組まれたプログラムが数多く発表された。」

とあります。そのため、あちこちに様々な実装が散見され、工学系の学校の授業などでも、プログラミングの例題として課題で出されたりします。  
なので、実装そのものに関しては、特に工夫もいらず、あまり書くこともないかなぁなんて思ったりしています。  
（なんか、pythonならでは的なものがあったら書こうかな）

### 実装（設計）

ゲームのメイン部分の設計を考えてみます。  
設計といってもやることはいくつかしかなく。  
大まかに、

出題、入力、判定、出力

がメインかなと思います。

#### 出題

出題は、C言語などではちょっとした工夫をしないと４桁のかぶらない数の列を作れませんが、python様にかかると２行です。

```python
import random

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

```

num = list(range(10))  
で  
\[0, 1, 2, 3, 4, 5, 6, 7, 8, 9\]  
のリストができるので、そこから４つの数字をランダムにチョイスします。（なんて命令がpythonにちょろっとあるのが笑えます）

random.sample(list, num)  
は、指定されたリスト(list)から、重複なしで(num)個の数字を取り出す命令です。  
これだけで、「４桁のランダムな並びの重複しない数字の列」が出来上がります。

#### 判定

次にプレイヤーから４桁の数字の列

yin = \[n1, n2, n3, n4\]

が入力されたときのヒットとブローの判定を考えてみます。  
ヒットの判定は、ループでそのまま一致を調べます。  
（pythonには、もっといい方法がある気がします）

```python
 for i in range( len(yin) ):
        if yin[i] == ans[i]:
            h += 1 # hがヒットの数

```

次にブローの数を数えます。  
あるリストlistにnという要素が含まれるかどうかは、pythonではその中に入っている型とかを考えずに

```python
    n in list

```

が**True**か**False**かで判定できます。  
したがって、ブローの数は、  
**「今判定している数がヒットじゃなかったときに、リストに含まれているかどうか」**  
を判定すればよいです。

```python
 for i in range( len(yin) ):
        if yin[i] == ans[i]:
            h += 1 # hがヒットの数
        else:
            if yin[i] in ans:
                b += 1 # bがブローの数

```

これだけでヒットとブローの判定ができます。  
これを、関数として書いてみます。  
yinがユーザの入力、yin = \[n1, n2, n3, n4\]  
ansが出題された数字列、ans= \[a1, a2, a3, a4\]  
を表しています。

```python
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])

```

### 入力

次に、プレイヤーの入力処理の部分を考えてみます。  
入力をベースに考えた処理の流れは、

1. ゲーム開始
2. 出題
3. プレイヤーの解答入力
4. 判定の表示
5. （HIT==4がTrueか？）
  - TRUEの場合 おめでとうと表示
  - FALSEの場合 ３へもどる

となります。

#### プレイヤーの入力

出題される数字列は、

**ans= \[a1, a2, a3, a4\]**

のlistの形で保存されています。  
先ほど作った関数、

**def judgement(yin, ans):**

で、ヒットとブローの判定をするには、入力した数字列を

**yin = \[n1, n2, n3, n4\]**

の形で関数に渡さなければなりません。  
プレイヤーが入力した４桁の数字は、通常inputで取得すると、４文字の文字列として、保存されてしまいます。これ整数一けたずつの数字にばらして要素数４のリストに変換します。

```python
    print("Hit＆Blowゲーム！")
    print("４桁の重複しない数字を入力してください。")
    print("->", end="")
    tmp = input()
    your_input = []
    for i in tmp:
        your_input.append(int(i))
    print(your_input)

```

実行結果

```python
Hit＆Blowゲーム！
４桁の重複しない数字を入力してください。
->1234
[1, 2, 3, 4]
```

簡単にできました。python様々です。

### 判定結果の表示

判定結果を、表示するためにプレイヤーの入力と生成された出題のリストを判定用関数に渡します。

**ans = make\_question()**

出題は、すでに生成され、ansに保存されているとします。  
プレイヤーの入力your\_inputとansがあれば、ヒットとブローの判定は、

**hit,blow = judgement(your\_input, ans)**

で、取得できます。ここでもpythonは、値を複数返すのが簡単だったりしてうれしいですね。

ちゃんと動くか確認します。

```python
    ans = make_question()
    print(ans)
    print("Hit＆Blowゲーム！")
    print("４桁の重複しない数字を入力してください。")
    print("->", end="")
    tmp = input()
    your_input = []
    for i in tmp:
        your_input.append(int(i))
    hit,blow = judgement(your_input, ans)
    print("hit = "+str(hit)+", blow = " + str(blow))

```

確認用に、**ans**を生成した直後に、表示しています。  
実際に実行してみます

結果：

```python
[7, 3, 5, 4]
Hit＆Blowゲーム！
４桁の重複しない数字を入力してください。
->7345
hit = 2, blow = 2
```

#### 正解まで繰り返す

この処理を、ヒットが４になるまで繰り返します。  
処理自体は簡単で、先ほどの入力の部分をまるっと、無限ループにして、**hit==4**の判定が**True**になったら、おめでとうメッセージを表示して**break**します。

```python
    ans = make_question()
    print(ans)
    print("Hit＆Blowゲーム！")

    while True:
        print("４桁の重複しない数字を入力してください。")
        print("->", end="")

        hit = 0
        blow = 0

        tmp = input()
        your_input = []

        for i in tmp:
            your_input.append(int(i))
        hit,blow = judgement(your_input, ans)
        print("hit = "+str(hit)+", blow = " + str(blow))

        if hit == 4:
            print("おめでとう、正解です :" + str(ans))
            break

```

実行してみます。  
実行結果：

```python
[5, 6, 4, 9]
Hit＆Blowゲーム！
４桁の重複しない数字を入力してください。
->4569
hit = 1, blow = 3
４桁の重複しない数字を入力してください。
->5649
hit = 4, blow = 0
おめでとう、正解です :[5, 6, 4, 9]
```

一応これで、ゲームらしい形はできます。

### 入力制限

現在は、プレイヤーの入力に特に制限を設けていないので、出題は重複のない４桁の数字になっていますが、プレイヤーは何でもかんでもこたえられてしまいます。

```python
[0, 5, 8, 3]
Hit＆Blowゲーム！
４桁の重複しない数字を入力してください。
->0000
hit = 1, blow = 3
４桁の重複しない数字を入力してください。
->5555
hit = 1, blow = 3
４桁の重複しない数字を入力してください。
->8888
hit = 1, blow = 3
４桁の重複しない数字を入力してください。
->0055
hit = 1, blow = 3
４桁の重複しない数字を入力してください。
->
```

さすがに、入力の制限を付けずにプレイヤーの良心にエラー回避のをゆだねるのは、アルゴリズム的にはだめすぎです(笑)

#### 入力の重複チェック

プレイヤーから入力された数字に、重複があったら再度入力を促すことにします。重複のチェックは、リストの中に同じ数字があるかどうかで判断すればよいです。  
python様には、集合(set)というデータ構造があります。集合は、重複のないある要素の集まりを表します。  
pythonでは、**list**から**set**の変換が可能です。  
つまり、重複の許されている**list**を重複のない**set**に変換できます。

```python
  lst = [1, 2, 2, 2, 2, 3, 4,]
    setfromlist = set(lst)
    print(lst, setfromlist)

```

結果

```python
[1, 2, 2, 2, 2, 3, 4] {1, 2, 3, 4}
```

  
これを利用して、変換前（リスト）と変換後（集合）の要素数が異なっていれば、重複がある、と判定します。  
  
```python
def has_not_duplicates(seq):
    return len(seq) == len(set(seq))

```

関数**def has\_not\_duplicates(seq):**により、入力に重複があるかどうかが**True**、**False**で返ってきます。

プレイヤーの入力に可ぶりがない場合のみ（def has\_duplicates(seq)がTrue）判定の処理をして、それ以外はスルーして入力に戻ればいいです。

```python
    while True:
        print("４桁の重複しない数字を入力してください。")
        print("->", end="")
        hit = 0
        blow = 0
        tmp = input()
        your_input = []
        for i in tmp:
            your_input.append(int(i))
        if has_not_duplicates(your_input):
            hit, blow = judgement(your_input, ans)
            print("hit = "+str(hit)+", blow = " + str(blow))
            if hit == 4:
                print("おめでとう、正解です :" + str(ans))
                break

```

### ちょっとしたゲーム要素を追加

最後に、スコア代わりに何手目で正解したかを表示する機能を追加してみます。  
入力ミス（重複エラー）を１ターンと数えるかどうかでちょっと変わってきますが、今回は数えないほうでやってみます。

プレイヤーの手数を表す**変数turn**を追加します。  
判定処理の部分で、**hit==4**（正解の時）以外の時には**手数turn**を増やします。

```python
  turn = 1
    ans = make_question()
    print(ans)
    print("Hit＆Blowゲーム！")

    while True:
        print("第%02d手目" % turn)
        print("４桁の重複しない数字を入力してください。")
        print("->", end="")
        hit = 0
        blow = 0
        tmp = input()
        your_input = []
        for i in tmp:
            your_input.append(int(i))
        if has_not_duplicates(your_input):
            hit, blow = judgement(your_input, ans)
            print("hit = "+str(hit)+", blow = " + str(blow))
            if hit == 4:
                print("おめでとう! %02d手目で正解です :" % turn)
                break
            else:
                turn += 1

```

  
実行結果：

```python
Hit＆Blowゲーム！
第01手目
４桁の重複しない数字を入力してください。
->1234
hit = 0, blow = 1
第02手目
４桁の重複しない数字を入力してください。
->1249
hit = 0, blow = 1
第03手目
４桁の重複しない数字を入力してください。
->9738
hit = 1, blow = 3
第04手目
４桁の重複しない数字を入力してください。
->3978
hit = 4, blow = 0
おめでとう! 04手目で正解です :
```

### 完成したソースコード一覧

今回のプログラムの全体像です。  

```python
import sys
import random

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))

def main():
    turn = 1
    ans = make_question()
    print("Hit＆Blowゲーム！")

    while True:
        print("第%02d手目" % turn)
        print("４桁の重複しない数字を入力してください。")
        print("->", end="")
        hit = 0
        blow = 0
        tmp = input()
        your_input = []
        for i in tmp:
            your_input.append(int(i))
        if has_not_duplicates(your_input):
            hit, blow = judgement(your_input, ans)
            print("hit = "+str(hit)+", blow = " + str(blow))
            if hit == 4:
                print("おめでとう! %02d手目で正解です :" % turn)
                break
            else:
                turn += 1

if __name__ == "__main__":
        main()

```

### 次回

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

次回以降は、今回作ったヒットアンドブローゲームにpygameでガワをはっていき、ビデオゲーム風に仕上げていきます(笑)  
このままでも、面白いですけどね。

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