[bj17081] RPG Extreme

Brie·2024년 4월 18일

코테 연습

목록 보기
7/24

문제

풀이

특별한 알고리즘이 사용되지는 않았지만 구현량이 많은 빡구현 문제다.
이런 구현을 할 때 특정 부분에서 틀리게 되면 디버그를 어떻게 할 것이냐가 중요하므로, 클린 코딩의 중요성을 깨닫게 된다.
유저들이 모아놓은 테스트 케이스가 많으므로, 이러한 TC를 이용해 디버깅하면 쉽게 풀 수 있다.

class Hero:
    def __init__(self, position):
        self.level = 1
        self.hp = 20
        self.max_hp = 20
        self.base_attack = 2
        self.base_defense = 2
        self.exp = 0
        self.weapon = None
        self.armor = None
        self.accessories = []
        self.position = position
        self.initial_position = self.position
        
    def show(self):
        print(f'LV : {self.level}')
        print(f'HP : {self.hp}/{self.max_hp}')
        print(f'ATT : {self.base_attack}+{self.weapon if self.weapon else 0}')
        print(f'DEF : {self.base_defense}+{self.armor if self.armor else 0}')
        print(f'EXP : {self.exp}/{self.level*5}')
        #print(f'Equipped : {self.accessories}')
        
    def get_exp(self, exp):
        exp = int(exp * (1.2 if 'EX' in self.accessories else 1))
        self.exp += exp
        while self.exp >= self.level*5:
            self.exp = 0
            self.level += 1
            self.max_hp += 5
            self.hp = self.max_hp
            self.base_attack += 2
            self.base_defense += 2
            
    def regeneration(self):
        self.hp = min(self.hp + 3, self.max_hp)
        
    def reincarnation(self):
        self.hp = self.max_hp
        self.position = self.initial_position
        self.accessories.remove('RE')
        
class Monster:
    def __init__(self, name, attack, defense, max_hp, exp, position, is_boss):
        self.name = name
        self.attack = attack
        self.defense = defense
        self.hp = max_hp
        self.max_hp = max_hp
        self.exp = exp
        self.position = tuple(position)
        self.is_boss = is_boss
        
class ItemBox:
    def __init__(self, item_type, effect, position):
        self.item_type = item_type
        self.effect = effect
        self.position = position

class GameMap:
    def __init__(self, grid, hero, monsters, item_boxes):
        self.grid = grid
        self.hero = hero
        self.monsters = monsters
        self.item_boxes = item_boxes
        
def simulate_combat(hero, monster):
    first_attack = True
    hunter = False
    courage = True if 'CO' in hero.accessories else False
    dexterity = True if 'DX' in hero.accessories else False
    if 'HU' in hero.accessories and monster.is_boss:
        hero.hp = hero.max_hp
        hunter = True
    while True:
        # Hero attacks first
        damage_modifier = 1
        if first_attack: 
            if courage and dexterity: damage_modifier = 3
            elif courage:  damage_modifier = 2
        damage_to_monster = max(1, (hero.base_attack + (hero.weapon if hero.weapon else 0))*damage_modifier - monster.defense)
        monster.hp -= damage_to_monster
        if monster.hp <= 0:
            return True  # Monster defeated

        # Monster retaliates
        damage_to_hero = max(1, monster.attack - (hero.base_defense + (hero.armor if hero.armor else 0)))
        if first_attack and hunter: damage_to_hero = 0
        hero.hp -= damage_to_hero
        if hero.hp <= 0:
            return False  # Hero defeated
        
        first_attack = False

def process_item_box(hero, item_box):
    if item_box.item_type == 'W':
        hero.weapon = int(item_box.effect)
    elif item_box.item_type == 'A':
        hero.armor = int(item_box.effect)
    elif item_box.item_type == 'O':
        if len(hero.accessories) < 4 and item_box.effect not in hero.accessories:
            hero.accessories.append(item_box.effect)

