diff --git a/README.md b/README.md index 93db812c..5f766d40 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,27 @@ # 미션 - 보스 몬스터 잡기 +## ✔️ 구현사항 + +- 플레이어 클래스 구현 + - [X] HP, MP + - [X] 물리 공격, 마법 공격 + - [X] 상태 업데이트 메서드 +- 보스몬스터 클래스 구현 + - [X] HP, MP + - [X] 랜덤 데미지 공격 + - [X] 상태 업데이트 메서드 + - [X] 몬스터 그림 GUI 구현 +- 입력 예외처리 구현 + - [X] Exception Class + - [X] 게임 초기 설정 예외처리 + - [X] 게임 중간 공격 입력 예외처리 +- 로직 구현 + - [X] 게임 core 로직 구현 + - [X] 디버깅&테스트 +- 인터페이스 구현 + - [X] 게임 진행상태 안내 메시지 UI + + ## 🔍 진행방식 - 미션은 **기능 요구사항, 프로그래밍 요구사항, 과제 진행 요구사항** 세 가지로 구성되어 있습니다. diff --git a/src/main/java/bossmonster/Main.java b/src/main/java/bossmonster/Main.java index d9488c65..3e8edfa8 100644 --- a/src/main/java/bossmonster/Main.java +++ b/src/main/java/bossmonster/Main.java @@ -1,7 +1,10 @@ package bossmonster; +import bossmonster.controller.GameUI; + public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); + public static void main(String[] args) throws Exception { + GameUI gameUI = new GameUI(); + gameUI.execute(); } } diff --git a/src/main/java/bossmonster/controller/GameUI.java b/src/main/java/bossmonster/controller/GameUI.java new file mode 100644 index 00000000..475f2f1e --- /dev/null +++ b/src/main/java/bossmonster/controller/GameUI.java @@ -0,0 +1,91 @@ +package bossmonster.controller; + +import bossmonster.exception.InvalidBossHPException; +import bossmonster.exception.InvalidPlayerHpMpException; +import bossmonster.exception.InvalidPlayerNameException; +import bossmonster.service.GameService; +import java.util.Scanner; + +public class GameUI { + private final Scanner sc; + private Integer bossHp, playerHp, playerMp; + private String playerName; + + public GameUI() { + this.sc = new Scanner(System.in); + this.setBossHp(); + this.setPlayerName(); + this.setPlayerHpMp(); + } + + private void setBossHp() { + System.out.println("! Welcome to Boss Monster Game !"); + while(true) { + try { + System.out.println("보스 몬스터의 HP를 입력해주세요. (100이상 300이하)"); + this.bossHp = this.sc.nextInt(); + + if(this.bossHp < 100 || this.bossHp > 300) + throw new InvalidBossHPException(); + + return; + } catch (InvalidBossHPException e) { + System.out.println("\n[ERROR] 유효한 보스 HP 값을 입력해주세요."); + } + } + } + + private void setPlayerName() { + while(true) { + try { + System.out.println("플레이어의 이름을 입력해주세요. (5자 이내)"); + this.playerName = this.sc.next(); + + if(this.playerName.length() > 5) + throw new InvalidPlayerNameException(); + + this.sc.nextLine(); + return; + } catch (InvalidPlayerNameException e) { + System.out.println("\n[ERROR] 올바른 플레이어 이름을 입력해주세요."); + } + } + } + + private void setPlayerHpMp() { + while(true) { + String playerStatInput; + try { + System.out.println("플레이어의 HP와 MP를 입력해주세요.(,로 구분 / HP와 MP의 합 최대 200 이내)"); + playerStatInput = this.sc.nextLine(); + + if(!playerStatInput.matches("^[0-9]{1,3},[0-9]{1,3}$")) // 콤마 앞뒤로 숫자 3자리 이내 + throw new IllegalArgumentException(); + + } catch (IllegalArgumentException e) { + System.out.println("\n[ERROR] 유효한 형태의 HP, MP 값을 입력해주세요 (Ex. 100,100)"); + continue; + } + + try { + String[] playerStat = playerStatInput.split(","); + this.playerHp = Integer.parseInt(playerStat[0]); + this.playerMp = Integer.parseInt(playerStat[1]); + + if(this.playerHp + this.playerMp > 200) + throw new InvalidPlayerHpMpException(); + } catch (InvalidPlayerHpMpException e) { + e.getStackTrace(); + System.out.println("\n[ERROR] 유효한 형태의 HP, MP 값을 입력해주세요 (Ex. 100,100)"); + continue; + } + + return; + } + } + + public void execute() { + GameService gameService = new GameService(this.bossHp, this.playerName, this.playerHp, this.playerMp); + gameService.play(); + } +} \ No newline at end of file diff --git a/src/main/java/bossmonster/domain/Boss.java b/src/main/java/bossmonster/domain/Boss.java new file mode 100644 index 00000000..325e5d6f --- /dev/null +++ b/src/main/java/bossmonster/domain/Boss.java @@ -0,0 +1,72 @@ +package bossmonster.domain; + +import java.util.Random; + +public class Boss { + private final Integer maxHp; + private Integer currentHp; + + public Boss(Integer hp) { + this.maxHp = hp; + this.currentHp = hp; + printStat(); + printFigure(1); + } + + public Integer getHp() { return this.currentHp; } + + public void printStat() { + System.out.println("\n======================================"); + System.out.println("BOSS HP [" + this.currentHp + "/" + this.maxHp + "]"); + System.out.println("______________________________________"); + } + + public void printFigure(final Integer figureType) { + if(figureType == 1) { //initial + System.out.println( + " ^-^\n" + + " / 0 0 \\\n" + + "( \" )\n" + + " \\ - /\n" + + " - ^ - " + ); + System.out.println("______________________________________"); + return; + } + if(figureType == 0) { //damaged + System.out.println( + " ^-^\n" + + " / X X \\\n" + + "( \"\\ )\n" + + " \\ - /\n" + + " - ^ - " + ); + System.out.println("______________________________________"); + return; + } + + System.out.println( //lose + " ^-^\n" + + " / ^ ^ \\\n" + + "( \"\\ )\n" + + " \\ 3 /\n" + + " - ^ - " + ); + System.out.println("______________________________________"); + } + + public void decreaseHp(final Integer hp) { + if(this.currentHp - hp < 0) { + this.currentHp = 0; + return; + } + + this.currentHp -= hp; + } + + public Integer attack() { + Random random = new Random(); + random.setSeed(System.currentTimeMillis()); + return random.nextInt(20); + } +} \ No newline at end of file diff --git a/src/main/java/bossmonster/domain/Player.java b/src/main/java/bossmonster/domain/Player.java new file mode 100644 index 00000000..f001b51b --- /dev/null +++ b/src/main/java/bossmonster/domain/Player.java @@ -0,0 +1,55 @@ +package bossmonster.domain; + +import bossmonster.exception.NoMPException; + +public class Player { + private final String name; + private final Integer maxHp; + private Integer currentHp; + private final Integer maxMp; + private Integer currentMp; + + public Player(String name, Integer hp, Integer mp) { + this.name = name; + this.maxHp = hp; + this.currentHp = hp; + this.maxMp = mp; + this.currentMp = mp; + printStat(); + } + + public String getName() { return name; } + + public Integer getHp() { return currentHp; } + + public void printStat() { + System.out.println(this.name + " HP [" + this.currentHp + "/" + this.maxHp + "]" + + " MP [" + this.currentMp + "/" + this.maxMp + "]"); + System.out.println("======================================\n"); + } + + public void decreaseHp(final Integer hp) { + if(this.currentHp - hp < 0) { + this.currentHp = 0; + return; + } + + this.currentHp -= hp; + } + + public Integer physicalAttack() { + if(this.currentMp + 10 > this.maxMp) + this.currentMp = this.maxMp; + else this.currentMp += 10; + + return 10; + } + + public Integer magicalAttack() throws NoMPException { + if(currentMp < 30) + throw new NoMPException(); + + this.currentMp -= 30; + return 20; + } +} \ No newline at end of file diff --git a/src/main/java/bossmonster/exception/InvalidBossHPException.java b/src/main/java/bossmonster/exception/InvalidBossHPException.java new file mode 100644 index 00000000..a6ea0526 --- /dev/null +++ b/src/main/java/bossmonster/exception/InvalidBossHPException.java @@ -0,0 +1,5 @@ +package bossmonster.exception; + +public class InvalidBossHPException extends RuntimeException { + public InvalidBossHPException() { } +} diff --git a/src/main/java/bossmonster/exception/InvalidPlayerHpMpException.java b/src/main/java/bossmonster/exception/InvalidPlayerHpMpException.java new file mode 100644 index 00000000..a0ee864d --- /dev/null +++ b/src/main/java/bossmonster/exception/InvalidPlayerHpMpException.java @@ -0,0 +1,5 @@ +package bossmonster.exception; + +public class InvalidPlayerHpMpException extends RuntimeException { + public InvalidPlayerHpMpException() { } +} diff --git a/src/main/java/bossmonster/exception/InvalidPlayerNameException.java b/src/main/java/bossmonster/exception/InvalidPlayerNameException.java new file mode 100644 index 00000000..84546efe --- /dev/null +++ b/src/main/java/bossmonster/exception/InvalidPlayerNameException.java @@ -0,0 +1,5 @@ +package bossmonster.exception; + +public class InvalidPlayerNameException extends RuntimeException { + public InvalidPlayerNameException() { } +} diff --git a/src/main/java/bossmonster/exception/NoMPException.java b/src/main/java/bossmonster/exception/NoMPException.java new file mode 100644 index 00000000..71af9ebb --- /dev/null +++ b/src/main/java/bossmonster/exception/NoMPException.java @@ -0,0 +1,5 @@ +package bossmonster.exception; + +public class NoMPException extends RuntimeException { + public NoMPException() { } +} diff --git a/src/main/java/bossmonster/service/GameService.java b/src/main/java/bossmonster/service/GameService.java new file mode 100644 index 00000000..1c9cc389 --- /dev/null +++ b/src/main/java/bossmonster/service/GameService.java @@ -0,0 +1,87 @@ +package bossmonster.service; + +import bossmonster.domain.Boss; +import bossmonster.domain.Player; +import bossmonster.exception.NoMPException; +import java.util.Scanner; + +public class GameService { + private final Scanner sc = new Scanner(System.in); + private final Player player; + private final Boss boss; + + private int attackNum = 0; + + public GameService(final Integer bossHp, final String playerName, final Integer playerHp, final Integer playerMp) { + System.out.println("\n보스 레이드를 시작합니다.\n"); + this.boss = new Boss(bossHp); + this.player = new Player(playerName, playerHp, playerMp); + } + + public void play() { + while(true) { + boss.decreaseHp(playerAttack()); + player.decreaseHp(bossAttack()); + attackNum += 1; + + if(boss.getHp() <= 0) { + this.win(); + break; + } + if(player.getHp() <= 0) { + this.lose(); + break; + } + + boss.printStat(); + boss.printFigure(0); + player.printStat(); + } + } + + public Integer playerAttack() { + Integer attackType, damage; + + while(true) { + try { + System.out.println("어떤 공격을 하시겠습니까? 공격 번호를 입력해주세요."); + System.out.println("1. 물리 공격\n2. 마법 공격"); + attackType = sc.nextInt(); + + if(attackType == 1) { + damage = player.physicalAttack(); + System.out.println("\n물리 공격을 했습니다. (입힌 데미지: " + damage + ")"); + return damage; + } + + if(attackType == 2) { + damage = player.magicalAttack(); + System.out.println("\n마법 공격을 했습니다. (입힌 데미지: " + damage + ")"); + return damage; + } + } catch (NoMPException e) { + System.out.println("\n[ERROR] MP가 부족합니다. 다른 공격 방법을 선택해주세요."); + } + } + } + + public Integer bossAttack() { + Integer damage; + + damage = boss.attack(); + System.out.println("보스가 공격했습니다. (입힌 데미지: " + damage + ")"); + return damage; + } + + public void win() { + System.out.println("\n" + player.getName() + " 님이 " + attackNum + "번의 전투 끝에 보스 몬스터를 잡았습니다."); + } + + public void lose() { + boss.printStat(); + boss.printFigure(-1); + player.printStat(); + System.out.println(player.getName() + "의 HP가 0이 되었습니다."); + System.out.println("보스 레이드에 실패하셨습니다."); + } +}