Python の勉強 スロットゲーム編 〜その5:if による条件分岐、真偽値、比較演算子〜

プログラミング

プレーヤーの名前に「king」と入力すると、ボーナスコインがもらえることが分かりました。今回は、「king」と入力した場合のみ……ということをプログラム上で実現する方法を勉強します。

プログラムではこの様な手法を「条件分岐」といいます。条件分岐を使うには「真偽値(ブール値、Boolean)」と「比較演算子」のことも知っておく必要があるので合わせて勉強していきましょう。

条件分岐

プログラムの用語にすると難しく感じるかも知れません。しかし実際は「もし~なら……します」というだけで、つまりは普段の生活でいたるところで登場する、とても日常的なものです。例えばこんなもの……

  • もし、今日が月曜日なら、可燃ゴミを出します
  • もし、私が元気なら、階段を使います
    そうじゃないなら、エレベータを使います
  • もし、テストの結果が 100 点なら、お小遣いを 500 円もらいます
    そうではなく、もし、テストの結果が 90 点以上なら、お小遣いを 200 円もらいます
    そうではなく、もし、テストの結果が 80 点以上なら、お小遣いを 100 円もらいます
    そうじゃないなら、罰金でお小遣いから 100 円払います

ここで一つだけ、3 つ目に示した例に関して、覚えていただきたい前提があります。それは「……します」という結果は一つしか選べないということです。
例えば、あなたのテスト結果が 100 点だったとします。お小遣いを 500 円もらいました。ここで(ずる賢い)あなたは思いました……「100点ということは、90点以上でもあるから、さらに 200 円もらえる!!」と。ですが、その望みが叶うことはありません。つまり「500円もらえる」か「200円もらえる」か「100円もらえる」か「100円払う」の内、どれか一つの結果を受け入れることになります。Python での条件分岐もこれと同じだと考えて下さい。

では次に、これをプログラムでどの様に表現するのかを見てみます。

「if」「elif」「else」を使った条件分岐

Python では

  • もし →「if」
    そうじゃない →「else」
    そうではなくもし →「elif」(= else if)
  • なら →「:」

を使って条件分岐を表現します。また例1のように、”そうじゃない” 場合に何もすることがなければ「else」を省略することができます。
ですが、このプログラムはまだ動きません。VS Code 上でも「today_id_monday」や「i_am_fine」の部分に

波線で警告が出ていますね。

真偽値(Boolean)

プログラムが「今日が月曜日」かどうか等の条件を判断する際、「真偽値」(しんぎち)を使います。真偽値は

  • 条件が成立・真実である場合を「真」 → プログラムでは True
  • その逆を「偽」 → プログラムでは False

という2つの値で表します。上のプログラムが動かなかったのは、「today_is_monday」や「i_am_fine」が True なのか False なのかを Python が知らなかったからです。逆にいうと Python に教えてあげる(設定してあげる)ことでプログラムが動くようになりますので、その様子をご確認ください。

「True」を設定した場合
# 例1
today_is_monday = True

if today_is_monday:
    print('可燃ゴミを出します')

# 例2
i_am_fine = True

if i_am_fine:
    print('階段を使います')
else:
    print('エレベータを使います')
「False」を設定した場合
# 例1
today_is_monday = False

if today_is_monday:
    print('可燃ゴミを出します')

# 例2
i_am_fine = False

if i_am_fine:
    print('階段を使います')
else:
    print('エレベータを使います')

Python の勉強以前に、フローチャートや skratch(スクラッチ)の経験がある人は、それと比較してみると良いかも知れません。フローチャートも skratch も経験がない場合は、「もし、 “I am fine” が本当のことなら、階段を使います。」といった具合に言語化してみましょう。それでも右画像にある False の場合は慣れるまで少し時間がかかるかも知れません。頑張りましょう!

ちなみに真偽値は他にも「Bool 値」(ブール値)や、「Boolean」(ブーリアン)と言うこともあります。

比較演算子

例3について考えてみましょう。ここでは TrueFalse を指定する代わりに、”テストの結果” を使って「100点?」「90点以上?」といった文脈を使いたくなるでしょう。そこで登場するのが “比較演算子” です。比較演算子を使うと True または False を式から作り出すことができます。

“等しい”、”等しくない”、”大きい”、”小さい” 等の比較以外にも、”含まれている” or “含まれていない” という比較も可能です。ゲーム中には登場しませんが一緒に覚えておきましょう。

x == yx と y が等しい
x != yx と y が等しくない
x > yx が y より大きい
x < yx が y より小さい
x >= yx が y 以上(≧)
x <= yx が y 以下(≦)
x in yx が y に含まれる
x not in yx が y に含まれない
“比較演算子” の種類

実際に使って確認してみましょう。

result_of_test = 100

