오늘은 난이도가 매우 어려워서 강의 하나밖에 나가지 못했다. 며칠을 고민해서 겨우 원하는 결과를 얻어내기는 했지만 여전히 처음부터 다시 하려고 하면 못할 것 같다. 포스팅을 하면서 머릿속을 다시 한번 정리해 봐야겠다. 어쨋든 TIL 시작
//Prompt
import java.util.Scanner;
public class Prompt {
public void runPrompt() {
Scanner scanner = new Scanner(System.in);
Calendar cal = new Calendar();
while(true) {
System.out.println("년을 입력하세요.");
int year = scanner.nextInt();
if (year < 1) {
System.out.println("bye");
break;
}
System.out.println("월을 입력하세요.");
int month = scanner.nextInt();
if (month < 1 || month > 12) {
System.out.println("잘못 입력하셨습니다.");
continue;
}
cal.printCalendar(year, month);
}
}
public static void main(String[] args) {
Prompt p = new Prompt();
p.runPrompt();
}
}
// Calendar
public class Calendar {
public static final int[] MAX_DAYS = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public static final int[] LEAP_MAX_DAYS = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public int maxDaysOfMonth(int year, int month) {
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
return LEAP_MAX_DAYS[month];
}
else {
return MAX_DAYS[month];
}
}
public void printCalendar(int year, int month) {
System.out.printf("\t\t<<%d년 %d월>>\n", year, month);
System.out.println("\tSU\tMO\tTU\tWE\tTH\tFR\tSA");
System.out.println("\t--------------------------");
int maxDay = maxDaysOfMonth(year, month);
int weekday = getWeekdays(year, month);
for (int i=0; i<weekday; i++) {
System.out.print("\t");
}
for (int j=1; j<7-weekday; j++) {
System.out.printf("\t%d", j);
}
System.out.println();
int cnt = 7 - weekday;
if (cnt == 7) {
cnt = 0;
}
for (int k=8-weekday; k<maxDay; k++) {
System.out.printf("\t%d",k);
if (k % 7 == cnt) {
System.out.println();
}
}
System.out.println();
System.out.println();
}
public int getWeekdays(int year, int month) {
int initialDay = 1; // 1년 1월 1일이 월요일 기준 잡음
// 년
int yearSum = 0;
for (int i=1; i<year; i++) {
for (int j=1; j<=12; j++) {
yearSum += maxDaysOfMonth(i,j);
}
}
// 월
int monthSum = 0;
for (int k=1; k<month; k++) {
monthSum += maxDaysOfMonth(year, k);
}
return (initialDay + yearSum + monthSum) % 7;
}
}
년, 월의 입력만 받아서 실제 달력을 출력 시키는데에 가장 중요한 논리는 특정일을 기준점으로 두고 그 기준일로부터 날짜를 더하고 빼서 내가 원하고자 하는 날의 달력을 출력해 내는 것이다. 더 쉽게 설명을 하자면, 1년 1월 1일을 월요일로 기준을 두자. 이렇게 기준점만 두더라도 알 수 있는 사실이 여러가지가 있다. 한 달이 31일인 경우, 31 % 7 = 3일이므로 다음달 1일은 저번달 1일의 요일로부터 3일후의 요일이 된다. 1월 1일이 월요일이므로 2월 1일은 목요일이 된다. 한 달이 30일이면 2일 뒤의 요일이고, 28일이면 전달 1일의 요일과 같다. 그리고 년으로 넘어가서 윤년을 고려해보면 올해가 평년이면 올해 1월 1일 요일의 다음 요일이 그 다음해의 요일이 된다. 1년 1월 1일이 월요일이면 2년 2월 1일은 화요일이 된다. 왜냐하면 365 % 7 = 1일이기 때문이다. 올해가 윤년이라면 366 % 7 = 2일이므로 다음해의 1월 1일은 다다음 요일이 된다. 이러한 것들을 일반화해서 논리적으로 풀면 1년 1월 1일을 기준으로 잡고 입력받은 년도만큼 날짜를 더해서 7로 나눈 나머지만큼 요일을 계산할 수 있고, 더 나아가서 월까지 더하면 매 달의 요일을 계산할 수 있다.