【第6回】テキストアドベンチャーゲームで基本構文を学ぶ(解説編)

テキストアドベンチャー pythonで簡単プログラミング

#python #ゲーム #真偽値(True/False) #キーボード入力(input) #複数条件if
#プログラム終了(exit) #乱数(random) #変数関数外共有global

本記事では、前回の記事に書いた『テキストだけのアドベンチャーゲーム』の中身について解説します。

前回は、関数(def)、条件分岐(if)、繰り返し(while)についての構文を解説し、ゲームプログラムの中身にあるこれらの使用個所や、他の個所については解説しませんでした。
今回はそこを詳しく説明します。

本記事では、主としてWindows、および、python3を前提にしています。
スポンサーリンク

プログラムについて

解説するプログラムは以下になります。
大きく2つ(定義部と実行部)に分かれるため、分けて表示して解説します。

[adventure.py]

【定義部】

import sys                  # システム用モジュール
import random as rd         # 乱数を扱うモジュール

def checkDeath() :          # 生命点(HP)が無くなったかをチェックする関数
    global HP               # 生命点(HP)を関数外と共有する
    global score            # 得点(スコア)を関数外と共有する

    if HP <= 0 :            # 生命点(HP)が無くなった
        print("やられた")
        print("")
        print("スコア : " + str(score))
        print("")
        print("--- GAME OVER ---")
        sys.exit()          # プログラムを終了する

def slime() :               # スライムの場合の処理をする関数
    global HP
    global score

    print("スライムが現れた!")
    HP = HP - 10            # 生命点(HP)を減らす
    checkDeath()            # 生命点(HP)チェック関数を実行する
    score = score + 1       # 得点(スコア)を増やす
    print("攻撃されてHPが" + str(HP) + "になった")

def goblin() :              # ゴブリンの場合の処理をする関数
    global HP
    global score

    print("ゴブリンが現れた!")
    HP = HP - 30
    checkDeath()
    score = score + 1
    print("攻撃されてHPが" + str(HP) + "になった")

def dragon() :              # ドラゴンの場合の処理をする関数
    global HP
    global score

    print("ドラゴンが現れた!")
    HP = HP - 50
    checkDeath()
    score = score + 1
    print("攻撃されてHPが" + str(HP) + "になった")

【実行部】

HP = 100        # 生命点(Hit Point)
score = 0       # 得点(スコア)

while True :    # ずっと繰り返す
    print("3つの分かれ道があります。")
    print("どれに進みますか?")
    print("1 ... 左   2 ... 真ん中   3 ... 右")

    dir = int(input())              # 進む方向をキーボードから入力させる
    if dir < 1 or dir > 3 :
        print("谷に転落した!")
        print("")
        print("--- GAME OVER ---")
        sys.exit()

    monster = rd.randint(1,3)       # 1~3の乱数を発生させる
    monster = monster + dir - 1     # 進んだ方向(dir)でモンスターを変更する

    if monster > 3 :                # 変更した結果が3を超えたら
        monster = monster - 3       # 1に修正する(モンスターは1~3)のため

    if monster == 1 :
        slime()                     # スライムが出現する
    elif monster == 2 :
        goblin()                    # ゴブリンが出現する
    else :
        dragon()                    # ドラゴンが出現する

    print("")                       # 見栄えを整えるための空行を表示

中身の解説

今回のプログラムでは、定義部と実行部に大きく分かれていて、実行していく順番は実行部になります。
そのため、実行部から解説をしていきます。

実行部

初期化

まず、実行部の最初の2行ですが、ここでは、
生命点をHP、得点をscoreという変数で定義して、
HPを100、scoreを0に初期化しています。
変数とは、中学で学んだ変数と同じで、値を覚えておくためのハコだと考えてください。

HP = 100        # 生命点(Hit Point)
score = 0       # 得点(スコア)

繰り返し(無限ループ)の始まり

次に以下の”while True”の行が続きます。

while True :    # ずっと繰り返す
    print("3つの分かれ道があります。")
    print("どれに進みますか?")
    print("1 ... 左   2 ... 真ん中   3 ... 右")

    : (中略)

    print("")                       # 見栄えを整えるための空行を表示

“while”は前回の記事にあった『~の間』の繰り返しになります。

しかし、”while”の後ろの条件を書くところに”True”というキーワードがあります。
これは真偽値といい、真(True)か偽(False)のどちらかを表します。
わかりやすく、
真(True)=○、偽(False)=✕
と考えてください。

ここでは、真(True)なので、
『条件が○(真)である』=『条件を満たしている』
ということを表しています。

また、”True”は変数ではないため、変化しません。
そのため、『常に条件を満たしている』ことを意味するので、”while Ture :”は無限に繰り返す『無限ループ』になります。

“while”に続く行は、プログラムの最後まで全ての行の頭に、いくつかの空白が付いています。(この、いくつかの空白のことをインデントと呼びます)
つまり、プログラムの最後まですべて、”while”の中にあり、プログラムの最後までグルグルと繰り返すことになります。

以上から、print(“3つの分かれ道があります。”) というところから、モンスターが現れるところまでが、ゲームオーバーになるまで、ずっと繰り返します。

