よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

運の采配

運はどのような結果をもたらすでしょうか。保有資産のゲームという分かりやすい形で表示してみます。



【ルール】
参加者の全員が同じ収入で同じ支出と仮定します。ひと月に、全員が同じ金額の10円を得て、同じ金額の1円を使うとしましょう。
誰かが使った1円は、その他の誰かの臨時収入になります。その他の誰かを選ぶ時にrandomを使うことにします。
運が良ければ臨時収入をたくさん得続け、運が悪ければ臨時収入が得られません。

  • 1ターンをひと月とする。
  • 指定ターンの終わった時点での総合金額を競うゲーム。
  • ひと月あたりの定収入は全員等しく10円とする。
  • ひと月あたりの支出も全員等しく1円とする。
  • 誰かの支出はその他の誰かの収入になるとする。

    【予想】
    参加者全員が同額の支出入だし、支出の額も少なく、臨時収入を得る確率も全員同じなのだから大して差が拡がらず、保有金額は全員平均的になるだろうと思いますが、果たして…



では、ここからは実際にプログラムを作って行きます。



参加者リスト作成関数


参加人数を指定すると、メンバーのリストを自動で作ります。

def make_member_list(num:int)->list:   
    # 参加者リスト
    member_list = ["No." + str(i+1) for i in range(num)]
    return member_list

実行


# 参加人数の指定
n = 7

# 参加者リスト
member_list = make_member_list(n)
print(member_list)
['No.1', 'No.2', 'No.3', 'No.4', 'No.5', 'No.6', 'No.7']

参加人数を適当に7名としました。ラッキーセブンは誰なのか!?
各人の名前はNoで分けました。囚人番号のようです…



臨時収入を得る参加者をランダムに選ぶ


参加者リストから自分以外のメンバーをrandom.choice()で選びます。もし自分が選ばれたらチョイスをやり直すようにifで分けます。
選ばれた参加者のリストを返します。

import random

def choose_member(member_list:list)->str:
    choose_list = []
    
    for num in member_list:
        while True:
            choose_member = random.choice(member_list)

            if choose_member != num:
                choose_list.append(choose_member)
                break
            else:
                pass
    
    return choose_list

実行


# 参加人数
n = 7

# 参加者リスト
member_list = make_member_list(n)
# 臨時収入の人選
choose_list =choose_member(member_list)
print(choose_list)
['No.2', 'No.6', 'No.7', 'No.1', 'No.4', 'No.3', 'No.1']

このリストに多く載るほど運の良い人です。



選ばれた参加者のリストから出現回数を数える関数


標準ライブラリのcollectionsを使って選ばれた参加者のリストから各要素の出現回数をカウントし、辞書を返します。

import collections

def lucky_counter(choose_list:list)->dict:
    lucky_count_dict = collections.Counter(choose_list)
    
    return lucky_count_dict

実行

# 参加人数
n = 7

# 参加者リスト
member_list = make_member_list(n)
# 臨時収入の人選
choose_list =choose_member(member_list)
# 選ばれた人の出現回数をカウント
count_dict = lucky_counter(choose_list)
print(count_dict)
Counter({'No.4': 2, 'No.1': 2, 'No.7': 2, 'No.2': 1})



定支出入差額算出関数


全員が毎月定額で10円得て1円使うので、9円ずつ保有金額が増えることになります。

# 収入と支出の差額を計算する関数
def in_and_out(income:int,outgo:int)->int:
    # 収入と支出の差額
    diff = income - outgo
    return diff

実行

income = 10
outgo = 1

diff = in_and_out(income,outgo)
print(diff)
9



参加者所有額の辞書化関数


上で作ったlist型の参加者リストを引数にして辞書に自動で作成します。
所有金額の初期値はゼロ円。

def start_asetts_dict(member_list:list)->dict:
    # 資産額リスト
    asetts_dict = {name:0 for name in member_list}
    
    return asetts_dict

実行

# 参加人数
n = 7

# 参加者リスト
member_list = make_member_list(n)

# 資産額ディクト
asetts_dict = start_asetts_dict(member_list)
print(asetts_dict)
{'No.1': 0, 'No.2': 0, 'No.3': 0, 'No.4': 0, 'No.5': 0, 'No.6': 0, 'No.7': 0}