def move_hero(game_map, moves):
    directions = {'L': (0, -1), 'R': (0, 1), 'U': (-1, 0), 'D': (1, 0)}
    hero = game_map.hero
    grid = game_map.grid
    monsters_dict = {monster.position: monster for monster in game_map.monsters}
    item_boxes = {(box.position[0], box.position[1]): box for box in game_map.item_boxes}
    turn_count = 0
    hero_killed_by = None

    def in_bounds(pos):
        return 0 <= pos[0] < len(grid) and 0 <= pos[1] < len(grid[0])

    for move in moves:
        turn_count += 1
        dx, dy = directions[move]
        new_position = (hero.position[0] + dx, hero.position[1] + dy)
        
        if not in_bounds(new_position) or grid[new_position[0]][new_position[1]] == '#':
            pass
        else: 
            hero.position = new_position
            
            # Check for item box at the new position
            if hero.position in item_boxes:
                item_box = item_boxes.pop(hero.position)
                process_item_box(hero, item_box)
                grid[hero.position[0]][hero.position[1]] = '.'
            
            # Check for monster at the new position
            if hero.position in monsters_dict:
                monster = monsters_dict[hero.position]
                combat_result = simulate_combat(hero, monster)
                if not combat_result:  # Hero defeated
                    if 'RE' in hero.accessories:
                        monster.hp = monster.max_hp
                        hero.reincarnation()
                    else:
                        hero_killed_by = monster.name
                        hero.hp = 0
                        return turn_count, f"YOU HAVE BEEN KILLED BY {hero_killed_by}.."
                else:
                    if 'HR' in hero.accessories: hero.regeneration()
                    hero.get_exp(monster.exp)
                    if monster.is_boss:
                        return turn_count, f"YOU WIN!"
                    monsters_dict.pop(hero.position)  # Remove defeated monster
                    grid[hero.position[0]][hero.position[1]] = '.'
        
        # Check for spike trap
        if grid[hero.position[0]][hero.position[1]] == '^':
            if 'DX' in hero.accessories: # Damage from spike trap
                hero.hp -= 1
            else:
                hero.hp -= 5
            if hero.hp <= 0:
                if 'RE' in hero.accessories:
                    hero.reincarnation()
                else:
                    hero_killed_by = "SPIKE TRAP"
                    hero.hp = 0
                    return turn_count, f"YOU HAVE BEEN KILLED BY {hero_killed_by}.."

    return turn_count, "Press any key to continue."
        
N,M = map(int, input().split())
grid = [list(input()) for _ in range(N)]

monsters = []
item_boxes = []
isBoss = tuple([])
for i in range(N):
    for j in range(M):
        if grid[i][j] == '@':
            hero = Hero(tuple([i, j]))
            grid[i][j] = '.'
        if grid[i][j] == 'M':
            isBoss = tuple([i, j])
hero_moves = input()
while 1:
    try:
        x, y, *l = input().split()
        if len(l) == 5:
            monsters.append(Monster(l[0], int(l[1]), int(l[2]), int(l[3]), int(l[4]), tuple([int(x)-1, int(y)-1]), True if tuple([int(x)-1, int(y)-1]) == isBoss else False))
        elif len(l) == 2:
            item_boxes.append(ItemBox(l[0], l[1], tuple([int(x)-1, int(y)-1])))
    except: break
game_map = GameMap(grid, hero, monsters, item_boxes)
turn_count, txt = move_hero(game_map, hero_moves)
for i in range(len(game_map.grid)):
    if i == game_map.hero.position[0] and game_map.hero.hp > 0:
        print(''.join(game_map.grid[i][:game_map.hero.position[1]]+['@']+game_map.grid[i][game_map.hero.position[1]+1:]))
    else:
        print(''.join(game_map.grid[i]))
print(f"Passed Turns : {turn_count}")
hero.show()
print(txt)

0개의 댓글