Created
November 28, 2018 07:17
-
-
Save grantfree035/2d623a06646dd3fb1961add0b74a7983 to your computer and use it in GitHub Desktop.
Magic Matrix in Python 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
magic square is a n x n matrix of distinct positive integers from 1 to n^2. | |
where the sum of any row, column, or diagonal of length n is always equal to | |
the same number: the magic constant. | |
The magic square has been well studied in history, so the magic constant can | |
be calculated: Magic Constant (M) = n * ((n^2 + 1) / 2). | |
In this problem n will be 3, which means we now know the magic constant: | |
n = 3 | |
M = 15 | |
Knowing that every sum is 15 we can come up with a configuration. | |
Since the center affects all sums, we know it must be 5 and the opposing edges | |
will add to 10, summing to 15. Here is an initial configuration: | |
5 5 5 x 1 x 8 1 6 | |
5 5 5 => 3 5 7 => 3 5 7 | |
5 5 5 x 9 x 4 9 2 | |
All configurations are really the same order just flipped in some way. | |
Using reflections here are all of the possible configurations: | |
| 8 3 4 | 4 3 8 | | |
| 1 5 9 | 9 5 1 | | |
| 6 7 2 | 2 7 6 | | |
-------|-------|-------|------- | |
8 1 6 | | | 6 1 8 | |
3 5 7 | | | 7 5 3 | |
4 9 2 | | | 2 9 4 | |
-------|-------|-------|------- | |
4 9 2 | | | 2 9 4 | |
3 5 7 | | | 7 5 3 | |
8 1 6 | | | 6 1 8 | |
-------|-------|-------|------- | |
| 6 7 2 | 2 7 6 | | |
| 1 5 9 | 9 5 1 | | |
| 8 3 4 | 4 3 8 | | |
Problem: | |
You will be given a 3x3 matrix S of integers in the inclusive range [1,9]. | |
We can convert any digit A to any other digit B in the range [1,9] at cost | |
of |A - B|. Given S, convert it into a magic square at minimal cost. Print | |
this cost on a new line. | |
Note: The resulting magic square must contain DISTINCT integers in the | |
inclusive range [1,9]. | |
Solution: | |
It would take too much time to create an algorithm that would tweak the | |
numbers until it found an optimal solution of minimal cost. Instead, since | |
there are only 8 configurations, we are going to use a LOOKUP TABLE! fast | |
and efficient. Using the lookup table, we can calculate the cost of | |
converting to each configuration and pick the MINIMAL cost. | |
""" | |
class Magic(object): | |
# All 8 configurations | |
magic_square_lookup = [ | |
[[8, 1, 6], [3, 5, 7], [4, 9, 2]], | |
[[6, 1, 8], [7, 5, 3], [2, 9, 4]], | |
[[4, 9, 2], [3, 5, 7], [8, 1, 6]], | |
[[2, 9, 4], [7, 5, 3], [6, 1, 8]], | |
[[8, 3, 4], [1, 5, 9], [6, 7, 2]], | |
[[4, 3, 8], [9, 5, 1], [2, 7, 6]], | |
[[6, 7, 2], [1, 5, 9], [8, 3, 4]], | |
[[2, 7, 6], [9, 5, 1], [4, 3, 8]], | |
] | |
@classmethod | |
def evaluate(cls, s): | |
""" | |
Evaluate the minimal cost to convert the muggle square into | |
a magic square | |
:param s: The input matrix S | |
:return: Minimal Cost | |
""" | |
# list of each configurations cost | |
costs = [] | |
# iterate through each configuration | |
for m in cls.magic_square_lookup: | |
# cost to convert to this magic square | |
cost = 0 | |
# group the rows of magic & muggle square and iterate | |
for m_row, s_row in zip(m, s): | |
# within grouped rows, group individual elements of | |
# magic & muggle and iterate | |
for m_el, s_el in zip(m_row, s_row): | |
# calculate conversion cost of each element | |
cost += abs(m_el - s_el) | |
# append conversion cost for given configuration | |
costs.append(cost) | |
# return minimal cost | |
return min(costs) | |
if __name__ == '__main__': | |
# Test Magic class | |
# test input | |
inputs = [ | |
[[4, 9, 2], [3, 5, 7], [8, 1, 5]], | |
[[4, 8, 2], [4, 5, 7], [6, 1, 6]], | |
[[5, 3, 4], [1, 5, 8], [6, 4, 2]] | |
] | |
# expected output | |
expected = [1, 4, 7] | |
# test loop and console output | |
for test_case in range(len(expected)): | |
result = Magic.evaluate(inputs[test_case]) | |
str_result = "Passed" if result == expected[test_case] else "Failed" | |
print(f'Test Case #{test_case}: {str_result}') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment