質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

Pythonで2個のサイコロの合計をグラフにする方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,253

score 7

#マークに従いながら、2個のサイコロを100回振って、各合計の(0〜12)回数をカウントして、グラフにしようとしています。
どのようなコードが適切か教えていただけると助かります!

  • 問題点
    現在このコードは動きます、しかしながら結果が出力されると0〜99までの数字が順番にでるため、全くランダムではありません。「最後にroll_diceとupdate_listの両方を呼び出すforループを作成して、サイコロを振り、その振りの結果に基づいてリストを更新しないといけないです。 ループはサイコロを振る回数を繰り返す必要があります。」このような説明があるのですが、どうやるのかがまったくわかりません。
import random

roll_list = []
                #holds the number of times each number was rolled
                # has 13 spots (0 - 12).  roll_list[1] is how many times
                # a 1 was rolled.
num_rolls = 100 # number of times to roll the dice


# initialize the roll_list[] so it has the correct number of spots
def init_list():
  for x in range(0,13):
    roll_list.append(x)

# use a for loop and list.append( x ) to fill the roll_list with 13 zeros

# returns the sum of the two dice that were rolled
def roll_dice():
  dice1 = random.randint(1, 6)
  dice2 = random.randint(1, 6)
  twodice = dice1 + dice2
  return roll_dice()
    # roll 2 standard die and return the sum (should be from 2 to 12)
    # random.randint() will be helpful here
    # change this line so it returns the correct sum

def update_list():
  if twodice == 0:
    roll_list[0] += 1
  elif twodice == 1:
    roll_list[1] += 1
  elif twodice == 2:
    roll_list[2] += 1
  elif twodice == 3:
    roll_list[3] += 1
  elif twodice == 4:
    roll_list[4] += 1
  elif twodice == 5:
    roll_list[5] += 1
  elif twodice == 6:
    roll_list[6] += 1
  elif twodice == 7:
    roll_list[7] += 1
  elif twodice == 8:
    roll_list[8] += 1
  elif twodice == 9:
    roll_list[9] += 1
  elif twodice == 10:
    roll_list[10] += 1  
  elif twodice == 11:
    roll_list[11] += 1
  elif twodice == 12:
    roll_list[12] += 1
  return update_list()
    # add 1 to the list location associated with the total roll value
    # example: if the total of the roll is 7, then add 1 to roll_list[7]

def print_histogram():
  maxBar = str(13)
  for z in roll_list:
    p = str(z)
    if p <= maxBar:
      p += '*'
  return print_histogram()
    # for 100% create and print a histogram of the results of all 
    # of the dice rolls
for roll_dice in range(num_rolls):
  print(roll_dice)

for update_list in range(num_rolls):
  print(update_list)

サンプルのアウトプットです。

Sample Output:
[0, 0, 4, 2, 7, 12, 12, 22, 12, 13, 9, 3, 4]
 0: 
 1: 
 2: ****
 3: **
 4: *******
 5: ************
 6: ************
 7: **********************
 8: ************
 9: *************
10: *********
11: ***
12: ****
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • teamikl

    2020/05/10 14:30

    どのようにコードを動かされてますか?
    見た感じ、どの関数も再帰呼び出しになっていて、呼び出してみても

    >現在このコードは動きます、しかしながら結果が出力されると0〜99までの数字が順番にでるため、

    は確認できません。

    print文自体がないので、どのように確認されてるのでしょう。
    もし、手元のコードと違うもしくは追加でコードがある場合、
    質問文のコードの編集で提示お願いします。

    キャンセル

  • Spursfun2002

    2020/05/10 14:33

    すいません
    重要なところが抜けていましたね。
    すぐに修正いたしました。

    キャンセル

  • teamikl

    2020/05/10 14:37

    インデントが崩れているので、出来れば最初のコードと同じ個所に編集をお願いします。
    (コードにはクリップボードにコピーボタンがあるので、他の方が試しやすくなります)

    問題の現象は確認出来ました。回答欄に書きますね

    キャンセル

  • Spursfun2002

    2020/05/10 14:39

    すいません
    すぐ修正します。

    キャンセル

回答 3

checkベストアンサー

+1

問題の原因1 (追記されたコードより)

num_rolls = 100

for roll_dice in range(num_rolls):
    print(roll_dice)

for update_list in range(num_rolls):
    print(update_list)

関数定義で "roll_dice", "update_list" があるので、
関数を呼び出したいという意図は感じられますが、
ここで実際に起こっているのは以下のコードと同じです。

for num in range(100):
    print(num)


for ... in の所は変数名で、range(100)から取り出された値が入ります。

解決策: ※ 100回繰り返しは init_list() の中でやりたいことと想定して回答します

import random

