ゼロからのPython入門講座演習

スイカ割りゲーム

スイカ割りゲーム

練習として、簡単なゲームを作ってみましょう。将棋盤のようなマス目の入ったボードに隠されたスイカを、プレイヤーを操作して見つけるゲームです。

  1. スイカとプレイヤーは、ボード上のランダムなマスに配置されます。
  2. ヒントとして、スイカからプレーヤーまでの距離を報告します。
  3. プレイヤーは、北・南・東・西にそれぞれ一マスずつ移動できます。
  4. スイカとプレイヤーが同じマスに入るまで、2. と 3. を繰り返します。

ここでは、ボードは次の図のように左上のマスの座標は(0, 0)で、X座標は左から右に向かって(1, 0)、(2, 0)、…… と増えていき、Y座標は上から下に向かって (0, 1)、(0, 1)、(0, 2)、…… と増えていくようにしましょう。

image.png

プログラムの構成

このゲームの手順を、もう少し詳しく考えてみましょう。

  1. スイカとプレイヤーの初期位置を決めます。
  2. スイカとプレイヤーの位置がおなじになるまで、以下の処理を繰り返します。
    1. スイカからプレイヤーまでの距離を出力します。
    2. キーボードから文字をうけとります。
    3. 受け取った文字がnなら北、sなら南、eなら東、wなら西に一マス移動します。
  3. ゲーム終了のメッセージを表示します。

こんな感じでいけそうです。こういったプログラムの構成は、最初はうまくできないかもしれませんが、いろいろなプログラムを読んだり書いたりしているうちに、できるようになってきます。プログラミング言語の勉強だけではなかなか上達しませんので、簡単なものでも、アプリケーションを自分で考えて開発してみるのが大事です。

スイカとプレイヤーの初期位置

スイカとプレイヤーの位置は、毎回ランダムに違った場所になるようにします。あんまり距離が離れすぎてもゲームになりませんから、ここでは、スイカとプレイヤーのx座標とy座標は 0 から 4 までの範囲に収まるようにしましょう。

Pythonでは、乱数を生成するときには random モジュールを インポート します。スイカとプレイヤーの座標は 0 から 4 までの整数ですので、ここではrandomモジュールのrandrange関数を利用します。

インポートしたモジュールの関数は、モジュール名.関数名() の形式で呼び出します。忘れていたら、モジュールとimport を読んで復習してください。

randrange() は、

random.randrange(開始値, 終了値)

の形式で指定すると、開始値以上かつ終了値未満(開始値 ≦ 乱数 < 終了値) となる乱数を生成します。

次の例は、0以上5未満の乱数を3回生成しています。

In [2]:
import random
print(random.randrange(0, 5))
print(random.randrange(0, 5))
print(random.randrange(0, 5))
4
0
1

random.randrange()関数 を使って、スイカとプレイヤーの位置を決定するコードを書いてみましょう。スイカの位置のX座標とY座標は変数 suika_xsuika_yに、プレイヤーの位置のX座標とY座標は変数 player_xplayer_y に代入することにします。

スイカとプレイヤーの位置を決める処理は、次のようになります。

In [15]:
# スイカの位置を決める
suika_x = random.randrange(0, 5)  # スイカのx座標
suika_y = random.randrange(0, 5)  # スイカのy座標

# プレイヤーの位置を決める
player_x = random.randrange(0, 5)  # プレイヤーのx座標
player_y = random.randrange(0, 5)  # プレイヤーのy座標

ゲームのループ処理

次に、プレイヤーとスイカの位置が一致するまで繰り返すループ処理を考えましょう。

このループは、スイカとプレイヤーの位置が異なるあいだ繰り返す whileループ として記述できます。

while スイカとプレイヤーの位置が異なっている:
    ...

スイカとプレイヤーの位置が異なっている という条件は、

スイカのx座標とプレイヤーのx座標が違う

という条件と、

スイカのy座標とプレイヤーのy座標が違う

という条件の、どちらか一方でも ならば、スイカとプレイヤーの位置が異なっている と言えます。

スイカとプレイヤーのx座標が違う という条件は、比較演算子!= を使って、次のようにかけます。

suika_x != player_x

同様に、y座標が違う という条件は、

suika_y != player_y

となります。

さきほどの while ループ

while スイカとプレイヤーの位置が異なっている:
    ...

スイカとプレイヤーの位置が異なっている という条件は、この2つの条件のうち、どちらか一方でも となった場合ですから、論理演算子の or 演算子 を使って

while (suika_x != player_x) or (suika_y != player_y):
    ...

と書けます。行末の : を忘れないようにしてください。

スイカからプレイヤーまでの距離を求める

while ループの中では、まず、スイカからプレイヤーまでの距離を求めて表示します。

スイカからプレイヤーまでの距離は、次の式で求められます。

$$ 距離 = \sqrt{(player\_x-suika\_x)^2 + (player\_y-suika\_y)^2} $$

