public class NumberUtilManager {
// 정답, 유저입력 숫자 저장 List
private final Set<Integer> numSet = new HashSet<>();
private final List<Integer> numList = new ArrayList<>();
private final List<Integer> userNumList = new ArrayList<>();
Scanner sc = new Scanner(System.in);
// 게임 시작시 3개의 숫자를 생성. Set으로 중복을 제거하고 List로 변환시켜 셔플.
public void addNum() {
numSet.clear();
numList.clear();
while (numSet.size() < 3) {
// random 메소드를 통해 1~9 숫자 생성
numSet.add((int) (Math.random() * 9) + 1);
}
numList.addAll(numSet);
Collections.shuffle(numList);
System.out.println("< 게임을 시작합니다 >");
}
서로 다른 중복되지않는 3자리숫자 , 1~9 의 숫자(Math.random() * 9) + 1) 메소드를 이용하여 1~9의 숫자를 랜덤으로 받아 Set의 저장한다. Set의 저장하는 이유는 중복을 허용하지 않기 때문.Collections.shuffle(numList) 을 통해 생성된 3자리의 숫자를 랜덤하게 섞어준다.
// 유저에게 숫자를 연속된 문자열을 입력받아 List 저장
public void inputNum() {
// 외부에서 반복시 저장되어있던 값 삭제
userNumList.clear();
while (userNumList.size() < 3) {
System.out.println("숫자를 3자리로 입력하세요.");
userNumList.clear();
String userNum = sc.nextLine();
// 입력값 유효성 검사
if (userNum.length() >= 4) {
System.out.println("숫자를 3자리로 입력해주세요.");
} else {
// 문자열을 나누어서 각각의 int 타입 숫자로 일의 자릿수로 저장,
for (int i = 0; i < userNum.length(); i++) {
char c = userNum.charAt(i);
// 입력값 유효성검사.
if (userNumList.contains(Character.getNumericValue(c)) || Character.getNumericValue(c) == 0 || !Character.isDigit(c)) {
System.out.println("올바르지 않은 입력값입니다.");
userNumList.clear();
break;
} else {
// 올바른 데이터일 경우 List add
userNumList.add(Character.getNumericValue(c));
}
}
}
}
}
중복되지않은 3자리숫자 , 숫자 외 입력 불가while() 반복문을 통하여 유저에게 3자리 숫자를 한개의 문자열로 입력받아 4자리 미만인지 확인 후 문자열을 분해하여 1개의 문자를 유효성검사를 진행한다.if (userNumList.contains(Character.getNumericValue(c)) || Character.getNumericValue(c) == 0 || !Character.isDigit(c)) 조건문을 통해 중복값이 있는지, 0이 포함되있는지, 숫자외 문자인지 검사 한 뒤 userNumList 에 저장한다.
// Strike 와 Ball 의 갯수를 집계하는 메소드
public int judgeStrikesAndBalls() {
printAnswerLog();
int stkcnt = 0;
int ballcnt = 0;
nm.inputNum();
userList = nm.getUserNum();
for (int i = 0; i < numList.size(); i++) {
if (numList.get(i) == userList.get(i)) {
stkcnt++;
} else {
for (int j = 0; j < numList.size(); j++) {
if (userList.get(i) == numList.get(j)) {
ballcnt++;
}
}
}
}
dm.printScoreBoard(stkcnt, ballcnt);
return stkcnt;
}
public class DisplayManger {
// 게임의 상황을 출력해주는 메소드
public void printScoreBoard(int stkcnt, int ballcnt) {
if (stkcnt == 3) {
System.out.println("정답입니다.");
} else if (stkcnt >= 1 || ballcnt >= 1) {
System.out.println(stkcnt + "스트라이크 " + ballcnt + " 볼");
} else {
System.out.println("아웃");
}
}
}
요구조건 :

앞에선 입력한 유저입력값이 정해져있는 List를 userList = nm.getUserNum(); 로 받아와서 반복문을 통해 정답값List와 유저값List를 전체순회하여 해당 숫자가 스트라이크, 볼, 아웃을 카운트 하여 DisplayManger 에게 전달하여 값을 콘솔로 출력함.

