Boot Camp/[코드스쿼드] Java 백엔드 테스트

[3단계] 콘솔 태양계 출력 프로그램 완성

계란💕 2022. 12. 8. 20:54

  Ex) 연, 월, 일을 입력하면 태양계가 출력되도록 하라

  • 태양, 지구, 달 외에 다른 행성, 인공 위성 등을 추가해도 된다.

 

  Sol)

  • Planet 클래스
    • 2단계의 공전 클래스 메서드를 가져와서 조금만 수정했다.
    • 지구는 검은 별, 달은 달 모양으로 표시한다.
    • 은하수를 추가하는 메서드를 이용해서 은하수를 그린 다음에 태양, 지구, 달을 그린다.
    • 태양, 지구, 달 그리는 메서드를 모두 따로 만들었다.
<hide/>
public class Planet {

    static char[][] graph = new char[50][50];
    static Set<Character> sunCharSet = Set.of('\\', '!', '/', 'O', '-', '|', '.', '*', 'Y', 'o',
        'u', 'A', 'r', 'e', ' ', 'H', '"', 'V', '★', '☆', '☾', '☺', '○', '+'
    );
    static LocalDate enterDate;
    static String tmpYear, tmpMonth, tmpDay;
    static int year, month, day;

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static ArrayList<String> milkyWayList = new ArrayList<>();

    public static void addMilkyWayList1() {
        milkyWayList.add(".              +   .                   .   . .     .  .");
        milkyWayList.add("                   .                     .       .     *");
        milkyWayList.add(" .       *                           . . . .  .   .  + .");
        milkyWayList.add("                                         .   .  +  . . .");
        milkyWayList.add("    .                          .    .  .   .    .    . .");
        milkyWayList.add("                                .     .     . +.    +  .");
        milkyWayList.add("                                         .       .   . .");
        milkyWayList.add("             . .                  .    * . . .  .  +   .");
        milkyWayList.add("           +      .           .   .      +               ");
        milkyWayList.add("                         .       . +  .+. .              ");
        milkyWayList.add("   .                      .     . + .  . .     .      .");
        milkyWayList.add("           .      .    .     . .   . . .                ");
        milkyWayList.add("      *             .    . .  +    .  .      ");
        milkyWayList.add("          .     .    .  +   . .  *  .       . ");
        milkyWayList.add("               . + .  .  .  .. +  .");
        milkyWayList.add(".      .  .  .  *   .  *  . +..  .            * ");
        milkyWayList.add(" .      .   . .   .   .   . .  +   .    .            +");
        milkyWayList.add("                         . .                  .    * . . .  .  +   .");
    }

    public static void addMilkyWayList2() {
        milkyWayList.add("                       +      .           .   .      +               ");
        milkyWayList.add("                                     .       . +  .+. .              ");
        milkyWayList.add("               .                      .     . + .  . .     .      .");
        milkyWayList.add("                       .      .    .     . .   . . .                ");
        milkyWayList.add("                  *             .    . .  +    .  .      ");
        milkyWayList.add("                      .     .    .  +   . .  *  .       . ");
        milkyWayList.add("                           . + .  .  .  .. +  .");
        milkyWayList.add("            .      .  .  .  *   .  *  . +..  .            * ");
        milkyWayList.add("             .      .   . .   .   .   . .  +   .    .            +");
        milkyWayList.add("                                        . .                  .    * . . .  .  +   .");
        milkyWayList.add("                                      +      .           .   .      +               ");
        milkyWayList.add("                                                    .       . +  .+. .              ");
        milkyWayList.add("                              .                      .     . + .  . .     .      .");
        milkyWayList.add("                                      .      .    .     . .   . . .                ");
        milkyWayList.add("                                 *             .    . .  +    .  .      ");
        milkyWayList.add("                                     .     .    .  +   . .  *  .       . ");
        milkyWayList.add("                                          . + .  .  .  .. +  .");
        milkyWayList.add("                           .      .  .  .  *   .  *  . +..  .            * ");
        milkyWayList.add("                            .      .   . .   .   .   . .  +   .    .            +");
    }

