[백준 17081] RPG Extreme (JAVA)

solser12·2021년 11월 28일
0

Algorithm

목록 보기
45/56

문제


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

풀이


복잡한 구현문제입니다. 실수할 수 있는 부분들을 확인하고 구현하면 됩니다.

  1. 주인공이 죽었을 때 체력은 음수가 아닌 0
  2. 보스를 죽이고 나서 경험치를 받고 결과 출력
  3. 몬스터와 전투중 사망 후 부활했을 시 전투중이던 몬스터 초기화
  4. 무기, 방어구 발견 시 무조건 교체
  5. 악세사리를 4개 장착 시 더 이상 악세사리 착용 불가
    -> 부활 악세사리 경우 부활 시 착용 가능
  6. 죽었을 때 지도에 표시하지 않기

코드


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.StringTokenizer;

public class Main {

    public static int N, M;
    public static char[][] map;
    public static int[][] indexCheck;
    public static Monster[] monsters;
    public static Item[] items;
    public static Hero hero;
    public static char[] command;
    public static Loc startLoc;

    public static void main(String[] args) throws IOException {

        start();

        int turn = 0;
        Loc loc = startLoc;
        for (char c : command) {
            turn++;
            loc = hero.move(c);
            char object = map[loc.x][loc.y];

            if (object == '^') {
                if (hero.stepOnSpike() && hero.die()) {
                    System.out.println(showResult(turn, 1, "SPIKE TRAP"));
                    System.exit(0);
                }
            } else if (object == 'B') {
                Item item = items[indexCheck[loc.x][loc.y]];
                if (item.type == 'W') {
                    hero.wearWeapon(item.val);
                } else if (item.type == 'A') {
                    hero.wearArmor(item.val);
                } else {
                    hero.wearAccessory(item.val);
                }
                map[loc.x][loc.y] = '.';
            } else if (object == '&') {
                Monster monster = monsters[indexCheck[loc.x][loc.y]];
                if (hero.battle(monster, false)) {
                    if (hero.die()) {
                        System.out.println(showResult(turn, 1, monster.name));
                        System.exit(0);
                    }
                } else {
                    map[loc.x][loc.y] = '.';
                }
            } else if (object == 'M') {
                Monster monster = monsters[indexCheck[loc.x][loc.y]];
                if (hero.battle(monster, true)) {
                    if (hero.die()) {
                        System.out.println(showResult(turn, 1, monster.name));
                        System.exit(0);
                    }
                } else {
                    map[loc.x][loc.y] = '@';
                    System.out.println(showResult(turn, 0, null));
                    System.exit(0);
                }
            }
        }

        map[loc.x][loc.y] = '@';
        System.out.println(showResult(turn, 2, null));
    }

