18382번 2048

문제


img01

18382번 2048 - 백준

설계


앗 영어문제

2048 게임의 최종 점수를 출력하는 문제이다.
입력으로 앞으로의 움직임과 나타날 블럭이 주어지므로 시뮬레이션만 잘하면 되는 문제다.
4x4 배열을 만들고 움직임에 따라 타일을 조작하며 합쳐지면 점수에 그만큼 더해준다.

구현


1. 입력 받기
score = int(input())

# 무빙
moving_input = input()
moving = [moving_input[i:i+4] for i in range(0, len(moving_input), 4)]

# 현재 판
board_input = list(map(int, input().split()))
board = [board_input[i*4:(i+1)*4] for i in range(4)]
2. 입력 파싱
# 무빙만큼 반복
for move in moving:
    dir = move[0]
    value = int(move[1])
    x = int(move[2])
    y = int(move[3])

    board, gained = move_board(board, dir)
    score += gained

    board[x][y] = value

print(score)
3. 실제 무빙 로직
def move_board(board, dir):
    gained = 0

    # 방향에 따라 움직일 방향 설정
    dir_delta = {
        'U': (0, -1),
        'D': (0, 1),
        'L': (-1, 0),
        'R': (1, 0),
    }

    dx, dy = dir_delta[dir]

    # 병합 여부 확인
    merged = [[False]*4 for _ in range(4)]

    # 벽은 무시하고 탐색해야해서 이동 순서 조정
    range_x = range(4)
    range_y = range(4)
    if dir == 'R':
        range_x = range(2, -1, -1)
    if dir == 'D':
        range_y = range(2, -1, -1)
    if dir == 'L':
        range_x = range(1, 4)
    if dir == 'U':
        range_y = range(1, 4)

    # 설정 범위내 무빙
    for y in range_y:
        for x in range_x:
            # 0이면 무시
            if board[y][x] == 0:
                continue

            # 현재 좌표
            cx, cy = x, y
            while True:
                # 목표 좌표
                nx, ny = cx + dx, cy + dy

                # 벽 만나면 중단
                if not (0 <= nx < 4 and 0 <= ny < 4):
                    break

                # 빈 칸이면 이동
                if board[ny][nx] == 0:
                    board[ny][nx] = board[cy][cx]
                    board[cy][cx] = 0
                    cx, cy = nx, ny

                # 같은 숫자 + 병합 안 됐으면 합치기
                elif board[ny][nx] == board[cy][cx] and not merged[ny][nx]:
                    board[ny][nx] *= 2
                    board[cy][cx] = 0
                    merged[ny][nx] = True
                    gained += board[ny][nx]
                    break
                # 다른 숫자면 무시
                else:
                    break
    
    return board, gained

채점


img02

반성


4X4 보드에 좌표계산하며 시뮬레이션 하는 식으로 해결했는데 파이썬에서는 좌표계산보다 줄단위 처리가 낫다고 한다.
파이썬의 자료구조와 문법은 좌표 반복보단 리스트 전체 조작에 강력하게 최적화돼 있기 때문이라고
리스트가 가변 배열이고 병합, 필터링 등 기능이 내장되어 있다고 한다.

def slide_left(row):
    new_row = [x for x in row if x != 0]
    # 병합 처리
    ...
    return new_row

이런 식으로 해결할 수 있다고…

2중 반복문을 안써도 되고 코드가 단순해지며 보드 회전을 통해 슬라이드 함수 하나로 처리도 가능하다.

transpose = [list(row) for row in zip(*board)]  # 전치 행렬
reversed_board = [row[::-1] for row in board]   # 행 반전

c나 java와는 좀 다르다.
파이썬 고수가 되려면 한참 멀었다.

코드 확인


Link to GitHub

Updated: