ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [PS] 17081) RPG Extreme
    백준 PS 2022. 11. 1. 16:30

    https://www.acmicpc.net/problem/17081

     

    17081번: RPG Extreme

    요즘 택희는 RPG 게임을 하고 있다. 던전을 헤쳐나가며 몬스터를 물리치고, 아이템을 모으고, 레벨 업을 하여 보스 몬스터를 물리치는 전형적인 RPG 게임이다. 이 게임은 N×M 2차원 그리드 위에서

    www.acmicpc.net

    Platinum2) 17081.RPG Extreme

     

    • 구현, 시뮬레이션

    Platinum 구현 문제라 조건이 많고 세세한 부분 컨트롤에 유의하자. 구현 자체 코딩에는 많은 시간이 걸리지 않았지만 AC를 받는 것까지가 어려웠다. 개인적으로 빼먹었던 조건과 질문 검색의 유의사항을 정리해보자

    1. 아이템 박스는 방문시 교체가 일어나지 않아도 없어진다.
    2. 움직일 수 없는 상황에 가시를 밟고 있다면 중복해서 데미지를 입는다.
    3. 보스의 이름은 "Boss"가 아닐 수 있다.
    4. RE 장신구로 살아나게 되면 몬스터 또한 체력을 회복한다.
    5. player가 죽으면 보드에 @은 출력되지 않는다.
    6. player의 hp가 0이하로 떨어져 죽더라도 player의 hp 출력은 0으로 한다.

    유의해야할 조건들은 이정도가 있고 다른 조건들도 잘 컨트롤할 수 있도록 문제 요구사항을 확인하자.

    세부적은 코드 내용은 다음과 같다.

    # U R D L
        dx = [-1,0,1,0]
        dy = [0,1,0,-1]
        
        def getdata():
            n, m = map(int,input().split())
            board = list(list(input().rstrip()) for _ in range(n))
            command = list(map(str,input().rstrip()))
            for idx, dir in enumerate(command) :
                if dir == 'U' :
                    command[idx] = 0
                elif dir == 'R' :
                    command[idx] = 1
                elif dir == 'D' :
                    command[idx] = 2
                else :
                    command[idx] = 3
            k, l = 0, 0
            for i in range(n) :
                for j in range(m) :
                    if board[i][j] == '&' or board[i][j] == 'M' :
                        k += 1
                    if board[i][j] == 'B' :
                        l += 1
                    if board[i][j] == '@' :
                        ix, iy = i, j
            monster, box = dict(), dict()
            for i in range(k) :
                tmp=list(input().split())
                monster[int(tmp[0])-1,int(tmp[1])-1] = [int(tmp[3]), int(tmp[4]), int(tmp[5]), int(tmp[6]), tmp[2]]
            for i in range(l) :
                tmp = list(input().split())
                box[int(tmp[0])-1, int(tmp[1])-1] = [tmp[2], tmp[3]]
            return n, m, k, l, board, command, monster, box, ix, iy
    
        n, m, k, l, board, command, monster, box, ix, iy = getdata()

    위의 코드는 이동 방향을 나타낼 dx, dy의 정의와 주어진 입력을 받아올 getdata 함수이다. ix, iy로 player의 첫 위치를 지정하고 monster와 box는 dictionary를 이용하여 좌표를 key로, 내용을 value로 받았다.

    def move(board, x, y, dir) :
            nx = x+dx[dir]
            ny = y+dy[dir]
            if 0<=nx<n and 0<=ny<m and board[nx][ny] != '#' :
                return nx, ny
            else :
                return x, y
                
    # LV, HP, ATT, DEF, EXP
        player = [1, 20, 2, 2, 0]
        max_hp = 20
        max_exp = 5
        # weapon, armor, accessories*4
        equipment = [0, 0, 0, 0, 0, 0]

    board에서 움직이게 될 player의 move함수이다. 움직일 수 없는 경우는 그대로 그 자리에 가만히 있고, 움직일 수 있는 경우만 움직인다. player와 장비에 대한 사전 정의는 주석으로 설명이 되어 있다.

    def printplayer(board, player, equipment, turn, max_hp, max_exp) :
            for i in range(n) :
                for j in range(m) :
                    print(board[i][j], end="")
                print()
            print(f"Passed Turns : {turn}")
            print(f"LV : {player[0]}")
            print(f"HP : {player[1]}/{max_hp}")
            print(f"ATT : {player[2]}+{equipment[0]}")
            print(f"DEF : {player[3]}+{equipment[1]}")
            print(f"EXP : {player[4]}/{max_exp}")

    printplayer는 출력을 위해 현재 player의 상태와 진행된 턴에 대한 출력함수이다.

    def sol(max_hp, max_exp) :
            turn = 0
            sx, sy = ix, iy
            board[ix][iy] = '.'
            for dir in command :
                sx, sy = move(board, sx, sy, dir)
                turn += 1
                if board[sx][sy] == '^' :
                    if 'DX' in equipment :
                        player[1] -= 1
                    else :
                        player[1] -= 5
                    if player[1] <= 0 :
                        if 'RE' not in equipment :
                            player[1] = 0
                            printplayer(board, player, equipment, turn, max_hp, max_exp)
                            print("YOU HAVE BEEN KILLED BY SPIKE TRAP..")
                            return
                        else :
                            sx, sy = ix, iy
                            player[1] = max_hp
                            equipment.remove('RE')
                if board[sx][sy] == '&' :
                    tmp = monster[(sx, sy)]
                    m_hp = tmp[2]
                    flag = 0
                    if 'CO' in equipment :
                        flag = 1
                    while True :
                        if flag == 0 :
                            tmp[2] -= max(1, player[2]+equipment[0]-tmp[1])
                        if flag == 1 :
                            if 'DX' not in equipment :
                                tmp[2] -= max(1, (player[2]+equipment[0])*2-tmp[1])
                            else :
                                tmp[2] -= max(1, (player[2] + equipment[0]) * 3 - tmp[1])
                            flag = 0
                        if tmp[2] <= 0 :
                            board[sx][sy] = '.'
                            if 'EX' in equipment :
                                player[4] += int(tmp[3]*(1.2))
                            else :
                                player[4] += int(tmp[3])
                            if player[4] >= max_exp :
                                player[4] = 0
                                player[0] += 1
                                max_hp += 5
                                player[1] = max_hp
                                player[2] += 2
                                player[3] += 2
                                max_exp += 5
                            if 'HR' in equipment :
                                player[1] += 3
                                if player[1] >= max_hp :
                                    player[1] = max_hp
                            break
                        player[1] -= max(1, tmp[0]-player[3]-equipment[1])
                        if player[1] <= 0 :
                            if 'RE' not in equipment :
                                player[1] = 0
                                printplayer(board, player, equipment, turn, max_hp, max_exp)
                                print(f"YOU HAVE BEEN KILLED BY {tmp[4]}..")
                                return
                            else :
                                sx, sy = ix, iy
                                player[1] = max_hp
                                equipment.remove('RE')
                                tmp[2] = m_hp
                                break
                if board[sx][sy] == 'B':
                    tmp = box[sx, sy]
                    if tmp[0] == 'W' :
                        equipment[0] = int(tmp[1])
                    elif tmp[0] == 'A' :
                        equipment[1] = int(tmp[1])
                    else :
                        if tmp[1] not in equipment :
                            for i in range(2, 6) :
                                if equipment[i] == 0:
                                    equipment[i] = tmp[1]
                                    break
                    board[sx][sy] = '.'
                if board[sx][sy] == 'M' :
                    Hflag = 0
                    if 'HU' in equipment :
                        player[1] = max_hp
                        Hflag = 1
                    tmp = monster[sx, sy]
                    m_hp = tmp[2]
                    flag = 0
                    if 'CO' in equipment:
                        flag = 1
                    while True:
                        if flag == 0:
                            tmp[2] -= max(1, player[2] + equipment[0] - tmp[1])
                        if flag == 1:
                            if 'DX' not in equipment:
                                tmp[2] -= max(1, (player[2] + equipment[0]) * 2 - tmp[1])
                            else:
                                tmp[2] -= max(1, (player[2] + equipment[0]) * 3 - tmp[1])
                            flag = 0
                        if tmp[2] <= 0:
                            if 'EX' in equipment:
                                player[4] += int(tmp[3] * (1.2))
                            else:
                                player[4] += int(tmp[3])
                            if player[4] >= max_exp:
                                player[4] = 0
                                player[0] += 1
                                max_hp += 5
                                player[1] = max_hp
                                player[2] += 2
                                player[3] += 2
                                max_exp += 5
                            if 'HR' in equipment:
                                player[1] += 3
                                if player[1] >= max_hp:
                                    player[1] = max_hp
                            board[sx][sy] = '@'
                            printplayer(board, player, equipment, turn, max_hp, max_exp)
                            print("YOU WIN!")
                            return
                        if Hflag == 0 :
                            player[1] -= max(1, tmp[0] - player[3] - equipment[1])
                        else :
                            Hflag = 0
                        if player[1] <= 0:
                            if 'RE' not in equipment:
                                player[1] = 0
                                printplayer(board, player, equipment, turn, max_hp, max_exp)
                                print(f"YOU HAVE BEEN KILLED BY {tmp[4]}..")
                                return
                            else:
                                sx, sy = ix, iy
                                player[1] = max_hp
                                equipment.remove('RE')
                                tmp[2] = m_hp
                                break
                # print(f"==={turn}th===")
                # board[ix][iy]='.'
                # dd = board[sx][sy]
                # board[sx][sy] = '@'
                # printboard(board,n)
                # print(f"===player===")
                # print(player)
                # print(f"===equipment===")
                # print(equipment)
                # board[sx][sy] = dd
            board[sx][sy] = '@'
            printplayer(board,player,equipment,turn,max_hp,max_exp)
            print("Press any key to continue.")

    전체적인 조건과 움직임을 담고 있는 solution 함수이다. 각 command의 움직임에 따라 player를 이동시키고, 만나는 각 B, &, M마다 조건에 맞는 행동을 담고 있다. 중간 중간 equipment의 장신구에 의해 조건문이 많이 붙어 있으며 출력을 위한 board도 따로 신경써주어야 한다.

    따로 쓰이는 알고리즘이나 아이디어는 없으나 세세한 조건을 잘 따져야하기 때문에 난이도가 높게 형성되어 있는 것 같다. 실제로 정답률도 낮다. 코드를 다 작성하고 예제 출력은 정확히 나오나 AC를 못 받는 경우가 많은 것 같고, 이런 상황에서 어느 부분이 틀렸는지 확인하기도 쉽지 않다. 코드를 논리적 흐름에 따라 더 깔끔하게 작성하고, 반복되는 부분을 함수화하여 사용하면 보다 쉽게 오류 부분을 찾을 수 있을 것 같다.

    '백준 PS' 카테고리의 다른 글

    [PS] 2178) 미로 탐색  (0) 2022.11.14
    [PS] 2293) 동전 1  (0) 2022.11.14
    [PS] 1806) 부분합  (0) 2022.10.24
    [PS] 14939) 불끄기  (1) 2022.10.21
    [PS] 1509) 펠린드롬분할  (0) 2022.10.21
Designed by Tistory.