    public static String showResult(int turn, int type, String name) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                sb.append(map[i][j]);
            }
            sb.append('\n');
        }

        sb.append("Passed Turns : ").append(turn).append('\n');
        sb.append("LV : ").append(hero.level).append('\n');
        sb.append("HP : ").append(hero.curHp).append('/').append(hero.maxHp).append('\n');
        sb.append("ATT : ").append(hero.attack).append('+').append(hero.weapon).append('\n');
        sb.append("DEF : ").append(hero.defense).append('+').append(hero.armor).append('\n');
        sb.append("EXP : ").append(hero.curExp).append('/').append(hero.maxExp).append('\n');
        if (type == 0) {
            sb.append("YOU WIN!\n");
        } else if (type == 1) {
            sb.append("YOU HAVE BEEN KILLED BY ").append(name).append("..\n");
        } else {
            sb.append("Press any key to continue.\n");
        }

        return sb.toString();
    }

    public static void start() throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        map = new char[N][M];
        indexCheck = new int[N][M];

        int monsterCount = 0, itemCount = 0;
        for (int i = 0; i < N; i++) {
            String input = br.readLine();
            Arrays.fill(indexCheck[i], -1);
            for (int j = 0; j < M; j++) {
                char c = input.charAt(j);
                if (c == '@') {
                    hero = new Hero(new Loc(i, j));
                    startLoc = new Loc(i, j);
                    map[i][j] = '.';
                } else {
                    map[i][j] = c;
                    if (c == '&' || c == 'M') {
                        monsterCount++;
                    } else if (c == 'B') {
                        itemCount++;
                    }
                }
            }
        }
        monsters = new Monster[monsterCount];
        items = new Item[itemCount];

        command = br.readLine().toCharArray();

        for (int i = 0; i < monsterCount; i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken()) - 1;
            int y = Integer.parseInt(st.nextToken()) - 1;
            String name = st.nextToken();
            int attack = Integer.parseInt(st.nextToken());
            int defense = Integer.parseInt(st.nextToken());
            int hp = Integer.parseInt(st.nextToken());
            int exp = Integer.parseInt(st.nextToken());
            indexCheck[x][y] = i;
            monsters[i] = new Monster(name, attack, defense, hp, exp);
        }

        HashMap<String, Integer> accMap = new HashMap<>();
        accMap.put("HR", 0);
        accMap.put("RE", 1);
        accMap.put("CO", 2);
        accMap.put("EX", 3);
        accMap.put("DX", 4);
        accMap.put("HU", 5);
        accMap.put("CU", 6);

        for (int i = 0; i < itemCount; i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken()) - 1;
            int y = Integer.parseInt(st.nextToken()) - 1;
            char type = st.nextToken().charAt(0);
            int val;
            if (type == 'O') {
                val = accMap.get(st.nextToken());
            } else {
                val = Integer.parseInt(st.nextToken());
            }
            indexCheck[x][y] = i;
            items[i] = new Item(type, val);
        }

        br.close();
    }

    public static class Hero {

        Loc loc;
        int maxHp = 20, curHp = 20, level = 1, curExp = 0, maxExp = 5, attack = 2,
                defense = 2, armor = 0, weapon = 0, accCount = 0;
        boolean[] accessories = new boolean[7]; // HR, RE, CO, EX, DX, HU, CU
        int[][] dt = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
        HashMap<Character, Integer> commandMap = new HashMap<>();

        public Hero(Loc loc) {
            this.loc = loc;
            commandMap.put('U', 0);
            commandMap.put('L', 1);
            commandMap.put('D', 2);
            commandMap.put('R', 3);
        }

        public Loc move(char c) {
            int d = commandMap.get(c);
            int dx = loc.x + dt[d][0];
            int dy = loc.y + dt[d][1];
            if (check(dx, dy)) {
                this.loc.x = dx;
                this.loc.y = dy;
                return loc;
            }
            return loc;
        }

        // 죽었을 때
        public boolean die() {
            if (!accessories[1]) {
                curHp = 0;
                return true;
            }

            this.loc = new Loc(startLoc.x, startLoc.y);
            curHp = maxHp;
            accessories[1] = false;
            return false;
        }

        public boolean battle(Monster monster, boolean isBoss) {

            // 첫번째 공격
            int monsterHp = monster.hp;
            int totalAttack = attack + weapon;
            int totalDefense = defense + armor;
            int heroDamage = Math.max(1, totalAttack - monster.defense);
            if (accessories[2]) monsterHp -= Math.max(1, (totalAttack * (accessories[4] ? 3 : 2)) - monster.defense);
            else monsterHp -= heroDamage;
            if (monsterHp <= 0) {
                win(monster.exp);
                return false;
            }

            // 첫번째 방어
            int monsterDamage = Math.max(1, monster.attack - totalDefense);
            if (isBoss && accessories[5]) curHp = maxHp;
            else curHp -= monsterDamage;
            if (curHp <= 0) return true;

            // 그 후
            int heroHit = (monsterHp / heroDamage) + ((monsterHp % heroDamage == 0) ? 0 : 1);
            int totalMonsterDamage = monsterDamage * (heroHit - 1);
            if (curHp <= totalMonsterDamage) return true;
            curHp -= totalMonsterDamage;
            win(monster.exp);
            return false;
        }

        // 승리했을 시
        public void win(int exp) {
            if (accessories[0]) {
                curHp = Math.min(curHp + 3, maxHp);
            }

            curExp += (int) (exp * (accessories[3] ? 1.2 : 1));

            // 레벨업
            if (curExp >= maxExp) {
                level++;
                curExp = 0;
                maxExp = level * 5;
                maxHp += 5;
                curHp = maxHp;
                attack += 2;
                defense += 2;
            }
        }

        // 스파이크 밟았을 때
        public boolean stepOnSpike() {
            curHp -= accessories[4] ? 1 : 5;
            return curHp <= 0;
        }

        // 무기 착용
        public void wearWeapon(int weapon) { this.weapon = weapon; }

        // 방어구 착용
        public void wearArmor(int armor) {
            this.armor = armor;
        }

        // 악세사리 착용
        public void wearAccessory(int type) {
            if (accCount < 4 && !accessories[type]) {
                accessories[type] = true;
                accCount++;
            }
        }

        public boolean check(int x, int y) {
            return x >= 0 && x < N && y >= 0 && y < M && map[x][y] != '#';
        }
    }

    public static class Item {
        char type;
        int val;

        public Item(char type, int val) {
            this.type = type;
            this.val = val;
        }
    }

    public static class Monster {
        String name;
        int attack, defense, hp, exp;

        public Monster(String name, int attack, int defense, int hp, int exp) {
            this.name = name;
            this.attack = attack;
            this.defense = defense;
            this.hp = hp;
            this.exp = exp;
        }
    }

    public static class Loc {
        int x, y;

        public Loc(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}
profile
더 나은 방법을 생각하고 고민합니다.

0개의 댓글