-
우아한 테크코스 - 3기 1주 차 프리코스 후기생각과 일상/혼자의 생각 2020. 12. 17. 17:32
우아한 테크코스 3기 지원해 합격하고, 3주간 프리코스를 진행했다. 프리코스를 진행하며 자바를 처음 공부하게 돼 많이 헤맸지만, 주어진 과제를 혼자 해 나가며 많이 성장함을 느꼈고, 완료했을 때 성취감을 느꼈다.
물론 다른 지원자분들과 코드를 비교해보면 참 많이 부족함도 느꼈지만 좋은 코드들을 보며 더 공부하고 배워야겠다고 다짐할 수 있는 기회가 됐다.
3주 차까지의 프리코스가 모두 끝나고 최종 온라인 코딩 테스트를 기다리고 있다. 프리코스가 진행되는 3주 간은 프리코스 과제에 대해 정리를 해가며 블로그에 올릴 여유가 없었기 때문에 지금이라도 정리해보려 한다. 도움이 되는 내용은 없고 그냥 개인 기록용..
1주 차 미션은 숫자야구 게임이었다.
처음 미션을 보고, 기능 구현 목록 작성에만 이틀 정도가 걸렸다. 그리고 프로그래밍 요구사항에서 패키지 구조와 구현은 변경하지 않는다는 게 무슨 말인지도 모르겠어서 또 검색, RandomUtils 기능도 몰라서 검색, 검색 검색 검색의 연속
작성한 README에 적힌 기능 구현 목록 순서대로 구현을 해야 했기에 1-9까지 서로 다른 난수 3개를 생성하는 기능부터 구현했다. 제출한 코드와 프로그램을 다시 짜 본 코드를 같이 나열해 비교해봐야겠다.
1. 1 - 9까지 서로 다른 3개의 난수 생성
package baseball; import utils.RandomUtils; public class ThreeNumGenerator { private static int[] comNum = new int[3]; public static int[] generate() { /* 길이 3의 배열 생성 후 각 인덱스에 임의의 수 할당 */ comNum[0] = RandomUtils.nextInt(1, 9); comNum[1] = RandomUtils.nextInt(1, 9); comNum[2] = RandomUtils.nextInt(1, 9); /* 각 인덱스에 겹치는 수가 있다면 새로운 값을 할당해 겹치는 수가 없게 만듦 */ while (comNum[0] == comNum[1] || comNum[0] == comNum[2] || comNum[1] == comNum[2]) { comNum[1] = RandomUtils.nextInt(1, 9); comNum[2] = RandomUtils.nextInt(1, 9); } return comNum; } }
package baseball; import utils.RandomUtils; public class Answer { private final int MIN_NUM_IN_RANGE = 1; private final int MAX_NUM_IN_RANGE = 9; private int[] answer = new int[3]; public int[] generateAnswer() { for (int i = 0; i < answer.length; i++) { answer[i] = RandomUtils.nextInt(MIN_NUM_IN_RANGE, MAX_NUM_IN_RANGE); } validAnswerCheck(answer); return answer; } private boolean validAnswerCheck(int[] comNum) { for (int i = 0; i < comNum.length; i++) { comNum[i] = RandomUtils.nextInt(MIN_NUM_IN_RANGE, MAX_NUM_IN_RANGE); for (int j = 0; j < i; j++) { i = makeDifferent(comNum, i, j); } } return true; } private int makeDifferent(int[] comNum, int i, int j) { if(comNum[i]== comNum[j]) { i--; } return i; } }
상수 사용과 메서드 나눔으로 전체적으로 코드가 더 길어졌다. 그러나 하드 코딩하지 않았기 때문에 배열의 길이가 길어지더라도 난수 생성하는데 조건을 하나하나 지정해줄 필요가 없어졌다. 근데 이중 for문으로 돌고 있기 때문에 좋은 코드인지는 아직 판단이 잘 안 선다.
2. 서로 다른 3자리 숫자 입력받기
package baseball; import java.util.Scanner; import java.util.stream.Stream; public class UserInput { private static Scanner input = new Scanner(System.in); private static int[] userNum; private static String userNumString; public int[] getUserNum () { System.out.print("숫자를 입력해주세요 : "); userNumString = input.nextLine(); if (userNumValidation(userNumString)) { userNum = Stream.of(userNumString.split("")).mapToInt(Integer::parseInt).toArray(); return userNum; } else { throw new IllegalArgumentException(); } } private boolean userNumValidation(String num) { /* 예외 1) 문자가 입력된 경우 */ try { int parsedNum = Integer.parseInt(num); if (!(99<parsedNum && parsedNum<1000)) { return false; } } catch(NumberFormatException error) { return false; } /* 예외 2) 입력 길이가 3이 아닌 경우*/ if (num.length() != 3) { return false; } /* 예외 3) 입력 값 중 0이 포함된 경우*/ if (num.contains("0")) { return false; } /* 예외 4) 서로 다른 수가 아닌 경우 */ if (num.charAt(0)==num.charAt(1) || num.charAt(0)==num.charAt(2) || num.charAt(1)==num.charAt(2)) { return false; } /* 예외가 아닌 경우 true 반환 */ return true; } }
package view; import java.util.Scanner; public class InputView { private static final String ASK_INPUT_MESSAGE = "숫자를 입력해주세요 : "; private static final String ASK_RESTART_MESSAGE = "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."; private static Scanner scanner = new Scanner(System.in); public static String askInputNum() { System.out.printf(ASK_INPUT_MESSAGE); String input = scanner.nextLine(); return input; } public static String askRestart() { System.out.println(ASK_RESTART_MESSAGE); String input = scanner.nextLine(); return input; } }
package baseball; import view.InputView; public class User { private static final String NOT_VALID_LENGTH_ERROR = "올바른 길이의 입력이 아닙니다. 서로 다른 3자리 수를 입력해주세요."; private static final String NOT_VALID_NUMBER_ERROR = "올바른 입력이 아닙니다. 서로 다른 3자리 수를 입력해주세요."; private static final String NOT_DIFFERENT_NUMBER_ERROR = "서로 다른 3자리 수를 입력해주세요."; private int[] userAnswer = new int[3]; public int[] getUserAnswer() { String input = InputView.askInputNum(); isValidInput(input); userAnswerToIntArray(input); return userAnswer; } private void userAnswerToIntArray(String input) { for (int i = 0; i < userAnswer.length; i++) { userAnswer[i] = input.toCharArray()[i] - '0'; } } private boolean isValidInput(String input) { return validInputLength(input) && validNumber(input) && allDifferentNumber(input); } private boolean validInputLength(String input) { if (input.equals("\n")) { throw new IllegalArgumentException(NOT_VALID_LENGTH_ERROR); } if (input.toCharArray().length != 3) { throw new IllegalArgumentException(NOT_VALID_LENGTH_ERROR); } return true; } private boolean validNumber(String input) { for (char num : input.toCharArray()) { if (!(49 <= num && num <= 57)) throw new IllegalArgumentException(NOT_VALID_NUMBER_ERROR); } return true; } private boolean allDifferentNumber(String input) { char[] userInput = input.toCharArray(); while (true) { if (userInput[0] != userInput[1] && userInput[1] != userInput[2] && userInput[0] != userInput[2]) { break; } throw new IllegalArgumentException(NOT_DIFFERENT_NUMBER_ERROR); } return true; } }
제출한 코드는 사용자의 입력을 받고, 유효성까지 판별한다. 3주 차에 MVC 모델을 배워 사용해서 그런지 다시 작성한 코드는 입력을 받는 클래스와 입력 유효성을 판단하는 클래스를 나눠서 구현했다. 그리고 예외 경우를 나눈 코드도 엄청 긴데, 2주 차부터는 한 메서드당 15라인을 넘어가지 않아야 한다는 제한사항이 있었기에 거기에 맞춰서 다시 구현하지 않았나 싶다. 유저 인스턴스를 생성해 유저가 입력을 검사도 하고, 올바르지 않은 입력인 경우엔 에러를 던지도록 했다.
3. 게임 로직 (볼, 스트라이크 판단)
package baseball; import java.util.Scanner; public class NumberCompare { private static int strike = 0; private static int ball = 0; private static final String nothing = "낫싱"; private static Scanner input = new Scanner(System.in); public void compare(int[] com, int[] user) { for (int i=0; i < 3; i++) { for (int j=0; j<3; j++) { NumberCompare.compareWithcomNum(com[i], user[j], i, j); } } } public static void compareWithcomNum(int comNum, int userNum, int i, int j) { if (comNum==userNum && i == j) { // 숫자와 자리(인덱스) 모두 같은 경우 strike++; } else if (comNum==userNum && i != j) { // 숫자는 같지만 자리(인덱스)는 다른 경우 ball++; } } public static void printScore() { if (strike==0 && ball==0) { System.out.println(nothing); } else { System.out.println(ball + "볼 " + strike + "스트라이크"); NumberCompare.resetScore(); // 점수 출력 후 새로운 입력을 받으므로 점수 초기화 } } public static void resetScore() { strike = 0; ball = 0; } public boolean gameClear() { if (strike==3) { return true; } return false; } }
package baseball; import java.util.Scanner; public class Baseball { private static ThreeNumGenerator threeNumGenerator = new ThreeNumGenerator(); private static UserInput userInput = new UserInput(); private static NumberCompare numberCompare = new NumberCompare(); private static int[] comNum; private static int[] userNum; /* 게임 실행 및 종료 함수 */ public static void gameRun() { comNum = threeNumGenerator.generate(); while (true) { userNum = userInput.getUserNum(); numberCompare.compare(comNum, userNum); if(numberCompare.gameClear()) { System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료"); break; } numberCompare.printScore(); numberCompare.resetScore(); } Baseball.asktoRestart(); } /* 게임 종료 후 재시작할 지 묻는 메소드 */ public static void asktoRestart() { Scanner input = new Scanner(System.in); System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요."); String useranswer = input.nextLine(); switch (useranswer) { case "1": { // 입력 값 1인 경우 numberCompare.resetScore(); Baseball.gameRun(); } case "2": { // 입력 값 2인 경우 break; } default: { // 입력 값이 1이나 2가 아닌 경우 throw new IllegalArgumentException(); } } } }
package baseball; import view.InputView; import view.OutputView; public class BaseBall { private static final String NOT_VALID_INPUT = "올바르지 않은 입력입니다."; public int ball; public int strike; private Answer answer = new Answer(); private User user = new User(); public void run() { int[] comNum = answer.generateAnswer(); startGame(comNum); OutputView.winGame(); askRestart(); } private void startGame(int[] comNum) { while (true) { int[] userNum = user.getUserAnswer(); compareTwoPlayer(comNum, userNum); printScore(); if (strike==3) { break; } resetScore(); } } private void askRestart() { String restart = InputView.askRestart(); if (restart.equals("1")) { resetScore(); run(); } if (!restart.equals("2")) { throw new IllegalArgumentException(NOT_VALID_INPUT); } } private void printScore() { if (strike == 0 && ball == 0) { OutputView.printNothing(); } if (strike != 0 && ball != 0) { OutputView.printBallAndStrike(ball, strike); } if (strike == 0 && ball != 0) { OutputView.printBall(ball); } if (strike != 0 && ball == 0) { OutputView.printStrike(strike); } } private void compareTwoPlayer(int[] comNum, int[] userNum) { for (int i = 0; i < comNum.length; i++) { for (int j = 0; j < comNum.length; j++) { if (comNum[i] == userNum[j] && i == j) { strike++; } if (comNum[i] == userNum[j] && i != j) { ball++; } } } } private void resetScore() { ball = 0; strike = 0; } }
먼저 이중 for문을 통해 컴퓨터와 유저의 입력을 비교하던 것을 strike가 3이 될 때까지 반복해서 입력을 받도록 했고, 비교하는 클래스와 게임을 구현하는 클래스를 나눠서 구현하지 않고, 게임 로직을 구현하는 한 클래스에서 시작과 비교, 점수 출력, 다시 시작까지 묻고 입력을 받아 재시작하는 것 까지 구현했다.
4. 게임 시작
package baseball; import java.util.Scanner; public class Application { public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); // TODO 구현 진행 BaseBall baseBall = new BaseBall(); baseBall.run(); } }
package baseball; import java.util.Scanner; public class Application { public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); // TODO 구현 진행 BaseBall baseBall = new BaseBall(); baseBall.run(); } }
미션을 제출하고 검토하는 과정에서 정답 출력이 잘못된다는 것을 알고 유독 더 아쉬웠던 미션이었다. 그래도 거의 3일정도 걸리고, 자바 기본 API도 계속 검색하면서 작성하던 3주 전 보다는 성장했다는 게 보이는 것 같기도 하다..!
'생각과 일상 > 혼자의 생각' 카테고리의 다른 글
우아한 테크코스 3기 2주차 회고 (첫 번째 미션을 끝내고..) (0) 2021.02.15 우아한 테크코스 - 3기 3주 차 프리코스 후기 (0) 2020.12.18 우아한 테크코스 - 3기 2주 차 프리코스 후기 (0) 2020.12.18 블로그를 시작한 지 두 달이 지나고 (0) 2020.10.22 블로그를 시작한 이유 (0) 2020.08.01