スタート時点での参加者の所有金額の辞書が出来ました。



月締め支出入計算関数


定支出入と臨時収入を計算して辞書を返します。

定支出入加算


def add_asetts(asetts_dict:dict, diff:int)->dict:
    
    for k,v in asetts_dict.items():
        v = v + diff
        asetts_dict[k] = v
    new_asetts_dict = asetts_dict
    
    return new_asetts_dict


臨時収入加算関数


def lucky_add_asetts(asetts_dict:dict, lucky_count_dict:dict, outgo:int)->dict:
    
    for name, v in lucky_count_dict.items():
        asetts_dict[name] = asetts_dict[name] + v*outgo
    
    last_asetts_dict = asetts_dict
    
    return last_asetts_dict

実行


# 参加人数
n = 7
# 参加者リスト
member_list = make_member_list(n)
# 資産額ディクト
asetts_dict = start_asetts_dict(member_list)
# 定収入
income = 10
# 定支出
outgo = 1
# 支出入差額
diff = in_and_out(income,outgo)
# 所有金額に差額を追加
new_asetts_dict = add_asetts(asetts_dict,diff)
# ラッキーメンバー
choose_list = choose_member(member_list)
# ラッキーカウンター
lucky_dict = lucky_counter(choose_list)

# 所有金額に臨時収入を加算
lucky_add_asetts(new_asetts_dict,lucky_dict,outgo)
{'No.1': 10,
 'No.2': 10,
 'No.3': 9,
 'No.4': 10,
 'No.5': 10,
 'No.6': 9,
 'No.7': 12}



実行用のメイン関数作成


細々した機能を別個の関数にした為に、実行する部分が矢鱈と長くなった。
一応動いたので実行部分をまとめる

def main(n:int,income:int,outgo:int,turns:int)->dict:
    
    # 参加者リスト
    member_list = make_member_list(n)
    # 初期資産額ディクト
    asetts_dict = start_asetts_dict(member_list)
    # 支出入差額
    diff = in_and_out(income,outgo)
        
    for turn in range(turns):
        # 所有金額に差額を追加
        new_asetts_dict = add_asetts(asetts_dict,diff)
        # ラッキーメンバー
        choose_list = choose_member(member_list)
        # ラッキーカウンター
        lucky_dict = lucky_counter(choose_list)
        # 所有金額に臨時収入を加算
        last_asetts_dict = lucky_add_asetts(new_asetts_dict,lucky_dict,outgo)
    
    return last_asetts_dict



最終実行


1ターン後の保有

# 参加人数
n = 7
# 定収入
income = 10
# 定支出
outgo = 1
# ターン回数
turns = 1

result = main(n,income,outgo,turns)
print(result)
print("~~~~~~~~~~~~~~~~~~~~~~~~")
{'No.1': 11, 'No.2': 10, 'No.3': 10, 'No.4': 9, 'No.5': 11, 'No.6': 10, 'No.7': 9}
~~~~~~~~~~~~~~~~~~~~~~~~



数ヵ月後の保有


3ヶ月後のと24ヶ月後を出してみる。
金額だけのリストも出す。

# 参加人数
n = 7
# 定収入
income = 10
# 定支出
outgo = 1

#3ヶ月後の保有金額
# ターン回数
turns = 3
result_3 = main(n,income,outgo,turns)
print(result_3)
print(result_3.values())
print("~~~~~~~~~~~~~~~~~~~~~")

# 24ヶ月後の保有金額
turns = 24
result_24 = main(n,income,outgo,turns)
print(result_24)
print(result_24.values())
print("~~~~~~~~~~~~~~~~~~~~~")
{'No.1': 28, 'No.2': 30, 'No.3': 30, 'No.4': 31, 'No.5': 29, 'No.6': 30, 'No.7': 32}
dict_values([28, 30, 30, 31, 29, 30, 32])
~~~~~~~~~~~~~~~~~~~~~
{'No.1': 242, 'No.2': 237, 'No.3': 249, 'No.4': 241, 'No.5': 234, 'No.6': 238, 'No.7': 239}
dict_values([242, 237, 249, 241, 234, 238, 239])
~~~~~~~~~~~~~~~~~~~~~

