Generando cuadrados mágicos
Jorge Martínez Garrido
February 12, 2022
Se entiende por cuadrado mágico aquella matriz de tamaño $n \times n$ que presenta la propiedad de que sus filas, columnas y diagonales suman lo mismo. Dicha suma se conoce con el nombre de número mágico y se representa por la letra $M$.
Los cuadrados mágicos han sido asociados a temas esotéricos desde que se tiene conocimiento de los mismos y pueden encontrarse en numerosas construcciones, tal y como sucede en la Sagrada Familia:

Método de Simón de Louberre
En este post vamos a presentar un algortimo para generar cuadrados mágicos. Sin embargo, dicho algortimo solo funcionará para cuadrados mágicos impares, es decir, para valores de $n$ tal que $n=3$, $n=5$, $n=7$. De forma general, esto se escribe como $n=2i + 1$, siendo $i$ cualquier número natural.
El algoritmo fue desarrollado por Simón de Louberre, si bien el método ya era conocido por astrónomos orientales1. Las siguientes reglas aplican para generar los cuadrados mágicos de Loouberre:
Comenzando en la casilla central de la primera fila con el primer número, se rellena la diagonal quebrada con los siguientes en sentido NO (o NE). Completada la primera diagonal se desciende una posición y se rellena la segunda en el mismo sentido que la anterior, repitiéndose el paso anterior con el resto de diagonales hasta completar el cuadrado.

Calculando el número mágico
Vamos a crear una función que calcule el nñumero mágico $M$ de un cuadrado mágico. La fórmula es la siguiente:
$$ M = \frac{n(n^2 + 1)}{2} $$
Escrita en forma de una función de Python podemos tener:
def calcular_numero_magico(n):
"""
Calcula el número mágico M de un cuadrado mágino de tamaño nxn.
Parameters
----------
n: int
Tamaño característico del cuadrado mágico.
Returns
-------
M: int
Número mágico.
Notes
-----
Python aplica un type casting, por lo que debemos forzar la conversion de un flotante
a un entero.
"""
M = int(n * (n ** 2 + 1) / 2)
return M
Así pues, para el caso de un cuadrado tal que $n=5$, el número mágico resulta ser de:
M = calcular_numero_magico(n=5)
print(f"El número mágico para n = 5 resulta ser {M = }")
El número mágico para n = 5 resulta ser M = 65
Algoritmo de Louberre
Quizás puede parecer algo complejo el moverse por una matriz; más aún si tenemos que hacerlo siguiendo las reglas de Louberre. Pero utilizando la geometría modular (muy aplicada para evitar los límites de una lista, cadena, matriz…) podemos generar el siguiente código:
def generar_cuadrado_magico(n):
"""
Devuelve un cuadrado mágico de tamaño nxn.
Parameters
----------
n: int
Tamaño caracterísitco del cuadrado mágico.
Returns
-------
cuadrado_magico: list
Cuadrado mágico en forma de listas anidadas (cada lista es una fila).
Notes
-----
Utilizando la librería Numpy podríamos simplificar el algoritmo. No obstante, por el nivel impartido
en clase hemos preferido utilizar aquí Python puro.
"""
# Preparamos el cuadrado con 'n' filas (en forma de lista) vacias
cuadrado_magico = [[0 for _ in range(n)] for _ in range(n)]
# Comenzamos en la primera fila y en la columna central
i, j = 0, n // 2
# El primer número del cuadrado mágico será el x=1
x = 1
# Aplicamos el algoritmo
while x < n ** 2:
# Añadimos el número en la posición que le corresponde
cuadrado_magico[i][j] = x
x += 1
# Calculamos la posición futura
i_nueva, j_nueva = (i - 1) % n, (j + 1) % n
# Comprobamos que no haya ningún número en la nueva casilla
if cuadrado_magico[i_nueva][j_nueva]:
i += 1
else:
i, j = i_nueva, j_nueva
return cuadrado_magico
Siguiendo el ejemplo de $n=5$, podemos encontrar el siguiente cuadrado mágico de Louberre:
cuadrado_magico = generar_cuadrado_magico(n=5)
print(f"Cuadrado magico para n = 5\n{cuadrado_magico}")
Cuadrado magico para n = 5
[[17, 24, 1, 8, 15], [23, 5, 7, 14, 16], [4, 6, 13, 20, 22], [10, 12, 19, 21, 3], [11, 18, 0, 2, 9]]
Pretty print de un cuadrado mágico
Por el término “pretty print” se entiende a mejorar la forma en la que el resultado de un cuadrado mágico se muestra por pantalla. Para ello, vamos a crear una función llamada print_cuadrado_mágico
que imprima en la consola de forma elegante nuestro cuadrado:
def print_cuadrado_magico(cuadrado_magico):
"""
Imprime de forma elegante un cuadrado mágico.
Parameters
----------
cuadrado_magico: list
Listas anidadas representando las filas de un cuadrado mágico.
"""
for fila in cuadrado_magico: print(fila, end="\n")
Aplicando la función anterior conseguimos el siguiente resultado:
print_cuadrado_magico(cuadrado_magico)
[17, 24, 1, 8, 15]
[23, 5, 7, 14, 16]
[4, 6, 13, 20, 22]
[10, 12, 19, 21, 3]
[11, 18, 0, 2, 9]