본문 바로가기
Programming/Python

[Python] 홀수 마방진 만들기 (자동, 공식)

by castberry_ 2021. 5. 13.
반응형

마방진이란

세로 줄, 가로 줄, 대각선의 있는 숫자의 합이 모두 같으며, 자연수가 중복되지 않는다는 조건이 있다. 

마방진(Magic Square)의 방은 사각형, 진은 늘여 놓는 다는 뜻으로 정사각형의 자연수 배열이다.  

 

홀수 마방진

가로의 크기, 세로의 크기가 홀수인 마방진을 뜻한다. 

ex . 3차 마방진

4 9 2
3 5 7
8 1 6

4+3+8 = 15 

9+5+1 = 15 

... 

4+5+6 =15

세로 줄, 가로 줄, 대각선의 있는 숫자의 합이 15로 모두 같다. 

 

홀수 마방진의 공식

홀수 마방진을 채워넣는 것에는 한 가지의 공식이 있으며 이 공식만이 유일한 답은 아니다. (3차 마방진의 풀이는 여러 가지이다.  )

정사각형의 맨 아랫줄 가운데에 숫자 1을 둔다.

이전 숫자 위치에서 오른쪽 아래칸이 비어있으면 다음 숫자를 채운다.

이전 숫자 위치에서 오른쪽 아래칸이 비어있지 않다면, 이전 숫자의 위 칸에 다음 숫자를 채운다.

오른쪽 아래칸이 사각형의 영역 밖이면 다음의 규칙을 따른다.
    - 수평 및 수직으로 이동해서 마지막 칸이 비어 있으면 해당 칸에 다음 숫자를 채운다.
    - 수평 및 수직으로 이동해도 칸이 없는 경우 이전의 숫자 위치 위쪽 칸에 다음 숫자를 채운다.

 

다음의 규칙을 따르면 3차 방정식의 풀이는 다음의 순서와 같다. 

1.

     
     
  1  

 

2.

    2
     
  1  

 

3.

    2
3    
  1  

 

4.

4   2
3    
  1  

 

5.

4   2
3 5  
  1  

 

6.

4   2
3 5  
  1 6

 

7.

4   2
3 5 7
  1 6

 

8.

4   2
3 5 7
8 1 6

 

9.

4 9 2
3 5 7
8 1 6

 