Pythonでは、mathモジュールのsqrt()関数 で平方根を計算できます。次のように mathモジュールを import して、距離を計算してみましょう。

import math
diff_x = player_x - suika_x
diff_y = player_y - suika_y
distance = math.sqrt(diff_x**2 + diff_y**2)

この処理は、2点間の距離を求める 関数 として定義しましょう。

import math

def calc_distance(x1, y1, x2, y2):
    diff_x = x1 - x2
    diff_y = y1 - y2
    return math.sqrt(diff_x**2 + diff_y**2)

このように関数として calc_distance() を定義しておけば、スイカとプレイヤーの距離は次のように求められます。

distance = calc_distance(player_x, player_y, suika_x, suika_y)

と計算できます。

プレイヤーの移動処理

while ループ中では、スイカとプレイヤーの距離を表示してから、input()関数を使ってユーザからのキー入力を読み取り、キーに従ってプレイヤーの位置を移動します。ユーザが入力した文字が nなら北、sなら南、eなら東、wなら西に一マス移動します。それ以外の文字なら、何もしません。

プレイヤーを北に移動する場合は、プレイヤーのy座標(player_y)を -1 して、ボードの上方に移動します。逆に、南に移動する場合はy座標を +1 して下方に移動します。

同様に、プレイヤーを西に移動する場合にはプレイヤーのx座標(player_x)を -1 し、東に移動する場合には +1 します。

この処理をまとめると、次のようになります。

c = input("n:北に移動 s:南に移動 e:東に移動 w:西に移動")
if c == "n":
    player_y = player_y - 1
elif c == "s":
    player_y = player_y + 1
elif c == "w":
    player_x = player_x - 1
elif c == "e":
    player_x = player_x + 1

input()で入力された文字列は変数 c に代入されます。 まず、if文 の条件として c == "n" という比較演算を指定して、c が 文字列 "n" と等しいかどうかをチェックしています。c の値が "n" の場合は比較演算子 == の結果は となり、プレイヤーを北に移動しています。

c == "n" の場合は、次にelif節 に 指定した c == "s" という比較を行い、c が 文字列 "n" と等しいかどうかをチェックしています。この演算子が であればプレイヤーを南に移動します。

同様に、c == "s" の場合には、次の elif節の c == "w" の真偽を判定します。これも なら最後に c == "e" を判定して、入力に応じたプレイヤーの位置を移動します。

まとめると

これで、スイカ割りゲームを構成する部品が一通り揃いました。まとめると次のようになります。

In [1]:
import random
import math

def calc_distance(x1, y1, x2, y2):
    # 2点間の距離を求める
    diff_x = x1 - x2
    diff_y = y1 - y2
    return math.sqrt(diff_x**2 + diff_y**2)


suika_x = random.randrange(0, 5)  # スイカのx座標
suika_y = random.randrange(0, 5)  # スイカのy座標

player_x = random.randrange(0, 5) # プレイヤーのx座標
player_y = random.randrange(0, 5) # プレイヤーのy座標

# スイカとプレイヤーの位置が異なる間、処理を繰り返す
while (suika_x != player_x) or (suika_y != player_y):

    # スイカとプレイヤーの距離を表示する
    distance = calc_distance(player_x, player_y, suika_x, suika_y)
    print("スイカへの距離:", distance)
    
    # キー入力に応じて、プレイヤーを移動する
    c = input("n:北に移動 s:南に移動 e:東に移動 w:西に移動")
    if c == "n":
        player_y = player_y - 1
    elif c == "s":
        player_y = player_y + 1
    elif c == "w":
        player_x = player_x - 1
    elif c == "e":
        player_x = player_x + 1

print("スイカを割りました!")
スイカへの距離: 3.1622776601683795
n:北に移動 s:南に移動 e:東に移動 w:西に移動 n
スイカへの距離: 3.605551275463989
n:北に移動 s:南に移動 e:東に移動 w:西に移動 s
スイカへの距離: 3.1622776601683795
n:北に移動 s:南に移動 e:東に移動 w:西に移動 s
スイカへの距離: 3.0
n:北に移動 s:南に移動 e:東に移動 w:西に移動 e
スイカへの距離: 2.0
n:北に移動 s:南に移動 e:東に移動 w:西に移動 e
スイカへの距離: 1.0
n:北に移動 s:南に移動 e:東に移動 w:西に移動 e
スイカを割りました!

一般的なPythonの慣習で、import 文はプログラムの先頭に記述します。また、calc_distance() などの関数は、import 文に続けて記述します。

これで「スイカ割りゲーム」の完成です。

この例題は短いプログラムですが、本格的なプログラムを書くために必要な要素がたくさん含まれています。このぐらいのプログラムをスラスラ書けるようになると、初歩的なプログラミングの考え方をマスターしたと言えるでしょう。時間がかかっても、しっかり理解しましょう。



【Copyright © 2001-2020 python.jp】 【Privacy Policy】 python_japan