Pythonの二次元リストでゲームの盤面を作る!行と列の順番と作り方の落とし穴|ゲームで学ぶアルゴリズム 第1回
「ゲームの盤面って、プログラムの中ではどうやって持っているの?」「board[1][4] みたいに [ ] が2つ並ぶと、どっちが縦でどっちが横かわからなくなる…」
そう感じたこと、ありますよね。この記事は、ゲームづくりを題材にアルゴリズムの考え方を1つずつ身につける連載「ゲームで学ぶアルゴリズム」の第1回です。今回は、迷路・パズル・ボードゲームの土台になる二次元リストで盤面を表す方法を取り上げます。
対象は、リストと for 文をひととおり使ったことがある初心者〜初級者の方です。動作確認は Python 3.13 で行いました。一緒に見ていきましょう! 😊
二次元リストとは?「リストを並べたリスト」

二次元リストとは、要素がリストになっているリストのことです。
イメージとしては、方眼紙です。横1列ぶんのマスを1つのリストにして、その行を上から順に並べたものが盤面になります。
board[行]で、1行ぶんのリストが取り出せるboard[行][列]で、1マスの中身が取り出せる- 番号はどちらも 0から数える
サンプル1:小さなダンジョンの盤面を作って動かす
4行×6列のマップを作り、マスを読む・書きかえる・表示する、の3つをやってみます。
# 盤面(4行×6列)を二次元リストで表す
# "#"=壁 "."=床 "P"=プレイヤー "$"=コイン "G"=ゴール
board = [
["#", "#", "#", "#", "#", "#"],
["#", "P", ".", ".", "$", "#"],
["#", ".", "#", ".", "G", "#"],
["#", "#", "#", "#", "#", "#"],
]
print("行の数:", len(board))
print("列の数:", len(board[0]))
print("board[1]:", board[1])
print("board[1][4]:", board[1][4])
# プレイヤーを右に1マス動かす(元の場所は床にもどす)
board[1][1] = "."
board[1][2] = "P"
# 1行ずつ文字をつなげて盤面を表示する
for row in board:
print("".join(row))

実行結果はこうなりました。
行の数: 4
列の数: 6
board[1]: ['#', 'P', '.', '.', '$', '#']
board[1][4]: $
######
#.P.$#
#.#.G#
######
ここが重要です👇
len(board)は行の数(4)、len(board[0])は1行の長さ=列の数(6)ですboard[1][4]は「1行目の、4列目」なので$(コイン)でした。先に行(縦の位置)、あとに列(横の位置)の順です- マスに代入するだけで盤面が変わります。プレイヤーの移動は「元のマスを床にもどす → 新しいマスに P を置く」の2行です
"".join(row)で1行の文字をつなげると、盤面らしく表示できます
⚠️ よくあるのが、行と列を逆に書いてしまうミスです。コインを「横に4、縦に1」と考えて board[4][1] と書くと、行は0〜3までしかないので、実行したところ IndexError: list index out of range で止まりました。盤面が正方形だとエラーにならずに別のマスを読んでしまうので、さらに気づきにくくなります。迷ったら「board[縦][横]」と覚えておきましょう。
サンプル2:空の盤面を作るときの落とし穴
マップを手で書くのは小さいうちだけで、ふつうは「全部床の盤面」をコードで作ります。ここで多くの人がつまずきます。これ、実行せずに答えられますか? bad の0行目だけを変えたとき、盤面はどう表示されるでしょうか。
# まちがい:* で行をふやす
bad = [["."] * 4] * 3
bad[0][1] = "X" # 0行目の1列目だけ変えたつもり
print("--- * で作った盤面 ---")
for row in bad:
print("".join(row))
print("0行目と1行目は同じもの?", bad[0] is bad[1])
# 正しい:行ごとに新しいリストを作る
good = [["."] * 4 for _ in range(3)]
good[0][1] = "X"
print("--- for で作った盤面 ---")
for row in good:
print("".join(row))
print("0行目と1行目は同じもの?", good[0] is good[1])

