자바(JAVA)/미니 프로젝트 & 기초 공부

자바(JAVA) 미니 프로젝트-간단한 캘린더 프로그램 만들기 2 (5단계~7단계)

개발학생 2022. 3. 30. 00:34
반응형

4. 가상의 달력 모양 출력하기 (요일까지는 안 맞춘 버전)

*변동사항

  1. 월을 입력하면 해당 월의 달력이 출력되도록 한다. (*윤년일 경우에는 2월 달력을 29일까지 출력한다.)
  2. 달력의 모양은 1단계에서 작성했던 모양으로 만든다.
  3. -1을 입력받기 전까지 반복 입력받는다.
  4. Calendar 클래스가 너무 길어지므로, 메인 함수 부분을 새로 만든 Prompt 클래스로 옮김

- Prompt 클래스

import java.util.Scanner;

public class Prompt {
	public void runPrompt() {
		// 스캐너 열기
		Scanner sc = new Scanner(System.in);
		// 자바의 Calendar 클래스를 이름을 정해서 생성
		Calendar cal = new Calendar();

		int month = 1;
		int year = 2022;

		// 횟수가 사라지지 않는 반복 - while문에 true를 사용하여 무한루프
		while (true) {
			// 년도를 입력하라는 문구와 프롬프트 문자 및 커서 출력, year라는 변수로 년도에 해당하는 숫자를 입력받음
			System.out.println("년도를 입력하세요");
			System.out.print("YEAR> ");
			year = sc.nextInt();
			// 달을 입력하라는 문구와 프롬프트 문자 및 커서 출력, month라는 변수로 달에 해당하는 숫자를 입력받음
			System.out.println("달을 입력하세요");
			System.out.print("MONTH> ");
			month = sc.nextInt();
			// month에 -1을 입력할경우 프로그램 종료
			if (month == -1) {
				break;
			}
			// month가 12보다 클 경우 프로그램 다시 실행 (루프의 처음으로 돌아감)
			if (month > 12) {
				continue;
			}
			// 메인 메소드에서 Calendar 클래스인 cal 뒤에, void 메소드 printCalendar를 호출하여 가상 달력 출력
			cal.printCalendar(year, month);
		}

		// "Bye~" 문구 출력
		System.out.println("Bye~");
		// 스캐너 닫기
		sc.close();
	}

	public static void main(String[] args) {
		// 셀 실행
		Prompt p = new Prompt();
		p.runPrompt();
	}

}

 

- Calendar 클래스

public class Calendar {
	// 정적 메소드들을 만들어, 1월~12월의 윤년/평년 최대 일수들을 각각 순서대로 배열 안에 넣음
	public static final int[] MAX_DAYS = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	public static final int[] LEAP_MAX_DAYS = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	// 입력한 연도가 윤년인지 확인
	public boolean isLeapYear(int year) {
		if (year % 4 == 0 && (year % 100 != 0 || year % 400 != 0))
			return true;
		else
			return false;
	}

	// 윤년이면 LEAP_MAX_DAYS 메소드를 호출하고, 평년이면 MAX_DAYS 메소드 호출
	public int getMaxDaysOfMonth(int year, int month) {
		if (isLeapYear(year)) {
			return LEAP_MAX_DAYS[month - 1];
		} else {
			return MAX_DAYS[month - 1];
		}
	}

	// 가상 달력 (void 메소드인 printCalendar를 만들어 가상의 달력 생성)
	public void printCalendar(int year, int month) {
		System.out.printf("    <<%4d년%3d월>>\n", year, month);
		System.out.println(" SU MO TU WE TH FR SA");
		System.out.println("----------------------");

		int maxDay = getMaxDaysOfMonth(year, month);

		// for 문을 통해, 가상 달력에 1~31일사이의 날짜가 찍히게 함
		for (int i = 1; i <= maxDay; i++) {
			System.out.printf("%3d", i);
			if (i % 7 == 0)
				System.out.println();
		}
	}

}

 

- 출력 결과 (입력한 년도와 달에 맞는 일자까지의 달력이 출력된다. 단, 1일은 일요일로 고정됨)

* 2100년 2월 입력 시

 

* 2017년 3월 입력 시

 

5. 가상의 달력 모양 출력하기
   (요일 입력해서 요일에 맞는 달력을 출력하는 버전)

