はじめに
こんにちは。Yuinaです。
今日はこちらの問題の疑似言語を参考にPythonで魔法陣を作成します。
魔法陣の説明につきましては、こちらのサイトで詳しく解説されていました。大変わかりやすかったので掲載しておきます。
それでは、よろしくお願いいたします。
コード
from collections import deque
# --- データの定義 ---
SOTO_MIGI = -1
SOTO_SHITA = -2
SOTO_KADO = -3
def shokika(N):
houjin = [[0] * (N + 2) for _ in range(N + 2)]
for y in range(1, N + 1):
for x in range(1, N + 1):
houjin[y][x] = 0
for y in range(1, N + 1):
houjin[y][N + 1] = SOTO_MIGI
for x in range(1, N + 1):
houjin[N + 1][x] = SOTO_SHITA
houjin[N + 1][N + 1] = SOTO_KADO
return houjin
def mahoujin(N):
if N % 2 == 0 or N <= 0:
print("魔法陣は奇数サイズである必要があります。")
return None
y = N
x = N // 2 + 1
houjin = shokika(N)
suuji = 1
houjin[y][x] = suuji
while suuji < N * N:
yb = y
xb = x
y += 1
x += 1
if houjin[y][x] == SOTO_SHITA:
y = 1
elif houjin[y][x] == SOTO_MIGI:
x = 1
elif houjin[y][x] == SOTO_KADO:
y = N - 1
x = 1
elif houjin[y][x] != 0:
y = yb - 1
x = xb
suuji += 1
houjin[y][x] = suuji
return houjin
def print_mahoujin(houjin, N):
if houjin is None:
return
print(f"{N}x{N}の魔法陣:")
for y in range(1, N + 1):
for x in range(1, N + 1):
print(f"{houjin[y][x]:4d}", end=" ")
print()
N_size = 5
magic_square = mahoujin(N_size)
print_mahoujin(magic_square, N_size)
解説
from collections import deque
SOTO_MIGI = -1
SOTO_SHITA = -2
SOTO_KADO = -3
定数の宣言:
SOTO_MIGI
, SOTO_SHITA
, SOTO_KADO
は、魔法陣の境界を表すための定数です。それぞれ右端、下端、右下隅に対応しています。
def shokika(N):
houjin = [[0] * (N + 2) for _ in range(N + 2)]
for y in range(1, N + 1):
for x in range(1, N + 1):
houjin[y][x] = 0
for y in range(1, N + 1):
houjin[y][N + 1] = SOTO_MIGI
for x in range(1, N + 1):
houjin[N + 1][x] = SOTO_SHITA
houjin[N + 1][N + 1] = SOTO_KADO
return houjin
shokikaメソッド:
N x N のサイズの魔法陣を初期化します。
魔法陣の外側に境界を表す定数を配置することで、移動の際の条件分岐をシンプルにしています。
[0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, -2, -2, -2, -2, -2, -3]
5×5の魔法陣をshokikaメソッドで初期化した状態↑
def mahoujin(N): if N % 2 == 0 or N <= 0: print("魔法陣は奇数サイズである必要があります。") return None y = N x = N // 2 + 1 houjin = shokika(N) suuji = 1 houjin[y][x] = suuji # 境界に達した場合や既に数字が入っている場合 while suuji < N * N: yb = y xb = x y += 1 x += 1 # 計算した次の位置 (y, x) が下側の境界 (SOTO_SHITA、値は -2) であるかをチェックします。 if houjin[y][x] == SOTO_SHITA: y = 1 # もしそうなら、行を一番上 (y = 1) に移動します。 # 下側の境界でなかった場合、次に右側の境界 (SOTO_MIGI、値は -1) であるかをチェックします。 elif houjin[y][x] == SOTO_MIGI: x = 1 #もしそうなら、列を一番左 (x = 1) に移動します。 # 右側の境界でもなかった場合、次に右下隅の境界 (SOTO_KADO、値は -3) であるかをチェックします。 elif houjin[y][x] == SOTO_KADO: # もしそうなら、現在の位置の2つ上の行かつ一番左の列 (y = N - 1, x = 1) に移動します。 y = N - 1 x = 1 elif houjin[y][x] != 0: y = yb - 1 x = xb suuji += 1 houjin[y][x] = suuji return houjin
mahoujin
メソッド:
魔法陣を生成するメインの関数です。N
が奇数でない場合はエラーメッセージを表示します。中央のマスから開始し、数字を 1 から順に配置していきます。数字を配置する次のマスは、現在のマスの右上ですが、境界に達した場合や既に数字が入っている場合は、特定のルールに従って移動先を決定します。
5×5の魔法陣をmahoujinメソッドのループを1度だけ実行した状態:
[0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 2, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 1, 0, 0, -1]
[0, -2, -2, -2, -2, -2, -3]
5×5の魔法陣をmahoujinメソッドのループを2度だけ実行した状態:
[0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 2, 0, -1]
[0, 0, 0, 0, 0, 3, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 1, 0, 0, -1]
[0, -2, -2, -2, -2, -2, -3]
5×5の魔法陣をmahoujinメソッドのループを3度だけ実行した状態:
[0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 2, 0, -1]
[0, 0, 0, 0, 0, 3, -1]
[0, 4, 0, 0, 0, 0, -1]
[0, 0, 0, 0, 0, 0, -1]
[0, 0, 0, 1, 0, 0, -1]
[0, -2, -2, -2, -2, -2, -3]
5×5の魔法陣をmahoujinメソッドのループを4度だけ実行した状態:
[0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 2, 0, -1]
[0, 0, 0, 0, 0, 3, -1]
[0, 4, 0, 0, 0, 0, -1]
[0, 0, 5, 0, 0, 0, -1]
[0, 0, 0, 1, 0, 0, -1]
[0, -2, -2, -2, -2, -2, -3]
5×5の魔法陣をmahoujinメソッドのループを5度だけ実行した状態:
[0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 2, 0, -1]
[0, 0, 0, 0, 0, 3, -1]
[0, 4, 6, 0, 0, 0, -1]
[0, 0, 5, 0, 0, 0, -1]
[0, 0, 0, 1, 0, 0, -1]
[0, -2, -2, -2, -2, -2, -3]
def print_mahoujin(houjin, N): if houjin is None: return print(f"{N}x{N}の魔法陣:") for y in range(1, N + 1): for x in range(1, N + 1): print(f"{houjin[y][x]:4d}", end=" ") print()
print_mahoujin
メソッド:
生成された魔法陣を見やすい形式で表示します。
「:4d」はそのフィールドの最小の文字幅を指定しています。配列の縦を揃えるのに便利です。(Python公式ドキュメントより引用)
「end=” “」がないと以下のように改行して表示されてしまうので、必要です。
5x5の魔法陣: 24 0 18 2 9 23 12 0 19 3 ・・・
結果

結果は上のようになりました。
以上です。ありがとうございました✨