請設計一個萬年曆程式。程式需支援以下兩個功能:
(1) 輸入一個數字 Y表示年份、M表示月份,接著印出這個月份的日曆。
(2) 輸入一個數字 Y表示年份,接著印出該年各月的日曆。
(3)可選擇單欄印出 或者 雙欄印出的選項
每一個月的日曆中的星期次序為「日、一、二、三、四、五、六」,此外,請上網 Google
查詢如何計算任一日屬於一星期中的哪一日。(關鍵字:「Zeller’s formula」或「蔡勒公式」)
Solution Code
#include <stdio.h>
#include <stdlib.h>
void main() {
int choice;
while(true) {
choice = 0; //每次把選擇都初始化
printf("請選擇\n (1)進入程式\n (2)離開程式\n> ");
fflush(stdin);
scanf_s("%d", &choice);
printf("\n");
//離開程式
if(choice == 2) {
printf("See you!\n");
break;
}
//進入程式
else if(choice == 1) {
//引導使用者輸入
int mode = 0, column = 0, yy = 0, mm = 0;
do {
printf("請選擇印出模式\n (1)單欄\n (2)雙欄\n> ");
fflush(stdin);
scanf_s("%d", &column);
if(column != 1 && column != 2)
printf("\n僅支援單欄或雙欄印出!! 請重新輸入\n\n");
}while(column != 1 && column != 2);
do {
printf("\n請選擇指定方法\n (1)指定年份\n (2)指定年份與月份\n> ");
fflush(stdin);
scanf_s("%d", &mode);
if(mode != 1 && mode != 2)
printf("\n不存在的指定方法!! 請重新輸入\n");
}while(mode != 1 && mode != 2);
do {
printf("\n請輸入年份\n> ");
fflush(stdin);
scanf_s("%d", &yy);
if(yy <= 0)
printf("\n不支援西元前!! 請重新輸入\n");
}while(yy <= 0);
if(mode == 2) {
do {
printf("\n請輸入月份\n> ");
scanf_s("%d", &mm);
if(mm < 1 || mm > 12)
printf("\n錯誤的月份!! 請重新輸入\n");
}while(mm < 1 || mm > 12);
}
//開始印出萬年曆,先偷偷測閏年
/*
偷偷測閏年
閏年條件:
1.西元年被400整除
2.西元年被4整除但不被100整除
*/
int leapYear = 0;
if(yy % 400 == 0 || (yy % 4 == 0 && yy % 100 != 0))
leapYear = 1;
//判斷模式,印某年全部或者特定月份
if (mode == 2) {
//只印特定月份的狀況
int day = 1, weekOfStart, dayOfMonth, week;
printf("\n %d 年 %d 月\n", yy, mm);
printf("日 一 二 三 四 五 六\n");
//先來算算這個月有幾天...
switch(mm) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
dayOfMonth = 31;
break;
case 2:
if(leapYear)
dayOfMonth = 29;
else
dayOfMonth = 28;
break;
case 4:
case 6:
case 9:
case 11:
dayOfMonth = 30;
break;
}
/*
開始印日期囉~
看成表格的方式來印
*/
//先來找第一天是星期幾
if(mm == 1 || mm == 2) // 1月和2月要特別處理
weekOfStart = ((yy-1)%100 + ((yy-1)%100)/4 + ((yy-1))/100/4 - 2*((yy-1)/100) + 26*(mm+13)/10);
else
weekOfStart = (yy%100 + (yy%100)/4 + (yy/100)/4 - 2*(yy/100) + 26*(mm+1)/10);
if(weekOfStart < 0)
weekOfStart = (weekOfStart%7+7)%7;
else
weekOfStart = weekOfStart%7;
//印出萬年曆
while(day <= dayOfMonth) {
for(week = 0;week < 7;week++) {
if(day == 1)
{
if(week == weekOfStart) {
printf("01 ");
day++;
}
else
printf(" ");
}
else if(day <= dayOfMonth) {
if(day < 10)
printf("0");
printf("%d",day);
if(week < 6)
printf(" ");
day++;
}
}
printf("\n");
}
printf("\n");
} else {
//印某年全部
if(column == 1) {
for(mm = 1;mm < 13;mm++) { //控制月份
int day = 1, weekOfStart, dayOfMonth, week;
printf("\n %d 年 %d 月\n", yy, mm);
printf("日 一 二 三 四 五 六\n");
//先來算算這個月有幾天...
switch(mm) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
dayOfMonth = 31;
break;
case 2:
if(leapYear)
dayOfMonth = 29;
else
dayOfMonth = 28;
break;
case 4:
case 6:
case 9:
case 11:
dayOfMonth = 30;
break;
}
/*
開始印日期囉~
看成表格的方式來印
*/
//先來找第一天是星期幾
if(mm == 1 || mm == 2) // 1月和2月要特別處理
weekOfStart = ((yy-1)%100 + ((yy-1)%100)/4 + ((yy-1)/100)/4 - 2*((yy-1)/100) + 26*(mm+13)/10);
else
weekOfStart = (yy%100 + (yy%100)/4 + (yy/100)/4 - 2*(yy/100) + 26*(mm+1)/10);
if(weekOfStart < 0)
weekOfStart = (weekOfStart%7+7)%7;
else
weekOfStart = weekOfStart%7;
//印萬年曆了
while(day <= dayOfMonth) {
for(week = 0;week < 7;week++) {
if(day == 1) {
if(week == weekOfStart) { //直到和該月第一天星期一樣才開始印日期
printf("01 ");
day++;
}
else
printf(" ");
}
else if(day <= dayOfMonth) {
if(day < 10)
printf("0");
printf("%d",day);
if(week < 6)
printf(" ");
day++;
}
}
if(day <= dayOfMonth)
printf("\n"); //週換行
}
printf("\n"); //月份換行
}
printf("\n"); //最後空一行
} else {
//用兩欄去印
for(mm = 1;mm < 13;mm+=2) { //控制月份,一次跳兩個月
int dayOdd = 1, dayEven = 1, weekOfStartOfOdd, weekOfStartOfEven, dayOfMonthOfOdd, dayOfMonthOfEven, week;
printf("\n %d 年 %d 月\t\t %d 年 %d 月\n", yy, mm, yy, mm+1);
printf("日 一 二 三 四 五 六\t\t日 一 二 三 四 五 六\n");
//先偷偷算單雙數月的天數
switch(mm) {
case 1:
dayOfMonthOfOdd = 31;
if(leapYear)
dayOfMonthOfEven = 29;
else
dayOfMonthOfEven = 28;
break;
case 3:
dayOfMonthOfOdd = 31;
dayOfMonthOfEven = 30;
case 5:
dayOfMonthOfOdd = 31;
dayOfMonthOfEven = 30;
case 7:
dayOfMonthOfOdd = 31;
dayOfMonthOfEven = 31;
case 9:
dayOfMonthOfOdd = 30;
dayOfMonthOfEven = 31;
case 11:
dayOfMonthOfOdd = 30;
dayOfMonthOfEven = 31;
}
//先來找第一天
if(mm == 1) { // 1月和2月要特別處理
weekOfStartOfOdd = ((yy-1)%100 + ((yy-1)%100)/4 + ((yy-1)/100)/4 - 2*((yy-1)/100) + 26*(mm+13)/10);
weekOfStartOfEven = ((yy-1)%100 + ((yy-1)%100)/4 + ((yy-1)/100)/4 - 2*((yy-1)/100) + 26*(mm+14)/10);
} else {
weekOfStartOfOdd = (yy%100 + (yy%100)/4 + (yy/100)/4 - 2*(yy/100) + 26*(mm+1)/10);
weekOfStartOfEven = (yy%100 + (yy%100)/4 + (yy/100)/4 - 2*(yy/100) + 26*(mm+2)/10);
}
if(weekOfStartOfOdd < 0)
weekOfStartOfOdd = (weekOfStartOfOdd%7+7)%7;
else
weekOfStartOfOdd = weekOfStartOfOdd%7;
if(weekOfStartOfEven < 0)
weekOfStartOfEven = (weekOfStartOfEven%7+7)%7;
else
weekOfStartOfEven = weekOfStartOfEven%7;
//印出萬年曆
while(dayOdd <= dayOfMonthOfOdd || dayEven <= dayOfMonthOfEven) { //控制列
for(week = 0;week < 15;week++) {
//先印單數月的部分
if(week < 7) {
if(dayOdd == 1) {
if(week == weekOfStartOfOdd) {
printf("01 ");
dayOdd++;
}
else
printf(" ");
}
else if(dayOdd <= dayOfMonthOfOdd) {
if(dayOdd < 10)
printf("0");
printf("%d",dayOdd);
if(week < 6)
printf(" ");
dayOdd++;
}
//處理提早結束的問題
if(dayOdd > dayOfMonthOfOdd) {
if(week < 6)
printf(" ");
else
printf(" ");
}
}
//雙數月的部分
else if(week > 7) {
if(dayEven == 1) {
if(week - 8 == weekOfStartOfEven) {
printf("01 ");
dayEven++;
}
else
printf(" ");
}
else if(dayEven <= dayOfMonthOfEven) {
if(dayEven < 10)
printf("0");
printf("%d",dayEven);
if(week < 15)
printf(" ");
dayEven++;
}
}
else //兩個月中間空兩個tab
printf("\t\t");
}
printf("\n");
}
}
printf("\n");
}
}
}
else
printf("選擇錯誤,請重新輸入!\n\n");
}
system("pause");
}
沒有留言:
張貼留言