
문제
기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.
같은 수가 같은 자리에 있으면 스트라이크, 다른 자리에 있으면 볼, 같은 수가 전혀 없으면 포볼 또는 낫싱이란 힌트를 얻고, 그 힌트를 이용해서 먼저 상대방의 수를 맞추면 승리한다.
[예] 상대방의 수가 425일 때,
123을 제시한 경우 : 1 스트라이크
456을 제시한 경우 : 1 스트라이크 1볼
789를 제시한 경우 : 낫싱
위 숫자 야구게임에서 상대방의 역할을 컴퓨터가 한다. 컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다. 게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
게임 진행 결과는 다음과 같다.

프로그래밍 구현 제약사항
- 함수(또는 메소드) 하나의 크기가 최대 10라인을 넘지 않도록 구현한다.
- 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다 (예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다).
- 전역 변수를 사용하지 않는다.
힌트
- 컴퓨터가 3개의 값을 선택할 때 각 언어별 random 함수(또는 메소드) 또는 shuffle 함수(또는 메소드)를 이용하면 편한다.
- 반복문을 2중(반복문 안의 반복문)으로 사용하면 한번에 고려할 부분이 많다. 2중 반복문을 1중 반복문 2개로 나누어 처리하는 방법은 없는지 고려해 본다.
- indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
정답 코드
< 내 정답 코드 >
public class NumberBaseBall {
public static void main(String[] args) {
List<String> computerNum = makeNums();
List<String> playerNum = new ArrayList<>();
String answer = "";
int total = 0;
int strike = 0;
int ball = 0;
int chance = 0;
while (true) {
playerNum = inputNums();
total = calTotal(computerNum, playerNum);
strike = calStrike(computerNum, playerNum);
ball = calBall(total, strike);
answer = calGame(strike, ball);
if (answer.equals("3 스트라이크")) {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
System.exit(0);
} else {
System.out.println(answer);
}
}
}
// 컴퓨터의 숫자 반환 메서드
static List<String> makeNums() {
Set<String> set = new HashSet<>();
while (true) {
set.add(String.valueOf((int)(Math.random() * 9) + 1));
if (set.size() == 3) {
break;
}
}
List<String> list = new ArrayList<>(set);
Collections.shuffle(list);
return list;
}
// 사용자의 숫자 입력 메서드
static List<String> inputNums() {
Scanner scan = new Scanner(System.in);
List<String> list = new ArrayList<>();
int input = 0;
while (true) {
System.out.print("숫자를 입력해주세요 ex)123 : ");
input = scan.nextInt();
if (input < 123 || input > 987) {
System.out.println("잘못된 범위입니다. 다시 입력해주세요.");
continue;
}
list = Arrays.asList(String.valueOf(input).split(""));
Set<String> tmpSet = new HashSet<>(list);
if (tmpSet.size() != 3) {
System.out.println("중복된 숫자는 안됩니다. 다시 입력해주세요.");
continue;
}
break;
}
return list;
}
// strike 와 ball 의 개수에 따라 경기 결과를 반환 메서드
static String calGame(int strike, int ball) {
StringBuilder sb = new StringBuilder();
if (strike == 3) {
sb.append("3 스트라이크");
} else if (strike > 0 && strike <= 2) {
sb.append(strike + " 스트라이크 ");
}
if (ball > 0) {
sb.append(ball + "볼");
} else if (strike == 0 && ball == 0) {
sb.append("낫싱");
}
return sb.toString();
}
// 총 해당 숫자 개수인 total 구하는 메서드
static int calTotal(List<String> computer, List<String> player) {
int total = 0;
for (int i = 0; i < computer.size(); i++) {
if (computer.contains(player.get(i))) {
total++;
}
}
return total;
}
// strike 계산 메서드
static int calStrike(List<String> computer, List<String> player) {
int strkike = 0;
for (int i = 0; i < computer.size(); i++) {
if (computer.get(i).equals(player.get(i))) {
strkike++;
}
}
return strkike;
}
// ball 계산 메서드
static int calBall(int total, int strike) {
return total - strike;
}
}
< 타인 답변 코드 >
import java.util.*;
public class MainGame {
public static void main(String[] args) {
GenerateRandomNum randomNum = new GenerateRandomNum();
Input input = new Input();
Judge judge = new Judge();
Playagain playagain = new Playagain();
boolean again = true;
while (again){
List<Integer> computer = randomNum.create();
String result = "";
while (!result.equals("3스트라이크")){
result = judge.judgement(computer, input.playerNumber());
System.out.println(result);
}
again = playagain.playagain();
}
}
}
// 경기 재시작 여부 확인 (Playagain 클래스)
public class Playagain {
public boolean playagain(){
System.out.println("축하합니다! 경기를 다시 시작하겠습니까? 다시 시작 : 1, 종료 : 2");
Scanner scanner = new Scanner(System.in);
char answer = scanner.next().charAt(0);
if(answer == '1'){
return true;
}
return false;
}
}
// 입력값 받기. (Input 클래스)
public class Input {
public List<Integer> playerNumber(){
System.out.println("숫자를 입력해주세요");
Scanner scanner = new Scanner(System.in);
List<Integer> playerNum = new ArrayList<>();
String input = scanner.next();
for(String number: input.split("")){
playerNum.add(Integer.parseInt(number));
}
return playerNum;
}
}
// 스트라이크 볼 최종결정하기. (Judgement 클래스)
public class Judge {
Compare compare = new Compare();
public String judgement(List<Integer> computer, List<Integer> player){
int total = compare.howMany(computer, player);
int strike = compare.countStrike(computer, player);
int ball = total - strike;
if(total == 0){
return "낫싱";
} else if (strike == 0){
return ball + "볼";
} else if (ball == 0){
return strike + "스트라이크";
}
return ball + "볼 " + strike + "스트라이크";
}
}
// 컴퓨터의 수(3자리)와 플레이어의 수(3자리)를 비교하기. (Compare 클래스)
public class Compare {
public int howMany(List<Integer> computer, List<Integer> player){
int result = 0;
for(int i = 0; i < player.size(); i++){
if(computer.contains(player.get(i))){
result += 1;
}
}
return result;
}
public int countStrike(List<Integer> computer, List<Integer> player){
int strike = 0;
for(int i = 0; i < player.size(); i++){
if(computer.get(i) == player.get(i)){
strike += 1;
}
}
return strike;
}
}
// 1부터 9까지의 서로 다른 임의의 수 3개를 생성하기. (GenerateRandomNum 클래스)
public class GenerateRandomNum {
public int randomMake(){
Random random = new Random();
return random.nextInt(9) + 1;
}
public List<Integer> create(){
List<Integer> computerNumber = new ArrayList<>();
while (computerNumber.size() < 3){
int randomNumber = randomMake();
if(computerNumber.contains(randomNumber)){
continue;
}else {
computerNumber.add(randomNumber);
}
}
return computerNumber;
}
}
이것을 주의하자!
- 쉬울 줄 알았는데 막상 구현하려고 하니 생각보다 어려웠다.
- 맞춰야 하는 컴퓨터의 수를 만들 때 숫자 중복을 피하기 위해서 Set 인터페이스를 사용했고, 무한 반복을 하면서 Set 의 사이즈가 3이 되면 반복문을 나갔다. Set 프레임워크에 그대로 저장하면 임의의 규칙으로 저장 순서가 일정한 문제가 있다. 따라서 Set 을 List 로 변환한 다음, Collections.shuffle( ) 메서드로 순서를 섞었다. 비로소 중복이 되지 않는 3자리 수가 만들어졌다.
- 사용자 입력을 받는 것도 메서드로 구현했다. 여기서 범위 이탈 및 중복 숫자를 넣었을 때 유효성을 체크하는 코드를 넣었다. 범위를 체크하기 위해서 int 형으로 입력받아 if 문으로 걸렀고, 중복된 숫자를 확인하려고 Set 컬렉션 프레임워크를 만들어 사이즈가 3이 안되면 다시 입력하게 했다. 반환은 List<String> 이다.
- 두 List 를 받아서 원소가 포함되어 있는지 contains( ) 메서드로 확인했다. 포함되어 있으면 total ++ 을 했다.
- 총 몇 개의 원소가 포함되어 있는지 total 을 구했으면, Strike 개수를 구한다. 그리고 total 에서 Strike 개수를 빼면 ball 이 된다.
- 구한 Strike 와 ball 의 개수를 가지고 조건식에 맞춰 결과를 출력했다. StringBuilder 을 이용했으며, 만약 "3 스트라이크"면 게임을 종료하게 만들었다.
- 타인 답변 코드를 보면 객체지향적으로 작성됐다. 그래서 더 깔끔한 것 같기도 하다. 이 코드도 역시 전체 일치하는 숫자를 구한 다음, 스트라이크 개수를 빼서 볼의 개수를 구했다.
- 현재 List 와 contains( ) 메서드를 통해 구했는데, String 문자열에서 indexOf( ) 메서드를 통해 ball 을 구하는 방법도 있다. 먼저 Strike 를 구한 다음, indexOf( ) 의 결과가 - 1 이면 해당 숫자가 없다는 뜻이기 때문에 - 1 이 아니라면 ball 이 하나 늘어날 수 있다.
'코딩 테스트' 카테고리의 다른 글
| [프로그래머스] (Lv.2) N개의 최소공배수 ** (0) | 2022.09.14 |
|---|---|
| [프로그래머스] (Lv.2) 멀리 뛰기 (0) | 2022.09.14 |
| [프로그래머스] (Lv.2) 구명보트 *** (0) | 2022.09.13 |
| [프로그래머스] (Lv.2) 짝지어 제거하기 ** (1) | 2022.09.13 |
| [프로그래머스] (Lv.2) 카펫 *** (0) | 2022.09.13 |