The Debugging Chronicles : "코드의 미학"

포켓몬 잡기 02 본문

Project

포켓몬 잡기 02

sweetseonah1004 2024. 7. 11. 11:36

몇일간의 조원들과의 회의와 코드 리뷰를 통해서 다음과 같이 코드가 변경되었다.

 

//함수 추가 전체코드
import java.util.*;

class Poketmon {
	String name; // 포켓몬 이름
	String type; // 포켓몬 속성타입
	int exp; // 현재 경험치
	int level; // 등급
	String sound; // 울음소리
	String skill; // 공격기술
	static Random rand = new Random(); //랜덤 함수 생성

	Poketmon(String type, String name, String sound, String skill) { // 멤버변수 초기화 설정
		this.name = name; 
		this.type = type; 
		this.exp = 0; 
		this.level = Poketmon.rand.nextInt(5) + 1;
		this.sound = sound;
		this.skill = skill;
	}

	void hello() {
		System.out.println("나와라 " + this.name + "! , " + this.sound + "~!");
	}

	void attack() {// 공격 성공 여부 출력 메서드
		/*
		 * 랜덤으로 받아와서 확률 비교후 50%로 boolean 값으로 반환 성공이면 포켓몬(name) 잡기 성공! 실패이면 “잡기
		 * 실패하였습니다.도망갑니다.”
		 */
		System.out.println(this.name + "(는)은 " + this.skill + "(을)를 사용했다.");
		if (Math.random() <= 0.5) {
			// 50%확율로 포켓몬을 잡기 위해 Math.random()으로 0.0~1.0 확인 후 0.5 이상이면 잡았다고 나오고 levelUp 실행
			// -> boolean값으로 반환하지 않고 그대로 출력하도록 수정
			levelUp();
		} else {
			System.out.println("포켓몬이 도망갔다..");
		}

	}

	void levelUp() {// 공격 성공에 대한 경험치 증가 및 레벨업 안내 메서드
		/* if(menu==1) while() 사용(유효성 검사 후 잘못된 값 입력 시, 재진행
		level 최대값 100,exp 최대값 100으로 설정
		if(exp ≥ 100) -100 반복 진행.(level++) 
		if(exp가 100보다 작으면, exp값 도출}
		 */
		int xp = rand.nextInt(451) + 50; // 랜덤 경험치 최소값50~최대값 500
		// 최대값은 500에서 50을 더하면 50~549이 되기에 경험치 랜덤값을 451로 지정
		int levelcnt = 0; // 얼마나 레벨이 올랐는지 확인시켜주기 위함
		this.exp += xp;
		System.out.println(xp + "경험치를 얻었다!(현재 경험치:" + this.exp + ")");
		while (true) {
			if (this.exp >= 100) { // 현재 경험치가 100이상이면
				this.exp -= 100; // 다시 비교를 위해 현재 경험치에 -100을 해서 다시 저장
				this.level++; // 경험치 100이 넘었으니 level값 추가
				levelcnt++;// 내가 현재 얻은 경험치+원래있던 경험치에서 얼마나 레벨업했는지 확인을 위함
				System.out.println("레벨업!");
			} else { // this.exp가 100미만이면 while문 종료
				break;
			}
		}
		
		if (levelcnt > 0) {//이름과 얼마나 업했는지 레벨 +현재 남은 경험치 출력
			// levelcnt가 0초과 시 레벨업 된 내용을 출력
			// 50~99(exp)까지의 값이 더 적으니 levelcnt 비교는 0초과되었을 때 출력
			System.out.println(this.name + "(은)는 " + levelcnt + "레벨업해서");
			System.out.println(this.level + "레벨이 되었다!(현재 경험치:" + this.exp + ")");
		}
	}

	@Override
	public String toString() {
		return "[" + this.name +" " + this.type+ "타입" + " Lv." + this.level + " exp:" + this.exp + "] ";
	}
}

class Fishking extends Poketmon { // 포켓몬 하위 클래스(잉어킹)

	Fishking() {// 잉어킹 타입, 이름, 울음소리, 공격기술
		super("물", "잉어킹", "쓲쓲", "몸통 박치기");
	}

}

class Diglett extends Poketmon { // 포켓몬 하위 클래스(디그다)