num_rolls = 100
roll_list = [0] * 13  # update_list関数の為に0..12迄のリスト(長さ13)を準備

def update_list(twodice): # <== 引数: 値を受け取る
    # 合計値の出現数をカウント
    roll_list[twodice] += 1

def roll_dice():
    dice1 = random.randint(1, 6)
    dice2 = random.randint(1, 6)
    twodice = dice1 + dice2
    return twodice # <== 戻り値: 計算結果を返す

def init_list():
    for _ in range(num_rolls): # num_rolls回繰り返し
        twodice = roll_dice()  # ダイスを振る
        update_list(twodice)   # 集計

def print_histgram():
    for num in range(len(roll_list)):
        count = roll_list[num]
        print("{:2} {}".format(num, "*" * count))  # グラフ出力

if __name__ == "__main__":
    init_list()
    print_histgram()

他の問題: roll_dice, update_list, print_histogram 関数もそれぞれ問題があります。
まだ、現状では関数の呼び出し自体がうまく行ってないことから、
問題点を把握されていないと思います。

def roll_dice():
   ... # 省略
    return roll_dice()

注意深くコードをみると、update_list(), print_histogram() も同じように
最後の return で自分自身を呼び出しています。
この様なコードを「再帰呼び出し」と言って、有用な場合もあるのですが
この場合は、永遠と同じ関数を呼び出し続けて最後にはエラーになります。

まずは、基本的な関数の使い方を調べて見て下さい。

  • 関数へ値を渡す方法 (引数)
  • 関数から値を返す方法 (戻り値)

関数の中身の処理自体(ダイスを2つ足し合わせる、出現頻度の集計)は、
(改善の余地はあるものの)期待通りのロジックになっているので大丈夫です。


  • 他の方法: 集計には collections.Counter が使えます。
  • グラフ出力 Pythonではシーケンス型と数値を掛けると、回数分繰り返します
print("#" * 4) # => "####"

roll_list = [0] * 13
print(roll_list) # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

  

参考:
PythonのCounterでリストの各要素の出現個数をカウント

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/10 21:11

    なるほど、もっと勉強します!
    丁寧に問題点と改善を教えていただきありがとうございました。

    キャンセル

+1

回答ではないですが、他人のプログラムを読んでみるのもいい勉強になると思いますので、私ならこう書くという実装例を示しておきます。
なぜこのように書いて動くのか、プログラムをバラバラに分解して動作や言語仕様を確認してみてください。

import random

DICE_NUMBERS = 1, 2, 3, 4, 5, 6

def roll_dice(num):
    return [random.choice(DICE_NUMBERS) for _ in range(num)]

def make_histgram(num_dice, roll_times):
    histgram = [0] * (max(DICE_NUMBERS) * num_dice + 1)
    for _ in range(roll_times):
        histgram[sum(roll_dice(num_dice))] += 1
    return histgram

def print_histgram(histgram):
    width = len(str(len(histgram)))
    for i, times in enumerate(histgram):
        print(f"{i:{width}}:", '*' * times)

def main():
    histgram = make_histgram(num_dice=2, roll_times=100)
    print(histgram)
    print_histgram(histgram)

if __name__ == '__main__':
    main()

Pythonインタープリタでの動作確認例:

>>> import random
>>> DICE_NUMBERS = 1, 2, 3, 4, 5, 6
>>> random.choice(DICE_NUMBERS)
2
>>> random.choice(DICE_NUMBERS)
5
>>> [random.choice(DICE_NUMBERS) for _ in range(2)]
[4, 6]
>>> [random.choice(DICE_NUMBERS) for _ in range(2)]
[5, 1]
>>> sum([5, 1])
6

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

2個のサイコロを100回振って、各合計の(0〜12)回数をカウント

2個のダイスの目は独立して発生するものなので。ダイスAを100回、ダイスBを100回を独立に振って、回目ごとに合計値を数をカウントすることと同じことです。
よって以下のコードで出目とその出現数を計算することができます。

# ダイスAおよびBの出目をランダムに100個リスト化
Dice_A = np.random.choice([1,2,3,4,5,6],p=[1/6,1/6,1/6,1/6,1/6,1/6],size=100,replace=True)
Dice_B = np.random.choice([1,2,3,4,5,6],p=[1/6,1/6,1/6,1/6,1/6,1/6],size=100,replace=True)

# 出目を合計する。(ダイスAのN回目の出目とダイスBのN回目の出目を合計する)
Total = Dice_A + Dice_B

# 合計値単位に出現回数をカウントする。(Val:出目 Cnt:出目ごとの出現回数) 
Val , Cnt = np.unique(Total,return_counts=True)

説明文通りに実装しなさいということであれば無視してください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る