코딩 테스트

[코드스쿼드] 숫자 야구게임

ImKDM 2022. 9. 14. 15:26
728x90

문제


기본적으로 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 이 하나 늘어날 수 있다.