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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

370閲覧

シミュレートでリストにエラーが発生してしまう

eg88

総合スコア29

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/06/15 10:16

編集2020/11/14 13:52

前提・実現したいこと

シミュレーションするプログラミングを作成しています。しかし、リストのインデックスについてエラーが発生してしまいます。どう改善すれば良いでしょうか。

<方針>
・地面をN×Nのマス目とし、2次元配列tree[x][y]で表す。木があるところを1,無いところを0とし、一定確率P で生えている。
・火災を表現するために燃えている木を2,燃え尽きた木を3とする。
tree[x][y]=2 :(x,y)が燃えている

<ルール>
・(x,y)が2のとき、次のステップで3となる。
・(x,y)が1のとき、上下左右四つの隣接点のいずれかが2であれば、次のステップで(x,y)は2になる。
・上の条件に当てはまらない場合、状態は変化しない。

  tree[x][y]の初期値は0か1とし、第1ステップでどこか一カ所の木を2の状態にする(火災発生)。そして、完全に鎮火するまでステップを更新していく。
最終的に燃えてしまう(状態3になる)土地の面積は全体の割になるか求める。

長くなりましたが、よろしくお願いします。

発生している問題・エラーメッセージ

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-1-228afae0222f> in <module> 30 for y in tree[1:-1]: 31 for x in y[1:-1]: ---> 32 if tree[x][y] == green and (tree[x+1][y]==burn or tree[x-1][y]==burn or tree[x][y+1]==burn or tree[x][y-1]==burn): 33 temp[x][y] = tree[x][y] + 1 34 TypeError: list indices must be integers or slices, not list

該当のソースコード

python

1import random 2import numpy as np 3 4 5N=4 6P=0.8 7 8 #要素が確率P で1、1-P で0になるN*Nの二次元リストを作成 9tree= [random.choices([0, 1], weights=[1-P, P], k=N) for y in range(N)] 10 11 #どれか一つの要素1を2にする 12while True: 13 idx_y = random.randrange(len(tree)) 14 idx_x = random.randrange(len(tree[0])) 15 if tree[idx_x][idx_y] == 1: 16 tree[idx_x][idx_y] = 2 17 break 18 else: 19 continue 20 21 22empty = 0 23green = 1 24burn = 2 25end = 3 26 #外枠を除いた内側、 二次元リストの端、端を除いた外枠の辺で場合分け 27 #リストの要素に2がなくなるまで続けたい 28while True: 29 # 1<= x <=N-2, かつ 1<= y <=N-2 の範囲 :内側 30 for y in tree[1:-1]: 31 for x in y[1:-1]: 32 if tree[x][y] == green and (tree[x+1][y]==burn or tree[x-1][y]==burn or tree[x][y+1]==burn or tree[x][y-1]==burn): 33 temp[x][y] = tree[x][y] + 1 34 35 36         #端 37 if tree[0][0] == green and ( tree[x+1][y]==burn or tree[x][y+1]==burn ): 38 tre[0][0] += 1 39 40 if tree[N-1][0] == green and ( tree[x-1][y]==burn or tree[x][y+1]==burn ): 41 tree[N-1][0] += 1 42 43 if tree[0][N-1] == green and ( tree[x+1][y]==burn or tree[x][y-1]==burn ): 44 tree[0][N-1] += 1 45 46 if tree[N-1][N-1] == green and ( tree[x-1][y]==burn or tree[x][y-1]==burn ): 47 tree[N-1][N-1] += 1 48 49 50            #端以外の外辺 51 for x in y[1:-1]: 52 if tree[x][0] == green and (tree[x+1][y]==burn or tree[x-1][y]==burn or tree[x][y+1]==burn ):   53 temp[x][0] = tree[x][0] + 1 54 55 if tree[x][N-1] == green and (tree[x+1][y]==burn or tree[x-1][y]==burn or tree[x][y-1]==burn ): 56 temp[x][N-1] = tree[x][N-1] + 1 57 58 for y in tree[1:-1]: 59 if tree[0][y] == green and (tree[x+1][y]==burn or tree[x][y+1]==burn or tree[x][y-1]==burn ): 60 temp[0][y] = tree[0][y] + 1 61 62 if tree[N-1][y] == green and (tree[x-1][y]==burn or tree[x][y+1]==burn or tree[x][y-1]==burn ): 63 temp[N-1][y] = tree[N-1][y] + 1 64 65                #鎮火する 66 for y in N: 67 for x in y: 68 if tree[x][y] == 2: 69 temp[x][y] = end 70 71 for y in tree: 72 for x in y: 73 tree[x][y] = temp[x][y] 74 break 75 76A = tree.count(3)/N*N 77print(A)

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/06/15 10:54

うまく動かないとはどうなるんでしょうか。そこらへんの詳細な説明を、質問編集して追記しましょう
eg88

2019/06/15 11:54

失礼しました。編集します。
guest

回答2

0

ベストアンサー

numpy を import しているのであれば、numpy の機能を使って全部実装してみてはどうでしょうか。

サンプルコード

python