    public static void drawMilkyWay(int[] centerOfSun) {
        addMilkyWayList1();
        addMilkyWayList2();
        int row = centerOfSun[0];
        int col = centerOfSun[1];
        int cnt = 0;
        int startRow = row - 10;
        char[] chars = milkyWayList.get(cnt++).toCharArray();
        while (cnt < milkyWayList.size()) {
            for (int i = 0; i < chars.length; ++i) {

                if (startRow + cnt < 0 || startRow + cnt >= graph.length ||
                    col - 20 + i < 0 || col - 20 + i >= graph[0].length) {
                    continue;
                }
                graph[startRow + cnt][col - 20 + i] = chars[i];
            }
            chars = milkyWayList.get(cnt++).toCharArray();
        }
    }

    public static LocalDate enterDate() throws IOException {
        StringTokenizer st = new StringTokenizer(br.readLine());
        try {
            tmpYear = st.nextToken();
            tmpMonth = st.nextToken();
            tmpDay = st.nextToken();
            year = Integer.parseInt(tmpYear.substring(0, tmpYear.length() - 1));
            month = Integer.parseInt(tmpMonth.substring(0, tmpMonth.length() - 1));
            day = Integer.parseInt(tmpDay.substring(0, tmpDay.length() - 1));
        } catch (NoSuchElementException e) {
            throw new NoSuchElementException("[ERROR] 날짜는 y년 m월 d일 형태로만 입력 가능합니다.");
        } catch (NumberFormatException e) {
            throw new NumberFormatException("[ERROR] 날짜는 y년 m월 d일 형태로만 입력 가능합니다.");
        }
        try {
            enterDate = LocalDate.of(year, month, day);
        } catch (DateTimeException e) {
            throw new DateTimeException("[ERROR] 날짜는 y년 m월 d일 형태로만 입력 가능합니다.");
        }
        return enterDate;
    }

    public static void drawSun(int[] center) {   // 예외 처리 필요
        int row = center[0];
        int col = center[1];
        graph[row - 1][col - 2] = '\\';
        graph[row - 1][col - 1] = ' ';
        graph[row - 1][col] = '!';
        graph[row - 1][col + 1] = ' ';
        graph[row - 1][col + 2] = '/';
        graph[row][col - 2] = '-';
        graph[row][col - 1] = ' ';
        graph[row][col] = '○';
        graph[row][col + 1] = ' ';
        graph[row][col + 2] = '-';
        graph[row + 1][col - 2] = '/';
        graph[row + 1][col - 1] = ' ';
        graph[row + 1][col] = '|';
        graph[row + 1][col + 1] = ' ';
        graph[row + 1][col + 2] = '\\';
    }

    public static void drawPositionMsg(int[] myPosition) {
        int myPositionRow = myPosition[0];
        int myPositionCol = myPosition[1];
        String msg = "\"You Are Here!\"";
        char[] msgArr = msg.toCharArray();
        int msgRow = myPositionRow - 5;
        int startCol = myPositionCol - 5;
        if (startCol + msg.length() >= graph[0].length) {
            startCol -= startCol + msg.length() - graph[0].length;
        }
        if (startCol + msg.length() < 0) {
            startCol = 0;
        }
        for (int i = startCol; i < startCol + msg.length(); ++i) {
            if (msgRow < 0 || msgRow >= graph.length || i < 0 || i >= graph[0].length ||
                i - startCol < 0 || i - startCol >= msgArr.length) {
                continue;
            }
            graph[msgRow][i] = msgArr[i - startCol];
        }
    }

    public static void drawArrow(int[] myPosition) {
        int myPositionRow = myPosition[0];
        int myPositionCol = myPosition[1];
        int startRow = myPositionRow - 4;
        graph[startRow][myPositionCol] = '|';
        graph[startRow + 1][myPositionCol] = '|';
        graph[startRow + 2][myPositionCol - 1] = '\\';
        graph[startRow + 2][myPositionCol] = '|';
        graph[startRow + 2][myPositionCol + 1] = '/';
        graph[startRow + 3][myPositionCol] = 'V';
    }

    public static char[][] drawPlanet(int diameter) {
        char[][] circle = new char[diameter][diameter];
        int radiusIdx = diameter / 2;
        for (int i = 0; i < radiusIdx; ++i) {
            int tmpIdx = i + radiusIdx;
            int min = Math.min(tmpIdx, diameter - 1 - tmpIdx);
            int max = Math.max(tmpIdx, diameter - 1 - tmpIdx);
            for (int j = min; j <= max; ++j) {
                circle[i][j] = '*';
            }
        }
        for (int i = radiusIdx; i < diameter; ++i) {
            int tmpIdx = i - radiusIdx;
            int min = Math.min(tmpIdx, diameter - 1 - tmpIdx);
            int max = Math.max(tmpIdx, diameter - 1 - tmpIdx);
            for (int j = min; j <= max; ++j) {
                circle[i][j] = '*';
            }
        }
        return circle;
    }