実行結果はこちらです。
--- * で作った盤面 ---
.X..
.X..
.X..
0行目と1行目は同じもの? True
--- for で作った盤面 ---
.X..
....
....
0行目と1行目は同じもの? False
ポイントをまとめるとこんな感じです👇
[["."] * 4] * 3で作った盤面は、0行目だけ変えたつもりが3行すべてに X が入りましたbad[0] is bad[1]がTrue。つまり、3つの行は同じ1本のリストを3回並べただけだったのです[["."] * 4 for _ in range(3)]と書くと、行ごとに新しいリストが作られるので、変えたマスだけが変わりました
1行の中の ["."] * 4 は問題ありません。行をふやすときだけは for を使う、と覚えておけば大丈夫です。
サンプル3:三目並べの「そろったか」を判定する
盤面を作れたら、次は盤面を調べる処理です。3×3の三目並べで、縦・横・斜めのどれかに同じ記号が3つ並んだかを判定してみます。
def find_winner(board):
"""三目並べの盤面(3×3)から勝者を返す。いなければ None"""
lines = []
for r in range(3):
lines.append(board[r]) # 横の3本
for c in range(3):
lines.append([board[r][c] for r in range(3)]) # 縦の3本
lines.append([board[i][i] for i in range(3)]) # 斜め(左上→右下)
lines.append([board[i][2 - i] for i in range(3)]) # 斜め(右上→左下)
for line in lines:
if line[0] != "." and line.count(line[0]) == 3:
return line[0]
return None
game1 = [
["O", "X", "."],
["X", "O", "."],
["X", ".", "O"],
]
game2 = [
["O", "X", "O"],
["O", "X", "."],
[".", "X", "."],
]
game3 = [
["O", "X", "O"],
[".", "X", "."],
[".", "O", "."],
]
for name, g in [("game1", game1), ("game2", game2), ("game3", game3)]:
print(name, "→", find_winner(g))
game1 → O
game2 → X
game3 → None
ここが重要です👇
- 横の1本は
board[r]をそのまま使えます。縦の1本は、列番号cを固定して行番号rだけ動かして集めます - 斜めは
board[i][i](0,0 → 1,1 → 2,2)とboard[i][2 - i](0,2 → 1,1 → 2,0)です。番号の並びを紙に書くとすぐ納得できます - 8本の「線」を1つのリストに集めてから同じ方法で調べるので、判定の部分は短く書けます。
"."(空きマス)が3つそろった場合を勝ちにしないよう、line[0] != "."を入れています - 実行すると、斜めにそろった game1 は
O、真ん中の縦にそろった game2 はX、どこもそろっていない game3 はNoneになりました
まとめ
- 二次元リストはリストを並べたリスト。方眼紙の1行が1つのリスト
- マスは
board[行][列]=board[縦][横]の順。逆にすると IndexError か、別のマスを読んでしまう - 行数は
len(board)、列数はlen(board[0]) - 空の盤面は
[["."] * 列数 for _ in range(行数)]。* 行数で作ると全行がいっしょに変わる - 縦・横・斜めの「線」を集めれば、そろったかの判定も同じ書き方でできる
次回の第2回は、画面上の x・y 座標とリストの番号を行き来する方法を取り上げます。「むずかしそう」を「できそう」に変えていきましょう。サンプル1のマップに壁やコインを足して、プレイヤーを好きなマスへ動かしてみてください。ぜひ試してみてください! 🚀
\ Pythonでゲームを作りたい方へ /
筆者は、入門を終えた人向けに、画面の中でキャラクターが動き、キーボードで操作するゲームを7本作る講座を公開しています。最短の手数を自動で探すパズルや、歩数の地図を見て追いかけてくるねこを、自分の手で書きながら「答えにたどり着く手順の考え方(アルゴリズム)」を身につけます。完成版の7本は、パソコンのブラウザでそのまま遊べます。
→ 作って学ぶPythonゲームプログラミング(完成した7本を遊んでみる)
基礎の文法に不安がある方は、先に無料の入門コース「作って学ぶPythonプログラミング入門」(全7章52レッスン)からどうぞ。
→ 無料の入門コースを見る
こちらも読まれています
📚 関連商品・おすすめ書籍
※本記事にはアフィリエイトリンクが含まれます。