繰り返しの中:メッセージ表示

では、”while”による繰り返しの中に入ります。

    print("3つの分かれ道があります。")
    print("どれに進みますか?")
    print("1 ... 左   2 ... 真ん中   3 ... 右")

説明するまでもないと思いますが、上記のメッセージを画面に表示しているだけです。
print()を実行すると改行されるので、3行で表示されます。

繰り返しの中:キーボード入力

次は、進む方向(左なら1, 真ん中なら2, 右なら3)をキーボードから入力させます。

    dir = int(input())              # 進む方向をキーボードから入力させる

input関数は、キーボードから文字が入力されてEnterが押されるのを待ちます。
そして、入力された文字列を返します。
int関数は、文字列(数字)を整数に変換します。
ただし、整数に変換できる数字でなかった場合は、エラーで終了してしまいます。
最終的にdir変数にキーボードから入力された数字が整数となって入ります。

次の行は以下です。

    if dir < 1 or dir > 3 :
        print("谷に転落した!")
        print("")
        print("--- GAME OVER ---")
        sys.exit()

if文ですが、条件を書くところが”dir < 1 or dir > 3″と複数の条件になっています。
これは、”or”が英語で”又は”の意味であるため、”dir < 1″、または、”dir > 3″を表しています。
そのため、”if dir < 1 or dir > 3 :”は、”もし、dir < 1 または、dir > 3の場合”という意味になります。

さらに、print関数でメッセージを出力した後、最後に”sys.exit()”があります。
これは、プログラムを終了する関数です。

以上から、1未満、または、3より大きい値を入力すると、踏み外して谷に落ちてしまい、ゲームオーバーとなってプログラムが終了します。

繰り返しの中:出現させるモンスターの抽選

では、次に進みます。
次の行では、rd.randint()という関数を実行しています。

    monster = rd.randint(1,3)       # 1~3の乱数を発生させる

ここで、”rd.”は何かですが、これは、定義部にある下記の乱数を扱うモジュールです。

import random as rd         # 乱数を扱うモジュール

乱数とは、常に不規則(randomランダム)に変化する数のことをいいます。
そして、”import random as rd”の行では、randomモジュールを”rd”として(=as)インポートしています。(asは長くなる記述を短縮するために使います)

よって、”rd.randint()”は、randomモジュールのrandint関数を実行することを意味します。
randint関数では、入力を2つ指定します。
”monster = randint(1,3)”は、1から3までの乱数を発生させて、monster変数に入れています。

ここで、進んだ方向によって3種類のモンスターのどれかが決まるようにするために、下記の行で計算をしています。

    monster = monster + dir - 1     # 進んだ方向(dir)でモンスターを変更する

    if monster > 3 :                # 変更した結果が3を超えたら
        monster = monster - 3       # 1に修正する(モンスターは1~3)のため

実は、dirの値を足さなくても、違うモンスターが出てくるので、ゲームのプレーヤにとっては、選んだ方向と関係なく出てきているのか、選んだから出てきているのかは分かりません。
しかし、方向を選んだ後に、『実はモンスターはここにいたのだー』というような表示をする場合には、役に立ちます。

さて、次の”if monster > 3 :”ですが、これは、dirを足した結果、monsterの値が3を超えてしまった場合に、”monster = monster – 3”として、1~3におさまるように引き算しています。

繰り返しの中:モンスターの出現

では、最後に下記を見てみます。

    if monster == 1 :
        slime()                     # スライムが出現する
    elif monster == 2 :
        goblin()                    # ゴブリンが出現する
    else :
        dragon()                    # ドラゴンが出現する

    print("")                       # 見栄えを整えるための空行を表示

ここでは、monster変数の値に従って、それぞれ、スライム、ゴブリン、ドラゴンを選別して実行しています。
ここは、前回のif文の構文どおりの内容になっています。
そして最後に表示調整のために空の行を表示しています。

定義部

定義部を再掲載します。

import sys                  # システム用モジュール
import random as rd         # 乱数を扱うモジュール

def checkDeath() :          # 生命点(HP)が無くなったかをチェックする関数
    global HP               # 生命点(HP)を関数外と共有する
    global score            # 得点(スコア)を関数外と共有する

    if HP <= 0 :            # 生命点(HP)が無くなった
        print("やられた")
        print("")
        print("スコア : " + str(score))
        print("")
        print("--- GAME OVER ---")
        sys.exit()          # プログラムを終了する

def slime() :               # スライムの場合の処理をする関数
    global HP
    global score

    print("スライムが現れた!")
    HP = HP - 10            # 生命点(HP)を減らす
    checkDeath()            # 生命点(HP)チェック関数を実行する
    score = score + 1       # 得点(スコア)を増やす
    print("攻撃されてHPが" + str(HP) + "になった")

def goblin() :              # ゴブリンの場合の処理をする関数
    global HP
    global score

    print("ゴブリンが現れた!")
    HP = HP - 30
    checkDeath()
    score = score + 1
    print("攻撃されてHPが" + str(HP) + "になった")

