본문 바로가기

백준

[파이썬] 백준 15778 Yut Nori (윷놀이)

Solved.ac
프로필

그냥 깡구현 문제인데 한번 꼬이면

답이 안보인다 ㅠㅠ

이번엔 내가 구현해 나가는 과정을 한 번 써 볼 것이다.

1. 판 그리기

pa = [
    '..----..----..----..----..----..',
    '..    ..    ..    ..    ..    ..',
    '| \\                          / |',
    '|  \\                        /  |',
    '|   \\                      /   |',
    '|    ..                  ..    |',
    '..   ..                  ..   ..',
    '..     \\                /     ..',
    '|       \\              /       |',
    '|        \\            /        |',
    '|         ..        ..         |',
    '|         ..        ..         |',
    '..          \\      /          ..',
    '..           \\    /           ..',
    '|             \\  /             |',
    '|              ..              |',
    '|              ..              |',
    '|             /  \\             |',
    '..           /    \\           ..',
    '..          /      \\          ..',
    '|         ..        ..         |',
    '|         ..        ..         |',
    '|        /            \\        |',
    '|       /              \\       |',
    '..     /                \\     ..',
    '..   ..                  ..   ..',
    '|    ..                  ..    |',
    '|   /                      \\   |',
    '|  /                        \\  |',
    '| /                          \\ |',
    '..    ..    ..    ..    ..    ..',
    '..----..----..----..----..----..'
    ]

그냥 예제출력을 복사했다.

2. 각 말들의 전진 칸 수 정하기

def dist(Yut):
    return [5,1,2,3,4][Yut.count('F')]

앞면의 개수만큼 전진하도록 했고 0개면 5칸을 전진하게 했다.

3. 말들의 위치 기록하기

길을 3가지로 나누어 관리했다.

1번 길은 가장 바깥길

2번 길은 우상향 대각선 길

3번 길은 우하향 대각선 길

뒷 원소는 각 길의 몇번째 위치인지 기록했다.

nowstat = {
    'A':(0, 0),
    'B':(0, 0),
    'C':(0, 0),
    'D':(0, 0),
    'a':(0, 0),
    'b':(0, 0),
    'c':(0, 0),
    'd':(0, 0),
    }

맨 처음에는 말이 나가지 않았다는 의미로 (0, 0)으로 초기화 해줬다.

4. 말들의 위치 재기록

2번에서 얻은 칸 수만큼 전진을 시키고 난 뒤 생각해보니 문제가 하나 있었다.

각 길에 겹치는 부분이 있는 것이었다.

겹치는 부분에서는 최단거리로 가야하므로 변환해주는 함수를 짰다.

def start(road, cnt, unit):
    if road == 1:
        if cnt == 5:
            nowstat[unit] = (2, 0)
        elif cnt == 10:
            nowstat[unit] = (3, 0)
    elif road == 2:
        if cnt == 3:
            nowstat[unit] = (3, 3)
        elif cnt >= 6:
            nowstat[unit] = (1, (cnt-6) + 15)

5. 말들의 위치를 판의 x, y값으로 변환

말을 내가 만든 기준으로 기록하긴 했지만

결국 판에 말을 넣어야 하기 때문에 길의 번호인 road인 칸 수인 cnt를 받으면

판의 x, y값을 리턴하는 함수를 만들었다.

def locate(road, cnt):
    if road == 0:
        return 0
    if road == 1:
        if cnt <= 5:
            x, y = 30, 30 - 6*cnt
        elif cnt <= 10:
            x, y = 30 - (cnt-5)*6, 0
        elif cnt <= 15:
            x, y = 0, 6*(cnt-10)
        elif cnt <= 20:
            x, y = 6*(cnt-15), 30
        else:
            return 0

    elif road == 2:
        if cnt <= 5:
            x, y = 30 - cnt*5, cnt * 5
        else:
            return 0

    else:
        if cnt <= 6:
            x, y = 5*cnt, 5*cnt
        else:
            return 0
    return (x, y)

물론 판에 존재하지 않을때는 0을 리턴했다.

6. 말들의 이동 표현

판에서 말의 이동을 보이려면 이전 칸의 말을 지우고

