Good day.
In this article, I will describe a method for obtaining normal magic squares of order n m , where n and m are positive natural numbers, provided that we know the normal magic square of order n
, , , "".
, , , , :
1 n2, n - , , , , .
, .
, .
, ( ). , , , - 66.
, , "".
, .
, , , : , , , /.
, , : "" , ( ), , , . , , L , , L, , .
(n=3 n=4), , . , . , , , , 55, 66, 77 99.
, , , 66. , , , 66 . , :)
99, , : - , " ", .
, : , , , . , , , , . , , , , .
, , , , , . , , . 33, , "". , : , 99, 9 , , . , ?
- , . , , !
2727, , 729 1 729, . , , , , , , ( -) ... . , , ?
NumPy + PyGame = Profit!
, , . Python 3.9 opensource- Numpy PyGame.
import numpy as np
import pygame as pg
# SortedList uses binary search instead full-list comparison cycle.
import sortedcontainers as scs
- , mx,y == x + y * n + 1, n - . -:
def create_matrix(n: int):
return np.arange(1, n ** 2 + 1).reshape(n, n)
3x3 4x4, :
m_3 = [[[1, 0], [0, 0], [1, 2], [2, 2]], [[2, 0], [2, 1], [0, 2], [0, 1]]]
m_4 = [[[0, 0], [2, 2]], [[1, 0], [0, 1]],
[[2, 0], [3, 1]], [[3, 0], [1, 2]],
[[0, 2], [1, 3]], [[1, 1], [3, 3]],
[[2, 1], [0, 3]], [[3, 2], [2, 3]]]
, NumPy , , :
# _m - input matrix, _x - base row length
def m_split(_m, _x):
return [np.vsplit(x, _x) for x in np.hsplit(_m, _x)]
# _m - input "previous splitted" matrix, _x - base row length
def m_join(_m, _x):
return np.vstack([np.hstack(np.vstack(_m)[x::_x]) for x in range(_x)])
, , :
# _m - input "previous splitted" matrix, idxs - indices of matrix cells.
def m_rot(_m, idxs):
# [-----X----][-----Y----]
a0 = _m[idxs[0][0]][idxs[0][1]]
for i in range(len(idxs) - 1):
_m[idxs[i][0]][idxs[i][1]] = _m[idxs[i + 1][0]][idxs[i + 1][1]]
_m[idxs[-1][0]][idxs[-1][1]] = a0
return _m
#_m - input "previous splitted" matrix, _steps - pattern of digits swaps (m_3, m_r, ...)...
def magic_steps(_m, _steps):
m0 = _m
for step in _steps:
m0 = m_rot(m0, step)
return m0
, , npow:
# _mss - magic steps (m_3, m_4, or ...)
def pow_square(_root, _pow, _mss):
m_dmag = lambda x, d: m_join(magic_steps(m_split(x, d), _mss), d)
_p = _root ** _pow
m0 = m_dmag(create_matrix(_p), _root)
for i in range(1, _pow):
m0 = m_join([[m_dmag(x, _root) for x in y] for y in m_split(m0, _root ** i)], _root ** i)
return m0
, , PyGame, turtle, :
# New to_star function computes and draw all lines from matrix on fly.
def to_star(_m):
dim = len(_m)
used = scs.SortedList()
max_sz = 980
tp = 10 # brush transparency.
sz = float(max_sz / dim)
j_to_xy = lambda _j, _d: [(_j - 1) % _d, int((_j - 1) / _d)]
# [matrix position] -> (drawing field point)
c_to_pg = lambda _xy: (float(_xy[1] * sz + 10), float(_xy[0] * sz + 10))
# pygame prepare:
pg.init()
pg.fastevent.init()
d_sz = (max_sz + 20, max_sz + 20)
_sc = pg.display.set_mode(d_sz)
_sc.fill((255, 255, 255))
pg.display.flip()
c = pg.time.Clock()
# start compute & draw
for _y in range(dim):
for events in pg.fastevent.get():
if events.type == pg.QUIT:
pg.quit()
return
sc = _sc.convert_alpha()
sc.fill([0, 0, 0, 0])
for _x in range(1, dim + 1):
j = _x + _y * dim
x, y = j_to_xy(j, dim)
if _m[y][x] == j or _m[y][x] in used:
continue
a = _m[y][x]
x, y = j_to_xy(a, dim)
b = _m[y][x]
used += [a]
pg.draw.line(sc, (0, 0, 0, tp), c_to_pg([x, y]), c_to_pg(j_to_xy(b, dim)))
_sc.blit(sc, (0, 0))
pg.display.update()
sc = _sc.convert_alpha()
sc.fill([0, 0, 0, 0])
for j in range(1, dim * dim + 1):
x, y = j_to_xy(j, dim)
if _m[y][x] == j:
# static point transparency is 50% higher than lines transparency.
pg.draw.circle(sc, (255, 255, 255, (tp + 50) % 100), c_to_pg([x, y]), 1.5)
_sc.blit(sc, (0, 0))
pg.display.update()
while True:
c.tick(60)
for events in pg.event.get():
if events.type == pg.QUIT:
pg.quit()
return
pg.display.update()
- main
, , :
if __name__ == '__main__':
pow = 3
root = 4
m1 = pow_square(root, pow, m_4)
try:
to_star(m1)
except pygame.error:
print('Drawing finished.')
print(m1)
# Compute sums of all digits in rows, columns and diagonals.
m2 = np.rot90(m1)
print([sum(x) for x in m1])
print([sum(x) for x in m2])
print(sum([m1[x, x] for x in range(root ** pow)]))
print(sum([m2[x, x] for x in range(root ** pow)]))
, . - 33, 44, 55, , , . 3n, 4n 5n , (, - )!
: > 1000. . .
PS Most likely, the code presented in the article has a huge number of optimization points, and, probably, the matrix should be processed multithreaded, but since this code has practically no other field of application, except for demonstrating the method for generating magic squares, it is left as it is. Apologies in advance for some lack of aesthetics in the code ...
UPD1. Field tests have shown that the method is applicable only to associative magic squares. The check was carried out only on normal magic squares. The code in this article has been updated for optimization purposes. Magic squares 2048x2048 and 2401x2401 were successfully formed.