	Diglett() {// 디그다 타입, 이름, 울음소리, 공격기술
		super("땅", "디그다", "디그다~", "모래 뿌리기");
	}
	
}

class Purin extends Poketmon { // 포켓몬 하위 클래스(푸린)

	Purin() {// 푸린 타입, 이름, 울음소리, 공격기술
		super("노멀", "푸린", "푸우린~", "돌진");
	}

}

class Sixtail extends Poketmon { // 포켓몬 하위 클래스(식스테일)

	Sixtail() {
		super("불", "식스테일", "카우우~", "불꽃세레");
	}

}

public class PoketmonPlayGame {

	public static void collectBook(int count, Poketmon[] datas) {// 현재 보유한 포켓몬 전체 출력
		System.out.println("========메뉴 선택========");
		System.out.println("     <보유중인 포켓몬>  ");
		System.out.println("번호   타입  이름  레벨  경험치");
		for (int i = 0; i < count; i++) { // 배열의 시작부터 끝까지 확인하며
			System.out.println("No." + (i + 1) + " " + datas[i]); // 배열에 저장되어 있는 포켓몬을 출력
					// appearedPoketmon 이라는 함수를 선언 하고 randomPoketmon은 인자 값으로 메인에서 선언한 포켓몬 이름의 배열을 갖는다
					// 그 포켓몬이름의 배열을 poketmonname의 저장되어 있는 값의 배열넘버를 rand.nextInt()사용하여 랜덤으로 돌릴 수 있게 하였다.
					// 그 후 나온 배열의 값은 위에서 선언한 함수인 randomPoketmon으로 찾아가게 됩니다.
					// 예를들어 poketmonname[0]번은 식스테일이기 때문에 배열에 저장된 이름인 식스테일을 찾아간다.
					// 그리고 randomPoketmon의 인자값인 String poketmonname을 가지고 있기 때문에 밑에 배열에서 확인한 그에 맞는 이름을 찾아가고
					// 밑에 if 구문을 만나 그 이름에 맞는 힙메모리에 생성한 객체들을 찾아가게 됩니다.
					// 생성된 객체들을 System.out.println()에서 datas[i]로 출력이 되게 하고
					// 이때 생성된 객체는 toString을 기본으로 출력하게 된다.
					// 이를 없애기 위해 최상위 클래스인 Object의 메서드인 toString을 오버라이딩 하여 주소값 대신 보여주고 싶은 것을 출력하게 하였다
		}	System.out.println("======================");
	}

	public static boolean isEmpty(int count) {// 잡은 포켓몬이 없을 때(無)
		if (count <= 0) {
			System.out.println("잡은 포켓몬이 없습니다..");
			return true;
		}
		return false;
	}

	public static boolean isFull(int count, Poketmon[] datas) { // 잡은 포켓몬 수가 저장가능 공간을 초과할 때
		if (count >= datas.length) {
			System.out.println("저장가능한 공간이 없습니다!");
			return true;
		}
		return false;
	}

	public static boolean selectColect(int selection, int count) { // 유효성 검사 데이터
		//사용자가 선택한 값이 등록된 포켓몬 수보다 작거나 같고, 선택한 값이 0보다 커야, 즉 1개 이상이어야 true를 반환함.
		if (selection <= count && selection > 0) { // 사용자가 입력한 값일 때
			return true; //참이면 true
		}
		return false; // 유효한 값 외에 있을 때
	}
	
	public static Poketmon randomPoketmon(String poketmonname) { 
	  // 선택한 포켓몬의 경험치와 레벨업 진행에 있어, 도감 목록에 중복 캐릭터가 있을 시, 
	  // 동일 캐릭터가 함께 레벨업과 경험치 증가되는 오류 해결하고자 만든 함수. 배열 내 값이 각 고유한 값임을 명시함.
	  if("식스테일".equals(poketmonname)) {// 만약 받아온 포켓몬이 식스테일이라면 new Sixttail 객체를 반환해줌
			return new Sixtail();
		}
		else if("푸린".equals(poketmonname)) {
			return new Purin();
		}
		else if("디그다".equals(poketmonname)) {
			return new Diglett();
		}
		else { //마지막 포켓몬인 잉어킹이 나오도록 설정
			return new Fishking();
		}
	}