print(result_of_test == 100) # result_of_test は 100 と等しい「==」    ==> True
print(result_of_test != 100) # result_of_test は 100 で等しくない「!=」 ==> False
print(result_of_test >  100) # result_of_test は 100 より大きい「>」    ==> False
print(result_of_test <  100) # result_of_test は 100 より小さい「<」    ==> False
print(result_of_test >= 100) # result_of_test は 100 以上(≧)「>=」   ==> True
print(result_of_test <= 100) # result_of_test は 100 以下(≦)「<=」   ==> True

print('--------------------------------------------------')

REEL_MARK_LIST = ['♠', '♥', '♥', '◆', '◆', '◆', '♣', '♣', '♣', '♣']

print('♥' in REEL_MARK_LIST)      # ♥が含まれている  ==> True
print('⚡' in REEL_MARK_LIST)      # ⚡が含まれている  ==> False
print('♥' not in REEL_MARK_LIST)  # ♥が含まれていない ==> False
print('⚡' not in REEL_MARK_LIST)  # ⚡が含まれていない ==> True
“比較演算子” を使って真偽値(True/False)を作っている様子

長くなりましたが、この比較演算子を使って例3のプログラムを書き直してみましょう。
プログラムはテストの結果が 100 点の場合のみ記載します。ご自身で値を変更してみて、動きがどう変化するかを確かめてみるといい勉強になると思います。

# 例3
test_of_result = 100

if test_of_result == 100:
    print('お小遣いを 500 円もらいます')
    print('やったぜ!')
elif test_of_result >= 90:
    print('お小遣いを 200 円もらいます')
    print('頑張ったぜ')
elif test_of_result >= 80:
    print('お小遣いを 100 円もらいます')
    print('あともう少し!')
else:
    print('……お小遣いから 100 円払います')
    print('残念。')
テストの結果が 100 点の様子
テストの結果が 85 点の様子
テストの結果が 79 点の様子

プレーヤー名「king」のボーナスについて

改めてスロットゲームのプログラムを確認してみましょう。「player_name」はどこから来たんだ!?という疑問があるかも知れませんが、それを理解するにはもう少し勉強が必要になりますのでここでは一旦、考えないことにしましょう。
とにかく「player_name が ‘king’ と等しい」場合のみ、KING_BONUS_COIN が追加されるんだということをイメージしていただければと思います。

「player_name」を ‘king’ と比較している場所

女王様用のボーナスを追加してみよう!

条件分岐になれるために、スロットゲームのプログラムに女王様(queen)用のボーナスを追加してみましょう。女王様だった場合のボーナスを 150 枚とします。(オレ様系、または亭主関白の方は 50 枚でいいです)

前々回の「003.py」をコピペして「005.py」を作成します。
“マジックナンバー” を使わないように、まず定数で QUEEN_BONUS_COIN を定義します。

# プレーヤーの名前が「queen」だった場合、ゲームスタート時の所持コイン数にボーナスするコイン数
QUEEN_BONUS_COIN = 150

そして、上で勉強した「そうではなく、もし(elif)」を使って……

elif player_name == 'queen':
    player_coin = player_coin + QUEEN_BONUS_COIN

実際に「queen」を入力して、150 枚のボーナスコインが加算される様子を確認します。

「queen」を入力して、所持コインが 273 枚に増えた様子

できました!
他にもご自身の名前を入力した時は 1,000 枚追加する!等、色々工夫ができますので是非、自分仕様に改造して下さい!

現時点のプログラムは以下の状態になっています。前回、ご紹介した「項目の比較」機能を使って確認してみて下さい。

"""スロットゲーム

簡単なスローっとゲームです。ゲームスタート時に保有しているコインを増やしましょう。
掛けコイン数を入力すると、スロットの結果が表示されます。
絵柄が揃うと、そのパターンに応じた配当倍率でコインを獲得することができます。
"""


import random   # "乱数" を生成するために必要なライブラリをメモリ上に読み込む(標準ライブラリ)


# スロット(リール)の中身を "定数" で定義する
# 配列のインデックスは 0 から始まるので、0 〜 9 番目に格納されている
# 定数は全て大文字で記載する
REEL_MARK_LIST = ['♠', '♥', '♥', '◆', '◆', '◆', '♣', '♣', '♣', '♣']

# プレーヤーの名前が「king」だった場合、ゲームスタート時の所持コイン数にボーナスするコイン数
KING_NAME = 'king'
KING_BONUS_COIN = 100

# プレーヤーの名前が「queen」だった場合、ゲームスタート時の所持コイン数にボーナスするコイン数
QUEEN_NAME = 'queen'
QUEEN_BONUS_COIN = 150


# ============================================================
# ゲームに必要な関数を定義する
# ============================================================

def show_start_message():
    """ゲーム開始のメッセージを表示する
    (This function is to be called to show the start message.)
    """
    print('--------------')
    print('スロットゲーム')
    print('--------------')