    // 태양, 지구, 달이 아닌 새로운 행성 그리기
    public static char[][] fillGraphWithPlanet(int[] center, int diameter) {
        int centerRow = center[0];
        int centerCol = center[1];
        char[][] planet = drawPlanet(diameter);     // diameter * diameter 크기의 행렬
        int radius = diameter / 2;
        for (int i = centerRow - radius; i < centerRow - radius + diameter; ++i) {
            for (int j = centerCol - radius; j < centerCol - radius + diameter; ++j) {
                // 그래프 범위를 벗어나면 일단 패스
                if (i < 0 || i >= graph.length || j < 0 || j >= graph[0].length) {
                    continue;
                }
                if (i - centerRow + radius < 0 || i - centerRow + radius >= planet.length
                    || j - centerCol + radius < 0 || j - centerCol + radius >= planet[0].length) {
                    continue;
                }
                graph[i][j] = planet[i - centerRow + radius][j - centerCol + radius];
            }
        }
        return graph;
    }

    public static char[][] fillGraphWithEarth(int[] center) {
        graph[center[0]][center[1]] = '★';
        return graph;
    }

    public static char[][] fillGraphWithMoon(int[] center) {
        graph[center[0]][center[1]] = '☾';
        return graph;
    }

    public static void printSolarSystem() {
        for (char[] row : graph) {
            for (char c : row) {
                if (sunCharSet.contains(c)) {
                    System.out.print(c);
                    continue;
                }
                System.out.print(" ");
            }
            System.out.println();
        }
    }
}

 

  • SolarSystem 클래스 
    • 2단계와 다르게 태양, 지구, 달에 지름을 없애고 해모양, 달모양, 별모양 특수기호를 넣는다.
    • 각도 구하는 부분은 공전 클래스 Revolution에 있는 메서드를 그대로 이용했다.
    • 날짜를 입력 받아서 각도를 구하기 => 회전 후 행, 열 구하기 => 그래프 채우기 과정으로 실행한다.
<hide/>
public class SolarSystem {

    public static void main(String[] args) throws IOException {
        System.out.println("날짜를 입력하세요. ex) yyyy년 M월 d일");
        LocalDate date = Planet.enterDate();
        double angleBetweenSunAndEarth = Revolution.dateToAngle(date);
        double angleBetweenEarthAndMoon = angleBetweenSunAndEarth * 12;
        double disFromSunToEarth = 20;
        double disFromEarthToMoon = 4;
        int[] centerOfSun = new int[]{25, 25};
        int[] centerOfEarth = Revolution.angleToCoordinate(centerOfSun, disFromSunToEarth, angleBetweenSunAndEarth);
        Planet.drawMilkyWay(centerOfSun);
        Planet.drawSun(centerOfSun);
        Planet.fillGraphWithEarth(centerOfEarth);
        Planet.drawPositionMsg(centerOfEarth);
        Planet.drawArrow(centerOfEarth);
        int[] centerOfMoon = Revolution.angleToCoordinate(centerOfEarth, disFromEarthToMoon, angleBetweenEarthAndMoon);
        Planet.fillGraphWithMoon(centerOfMoon);
        Planet.printSolarSystem();
    }
}

 

 

   Note) 입출력 예시

날짜를 입력하세요. ex) yyyy년 M월 d일
2020년  9월 20일

 

  

3단계 회고

  • 연이 추가됨에 따라서 2단계와 다른 차별점을 줘야할 것 같았다. 그런데, 평면 상에서 차이점을 구현하는게 가능한지 모르겠다.그래서 2단계랑 차이 없이 구현했다.
  • 수성, 금성, .... 등 다른 행성을 추가하고 싶었지만 거리, 위치, 공전 주기를 파악해서 그리는 게 어려워서 포기했는데 이 부분이 아쉽다. 시간이 더 있으면 공부해서 추가하면 더 멋있게 구현할 수 있었을 것 같다.
  • 애니메이션(4단계)은 한 번도 해본적이 없어서 구글링해서 찾다가 결국은 이미지 띄우기까지 밖에 못했다.
    • Thread.sleep() 을 이용해서 그림이 이동하도록 구현하면 되지 않을까 싶다.