*변동사항

  1. 1일에 해당하는 요일을 입력받아 달력을 출력
  2. 한글로 된 요일 이름은 su, mo, tu, we, th, fr, sa로 변경
  3. 입력한 월이 1~12 사이의 숫자가 아니면 오류 메세지 출력 (프로그램은 다시 실행)
  4. 년도에 -1을 입력하면 프로그램 종료 & Bye~ 출력

 

- Prompt 클래스

import java.util.Scanner;

public class Prompt {
	// @param week 요일명
	// @return 0 ~ 6 (0 = Sunday, 6 = Saturday)
	public int parseDay(String week) {
		if (week.equals("su"))
			return 0;
		else if (week.equals("mo"))
			return 1;
		else if (week.equals("tu"))
			return 2;
		else if (week.equals("we"))
			return 3;
		else if (week.equals("th"))
			return 4;
		else if (week.equals("fr"))
			return 5;
		else if (week.equals("sa"))
			return 6;
		else
			return 0;

	}

	public void runPrompt() {
		...
		int month = 0;
		int year = 0;
		int weekday = 0;

		// 횟수가 사라지지 않는 반복 - while문에 true를 사용하여 무한루프
		while (true) {
			...  
			if (year == -1)
				break;
			...
            
			// 첫째 날의 요일 입력하라는 문구와 프롬프트 문자 및 커서 출력, str_weekday 변수로 요일(문자)을 입력받음
			System.out.println("첫째 날의 요일을 입력하세요(su, mo, tu, we, th, fr, sa).");
			System.out.print("WEEKDAY> ");
			String str_weekday = sc.next();
			weekday = parseDay(str_weekday);

			// month가 12보다 크거나 1보다 작을 경우 프로그램 다시 실행 (루프의 처음으로 돌아감)
            // month > 12 뒤에 "|| month < 1"을 추가하고, print 문구 출력부분 추가
			if (month > 12 || month < 1) {
				System.out.println("잘못된 입력입니다.");
				continue;
			}
			// 메인 메소드에서 Calendar 클래스인 cal 뒤에, void 메소드 printCalendar를 호출하여 가상 달력 출력
			cal.printCalendar(..., weekday);
		}
		...
	}
	...
}

 

- Calendar 클래스

public class Calendar {
	...
	// 가상 달력 (void 메소드인 printCalendar를 만들어 가상의 달력 생성)
	public void printCalendar(..., int weekday) {
		...
        // "int maxDay"가 들어간 부분을 "빈 공간~" for 문의 아래로 이동시킴
        // "maxDay" 변수가 있는 for 문을 삭제함
		...
        
		// 빈 공간(공백)을 넣어 출력
		for (int i = 0; i < weekday; i++) {
			System.out.print("   ");
		}
        
		...
        
		int count = 7 - weekday;
		// count가 7보다 작으면 delim=count이고 그 외에는 delim=0
		int delim = count < 7 ? count : 0;

		// 첫째 주의 토요일까지 출력
		for (int i = 1; i <= count; i++) {
			System.out.printf("%3d", i);
		}
		System.out.println();

		// 둘째 주 부터 마지막 주 토요일까지 출력
		count++;
		for (int i = count; i <= maxDay; i++) {
			System.out.printf("%3d", i);
			if (i % 7 == delim)
				System.out.println();
		}
		System.out.println();
		System.out.println();
	}

}

 

- 출력 결과 (입력한 년도와 달, 그리고 1일로 설정할 요일에 맞는 달력이 출력된다. )

* 2017, 6, th(목요일) 입력시

 

* 2017, 2, su(일요일) 입력 시

 

* -1 입력 시                                                    * 2017년 13월 입력 시

 

6. 실제와 같은 달력 모양 출력하기
   (입력을 받지 않고, 요일 계산 알고리즘으로 달력을 출력)

 

*변동사항

  1. 요일 입력 받는 코드 삭제
  2. 요일 계산 알고리즘을 추가하여, 실제 달력과 같은 달력을 출력하게 함

 

- Prompt 클래스

import java.util.Scanner;

public class Prompt {
	// public int parseDay 부분 삭제
	int month = 0;
	int year = 0;

