請設計一個萬年曆程式。程式需支援以下兩個功能:
(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"); }
沒有留言:
張貼留言