def ask_player_name():
    """プレーヤーの名前を尋ねる
    (This function is to be called to ask player's name.)

    プレーヤーの名前を入力(input)してもらい、挨拶を表示(print)する
    入力されたプレーヤーの名前を返す(return)

    Returns:
        str: プレーヤーの名前
    """
    player_name = input('あなたの名前を入力して下さい: ')
    print('こんにちは ' + player_name + ' さん')
    return player_name

def ask_bets(player_coin):
    """現在の所持コイン数を表示した後、掛けるコイン数(bets)を尋ねる
    (This function is to be called to ask bets.)

    所持コイン数(player_coin)は数値なので、文字列に含めたい場合は文字列(string)に変換する必要がある ==> str() 関数
    input() 関数で入力した値は文字列(string)になるので整数(integer)に変換する ==> int() 関数

    Args:
        player_coin (int): プレーヤーの所持コイン数

    Returns:
        int: 掛けコイン数
    """
    print('------------------------------')
    print('現在の所持コイン数は ' + str(player_coin) + ' 枚です。')
    str_bets = input('掛けコイン数を入力して下さい: ')
    bets = int(str_bets)
    return bets

def show_and_get_result():
    """スロットの結果(絵柄)を表示し、結果を取得する
    (This function is to be called to show and get result.)

    Returns:
        str: スロットの結果(絵柄)
    """
    # TODO(佐藤宏行): ループ内で文字列を結合するのは避ける。代わりにリストに貯めて、最後に結合(join)すること
    # 参照: https://google.github.io/styleguide/pyguide.html#310-strings
    result_all = ''
    for i in range(3):
        index = random.randint(0, 9)
        result = REEL_MARK_LIST[index]
        result_all = result_all + result
    print(result_all)
    return result_all

def get_division(marks):
    """絵柄に応じた配当倍率を取得する
    (This function is to be called to get division.)

    Args:
        marks (str): スロットの結果(絵柄)

    Returns:
        int: 配当倍率
    """
    if marks == '♠♠♠':
        print('超大当たり!!')
        return 15
    elif marks == '♥♥♥':
        print('大当たり!')
        return 12
    elif marks == '◆◆◆':
        print('大当たり!')
        return 10
    elif marks == '♣♣♣':
        print('大当たり!')
        return 8
    elif marks[0:2] == '♠♠':
        print('当たり!')
        return 5
    else:
        print('ハズレ...')
        return -1

def calculate_coin(coin, bets, division):
    """掛けたコイン数(bets)と、配当倍率(division)を使用してプレーヤーの所持コイン数を精算する
    (This function is to be called to calculate (players's) coin.)

    Args:
        coin (int): プレーヤーの精算前の所持コイン数
        bets (int): 掛けコイン数
        division (int): 配当倍率

    Returns:
        int: 精算後のプレーヤーの所持コイン数
    """
    coin = coin + bets * division
    return coin


# ============================================================
# 実際にゲームを実行する
# ============================================================

# プレーヤーの所持コイン数
player_coin = 123

show_start_message()
player_name = ask_player_name()

if player_name == KING_NAME:
    player_coin = player_coin + KING_BONUS_COIN
elif player_name == QUEEN_NAME:
    player_coin = player_coin + QUEEN_BONUS_COIN

for message in ['1回目', '2回目', '最後だよ']:
    print(message)
    bets = ask_bets(player_coin)
    marks = show_and_get_result()
    division = get_division(marks)
    player_coin = calculate_coin(player_coin, bets, division)

print('終了です。{} さんの所持コイン数は...'.format(player_name))
print(f'最終的に {player_coin} 枚になりました!')

(おまけ)”king” や “queen” は定数じゃなくていいのか?

そう思ったあなたは鋭い!”マジックナンバー” という名前でご紹介しましたが、プログラム中に突然に出てくるのは、数字だけではありません。今回の 'king''queen' も同類です。この様に分かりやすい名前ならまだいいですが、'hcetgolbika' の様に適当な文字列で条件に使用する場合はどうでしょうか?
実はこの文字列、当ブログのドメイン「akiblog.tech」を逆さにしたものです。説明されれば納得ですが、いきなり説明もなくいきなり登場すると意味不明です。あとから見た人はサッパリ分からないでしょう。もしかしたら明日の自分も忘れてしまっているかも知れません……。こういう場合はコメント付きで定数にしておくべきですね。ただ定数ばかりになってしまうと、それも見づらくなってしまうかな…という思いもあります。バランスを考えながら定義していければいいかなと思うところです。

というわけで 'king''queen' については、このブログ中では定数にせず、このまま進めることにします。ただし念のため、定数として扱う場合についても、プログラムが正しく動くことを確認しておきましょう。

コメント

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