본문 바로가기
파이썬/파이썬 백준

백준 1307:마방진 코드수정

by soypablo 2022. 6. 19.

마방진 에서 데코레이터 부분 및 타입 어노테이션, 독스트링등을 작성하였다.

map에 들어가는 함수에 parameter가 두개가 필요한데, 하나만 쓰는 방법만 알고 여러개를 사용하는 방법을 몰라서 새로 공부해서 적용해 보았다.

functools.partial에서 d를 고정으로 적용하였더니 작동했다.

def iterize(function):
    def wrapper(x, d):
        if isinstance(x, list):
            return list(map(functools.partial(wrapper, d=d), x))
        else:
            return function(x, d)
    return wrapper


@iterize
def magic_plus(x, d):
    return x + ((N // 2) ** 2) * d

 

import functools


def make_odd_magic_square(n: int) -> list[list]:
    """Magic Square Algorithm for a odd Number"""
    # n^2크기 배열 생성
    arr = [[0 for _ in range(n)] for _ in range(n)]
    # 초기 인덱스 첫번째 행의 가운데 위치 now를 설정
    now = [n // 2, 0]
    # 주어진 규칙으로 숫자를 n^2번 배정한다.
    for _i in range(1, n**2 + 1):
        x, y = now
        arr[y][x] = _i
        new_x = x + 1 if x + 1 < n else 0
        new_y = y - 1 if y - 1 >= 0 else n - 1
        now = (x, y + 1) if arr[new_y][new_x] else (new_x, new_y)
    return arr


def make_double_even_magicsquare(n: int) -> list[list]:
    """Magic Square Algorithm for a double Even Number"""

    def fill_num(x: int, y: int, d: int, direction: str) -> None:
        """Fill in values ​​in one direction"""
        directions = {"NW": (-1, -1), "SW": (-1, 1), "NE": (1, -1), "SE": (1, 1)}
        now_direction = directions[direction]
        value = arr[y][x]
        _i = 0
        while (
            0 <= (_x := x + now_direction[0] * _i) < N
            and 0 <= (_y := y + now_direction[1] * _i) < N
        ):
            arr[_y][_x] = value + d * _i
            _i += 1

    # n^2크기 배열 생성
    arr = [[0 for _ in range(n)] for _ in range(n)]
    # 대각선, 0번 행, -1번행 값 삽입
    for _i in range(N):
        arr[0][_i] = _i + 1
        arr[_i][_i] = 1 + (N + 1) * _i if _i != 0 else 1
        arr[-(_i + 1)][_i] = N**2 - N + 1 - (N - 1) * _i
        arr[-1][-(_i + 1)] = N**2 - _i
    # 4 * 4 array swap
    for _i in range(N // 4):
        arr[0][_i * 4 + 1], arr[-1][-(_i * 4 + 2)] = (
            arr[-1][-(_i * 4 + 2)],
            arr[0][_i * 4 + 1],
        )
        arr[0][_i * 4 + 2], arr[-1][-(_i * 4 + 3)] = (
            arr[-1][-(_i * 4 + 3)],
            arr[0][_i * 4 + 2],
        )
    # diagonal value
    for _i in range(2, N, 2):
        if arr[0][_i] > N:
            fill_num(_i, 0, -(N + 1), "SE")
        else:
            fill_num(_i, 0, N + 1, "SE")

        if arr[N - 1][N - (_i + 1)] > N:
            fill_num(N - (_i + 1), N - 1, -(N + 1), "NW")
        else:
            fill_num(N - (_i + 1), N - 1, N + 1, "NW")

        if arr[0][_i - 1] > N:
            fill_num(_i - 1, 0, -(N - 1), "SW")
        else:
            fill_num(_i - 1, 0, N - 1, "SW")

        if arr[N - 1][N - _i] > N:
            fill_num(N - _i, N - 1, -(N - 1), "NE")
        else:
            fill_num(N - _i, N - 1, N - 1, "NE")

    return arr


def iterize(function):
    """Make it possible on an iterable object"""

    def wrapper(x:list or int, d:int) -> list or int:
        if isinstance(x, list):
            return list(map(functools.partial(wrapper, d=d), x))
        else:
            return function(x, d)

    return wrapper


@iterize
def magic_plus(x: int, d: int) -> int:
    """Add the value of magicsquare by ((N // 2) ** 2) * d"""
    return x + ((N // 2) ** 2) * d


def strachey_algorithm(n: int) -> list[list]:
    """Magic Square Algorithm for a Single Even Number"""
    arr = [make_odd_magic_square(n // 2) for _ in range(4)]
    arr[1] = list(magic_plus(arr[1], 2))
    arr[2] = list(magic_plus(arr[2], 3))
    arr[3] = list(magic_plus(arr[3], 1))
    # swap left k column k = n // 4 arr0, arr2
    for i in range(n // 4):
        for j in range(n // 2):
            arr[0][j][i], arr[2][j][i] = arr[2][j][i], arr[0][j][i]
    # swap right k-1 column
    for i in range(n // 4 - 1):
        for j in range(n // 2):
            arr[1][j][-(i + 1)], arr[3][j][-(i + 1)] = (
                arr[3][j][-(i + 1)],
                arr[1][j][-(i + 1)],
            )
    # swap arr[0]-left-medium cell <-> arr[2]-medium-medium cell,
    # swap arr[2]-left-medium cell <-> arr[0]-medium-medium cell,
    arr[0][n // 4][n // 4], arr[2][n // 4][n // 4] = (
        arr[2][n // 4][n // 4],
        arr[0][n // 4][n // 4],
    )
    arr[2][n // 4][0], arr[0][n // 4][0] = arr[0][n // 4][0], arr[2][n // 4][0]
    arr = [
        [i + j for n0, i in enumerate(arr[0]) if n0 == n1]
        for n1, j in enumerate(arr[1])
    ] + [
        [i + j for n0, i in enumerate(arr[2]) if n0 == n1]
        for n1, j in enumerate(arr[3])
    ]
    arr = [arr[i][0] for i in range(n)]
    return arr


if __name__ == "__main__":
    N = int(input())
    if N % 2 == 1:
        for i in make_odd_magic_square(N):
            print(*i)
    elif N % 4 == 0:
        for i in make_double_even_magicsquare(N):
            print(*i)
    else:
        for i in strachey_algorithm(N):
            print(*i)

'파이썬 > 파이썬 백준' 카테고리의 다른 글

[파이썬]10997:별 찍기 - 22  (0) 2023.05.22
1307:마방진 풀기 3, 4일차  (0) 2022.06.16
마방진:1307 2일차.  (0) 2022.06.14
1307:마방진 풀기 1일차.  (0) 2022.06.13