현재 칸에 말을 그려야 한다.

그래서 erase함수와 draw함수를 만들었다.

def erase(px, py, unit):
    for i in unit:
        if i in "aA":
            pan[py][px] = '.'
        elif i in "bB":
            pan[py][px+1] = '.'
        elif i in "cC":
            pan[py+1][px] = '.'
        else:
            pan[py+1][px+1] = '.'

def draw(nx, ny, unit):
    for i in unit:
        if i in "aA":
            if i == 'a': pan[ny][nx] = 'a'
            else: pan[ny][nx] = 'A'
        elif i in "bB":
            if i == 'b': pan[ny][nx+1] = 'b'
            else: pan[ny][nx+1] = 'B'
        elif i in "cC":
            if i == 'c': pan[ny+1][nx] = 'c'
            else: pan[ny+1][nx] = 'C'
        else:
            if i == 'd': pan[ny+1][nx+1] = 'd'
            else: pan[ny+1][nx+1] = 'D'

7. 말의 업기, 잡기 구현

6번까지 했으면 말들은 잘 이동 할 것이다.

근데 문제에서 짜증나게 업기와 잡기를 구현하라 했으니

말을 잡는 encounter 함수와 업는 union함수를 만들었다.

def encount(road, cnt, nx, ny, unit):
    L = []
    if unit in "abcd":
        for i in "ABCD":
            if road == nowstat[i][0] and cnt == nowstat[i][1]: L.append(i)
    else:
        for i in "abcd":
            if road == nowstat[i][0] and cnt == nowstat[i][1]: L.append(i)
    for i in L:
        nowstat[i] = (0, 0)
    if L:
        erase(nx, ny, L)

def union(proad, pcnt, road, cnt, px, py, nx, ny, unit):
    L = [unit]
    if unit in "abcd":
        for i in "abcd":
            if proad == nowstat[i][0] and pcnt == nowstat[i][1]: L.append(i)
    else:
        for i in "ABCD":
            if proad == nowstat[i][0] and pcnt == nowstat[i][1]: L.append(i)

    if px != -1:
        erase(px, py, L)
    if nx != -1:
        if proad == 0:
            draw(nx, ny, unit)
            start(road, cnt, unit)
        else:
            for i in L:
                nowstat[i] = (road, cnt)
                start(road, cnt, i)
            draw(nx, ny, L)

여기서 중요한 점은 업어서 이동한 말이나

잡혀서 돌아간 돌의 처리를 제대로 해줘야 한다는 것이다.

정답코드

더보기

import sys

r = sys.stdin.readline

pan = []
pa = [
    '..----..----..----..----..----..',
    '..    ..    ..    ..    ..    ..',
    '| \\                          / |',
    '|  \\                        /  |',
    '|   \\                      /   |',
    '|    ..                  ..    |',
    '..   ..                  ..   ..',
    '..     \\                /     ..',
    '|       \\              /       |',
    '|        \\            /        |',
    '|         ..        ..         |',
    '|         ..        ..         |',
    '..          \\      /          ..',
    '..           \\    /           ..',
    '|             \\  /             |',
    '|              ..              |',
    '|              ..              |',
    '|             /  \\             |',
    '..           /    \\           ..',
    '..          /      \\          ..',
    '|         ..        ..         |',
    '|         ..        ..         |',
    '|        /            \\        |',
    '|       /              \\       |',
    '..     /                \\     ..',
    '..   ..                  ..   ..',
    '|    ..                  ..    |',
    '|   /                      \\   |',
    '|  /                        \\  |',
    '| /                          \\ |',
    '..    ..    ..    ..    ..    ..',
    '..----..----..----..----..----..'
    ]

for i in pa:
    pan.append(list(i))

def dist(Yut):
    return [5,1,2,3,4][Yut.count('F')]

def start(road, cnt, unit):
    if road == 1:
        if cnt == 5:
            nowstat[unit] = (2, 0)
        elif cnt == 10:
            nowstat[unit] = (3, 0)
    elif road == 2:
        if cnt == 3:
            nowstat[unit] = (3, 3)
        elif cnt >= 6:
            nowstat[unit] = (1, (cnt-6) + 15)

