The Debugging Chronicles : "코드의 미학"
포켓몬 잡기 03 본문
//함수 추가 전체코드
package poketmon;
//함수 추가 전체코드
import java.util.*;
class Poketmon {
String name; // 포켓몬 이름
String type; // 포켓몬 속성타입
int exp; // 현재 경험치
int level; // 등급
static Random rand = new Random(); //랜덤 함수 생성
Poketmon(String type, String name) { // 멤버변수 초기화 설정
this.name = name;
this.type = type;
this.exp = 0;
this.level = Poketmon.rand.nextInt(5) + 1;
}
void hello() {
System.out.println("나와라 " + this.name + "! , " +"울음소리" + "~!");
}
void attack() {// 공격 성공 여부 출력 메서드
/*
* 랜덤으로 받아와서 확률 비교후 50%로 boolean 값으로 반환 성공이면 포켓몬(name) 잡기 성공! 실패이면 “잡기
* 실패하였습니다.도망갑니다.”
*/
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 { // 포켓몬 하위 클래스(잉어킹)
String sound; // 울음소리
String skill; // 공격기술
Fishking() {// 잉어킹 타입, 이름, 울음소리, 공격기술
this("몸통 박치기");
}
Fishking(String skill){
super("물", "잉어킹");
this.sound = "쓱쓱";
this.skill = skill;
}
@Override
void hello() {
// TODO Auto-generated method stub
System.out.println("나와라 " + this.name + "! , " + this.sound + "~!");
}
@Override
void attack() {
// TODO Auto-generated method stub
System.out.println(this.name + "(는)은 " + this.skill + "(을)를 사용했다.");
super.attack();
}
}
class Diglett extends Poketmon { // 포켓몬 하위 클래스(디그다)
String sound;
String skill;
Diglett() {// 디그다 타입, 이름, 울음소리, 공격기술
this("모래 뿌리기");
}
Diglett(String skill){
super("땅", "디그다");
this.sound = "디그다~";
this.skill = skill;
}
@Override
void hello() {
// TODO Auto-generated method stub
System.out.println("나와라 " + this.name + "! , " + this.sound + "~!");
}
@Override
void attack() {
// TODO Auto-generated method stub
System.out.println(this.name + "(는)은 " + this.skill + "(을)를 사용했다.");
super.attack();
}
}
class Purin extends Poketmon { // 포켓몬 하위 클래스(푸린)
String sound;
String skill;
Purin(){
this("돌진");
}
Purin(String skill) {// 푸린 타입, 이름, 울음소리, 공격기술
super("노멀", "푸린");
this.sound = "푸우린~";
this.skill = skill;
}
@Override
void hello() {
// TODO Auto-generated method stub
System.out.println("나와라 " + this.name + "! , " + this.sound + "~!");
}
@Override
void attack() {
// TODO Auto-generated method stub
System.out.println(this.name + "(는)은 " + this.skill + "(을)를 사용했다.");
super.attack();
}
}
class Sixtail extends Poketmon { // 포켓몬 하위 클래스(식스테일)
String sound;
String skill;
Sixtail (){
this( "불꽃세레");
}
Sixtail(String skill) {
super("불", "식스테일");
this.sound = "카우우~";
this.skill = skill;
}
@Override
void hello() {
// TODO Auto-generated method stub
System.out.println("나와라 " + this.name + "! , " + this.sound + "~!");
}
@Override
void attack() {
// TODO Auto-generated method stub
System.out.println(this.name + "(는)은 " + this.skill + "(을)를 사용했다.");
super.attack();
}
}
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 if("잉어킹".equals(poketmonname)){ //마지막 포켓몬인 잉어킹이 나오도록 설정
return new Fishking();
}
return null;
}
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("=================================");
int ans;
while (true) {
System.out.println("1. 사냥하기");
System.out.println("2. 도망가기");
ans = sc.nextInt();
if (ans == 1) { // 선택한 메뉴중 사냥하기가 선택되면 attack을 실행하여 확인시켜줌
datas[selection-1].attack();
} else if (ans == 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번 외에 번호를 입력했을 경우
} else {
System.out.println("====================================");
System.out.println("번호를 잘못 입력하셨습니다");
System.out.println("====================================");
break;
}
}
}
}
}
}
변경 사항
1. 면접 시, 주관있게
2. 복사기능 새로 생성하는 것 차이 아는지?
3. 랜덤 포켓몬 어떻게 생성되었는지 인지하는지?
4. 랜덤 포켓몬 잉어킹 - return null 혹은 새로운 기본 객체 ex. 푸린하여 설정하거나(마지막)
5. 메뉴 4번에서 continue 빼기
6. 재사용성보다 사용자 편리성 고려하기(menu)
7. 하위 객체 오버라이딩이 더 좋음.
8. 현재 코드는 강제성을 부여한 상황임. (4개)
9. 데이터 값이 늘어날 경우, 하위 객체에 생성하는 게 더 용이하기에 이후 설정에 대한 고려가 함께 프로그램 짤 때 이뤄져야 함.
'Project' 카테고리의 다른 글
중간 프로젝트 기능 발표를 위한 PPT 작업 (0) | 2024.09.25 |
---|---|
[Team Project - 코마] 중중프 완료 (0) | 2024.08.30 |
쇼핑몰 프로그램을 MVC 패턴으로 구현하기 (0) | 2024.07.24 |
포켓몬 잡기 02 (2) | 2024.07.11 |
포켓몬 잡기 01 (0) | 2024.07.08 |