二次元配列を可視化したりマップ上を移動させたりするときに混乱する、とある現象を解説します。
問題
一般に、二次元配列を用いたマップでは座標を(y, x)の順で表現します。
また、y座標が小さい点は上側にあり、大きい点は下側にあります。
そのため下の点は、(y+1, x)になります。
体験
5x5の二次元配列を作ります。
a = [
['b', 'c', 'd', 'e', 'f'],
['g', 'h', 'i', 'j', 'k'],
['l', 'm', 'n', 'o', 'p'],
['q', 'r', 's', 't', 'u'],
['v', 'w', 'x', 'y', 'z'],
]
たぶんこんな感じで作ると思います。
では、座標で要素を取り出す関数を考えてみましょう。
def get_a(x, y):
return a[x][y]
直感的にはこうしますよね?
では、以下を実行してみましょう。
get_a(1, 0)
'w'が表示されそうですよね?
ですが、実際は以下が表示されます。
'g'
次に、真ん中の'n'を表示します。
get_a(2, 2)
'n'
下の's'を表示しようとします。
y軸を-1すれば良さそうです。
get_a(2, 1)
'm'
左の'm'が表示されました。
解説
今回の二次元配列は、配列の配列という様になっています。したがって、a[0][0]というのは、最初の配列のうちの最初の要素ということになります。
つまり、y軸というのは何番目の配列かを指しており、x軸というのはその配列の何番目の要素かを指しているのです。
また、y軸に+1するというのは、次の配列にいくということなので、下に進むことになります。
言い換えると、原点が左上にあるということです。

二次元配列によるゲームマップ gemini-3-proにより生成
左上から始まり、右下に進んでいく特徴やn行のn文字目という風に指定する点で、文章と同じです。
よく考えたら、二次元配列を文章(アルファベットや記号の連続)として記述していくので当たり前ですね。
解決策
正直慣れてしまえばどうということはないのですが、解決法として、以下のような関数を用いるというのがあります。
def get_a(x, y):
y = (len(a)-1) - y # yを反転
return a[y][x] # xとyを入れ替え
ですが、いちいちこれを書くのは面倒なので、慣れてしまうことをおすすめします。
気づいたら原点が左上に合っても違和感を感じなくなります。
ですが、自分はいまだに間違ってコードを書いていることがあります。
おまけ
よく、for文のイテレータをiとかjにする人がいますが、2次元配列に対して用いると今回取り上げた現象が大暴れするので、ちゃんとx, yのような分かりやすい変数名を使いましょう。
for i in range(width):
for j in range(height):
a[i][j]
良くないコードです。
ミスを見逃す可能性が増えます。
for x in range(width):
for y in range(height):
a[x][y]
こうしましょう。
ミスがはっきりしましたね。
for y in range(height):
for x in range(width):
a[y][x]
ミスを直すことができました。