	public void runPrompt() {
		...
		// int month, int year은 runPrompt 밖으로 빼내서 맨 위쪽으로 옮기고, int weekday는 삭제
		// 횟수가 사라지지 않는 반복 - while문에 true를 사용하여 무한루프
		while (true) {
        	...
            // 첫째 날의 요일을 입력하는 코드(4줄 모두) 삭제
			...
            // 메인 메소드에서 Calendar 클래스인 cal 뒤에, void 메소드 printCalendar를 호출하여 가상 달력 출력
			// 맨 뒤의 weekday 삭제
            		cal.printCalendar(year, month);
		}
		...
	}
	...
}

 

- Calendar 클래스

import java.time.DayOfWeek;
import java.time.LocalDate;

public class Calendar {
	...
	// 가상 달력 (void 메소드인 printCalendar를 만들어 가상의 달력 생성)
    // printCalendar 옆 괄호에서 int weekday 삭제
	public void printCalendar(int year, int month) {
		...
		// get weekday automatically
		// 1. LocalDate 생성
		LocalDate date = LocalDate.of(year, month, 1);
		// 2. DayOfWeek 객체 구하기
		DayOfWeek dayofweek = date.getDayOfWeek();
		// 3. 숫자 요일 구하기
		int weekday = dayofweek.getValue();
		...
        // 없던 주석 추가함
		// 해당 년도 & 해당 달의 최대 일수 구하기
		int maxDay = getMaxDaysOfMonth(year, month);
		...
	}

}

 

- 출력 결과 (모두 실제 달력의 년 월 일 요일과 같다.)

 

7. 간단한 UI 구현 및 일정 등록 기능 추가

*변동사항

1. UI 구현

- 일정 등록

- 일정 검색

- 달력 보기

- h. 도움말 q. 종료

 

2. 위 UI에서 3, q 입력시에 달력 보기 및 종료, 1 입력 시 일정 등록까지 가능하게 함

 

- Prompt 클래스에 추가한 코드

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

public class Prompt {
	...
	public static void runCommand() {
		// 스캐너 열기
		Scanner sc = new Scanner(System.in);

		System.out.println("+-----------------+");
		System.out.println("| 1. 일정 등록");
		System.out.println("| 2. 일정 검색");
		System.out.println("| 3. 달력 보기");
		System.out.println("| h. 도움말  q. 종료");
		System.out.println("+-----------------+");

		System.out.println("명령을 입력하세요 (1, 2, 3, h, q)");
		System.out.print("COMMAND> ");
		String command = sc.nextLine();

		if (command.equals("1")) {
			System.out.println("[일정 등록] 날짜를 입력하세요.(ex.2020-01-01)\n>");
			String theDate = sc.nextLine();

			HashMap<String, ArrayList<String>> listMap = new HashMap<String, ArrayList<String>>();

			// 오늘 날짜
			String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
			// 오늘 날짜를 년, 월, 일로 나눔
			String[] toDate = today.split("-");

			// 기존의 일정이 없다면, 빈 ArrayList를 추가
			if (!listMap.containsKey(theDate)) {
				ArrayList<String> emptyList = new ArrayList<String>();
				listMap.put(theDate, emptyList);
			}

			// 기존의 일정이 있다면, 일정을 추가로 등록
			System.out.print("[일정 등록] 일정을 입력하세요. \n>");
			String theList = sc.nextLine();

			ArrayList<String> existList = listMap.get(theDate);

			existList.add(theList);
			listMap.put(theDate, existList);

		} else if (command.equals("2")) {
			System.out.println("일정 검색");
		} else if (command.equals("3")) {
			Prompt p = new Prompt();
			p.runPrompt();
		} else if (command.equals("h")) {
			System.out.println("도움말");
		} else if (command.equals("q")) {
			System.out.println("\nBye~");
			// 스캐너 닫기
			sc.close();
		} else {
			System.out.println("잘못된 입력입니다.");
			System.out.println("\n명령을 입력하세요 (1, 2, 3, h, q)");
			System.out.print("COMMAND> ");
			command = sc.nextLine();
		}
	}
		...
	public static void main(String[] args) {
		// 프롬프트 클래스 실행 (기존의 "p.rumPrompt();" 부분은 runCommand() 메소드에 들어감)
		runCommand();
	}

}

 

- Calendar 클래스: 추가사항 없음

 

- 출력 결과
 (3을 누르면 이전의 달력 출력 프로그램이 실행되고, q를 누구면 종료되고, 1을 누르면 일정을 등록할 수 있다.)

 

반응형