Python の勉強 スロットゲーム編 〜その8:リスト、タプル、辞書(ディクショナリ)、集合(セット)を使う〜

プログラミング

その6(こちら)で少しだけ登場した、リスト、辞書、集合についてもう少しだけ勉強しましょう。スロットゲームのプログラムにも反映します。

リスト(list)

リスト型を使うと、任意の型の要素を “複数個” 保持することができます。よく変数を “入れ物” で表現することがありますが、リストはこの入れ物が復数個つながっているイメージです。入れ物には順番が割り振られています。この順番はゼロ(0)から始まることに注意して下さい。入れ物を追加したり、削除したりすることもできます。入っているものを変更することができるのは普通の変数と同じです。

リストをイメージ化

実際にリストを定義したり、内容を取得するのは以下のようにします。

#
# list 型の変数を定義
#
#   角括弧「[」と「]」を使い、任意の型の要素を格納できる
#   各要素はカンマ「,」で区切る
#   最後の要素の後ろのカンマは、あっても無くても同じ
#
hoge = [0,                          # int 型    ここは 0 番目
               1.0,                 # float 型  ここは 1 番目
               'two',               # str 型    ここは 2 番目
               True,                # bool 型   ここは 3 番目
               ['inner', 'list'],   # list 型   ここは 4 番目
               ]
print(type(hoge))                   #==> <class 'list'>

#
# 要素を使う
#
print(hoge[1])                      #==> 1.0
print(hoge[-2])                     #==> True   ※後ろから数えるケース

#
# 要素の数を調べる
#
print(len(hoge))                    #==> 5      ※要素数は len() で取得可能

タプル(tuple)

タプルは変更できないリストです。定義する際は丸括弧「(」「)」を使う点がリストと異なります。ただし要素にアクセスする際には各括弧「[」「]」を使う点は同じです。混乱しないように!

タプルをイメージ化
#
# tuple 型の変数を定義
#
#   丸括弧「(」と「)」を使い、任意の型の要素を格納できる
#   各要素はカンマ「,」で区切る
#   最後の要素の後ろのカンマは、あっても無くても同じ
#
hoge = (0,                   # int 型    ここは 0 番目
        1.0,                 # float 型  ここは 1 番目
        'two',               # str 型    ここは 2 番目
        True,                # bool 型   ここは 3 番目
        ['inner', 'list'],   # list 型   ここは 4 番目
        )
print(type(hoge))            #==> <class 'tuple'>

#
# 要素を使う
#
print(hoge[1])               #==> 1.0
print(hoge[-2])              #==> True   ※後ろから数えるケース

#
# 要素の数を調べる
#
print(len(hoge))             #==> 5      ※要素数は len() で取得可能

辞書(dict)

辞書(dict)にも復数の値を格納することができます。しかし順番がありません。その代わりに名前を付けることができます。リストでは何番目に何が入っているかを覚えていないといけませんが、辞書では名前をたどって簡単に取り出すことができます。
一般的に、名前のことを「キー(key)」と呼び、格納する値のことを「バリュー(value)」と呼びます。キーには整数と文字列を用いることができます。文字列を使うほうが辞書(dict)を使うメリットを享受しやすいので、普通は文字列で指定します。

定義する際は波括弧「{」「}」を使い、要素を取り出したい時は角括弧「[」「]」を使います。

辞書をイメージ化
#
# 辞書(dict)型の変数を定義
#
#   波括弧「{」と「}」を使い、任意の型の要素を格納できる
#   各要素はコロン「:」でキー(key)とバリュー(value)で組を作り、各組はカンマ「,」で区切る
#   最後の要素の後ろのカンマは、あっても無くても同じ
#
hoge = {'satoh': 0,                 # int 型
        'akiblog': 1.0,             # float 型
        'Yamada': 'two',            # str 型
        333: True,                  # bool 型
        'inner': ['inner', 'list'], # list 型
       }
print(type(hoge))                   #==> <class 'dict'>

#
# 要素を使う
#
print(hoge['akiblog'])              #==> 1.0
print(hoge[333])                    #==> True

#
# 要素の数を調べる
#
print(len(hoge))                    #==> 5      ※要素数は len() で取得可能

集合(set)

集合(set)にも復数の値を格納することができますが、こちらは順序がなく、重複もない……という正に数学で登場する集合と同じものになります。