// 게임의 승패를 판정하는 메소드
public void judge(List<Integer> nums) {
judgeflag = !judgeflag;
while (judgeflag) {
numList = nums;
// 3개이상의 strike 시 게임승리
if (judgeStrikesAndBalls() == 3) {
judgeflag = !judgeflag;
}
}
}
정답을 맞출때까지 게임을 계속플레이while() 반복문을 이용하여 유저가 정답을 전부 맞출때까지 계속해서 플레이하게 유도.
// 유저에게 숫자를 연속된 문자열을 입력받아 List 저장
public void inputNum() {
// 외부에서 반복시 저장되어있던 값 삭제
userNumList.clear();
while (userNumList.size() < 3) {
System.out.println("숫자를 3자리로 입력하세요.");
userNumList.clear();
String userNum = sc.nextLine();
// 입력값 유효성 검사
if (userNum.length() >= 4) {
System.out.println("숫자를 3자리로 입력해주세요.");
} else {
// 문자열을 나누어서 각각의 int 타입 숫자로 일의 자릿수로 저장,
for (int i = 0; i < userNum.length(); i++) {
char c = userNum.charAt(i);
// 입력값 유효성검사.
if (userNumList.contains(Character.getNumericValue(c)) || Character.getNumericValue(c) == 0 || !Character.isDigit(c)) {
System.out.println("올바르지 않은 입력값입니다.");
userNumList.clear();
break;
} else {
// 올바른 데이터일 경우 List add
userNumList.add(Character.getNumericValue(c));
}
}
}
}
}
3자리수 , 중복불가 , 숫자 외 문자입력불가 if (userNumList.contains(Character.getNumericValue(c)) || Character.getNumericValue(c) == 0 || !Character.isDigit(c)) 조건문을 통해 입력값 유효성 검사. // 게임 시작시 메인메뉴 출력
public void printMainMenu() {
System.out.println("환영합니다! 원하시는 번호를 입력해주세요.");
System.out.println("1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기");
}
// MainMenu 선택에 따른 행동흐름 제어
private void controlMainMenuSelection() {
switch (MainmenuType.find(sc.nextLine())) {
case YES:
nm.addNum();
gm.judge(nm.getNumber());
break;
case HISTORY:
break;
case EXIT:
System.out.println("게임을 종료합니다.");
System.exit(0);
break;
}
}
public enum MainmenuType {
YES("1"),
HISTORY("2"),
EXIT("3");
// 프로그램이 실행되면 Map을 캐싱해 찾고자 하는 키값과 필드값을 매칭 스트림과 람다식을 활용.
private static final Map<String, MainmenuType> MAINMENU_TYPE_MAP_MAP =
Collections.unmodifiableMap(Stream.of(values()).collect(Collectors.toMap(MainmenuType::getMainmenu, Function.identity())));
private final String mainmenu;
// 생성자를 통한 String 매칭
MainmenuType(String mainmenu) {
this.mainmenu = mainmenu;
}
// 입력된 연산자를 통해 Map 안에서 열거 객체 리턴
public static MainmenuType find(String mainmenu) {
if (MAINMENU_TYPE_MAP_MAP.containsKey(mainmenu)) {
return MAINMENU_TYPE_MAP_MAP.get(mainmenu);
} else {
// 지정메뉴외 문자 입력시 예외발생
throw new NullPointerException("메뉴중에서 입력해주세요.");
}
}
public String getMainmenu() {
return mainmenu;
}
}
1을 입력시 게임시작 , 2를 입력시 기록확인 (Lv.3 추가기능) , 3을 입력시 게임종료enum MainmenuType Class 를 선언, switch (MainmenuType.find(sc.nextLine())) 조건문을 통해 유저가 입력한 필드값을 이용해 Eunm 열거상수를 받아 요구조건의 메뉴 기능 흐름을 따라간다.
// 게임의 승패판정 및 게임시도횟수 집계 메소드
public void judge(List<Integer> nums) {
judgeflag = !judgeflag;
while (judgeflag) {
numList = nums;
// 3개이상의 strike 시 게임승리
if (judgeStrikesAndBalls() == 3) {
gamecnt++;
gameCountList.add(gamecnt);
gamecnt = 0;
judgeflag = !judgeflag;
} else {
gamecnt++;
}
}
}
// MainMenu 선택에 따른 행동흐름 제어
private void controlMainMenuSelection() {
switch (MainMnuType.find(sc.nextLine())) {
case YES:
nm.addNum();
gm.judge(nm.getNumber());
break;
case HISTORY:
dm.printGameLog(gm.getGameCountList());
break;
case EXIT:
System.out.println("< 숫자 야구 게임을 종료합니다 >");
System.exit(0);
break;
}
}
// 현재까지 진행한 게임 시도횟수
public void printGameLog(List<Integer> gameLogList) {
// 진행된 게임 기록이 있는지 유효성 검사
if (gameLogList.isEmpty()) {
System.out.println("진행된 게임 기록이 없습니다.");
} else {
int gameCnt = 0;
System.out.println("<게임 기록 보기>");
// 패싱 받은 List 를 전체반복하며 유저 게임횟수 출력
for (int item : gameLogList) {
System.out.println(++gameCnt + " 번째 게임 : 시도횟수 - " + item);
}
}
}
현재 게임횟수 출력 , 사용자가 정답까지 도달한 횟수 출력judge() 메소드 안에서 반복문이 실행되며 유저가 정답에 도달하기전과 도달직후 횟수를 증가 및 List 에 저장.printGameLog() 메소드의 반복문을 통해 게임횟수 및 시도횟수를 출력. List가 비어있을시 예외처리.
// 유저 난이도 조절 메소드
public void setDifficulty() {
System.out.println("설정하고자 하는 자리수를 입력하세요.");
System.out.println("기본 난이도는 3 자리수 입니다.");
System.out.println("3, 4, 5 자리수 난이도만 설정이 가능합니다.");
while (true) {
String input = sc.nextLine();
// 3,4,5 외 숫자,문자 검증
if (input.matches("[3-5]+")) {
difficulty = Integer.parseInt(input);
System.out.println(difficulty + " 자리수 난이도로 설정되었습니다.");
break;
} else {
System.out.println("3,4,5 난이도만 선택이 가능합니다.");
}
}
}
// MainMenu 선택에 따른 행동흐름 제어
private void controlMainMenuSelection() {
switch (MainMnuType.find(sc.nextLine())) {
// 유저 난이도선택 메뉴
case SETDIFFT:
nm.setDifficulty();
nm.addNum();
gm.judge(nm.getNumber());
break;
// 게임 실행 메뉴
case YES:
nm.addNum();
gm.judge(nm.getNumber());
break;
// 유저 게임기록 출력 메뉴
case HISTORY:
dm.printGameLog(gm.getGameCountList());
break;
// 게임 종료 메뉴
case EXIT:
System.out.println("< 숫자 야구 게임을 종료합니다 >");
System.exit(0);
break;
}
}
private static int difficulty = 3;
// 현재 난이도 반환 메소드
public int getDifficulty() {
return difficulty;
}
자리수는 3,4,5 외엔 입력불가 , 자리수에 따른 게임 난이도 변화setDifficulty() 메소드를 통해 difficulty 필드에 값을 조정. difficulty 값을 static으로 설정한 이유는 값을 공유하여 사용할일이 더 많기 때문에.difficulty의 기준하에 맞춰지도록 변경.
찬스기능 추가 5자리 찬스점수 3점, 3~4자리 찬스점수 1점
1. 입력받은 자리 숫자 공개 - 찬스점수 2점 감소
2. 입력받은 자리 숫자 Up&Down - 찬스점수 1점 감소
3. 정답숫자 총합 공개 - 찬스점수 1점 감소
// 유저입력값을 받아 입력값 Index 에 해당하는 숫자 반환 메소드
public void getIndexNumber(List<Integer> nums) {
if (chance >= 2) {
System.out.println("알고 싶은 자리수를 입력해주세요");
while (true) {
int chanceIndex = sc.nextInt();
if (nums.size() > chanceIndex - 1) {
System.out.println(chanceIndex + " 번째 숫자는 " + nums.get(chanceIndex - 1) + " 입니다.");
chance -= 2;
break;
} else {
System.out.println("자리수 입력을 확인해주세요.");
sc.nextLine();
}
}
} else {
System.out.println("가진 찬스횟수가 부족합니다.");
}
}
찬스점수가 2점이상일것 , 자리인덱스를 정확히 입력할 것nums.get(chanceIndex - 1) 의 List 값을 가져와 값을 출력
// 유저입력값을 받아 입력값 Index 에 해당하는 숫자 가 큰지 작은지 반환하는 메소드
public void getIndexNumberUpDown(List<Integer> nums) {
if (chance >= 1) {
System.out.println("알고 싶은 자리수를 입력해주세요");
Loop1:
while (true) {
int chanceIndex = sc.nextInt();
sc.nextLine();
// 입력숫자와 Index 숫자를 비교하여 Up&Down 비교
if (nums.size() > chanceIndex - 1) {
while (true) {
System.out.println("Up & Down 기준 숫자를 입력해주세요.");
String standardNum = sc.nextLine();
// 입력비교값이 1~9 사이일경우만 진행
if (!standardNum.matches("[1-9]+")) {
System.out.println("1~9의 숫자만 입력해주세요");
} else {
if (Integer.parseInt(standardNum) > nums.get(chanceIndex - 1)) {
System.out.println("DOWN");
} else if (Integer.parseInt(standardNum) < nums.get(chanceIndex - 1)) {
System.out.println("UP");
} else if (Integer.parseInt(standardNum) == nums.get(chanceIndex - 1)) {
System.out.println("Same");
}
chance--;
break Loop1;
}
}
} else {
System.out.println("자리수 입력을 확인해주세요.");
sc.nextLine();
}
}
} else {
System.out.println("가진 찬스횟수가 부족합니다.");
}
}
찬스점수가 1점이상일것 , 자리인덱스를 정확히 입력할 것 , 입력값이 1~9사이의 숫자일것if (!standardNum.matches("[1-9]+")) 의 정규식 조건문을 통해 1~9 의 숫자만을 입력받을수 있다.
// 모든 정답 숫자의 합 출력 메소드
public void getSumAnswer(List<Integer> nums) {
if (chance >= 1) {
System.out.println("모든 번호의 합은");
int sum = nums.stream().mapToInt(num -> num).sum();
System.out.println(sum + " 입니다.");
chance--;
} else {
System.out.println("가진 찬스횟수가 부족합니다.");
}
}
찬스점수가 1점이상일것int sum = nums.stream().mapToInt(num -> num).sum(); 의 람다 스트림을 이용하여 모든 정답숫자의 총합을 출력한다.






