Reputation: 1972
I have magic square like this. The digits in the magic square 3x3 can only be from 1-9:
magic_square = [[5,3,4],
[1,5,8],
[6,4,2]]
I want to convert it to a proper 3x3 magic square with all rows, columns and diagonals equal to the sum 15, with the most minimal changes possible.
I have tried with permutations but I can't figure out a way to do it.
Upvotes: 3
Views: 1829
Reputation: 58211
It's not clear from the question what a "change" is, but this code assumes that it means replacing the value in one array location with a different value. An alternative meaning would be the number of swaps needed (which would need a little more code).
This code does the obvious thing: it generates all magic squares (of which there is only one up to reflections and rotations) and measures the distance to each, finding the smallest one.
import itertools
def ms():
rows = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
for p in itertools.permutations(range(1, 10)):
if all(sum(p[i] for i in r) == 15 for r in rows):
yield list(p)
def closest_ms(m):
m = sum(m, [])
return min(ms(), key=(lambda x: sum(i!=j for i, j in zip(m, x))))
magic_square = [[5,3,4],
[1,5,8],
[6,4,2]]
print(closest_ms(magic_square))
The code returns the magic square with 6 elements in common with the original:
8 3 4
1 5 9
6 7 2
Upvotes: 3