Mahir Islam
Mahir Islam

Reputation: 1972

How to convert a magic square into a proper magic square in Python 3?

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

Answers (1)

Paul Hankin
Paul Hankin

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

Related Questions