	public static void main(String[] args) { // 메인 실행 함수
		Random rand = new Random();
		Scanner sc = new Scanner(System.in);
		// 2024-07-08 2차 회의로 삭제 : 겹치는 변수
		// String[] datas=new String[100];//저는 포켓몬 데이터로 했을 때 작동가능. 임의 데이터 입력 시, 오류 발생해서
		// 일단 임의 데이터로 다른 값 정상 작동하는 지 확인 한 후,
		// 임의 값 지워서 사용자 입력값에 따라 울음소리가 출력될 수 있도록 진행할 필요가 있을 거 같아요~
		Poketmon[] datas = new Poketmon[100];
		String[] poketmonname = {"식스테일","푸린","디그다","잉어킹"};
		int count = 0; // 도감에 있는 포켓몬 개수
		int menu; //메인 메뉴
		int selection; //도감에 있는 포켓몬 선택(번호)
		while (true) {
			// 2024-07-08 2차 회의로 랜덤 포켓몬 출력은 vspoketmon 변수로 사용.
			//Poketmon[] vspoketmon = { new Sixtail(), new Purin(), new Diglett(), new Fishking()};
			// 2024-07-09 회의 진행하여 개발자메모리 과다 생성으로 randomPoketmon함수로 빼두었음
			// randomPoketmon -> 불러오기위해 문자열로 poketmonname 배열을 추가함
			//사용예시로 변수를 선언해봄
			//Poketmon apearedPoketmon = randomPoketmon(poketmonname[rand.nextInt(poketmonname.length)]);
			
			System.out.println("========메뉴 선택========");
			System.out.println("1. 게임하기");
			System.out.println("2. 전체상태출력");
			System.out.println("3. 울음소리듣기");
			System.out.println("4. 포켓몬잡기");
			System.out.println("0. 게임종료");
			System.out.println("======================");

			menu = sc.nextInt();
			if (menu == 0) { // 게임종료
				break;

			} else if (menu == 1) {// 게임하기
				if (isEmpty(count)) { // 현재 배열에 값이 없다면 처음으로 돌려보넴
					continue;
				}
				collectBook(count, datas);
				while (true) {
					System.out.print("포켓몬을 선택해주세요. >>");// 포켓몬을 잘못 선택할 수 있으니 유효성 검사로 확인
					selection = sc.nextInt(); // 포켓몬을 잘못 선택할 수 있으니 유효성 검사로 확인
					if (selectColect(selection, count)) {// 유효한 값을 입력했을때
						break;
					}
				}
				datas[selection-1].hello(); // 선택한 포켓몬 출력
				
				// 야생에 포켓몬 랜덤으로 보여주기
				System.out.println("=================================");
				//randomPoketmon 함수는 포켓몬 하위 객체를 반환하고 인자값으로 문자열을 받기위해 포켓몬 이름이 들어있는 문자열배열을 추가로 선언해주었습니다.
				//랜덤 포켓몬을 출력하기 위해 랜덤함수 입력값으로 포켓몬 이름이 들어있는 배열에 개수를 입력해준다.
				System.out.println("야생의 " + randomPoketmon(poketmonname[rand.nextInt(poketmonname.length)]) + " 나타났다!");
				System.out.println("■       ■ □□□□□");
				System.out.println(" ■     ■  □    ");
				System.out.println("  ■   ■   □□□□□");
				System.out.println("   ■ ■        □");
				System.out.println("    ■     □□□□□");
				System.out.println("내 포켓몬 "+datas[selection-1]);
				System.out.println("=================================");
				while (true) {
					System.out.println("1. 사냥하기");
					System.out.println("2. 도망가기");
					menu = sc.nextInt();

					if (menu == 1) { // 선택한 메뉴중 사냥하기가 선택되면 attack을 실행하여 확인시켜줌
						datas[selection-1].attack();
					} else if (menu == 2) {// 도망을 선택하면 도망갔다고 확인시켜줌
						System.out.println("도망을 선택했다...");
					} else {
						System.out.println("정확한 메뉴를 선택해주세요.");
						continue;// 잘못된 입력을 했으니 사냥 while로 반환
					}
					break;// 사냥 while 종료
				}
			} else if (menu == 2) {
				if (isEmpty(count)) { // 저장되어 있는 데이터가 없는 경우 메인화면으로
					continue;
				}
				collectBook(count, datas);

			} else if (menu == 3) {// 해당 캐릭터 선택 시 울음소리 듣기
				if (isEmpty(count)) {// 저장되어 있는 데이터가 없는 경우, 메인화면으로
					continue;
				}

				collectBook(count, datas);
				while (true) {
					System.out.print("포켓몬을 선택해주세요. >>");// 포켓몬을 잘못 선택할 수 있으니 유효성 검사로 확인
					selection = sc.nextInt(); // 사용자 포켓몬 번호 선택
					if (selectColect(selection, count)) {// 유효한 값을 입력했을때. 
						break;//while 종료. 아래 울음소리 출력.
					}//유효하지 않은 값 입력 시, while 반복 진행(포켓몬 재선택 요청)
				}
				datas[selection-1].hello();// selection = datas[selection-1]값(캐릭터 이름) ex. datas[0]=>고유번호 1
			
				
			} else if (menu == 4) {
				if (isFull(count, datas)) {//잡은 포켓몬수가 저장공간을 초과할 때 유효성 검사 진행
					continue;
				}
				// 랜덤으로 만난 캐릭터
				
				// 메뉴 1번과 같이 poketmonname[rand.nextInt(poketmonname.length)]로 풀어서 쓴다면 반복 사용되면서
				// 데이터가 중복되어서 다른 랜덤 값이 나올 수 있기 때문에 이를 피하기 위해서 appearedPoketmon으로 변수에 저장해서 값을 저장해서 사용했습니다.
	
				// 잘못된 메뉴를 선택하지 않았는지 확인하기 위해서 while문을 사용.
				while(true) {
					Poketmon appearedPoketmon = randomPoketmon(poketmonname[rand.nextInt(poketmonname.length)]);
					System.out.println("====================================");
					System.out.println(appearedPoketmon.name + "(이)가 나타났습니다.!!");
					System.out.println("====================================");
					System.out.println("포켓몬을 잡는다면 1번, 도망가고 싶다면 2번 숫자를 넣어주세요! >>> ");
					int ans = sc.nextInt();
					if (ans == 1) {
						System.out.println("====================================");
						System.out.println(" ■■■■■■■");
						System.out.println("■■■■■■■■■");
						System.out.println("■■■■@■■■■");
						System.out.println("□□□□□□□□□");
						System.out.println(" □□□□□□□");
						System.out.println("====================================");
						// datas에 담긴 값은 Poketmon 클래스로 인스턴스화 된 객체이므로
						// 객체의 이름을 출력하기 위해서는 .name을 해주어야 한다.
						System.out.println("축하합니다!" + appearedPoketmon.name + "(을)를 잡으셨습니다!!");
						System.out.println("====================================");
						datas[count++] = appearedPoketmon;
						break;
						// 도망가시겠습니까를 선택했을 경우
					} else if (ans == 2) {
						System.out.println("====================================");
						System.out.println("도망~~~~~");
						System.out.println("====================================");
						// 1,2번 외에 번호를 입력했을 경우
						continue;
					} else {
						System.out.println("====================================");
						System.out.println("번호를 잘못 입력하셨습니다");
						System.out.println("====================================");
						continue;
					}
				}
			}
		}
	}
}

 

>>>아쉬운 점

1.  selectcolect 함수를 절반만 뺴서 완성 한것.

while (true) {
    System.out.print("포켓몬을 선택해주세요. >>");// 포켓몬을 잘못 선택할 수 있으니 유효성 검사로 확인
    selection = sc.nextInt(); // 포켓몬을 잘못 선택할 수 있으니 유효성 검사로 확인
    if (selectColect(selection, count)) {// 유효한 값을 입력했을때
        break;
    }
}
datas[selection-1].hello(); // 선택한 포켓몬 출력

 위 와 같은 내용이 메뉴 1번과 3번에서 동일하게 반복되는데 내용을 다 빼지 못했다.

	public static boolean selectColect(int selection, int count) { // 유효성 검사 데이터
		//사용자가 선택한 값이 등록된 포켓몬 수보다 작거나 같고, 선택한 값이 0보다 커야, 즉 1개 이상이어야 true를 반환함.
		if (selection <= count && selection > 0) { // 사용자가 입력한 값일 때
			return true; //참이면 true
		}
		return false; // 유효한 값 외에 있을 때
	}

함수가 절반만 완성된 느낌....