平均的。
というか、このプログラムは期待通りに正しく動いてるんだろうか…



参加人数のみ増やして実行


7人から20人に増やしてみる。保有金額のみ表示にする。

# 参加人数
n = 20
# 定収入
income = 10
# 定支出
outgo = 1

#3ヶ月後の保有金額
# ターン回数
turns = 3
result_3_2 = main(n,income,outgo,turns)
#print(result_3_2)
print(result_3_2.values())
print("~~~~~~~~~~~~~~~~~~~~~")

# 24ヶ月後の保有金額
turns = 24
result_24_2 = main(n,income,outgo,turns)
#print(result_24_2)
print(result_24_2.values())
print("~~~~~~~~~~~~~~~~~~~~~")
dict_values([29, 31, 29, 29, 30, 32, 30, 28, 30, 34, 27, 30, 29, 30, 32, 29, 29, 29, 31, 32])
~~~~~~~~~~~~~~~~~~~~~
dict_values([234, 238, 238, 238, 233, 235, 240, 242, 241, 246, 237, 232, 243, 238, 252, 243, 237, 237, 243, 253])
~~~~~~~~~~~~~~~~~~~~~

平均的。



支出大幅アップで実行


1円から8円に変えてみる。

# 参加人数
n = 20
# 定収入
income = 10
# 定支出
outgo = 8

#3ヶ月後の保有金額
# ターン回数
turns = 3
result_3_3 = main(n,income,outgo,turns)
#print(result_3_3)
print(result_3_3.values())
print("~~~~~~~~~~~~~~~~~~~~~")

# 24ヶ月後の保有金額
turns = 24
result_24_3 = main(n,income,outgo,turns)
#print(result_24_3)
print(result_24_3)
print("~~~~~~~~~~~~~~~~~~~~~")
dict_values([14, 46, 22, 30, 22, 22, 54, 22, 30, 30, 30, 46, 30, 38, 14, 30, 14, 38, 30, 38])
~~~~~~~~~~~~~~~~~~~~~
{'No.1': 232, 'No.2': 224, 'No.3': 184, 'No.4': 264, 'No.5': 232, 'No.6': 280, 'No.7': 216, 'No.8': 304, 'No.9': 264, 'No.10': 264, 'No.11': 224, 'No.12': 216, 'No.13': 288, 'No.14': 216, 'No.15': 216, 'No.16': 248, 'No.17': 240, 'No.18': 256, 'No.19': 208, 'No.20': 224}
~~~~~~~~~~~~~~~~~~~~~



10年後の保有金額


120ヶ月後の保有金額を見てみる。

# 参加人数
n = 20
# 定収入
income = 10
# 定支出
outgo = 8

#3ヶ月後の保有金額
# ターン回数
turns = 3
result_3_4 = main(n,income,outgo,turns)
#print(result_3_4)
print(result_3_4.values())
print("~~~~~~~~~~~~~~~~~~~~~")

# 120ヶ月後の保有金額
turns = 120
result_120_4 = main(n,income,outgo,turns)
#print(result_120_4)
print(result_120_4.values())
print("~~~~~~~~~~~~~~~~~~~~~")
dict_values([46, 22, 38, 14, 6, 22, 38, 38, 46, 30, 6, 30, 62, 22, 38, 30, 22, 30, 30, 30])
~~~~~~~~~~~~~~~~~~~~~
dict_values([1288, 1184, 1280, 936, 1112, 1192, 1344, 1176, 1216, 1232, 1176, 1120, 1160, 1312, 1216, 1128, 1352, 1288, 1112, 1176])
~~~~~~~~~~~~~~~~~~~~~



参加人数を100人にして120ヶ月後の最大値と最小値のみ取り出す

# 参加人数
n = 100
# 定収入
income = 10
# 定支出
outgo = 8

# 120ヶ月後の保有金額
turns = 120
result_120_5 = main(n,income,outgo,turns)
#print(result_120_5)
#print(result_120_5.values())
print("最小値",min(result_120_5.values()))
print("最大値",max(result_120_5.values()))
print("~~~~~~~~~~~~~~~~~~~~~")
最小値 1016
最大値 1392
~~~~~~~~~~~~~~~~~~~~~



おわりに


このプログラムは正しいのか?…