Python 코드 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
def make_ma(size):
    ma = [[0 for j in range(size)] for i in range(size)]
    lastNum = size * size
 
    x = 0 # x가 높을수록 아래
    y = 0 # y가 높을수옥 오른쪽
 
    inputNum = 1
    MAX_INDEX = size - 1 # 마지막 줄의 인덱스
    ma[MAX_INDEX][MAX_INDEX//2= inputNum #맨 아래쪽 가운데
    x,y = MAX_INDEX, MAX_INDEX//2
    inputNum += 1
    #print(ma)
    while True:
        if inputNum > lastNum: #End?
            return ma
 
        if x + 1 > MAX_INDEX and y + 1 > MAX_INDEX: # 맨오른쪽 밑에서 오른쪽아래로 내려간 경우
            ma[x - 1][y] = inputNum
            #print(ma)
            x, y = x - 1, y
            inputNum += 1
        elif x + 1 > MAX_INDEX or y + 1 > MAX_INDEX: # 범위를 넘는가?
            if x + 1 > MAX_INDEX: #x가 넘는가?
                cnt = 0
                for i in range(size):
                    if ma[i][y+1== 0:
                        ma[i][y+1= inputNum
                        #print(ma)
                        inputNum += 1
                        x,y = i, y+1
                        cnt = 1
                        break
                if cnt == 0:#이동해도 칸이 없다면
                    ma[x-1][y] = inputNum
                    #print(ma)
                    x, y = x - 1, y
                    inputNum += 1
 
                cnt = 3
            elif y + 1 > MAX_INDEX:#y가 넘는가?
                for i in range(size):
                    if ma[x+1][i] == 0:
                        ma[x+1][i] = inputNum
                        #print(ma)
                        inputNum += 1
                        x , y = x + 1, i
                        cnt = 1
                        break
                if cnt == 3#이동해도 칸이 없다면
                    ma[x-1][y] = inputNum
                    #print(ma)
                    x , y = x -1 , y
                    inputNum += 1
        else:
            if ma[x+1][y+1== 0#오른쪽 아래칸이 비어있다면
                ma[x + 1][y + 1= inputNum
                #print(ma)
                x, y = x + 1, y + 1
                inputNum += 1
            else:
                ma[x - 1][y] = inputNum
                #print(ma)
                x, y = x - 1,y
                inputNum += 1
 
def print_ma(ma, size):
    for i in range(size):
        for j in range(size):
            print("\t", ma[i][j],sep="", end="")
        print()
 
def test_ma(ma, size):
    test_list = []
    sum = 0
    for i in range(size):
        sum = 0
        for j in range(size):
            sum += ma[i][j]
        test_list.append(sum)
    for i in range(size):
        sum = 0
        for j in range(size):
            sum += ma[j][i]
        test_list.append(sum)
    sum = 0
    for i in range(size):
        sum += ma[i][i]
    test_list.append(sum)
    sum = 0
    for i in range(size):
        sum += ma[i][size - 1 -i]
 
    test_list.append(sum)
    print(test_list)
 
while True:
    size = int(input("홀수 자연수 입력 : "))
    if size % 2 == 0:
        print("홀수를 입력하시오")
    if size % 2 == 1:
        break
 
ma = make_ma(size)
print_ma(ma, size)
test_ma(ma, size)
cs

 

깨져서 보이는 경우 ▼

def make_ma(size):
    ma = [[0 for j in range(size)] for i in range(size)]
    lastNum = size * size
 
    x = 0 # x가 높을수록 아래
    y = 0 # y가 높을수옥 오른쪽
 
    inputNum = 1
    MAX_INDEX = size - 1 # 마지막 줄의 인덱스
    ma[MAX_INDEX][MAX_INDEX//2] = inputNum #맨 아래쪽 가운데
    x,y = MAX_INDEX, MAX_INDEX//2
    inputNum += 1
    #print(ma)
    while True:
        if inputNum > lastNum: #End?
            return ma
 
        if x + 1 > MAX_INDEX and y + 1 > MAX_INDEX: # 맨오른쪽 밑에서 오른쪽아래로 내려간 경우
            ma[x - 1][y] = inputNum
            #print(ma)
            x, y = x - 1, y
            inputNum += 1
        elif x + 1 > MAX_INDEX or y + 1 > MAX_INDEX: # 범위를 넘는가?
            if x + 1 > MAX_INDEX: #x가 넘는가?
                cnt = 0
                for i in range(size):
                    if ma[i][y+1] == 0:
                        ma[i][y+1] = inputNum
                        #print(ma)
                        inputNum += 1
                        x,y = i, y+1
                        cnt = 1
                        break
                if cnt == 0:#이동해도 칸이 없다면
                    ma[x-1][y] = inputNum
                    #print(ma)
                    x, y = x - 1, y
                    inputNum += 1
 
                cnt = 3
            elif y + 1 > MAX_INDEX:#y가 넘는가?
                for i in range(size):
                    if ma[x+1][i] == 0:
                        ma[x+1][i] = inputNum
                        #print(ma)
                        inputNum += 1
                        x , y = x + 1, i
                        cnt = 1
                        break
                if cnt == 3: #이동해도 칸이 없다면
                    ma[x-1][y] = inputNum
                    #print(ma)
                    x , y = x -1 , y
                    inputNum += 1
        else:
            if ma[x+1][y+1] == 0: #오른쪽 아래칸이 비어있다면
                ma[x + 1][y + 1] = inputNum
                #print(ma)
                x, y = x + 1, y + 1
                inputNum += 1
            else:
                ma[x - 1][y] = inputNum
                #print(ma)
                x, y = x - 1,y
                inputNum += 1
 
def print_ma(ma, size):
    for i in range(size):
        for j in range(size):
            print("\t", ma[i][j],sep="", end="")
        print()
 
def test_ma(ma, size):
    test_list = []
    sum = 0
    for i in range(size):
        sum = 0
        for j in range(size):
            sum += ma[i][j]
        test_list.append(sum)
    for i in range(size):
        sum = 0
        for j in range(size):
            sum += ma[j][i]
        test_list.append(sum)
    sum = 0
    for i in range(size):
        sum += ma[i][i]
    test_list.append(sum)
    sum = 0
    for i in range(size):
        sum += ma[i][size - 1 -i]
 
    test_list.append(sum)
    print(test_list)
 
while True:
    size = int(input("홀수 자연수 입력 : "))
    if size % 2 == 0:
        print("홀수를 입력하시오")
    if size % 2 == 1:
        break
 
ma = make_ma(size)
print_ma(ma, size)
test_ma(ma, size)

 

make_ma 함수는 ma라는 마방진 2차원 배열을 만들며 

print_ma에서 마방진을 출력한다. 

다음 tast_ma에서 마방진의 가로 세로 합 (n차 마방진이라면 n * 2 + 2개)를 배열로 만들어 검증한다. 

이 알고리즘으로 31차 마방진을 만들 수도 있다. 


파이썬 마방진 만들기/ 홀수 마방진 만들기/ 


 

반응형

댓글