def dragon() :              # ドラゴンの場合の処理をする関数
    global HP
    global score

    print("ドラゴンが現れた!")
    HP = HP - 50
    checkDeath()
    score = score + 1
    print("攻撃されてHPが" + str(HP) + "になった")

先頭の1行目はすでに説明したところを見てください。

モンスターを出現させる関数

次に実行されるのは、モンスターを出現させる関数の処理です。
スライムを出現させるslime関数を見てみましょう。

def slime() :               # スライムの場合の処理をする関数
    global HP
    global score

    print("スライムが現れた!")
    HP = HP - 10            # 生命点(HP)を減らす
    checkDeath()            # 生命点(HP)チェック関数を実行する
    score = score + 1       # 得点(スコア)を増やす
    print("攻撃されてHPが" + str(HP) + "になった")

“def slime() :”は、前回解説しました自作関数の定義を示しています。
カッコ内に何も記載がないので、入力がないslime関数を定義しています。

では、次の行について

    global HP
    global score

HP, scoreはそれぞれ、生命点、得点の値を入れておく変数です。
しかし、前に“global”グローバルが付いています。
これは、広い範囲で使う変数だということを宣言するキーワードです。

HP, scoreは、どんなモンスターが出現しても変更する必要があり、プログラムの全域で共有する必要があります。
そのため、”global”を変数の前につけて、関数の外と共有する必要があります。
“global”を付けた場合と付けない場合で何が違うかについては、後述を参照ください。

次の行を見てみます。

    print("スライムが現れた!")
    HP = HP - 10            # 生命点(HP)を減らす
    checkDeath()            # 生命点(HP)チェック関数を実行する
    score = score + 1       # 得点(スコア)を増やす
    print("攻撃されてHPが" + str(HP) + "になった")

”スライムが現れた!”を表示した後に、生命点(HP)を10減らし、生命点が無くなっていないかをcheckDeath関数でチェックします。
そして、スコアを1増やして、”攻撃されてHPが~になった”と表示します。
生命点を減らしている行は『HP = HP – 10』で、HPから10を減らした値を、またHPに戻しています。
同様に、得点についても、『score = score + 1』で、scoreに1増やした値を、また、scoreに戻しています。
最後のprint関数の中では、”str(HP)”という記述がありますが、これは、HPの値が数値であり、str関数で文字列に変換しています。
もし、HPのままにして、『print(“攻撃されてHPが” + HP + “になった”)』を記述してしまうと、エラーになります。

ゴブリンとドラゴンについては、
・ 関数名が違っている
・ HPを減らす数値が多い
だけで、他の処理は全て丸写しになっているため、説明を省略します。

globalを付ける・付けないの違いについて

pythonでは、関数の中で変数を使うと、変数はその関数の中で初期化されて使用されます。
そして、下記のように、関数の外で同じ名前の変数を使っても、別の変数と見なされてしまいます。

X=100
                                                                                                                                                                                                                                           def hoge():                                                                                                                 
    X=0                                                                                                                     
    X=X+200                                                                                                                                                                                                                                                                                                                                                             

hoge()                                                                                                                  print(X)  

実行すると以下のように、hoge関数を実行したので、200になるのかと思っていたら、予想に反して、100が表示されます。

(base) PS D:\blog\python_beginner_adventure> python tmp.py                                                            100 

つまり、関数hogeから戻ってきたら、hogeの中で行った計算結果を忘れて、関数の外にあるX変数を思い出して処理してしまいます。

生命点がなくなったか確認する関数

生命点(HP)がなくなったかを確認し、無くなっていた場合はプログラムを終了させる関数”checkDeath”を以下に示します。

def checkDeath() :          # 生命点(HP)が無くなったかをチェックする関数
    global HP               # 生命点(HP)を関数外と共有する
    global score            # 得点(スコア)を関数外と共有する

    if HP <= 0 :            # 生命点(HP)が無くなった
        print("やられた")
        print("")
        print("スコア : " + str(score))
        print("")
        print("--- GAME OVER ---")
        sys.exit()          # プログラムを終了する

”def checkDeath() :”で関数”checkDeath”を定義しており、カッコの中に何も記載がないため、入力がありません。

次の行は、前述のとおり、生命点(HP)と得点(score)を関数の外と共有化しています。

“if HP <= 0 :”は、『もし、生命点(HP)が0以下(0を含む)になっていたら』という意味で、
その場合は、後ろのprint関数で”やられた”以降を表示します。

そして最後にsys.exit関数でプログラムを終了させています。

最後に

いかがでしたでしょうか?
今回はプログラムの中身について解説しました。
前回の記事では説明していなかった
・ 真偽値(○=True/✕=False)
・ キーボードからの入力(input関数)
・ 複数条件のif文(~か~のとき=if A or B)
・ プログラムを終了させる(sys.exit関数)
・ 乱数(random)
・ 変数を関数の外と共有する(global)

次回は、今回地味だったものをもっとゲームらしくして、楽しみながらわかりやすく解説しますので、ご期待ください!!!

この記事へのお問い合わせや、一歩踏み込んだサポートが必要な場合は、
ホームページからメールで受け付けています。お気軽にご連絡ください。

0

コメント

タイトルとURLをコピーしました