#python #ゲーム #真偽値(True/False) #キーボード入力(input) #複数条件if
#プログラム終了(exit) #乱数(random) #変数関数外共有global
本記事では、前回の記事に書いた『テキストだけのアドベンチャーゲーム』の中身について解説します。
前回は、関数(def)、条件分岐(if)、繰り返し(while)についての構文を解説し、ゲームプログラムの中身にあるこれらの使用個所や、他の個所については解説しませんでした。
今回はそこを詳しく説明します。
プログラムについて
解説するプログラムは以下になります。
大きく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)
次回は、今回地味だったものをもっとゲームらしくして、楽しみながらわかりやすく解説しますので、ご期待ください!!!
この記事へのお問い合わせや、一歩踏み込んだサポートが必要な場合は、
ホームページからメールで受け付けています。お気軽にご連絡ください。
コメント