def locate(road, cnt):
    if road == 0:
        return 0
    if road == 1:
        if cnt <= 5:
            x, y = 30, 30 - 6*cnt
        elif cnt <= 10:
            x, y = 30 - (cnt-5)*6, 0
        elif cnt <= 15:
            x, y = 0, 6*(cnt-10)
        elif cnt <= 20:
            x, y = 6*(cnt-15), 30
        else:
            return 0

    elif road == 2:
        if cnt <= 5:
            x, y = 30 - cnt*5, cnt * 5
        else:
            return 0

    else:
        if cnt <= 6:
            x, y = 5*cnt, 5*cnt
        else:
            return 0
    return (x, y)

def erase(px, py, unit):
    for i in unit:
        if i in "aA":
            pan[py][px] = '.'
        elif i in "bB":
            pan[py][px+1] = '.'
        elif i in "cC":
            pan[py+1][px] = '.'
        else:
            pan[py+1][px+1] = '.'

def draw(nx, ny, unit):
    for i in unit:
        if i in "aA":
            if i == 'a': pan[ny][nx] = 'a'
            else: pan[ny][nx] = 'A'
        elif i in "bB":
            if i == 'b': pan[ny][nx+1] = 'b'
            else: pan[ny][nx+1] = 'B'
        elif i in "cC":
            if i == 'c': pan[ny+1][nx] = 'c'
            else: pan[ny+1][nx] = 'C'
        else:
            if i == 'd': pan[ny+1][nx+1] = 'd'
            else: pan[ny+1][nx+1] = 'D'

def encount(road, cnt, nx, ny, unit):
    L = []
    if unit in "abcd":
        for i in "ABCD":
            if road == nowstat[i][0] and cnt == nowstat[i][1]: L.append(i)
    else:
        for i in "abcd":
            if road == nowstat[i][0] and cnt == nowstat[i][1]: L.append(i)
    for i in L:
        nowstat[i] = (0, 0)
    if L:
        erase(nx, ny, L)

def union(proad, pcnt, road, cnt, px, py, nx, ny, unit):
    L = [unit]
    if unit in "abcd":
        for i in "abcd":
            if proad == nowstat[i][0] and pcnt == nowstat[i][1]: L.append(i)
    else:
        for i in "ABCD":
            if proad == nowstat[i][0] and pcnt == nowstat[i][1]: L.append(i)

    if px != -1:
        erase(px, py, L)
    if nx != -1:
        if proad == 0:
            draw(nx, ny, unit)
            start(road, cnt, unit)
        else:
            for i in L:
                nowstat[i] = (road, cnt)
                start(road, cnt, i)
            draw(nx, ny, L)

nowstat = {
    'A':(0, 0),
    'B':(0, 0),
    'C':(0, 0),
    'D':(0, 0),
    'a':(0, 0),
    'b':(0, 0),
    'c':(0, 0),
    'd':(0, 0),
    }

N = int(r())
for _ in range(N):
    mal, yut = r().split()
    movecnt = dist(yut)
    pasta, pastb = nowstat[mal][0], nowstat[mal][1]
    try: pastx, pasty = locate(pasta, pastb)
    except: pastx, pasty= -1, -1
    if nowstat[mal] == (0, 0):
        a, b = 1, movecnt
    else:
        a = pasta
        b = pastb + movecnt
    nowstat[mal] = (a, b)
    start(a, b, mal)
    a, b = nowstat[mal][0], nowstat[mal][1]
    try: nowx, nowy = locate(a, b)
    except: nowx, nowy= -1, -1
    if nowx != -1:
        encount(a, b, nowx, nowy, mal)

    union(pasta, pastb, a, b, pastx, pasty, nowx, nowy, mal)

for i in pan:
    print("".join(i))

마치면서

내가 처음으로 100줄 넘게 적었던 코드이다.

처음엔 진짜 막막했는데 해보니까 되긴 하네요

굿

그리고 굳이 매 실행마다 판에 문자를 세기고 지울 필요는 없었는데

디버깅하기 편해서 저렇게 만들어놨다.

굿