1import numpy as np 2 3np.random.seed(42) # 乱数のシードを固定する。 4 5 6# 状態 7GROUND = 0 # 地面 8TREE = 1 # 木 9BURNING = 2 # 燃えている木 10BURNED = 3 # 燃え尽きた木 11 12# パラメータ 13size = 10, 10 # 地面の大きさ 14prob = 0.7 # 地面に木が生えてる確率 15 16# (1) マップを生成する。 17field = np.random.choice([GROUND, TREE], size, p=[1 - prob, prob]) 18 19# (2) マップの一箇所をランダムに選択し、2とする。 20rows = np.arange(size[0]) # 行方向のインデックス一覧 21cols = np.arange(size[1]) # 列方向のインデックス一覧 22field[np.random.choice(rows), np.random.choice(cols)] = BURNING 23 24history = [field] # 履歴 25 26while True: 27 # (3) 各反復の処理 28 new_field = field.copy() 29 30 # (3.1) 現在の状態が BURNING のセルは、BURNED にする。 31 new_field[field == BURNING] = BURNED 32 33 # (3.2) 「現在の状態が TREE」かつ「上下左右のいずれかのセルが BURNING」のセルは、 34 # BURNING にする。 35 bottom = np.take(field, rows - 1, axis=0, mode="clip") 36 top = np.take(field, rows + 1, axis=0, mode="clip") 37 left = np.take(field, cols - 1, axis=1, mode="clip") 38 right = np.take(field, cols + 1, axis=1, mode="clip") 39 40 indices_to_burn = (field == TREE) & ( 41 (bottom == BURNING) | (top == BURNING) | (left == BURNING) | (right == BURNING) 42 ) 43 new_field[indices_to_burn] = BURNING 44 45 # マップを更新する。 46 field = new_field 47 history.append(field) 48 49 # (4) 燃えている木がない場合は終了する。 50 if np.all(field != BURNING): 51 break 52 53# (5) 最終的に燃えてしまう土地の面積は全体の何割かを求める。 54burned_ratio = np.count_nonzero(field == BURNED) / field.size 55print(f"{burned_ratio:.2%}") # 55.00%

解説

    1. マップを生成する。

マップのうち、木である確率が prob だとすると、

形状が size の2次元配列を値 GROUND が確率 1 - prob、値 TREE が確率 prob で生成する。

np.random.choice([GROUND, TREE], size, p=[1 - prob, prob])

numpy.random.choice — NumPy v1.16 Manual

    1. マップの一箇所をランダムに選択し、2とする。

np.random.choice() で行、列をランダムに選択して、そのセルを BURNING にする。

    1. 以下の処理を繰り返す。
  • 3.1. 現在の状態が BURNING のセルは、BURNED にする。

numpy の boolean indexing を利用する。

new_field[field == BURNING] = BURNED

Indexing — NumPy v1.13 Manual

  • 3.2. 「現在の状態が TREE」かつ「上下左右のいずれかのセルが BURNING」のセルは、BURNING にする。

numpy.take() を利用して、隣接するセルの状態を取得する。
mode="clip" を指定することで、端のセルで隣接するセルが存在しない場合も対応できる。

numpy.take — NumPy v1.16 Manual

    1. 燃えている木がない場合は終了する。
if np.all(field != BURNING): break
    1. 最終的に燃えてしまう土地の面積は全体の何割かを求める。

field == BURNED が True となる要素の数を numpy.count_nonzero() で数えて、全体の要素数 field.size で割る。

burned_ratio = np.count_nonzero(field == BURNED) / field.size

numpy.count_nonzero — NumPy v1.16 Manual

可視化用コード

python

1import matplotlib.pyplot as plt 2from matplotlib.animation import FuncAnimation 3from matplotlib import colors 4 5# カラーマップを作成する。 6cmap = colors.ListedColormap(["gray", "green", "red", "black"]) 7norm = colors.BoundaryNorm(np.arange(5), cmap.N) 8 9fig = plt.figure() 10 11 12def plot(i): 13 plt.cla() 14 plt.imshow(history[i], cmap=cmap, norm=norm) 15 plt.title(f"step={i}") 16 17 18# アニメーションを作成する。 19anim = FuncAnimation(fig, plot, frames=len(history), interval=1000, repeat=True) 20 21# gif 画像として保存する。 22anim.save("animation.gif", writer="pillow")

イメージ説明

投稿2019/06/17 03:55

tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

eg88

2019/06/19 01:08

返信が遅くなり申し訳ありません。なんとか自己解決する見込みがついたので、まずは自力でやってみようと思います。その後はもちろんtiitoi様のコードも参考にさせていただきます。特に可視化用のコードはコード結果がとても分かりやすくて便利ですね。ご丁寧にありがとうございます。
guest

0

ソースコードに全角空白が含まれています。削除することでSyntax Errorは解消されます。
ただしソースには複数の論理的な問題点が含まれているようですので、全体の処理を見直す必要があると思われます。

投稿2019/06/15 10:34

can110

総合スコア38234

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

eg88

2019/06/15 10:57

分かりました。修正してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問