Tips

【python超初級】python初心者が数当てゲーム作ってみるよ【その3】

【python超初級】python初心者が数当てゲーム作ってみるよ【その3】

【python超初級】python初心者が数当てゲーム作ってみるよ【その3】

今さらながらpythonの勉強を始めました。他の言語を少しばかり触ったことはあるのですが、
pythonを扱うのは初めてなので、練習がてら簡単な数当てゲームを作成してみます。
4桁の異なる数値をランダムに生成して一致するまでに何ターンかかったかを競う有名なゲームです。
正式な名前は「ヒットアンドブロー」とか「マスターマインド」っていうみたいですね。(知らなかった。笑)

ルールは、

・重複のない4桁の数字(0~9)を当てる

・回答すると、その都度、ヒットとブローの数が出る

・ヒットは数字も桁の場所も同じ。ブローは数字はあたっているけど桁の場所が違う

・なるべく回数で答えたほうが良い

という感じです。

コマンドライン上で実行できるシンプルな造りにします。
(というか筆者がレベル的にまだそれしかできないです…)
なお、if文やfor文などの構文の解説は省きます。

それではスタート!!

※注 筆者はpython3.6.1をインストールしています。

【STEP3】2つの数値を求めるwhile文の処理を関数にする

前回までのコードを再度載せておきます。

import random

answer_num_ary = []

while len(answer_num_ary) < 4:
    random_num = random.randint(0, 9)
    append_flg = True
 
    for ary_element in answer_num_ary:
        if ary_element == random_num:
            append_flg = False
            break
    if append_flg == True:
        answer_num_ary.append(random_num)
    append_flg = True
 
input_num = input("数当てゲームを開始します。\n4桁の数値を入力してください:")
input_continue_flg = True
 
