c언어 교재에 단골로 나오는 소재는, 달력을 예쁘게 출력하는 것입니다. 처음 접해보면 어려울 수도 있는데요. 기능을 잘 쪼개고 들어가면 됩니다. 코딩 테스트에서도 기능을 잘 쪼개고 들어가는 것은 굉장히 유용한 스킬이니, 익혀 두시면 좋습니다.
일단, 간단한 플로우 먼저 그려봅시다.
복잡해 보이지만, 사실 yyyy년 mm월 1일의 요일과, yyyy년 mm월이 몇 일까지 있는지만 구하면 어렵지 않게 출력할 수 있음을 알 수 있습니다. 이 기능들을 또 쪼개 보겠습니다. yyyy년 mm월 1일의 요일을 알기 위해서는 기준이 되는 날의 요일을 알아야 합니다. 다음에, 월별로 몇 일까지 있는지를 알아야 합니다. 그래야, 기준 요일로부터 몇 일만큼 지났는지를 누적할 수 있기 때문입니다.
해당 기능을 구현하기 위해서 필요한 기능을 따로 정리해 보았습니다. 다음에 월별 날 수는 어떻게 구할까요? 12개의 월밖에 없으니, 그냥 배열로 저장해도 될 겁니다. 문제는 윤년인 경우에 2월은 29일까지 늘어난다는 점입니다. 그러면, 2월은 28일까지 있다고 저장을 해 놓고 윤년이라면 그 값에 1을 더하기만 하면 됩니다.
월별 날 수를 구하기 위해 필요한 것은, 윤년인지 판단하는 메소드임을 알 수 있습니다. 그런데, yyyy년 mm월이 몇 일까지 있을까는 또 어떤가요?
역시 월별 날 수를 구해야 함을 알 수 있습니다. 중복된 부분인가요? 이 부분을 모듈화 하면 됩니다.
먼저, get_day_of_month입니다. 이것은 yyyy년 mm월의 날 수를 구합니다. 36번째 줄에서, 월별로 몇 개의 일이 있는지를 초기화 합니다. 37번째 줄에서, leaf year이면 day_of_month[2]에 1을 추가합니다.
그러면, is_leaf_year 함수로 yyyy가 윤년인지 판단을 하면 되겠네요. 자바에서는 윤년을 고려하지 않은 월별 일 수를 필드로 선언해 두고, 2월의 날 수를 리턴하려고 할 때, 윤년이라면, 윤년을 고려하지 않은 2월 일 수인 28에 1을 더한 29를 리턴하면 됩니다. 그러면, 이러한 로직은 어디에 쓸까요?
yyyy년 mm월 1일의 요일을 구할 때도 쓸 수 있습니다. 1년 1월 1일이 월요일이라는 것을 알고 있다면요.
get_day에서도 써먹을 수 있습니다. 이것은 yyyy년 mm월 1일의 요일을 구하는 것입니다. 기준 일로부터 yyyy년 mm월 1일이 얼마만큼 지났느냐도 사실은, YYYY년 MM월의 일 수의 누적합이기 때문입니다. 32번째 줄에 (1 + past) % 7이 문제인데요. 1을 리턴하면 월요일, 2를 리턴하면 화요일, ... , 6을 리턴하면 토요일이라는 의미입니다.
이해하기 어려워 보이는데요. 가독성을 어떻게 하면 개선할 수 있을지는 고민해 보시는 것도 좋을 듯 싶어요. 어찌 되었던 핵심은, 기능별로 쪼개서, 모듈화를 시켰다는 것이고, 공통 부분을 함수로 빼 버렸다는 점입니다. 그리고 한 함수에 하나의 기능을 담으려고 했다는 것도 중요하게 볼 만 합니다. 네이밍만 고친다면요.
여기까지 구현하셨다면, 출력하는 부분은 크게 어렵지 않습니다.
yyyy년 mm월 1일의 시작 요일을 구하고, yyyy년 mm월의 일 수를 구합니다. 그리고 나서, print_cal 함수를 호출합니다.
15번째 줄에, 요일을 표시합니다. 다음에, 16번째 줄에 보면, start_day까지 빈 공백 4개를 출력하는데요. start_day가 0이면 일요일, 1이면 월요일, ... , 6이면 토요일을 의미합니다. 만약에 1일이 일요일부터 시작이라면 16번째 for loop를 돌지 않을 겁니다. 월요일이라면? 1번 도니까 4칸이 공백으로 있을 겁니다. 즉, 빈 칸을 만드는 작업을 합니다.
다음에, 18번째 부터가 문제인데요. 이것도 크게 어렵지 않습니다. 중요한 것은 21번째 줄에서 ke % 7의 값이 6이라면, 개행을 출력한다는 것인데요. 이는 ke % 7의 값이 6인 경우, 토요일이기 때문입니다. 실행 결과를 보겠습니다.
1993년 2월을 출력해 보았습니다.
잘 나왔음을 알 수 있습니다. 1995년 5월을 출력하면 어떨까요?
프로그램의 출력 결과는 위와 같습니다.
일치하네요. 전체 소스코드는 링크에 있습니다.
'구현' 카테고리의 다른 글
datetime 비교를 어떻게 할 수 있는지 예제 문제로 알아봅시다. (3) | 2021.06.03 |
---|---|
코딩테스트 조합 구하기 : 작은 수부터 뽑으면 쉽다 (4) | 2021.04.22 |
진법 변환 알고리즘을 구현해 봅시다. (0) | 2021.03.25 |
문자열 뒤집기 : 인코딩까지 고려하려면 어떻게 하면 좋을까요? (0) | 2020.12.13 |
java BigDecimal을 이용해서 실수를 다뤄 봅시다. (2) | 2020.08.23 |
최근댓글