📦
├─ .gitignore
├─ .idea
│ ├─ .gitignore
│ ├─ material_theme_project_new.xml
│ ├─ misc.xml
│ ├─ modules.xml
│ ├─ uiDesigner.xml
│ └─ vcs.xml
├─ BullsandCowsProjects.iml
├─ README.md
└─ src
└─ com
└─ bullsandcows
├─ lv1 : Lv.1 필수기능구현 숫자야구
│ ├─ Main.java : main 메소드 실행 Class
│ └─ manager : 각 기능별 Manager Class 집합 패키지
│ ├─ DisplayManger.java : 콘솔 출력 담당 Class
│ ├─ GameJudgeManager.java : 게임 승패 및 게임 결과(Strike, Ball) 체크 Class
│ ├─ NumberUtilManager.java : 정답숫자 생성, 유저 입력 숫자 유효성 검사 Class
│ └─ ServiceManager.java : 게임 전체 흐름 담당 Class
├─ lv2 : Lv.2 필수기능구현 숫자야구
│ ├─ Main.java
│ ├─ MainmenuType.java : MainMenu Enum Class
│ └─ manager
│ ├─ DisplayManger.java
│ ├─ GameJudgeManager.java
│ ├─ NumberUtilManager.java
│ └─ ServiceManager.java
├─ lv3 : Lv.3 필수기능구현 숫자야구
│ ├─ Main.java
│ ├─ MainMnuType.java
│ └─ manager
│ ├─ DisplayManger.java
│ ├─ GameJudgeManager.java
│ ├─ NumberUtilManager.java
│ └─ ServiceManager.java
├─ lv4 : Lv.4 필수기능구현 숫자야구
│ ├─ Main.java
│ ├─ MainMnuType.java
│ └─ manager
│ ├─ DisplayManger.java
│ ├─ GameJudgeManager.java
│ ├─ NumberUtilManager.java
│ └─ ServiceManager.java
└─ lvcustom : 찬스 추가 기능구현 숫자야구
├─ ChanceMainMenuType.java : 찬스메뉴 Enum Class
├─ Main.java
├─ MainMenuType.java
└─ manager
├─ ChanceManger.java : 찬스 추가 기능 담당 Class
├─ DisplayManger.java
├─ GameJudgeManager.java
├─ NumberUtilManager.java
└─ ServiceManager.java
©generated by Project Tree Generator