while input_continue_flg == True:
    input_num_ary = []
    if input_num.isdigit() == False:
        input_num = input("【エラー】4つの整数値を入力してください。:")
    elif input_num.isdigit() == True:
        if len(input_num) != 4:
            input_num = input("【エラー】4つの異なる数値を入力してください:")
        else:
            input_num2 = int(input_num)
            for i in range(0,4):
                input_num_ary.append(input_num2 // (10 ** (3-i)))
                input_num2 = input_num2 % (10 ** (3-i))
            if len(list(set(input_num_ary))) != 4:  
                input_num = input("【エラー】重複のない4つの数値を入力してください。:")
            else:
                input_continue_flg = False
     
print("入力した値は" + input_num + "です。")

5行目から15行目で答えとなるランダムな重複のない4つの数値を生成して、
配列に格納しています。これを関数として定義し直しましょう。
コードを以下のように書き換えます。

import random

def make_random_num():
    ary = []
    while len(ary) < 4:
        random_num = random.randint(0, 9)
        append_flg = True

        for ary_element in ary:
            if ary_element == random_num:
                append_flg = False
                break
        if append_flg == True:
            ary.append(random_num)
        append_flg = True
    return ary

answer_num_ary = make_random_num()

input_num = input("数当てゲームを開始します。\n4桁の数値を入力してください:")
input_continue_flg = True
 
while input_continue_flg == True:
    input_num_ary = []
    if input_num.isdigit() == False:
        input_num = input("【エラー】4つの整数値を入力してください。:")
    elif input_num.isdigit() == True:
        if len(input_num) != 4:
            input_num = input("【エラー】4つの異なる数値を入力してください:")
        else:
            input_num2 = int(input_num)
            for i in range(0,4):
                input_num_ary.append(input_num2 // (10 ** (3-i)))
                input_num2 = input_num2 % (10 ** (3-i))
            if len(list(set(input_num_ary))) != 4:  
                input_num = input("【エラー】重複のない4つの数値を入力してください。:")
            else:
                input_continue_flg = False
     
print("入力した値は" + input_num + "です。")

3行目から16行目で「make_random_num」という関数名でランダムな数値を求める
コードを関数として定義しています。
18行目でその関数を実行して、得られた戻り値を「answer_num_ary」に代入しています。
正直なところ、このゲームでは答えとなる4桁の値は最初の1回だけしか生成しませんので、
関数に定義しなおしてもあまりメリットはありませんね。

しかし、20行目から38行目の数値の入力と、その数値が4桁の異なる数値であるかの判別は
正解するまで何度も繰り返すことになります。
こちらは関数にしていつでも実行できるようにしておくとコードがスッキリしますね。

それでは、この20行目から38行目を関数に定義しなおしましょう。
ちょっと中身も変更します。

import random

def make_random_num():
    ary = []
    while len(ary) < 4:
        random_num = random.randint(0, 9)
        append_flg = True

        for ary_element in ary:
            if ary_element == random_num:
                append_flg = False
                break
        if append_flg == True:
            ary.append(random_num)
        append_flg = True
    return ary

answer_num_ary = make_random_num()

def input_and_check():
    input_num = input("4桁の数値を入力してください:")
    while True:
        input_num_ary = []
        if input_num.isdigit() == True and len(input_num) == 4:
            devision_num = int(input_num)
            for i in range(4):
                input_num_ary.append(devision_num // (10 ** (3-i)))
                devision_num = devision_num % (10 ** (3-i))
            if len(list(set(input_num_ary))) == 4:
                break
        input_num = input("【エラー】重複のない4桁の数値を入力してください:")
    return (input_num, input_num_ary)

(my_answer_num, my_answer_num_ary) = input_and_check()

print("入力した値は" + str(my_answer_num) + "です")
print("その値の配列は" + str(my_answer_num_ary) + "です")

20行目から32行目で「input_and_check」という関数名で、数字の入力と4桁の異なる数値
が入力されるまでチェックと繰り返し入力を行う処理を定義しています。
先ほどまではごちゃごちゃしすぎていたので、文字や重複した値が入力された場合は
すべて31行目の処理になるように変更しました。

異なる4桁の数値が入力された場合は30行目に到達してbreakされ、while文から抜ける
ことができます。

32行目で戻り値を定義しています。ここでタプルを使ってinput_numとinput_num_ary
という2つの値を戻り値として返しています。
例えば、「1234」と入力した場合はinput_numが1234という数値になり、
input_num_aryが[1,2,3,4]という配列になります。

これは次回やりますが、入力された数値を表示する場合は数値の方が都合がよく、
答えと比較する場合は配列の方が都合がいいので、このように2つの値を返すようにしておきます。

34行目でこのinput_and_check関数を実行し、その戻り値をmy_answer_numとmy_answer_num_aryに
それぞれ代入しています。
36、37行目はそれぞれの表示を確認するためのコードです。確認ができましたら削除してしまってOKです。

このファイルを実行してみた1例を以下に乗せておきます。

4桁の数値を入力してください:1111
【エラー】重複のない4桁の数値を入力してください:1212
【エラー】重複のない4桁の数値を入力してください:12345
【エラー】重複のない4桁の数値を入力してください:1111
【エラー】重複のない4桁の数値を入力してください:こんにちは
【エラー】重複のない4桁の数値を入力してください:1234
入力した値は1234です
その値の配列は[1, 2, 3, 4]です

【STEP4】関数を別ファイルに定義して別ファイルから実行する

関数の定義が無事にできました。一つのファイルに関数の定義&実行が書かれていると
煩雑になってしまうので、関数が定義しているファイルと、関数を実行するゲームのファイルに
分けたいと思います。
新しく同じディレクトリに「myDef.py」などの名前を付けた新しいファイルを作成します。
そのファイル内に定義した関数を移動させます。
≪myDef.py≫

import random

#ランダムな4桁の数値を求める関数
def make_random_num():
    ary = []
    while len(ary) < 4:
        random_num = random.randint(0, 9)
        append_flg = True

        for ary_element in ary:
            if ary_element == random_num:
                append_flg = False
                break
        if append_flg == True:
            ary.append(random_num)
        append_flg = True
    return ary

#数値の入力とその値が4桁の異なる数値かどうかのチェックを行う関数
def input_and_check():
    input_num = input("4桁の数値を入力してください:")
    while True:
        input_num_ary = []
        if input_num.isdigit() == True and len(input_num) == 4:
            devision_num = int(input_num)
            for i in range(4):
                input_num_ary.append(devision_num // (10 ** (3-i)))
                devision_num = devision_num % (10 ** (3-i))
            if len(list(set(input_num_ary))) == 4:
                break
        input_num = input("【エラー】重複のない4桁の数値を入力してください:")
    return (input_num, input_num_ary)

※inport randomはこのファイル内に記述します。

関数のコードを移動させたので、もともとのファイル(hitAndBlow.pyとしています)は
次のようになります。
≪hitAndBlow.py≫

import myDef

#ランダムな4桁の値を生成する
answer_num_ary = myDef.make_random_num()
#入力した4桁の値を取得する
(my_answer_num, my_answer_num_ary) = myDef.input_and_check()

print("入力した値は" + str(my_answer_num) + "です")
print("その値の配列は" + str(my_answer_num_ary) + "です")

こっちのファイルはただ関数を実行するだけですので、ものすごくスッキリしましたね!
ここで注意しなければならないのは、1行目のimport myDefというコードです。

関数を別ファイルで定義しました。そのためそのファイルをimportしなければ
hitAndBlow.pyファイルでは実行できなくなります。
また、別ファイルの関数を実行する場合は、4行目や6行目のように「ファイル名.関数名」
という形式で記述しなければなりません。「myDefファイルのmake_random_num()関数を実行するよ」
というイメージです。

今回はこれで終わりにしたいと思います。次回は最後の当たり判定を行って、
正解するまで何回答えたかなどの仕組みを実装していきたいと思います。

新連載はじまりました!独学で学ぶPython基礎 連載リンク

独学で学ぶ-Pythonプログラミング 連載

Recent News

Recent Tips

Tag Search