定義する際に波括弧「{」「}」を使うのは同じですが、こちらは “順序がない”、”重複を許さない” という性質から、各要素を取得するのではなく、その集合に含まれているかどうか?と判別するために使用します。

集合をイメージ化
#
# 辞書(dict)型の変数を定義
#
#   波括弧「{」と「}」を使い、任意の型の要素を格納できる
#   各要素はコロン「:」でキー(key)とバリュー(value)で組を作り、各組はカンマ「,」で区切る
#   最後の要素の後ろのカンマは、あっても無くても同じ
#
hoge = {0,                  # int 型
        1.0,                # float 型
        'two',              # str 型
        True,               # bool 型
                            # ['inner', 'list'] の様な list 型 はエラーになる
       }
print(type(hoge))           #==> <class 'set'>

#
# 存在チェック
#
print(1.0 in hoge)          #==> True    ※hoge に含まれている
print('akiblog' in hoge)    #==> False   ※hoge に含まれていない

#
# 要素の数を調べる
#
print(len(hoge))                    #==> 5      ※要素数は len() で取得可能

実践!ただし練習問題として!!(答えは下の方)

では実際にスロットゲーム内で使ってみましょう。

タプル(tuple)を使う ※リールの内容を変更されたくないから

「007.py」までのプログラムはスロット(リール)の中身をリスト(list)え定義していました。しかし上で勉強したように、リストは内容を変更することができます。スロットゲームではリールの内容を変更する必要がない…というか変更してはいけないので、タプル(tuple)に変更しましょう。
変更するのはこの箇所です。

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

辞書(dict)を使う ※特別な名前「king」「queen」と、そのボーナス

キーに「"king"」「"queen"」を使い、ボーナスコインをそれぞれのバリューに設定しましょう。入力した名前によってボーナスコインを付与していた場所にもこの辞書を使ってみましょう。
定数名は「BONUS_PLAYER_AND_COINS」として設定してみて下さい。

ちなみに集合(set)のところで登場した「in」は、辞書のキーに対しても使えます。以下をヒントにしてプログラムを修正してみて下さい!

#
# ヒント
#
dic = {'a': 100, 'b': 200}

# キーを直接指定して取得
print('a' in dic)               #==> True
print(dic['a'])                 #==> 100

# キーに "変数" を使って取得
k = 'b'
print(k in dic)                 #==> True
print(dic[k])                   #==> 200

集合(set)を使う ※さらなる特別名を!

スペシャルサンクス(special thanks)として、自分の特別な人の名前を集合で定義して下さい。定数名はズバリ「SPECIAL_THANKS」にしましょう!
もし BONUS_PLAYER_AND_COINS つまり「king」でも「queen」でも無かった場合でも、このスペシャルサンクスに含まれている名前を入力した場合は 50 枚のボーナスが付与されるようにしましょう。

レッツ、トライ!!

答え合わせ

以下に私が書いたプログラムを記載します。ご自身が書いたプログラムと比較してみて下さい。比較の仕方は、その4に記載しております。その7で比較用の拡張機能をインストールした人は、是非、その内のどれかの方法を試してみて下さい。

もちろん、スペシャルサンクス(SPECIAL_THANKS)に含まれる名前に差異があるのは問題ではありません。

"""スロットゲーム

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


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


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

# 特別なプレーヤーの名前と、その名前を使用した際のボーナスコイン数
BONUS_PLAYER_AND_COINS = {'king': 100, 'queen': 150}

# スペシャルサンクスの対象者名
# ボーナスコインは一律 50 枚とする
SPECIAL_THANKS = {'akira',      # 弊社社長。詳細は社長が作成最多ブログ記事のプロフィール欄をご確認下さい。
                  'hurry',      # 詳細はプロフィール欄から twitter をご確認下さい。
                  'shachi',     # https://shachi-web.com/
                  }
SPECIAL_THANKS_COIN = 50


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

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(f'こんにちは {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(f'現在の所持コイン数は {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 in BONUS_PLAYER_AND_COINS:
    player_coin = player_coin + BONUS_PLAYER_AND_COINS[player_name]
elif player_name in SPECIAL_THANKS:
    player_coin = player_coin + SPECIAL_THANKS_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:,} 枚になりました!')

コメント

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