[C/C++] 程式語言作業-時空旅人的萬年曆

摘要:[C/C++] 程式語言作業-時空旅人的萬年曆

題目的敘述如下: 

倘若在宇宙中某一個異次元世界當中,有一個星球的曆法和地球一樣,包括閏年規則、每個月天數、每周天數都一樣。唯一不同的是,它們的星期幾和地球有平行的差異,舉例來說,地球的星期一在那邊可能是星期三,星期二是星期四,以此類推 (有一個等差,但不見得完全相同)。
為了方便時空旅人,於是你要寫一個給他們用的萬年曆程式,只要輸入那個世界當中某西元年 (>=1)、月 (1~12)、日 (1~當月最大天數) 與星期幾 (0~6,0表示星期天)。然後就可以透過輸入西元年和月,得知在當地該月份的月曆。

 看到這樣的萬年曆變形題,我的解題概念是計算地球跟外星的offset,然後再用普通印萬年歷的方法即可完成。

除了main()以外,我定義了4個function

//判斷是否為閏年
int isLeapYear(int year);
//傳回這一天是星期幾
int getWeekday(int year, int month, int day);
int getWeekday(int year, int month, int day, int offset);
//根據輸入的year, month以及offset印出月歷
int printMonthCalendar(int year, int month, int offset);

其中判斷閏年的方法我參考閏年 - 維基百科的邏輯,在此就不贅述

int isLeapYear(int year) {
	return (year%400==0) || ((year%4==0) && (year%100!=0));
}

計算星期幾的公式也是網路上找的:
W = [Y-1] + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D

int getWeekday(int year, int month, int day, int offset) {
	//12個月各月的天數 
	int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	//如果是閏年,2月就多加1天變成29天 
	days[1] += isLeapYear(year);
	//計算這一天是一年中的第幾天 
	int d, i;
	d = day;
	for (i=0; i<month-1; i++) {
		d += days[i];
	}
	//根據公式去計算這一天是星期幾 
	year--;
	d += year + (year/4) - (year/100) + (year/400);
	d += offset + 7; //此處+7是避免d算出來是負值的情況
	d %= 7; //算出星期幾 
	return d;
}

完整的程式碼如下 

#include <stdio.h>

//判斷是否為閏年
int isLeapYear(int year);
//傳回這一天是星期幾
int getWeekday(int year, int month, int day);
int getWeekday(int year, int month, int day, int offset);
//根據輸入的year, month以及offset印出月歷
int printMonthCalendar(int year, int month, int offset);
	
//判斷是否為閏年 
int isLeapYear(int year) {
	return (year%400==0) || ((year%4==0) && (year%100!=0));
}

//傳回這一天是星期幾 
int getWeekday(int year, int month, int day) {
	return getWeekday(year, month, day, 0);
}

//傳回這一天是星期幾 
int getWeekday(int year, int month, int day, int offset) {
	//12個月各月的天數 
	int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	//如果是閏年,2月就多加1天變成29天 
	days[1] += isLeapYear(year);
	//計算這一天是一年中的第幾天 
	int d, i;
	d = day;
	for (i=0; i<month-1; i++) {
		d += days[i];
	}
	//根據公式去計算這一天是星期幾 
	year--;
	d += year + (year/4) - (year/100) + (year/400);
	d += offset + 7; //此處+7是避免d算出來是負值的情況
	d %= 7; //算出星期幾 
	return d;
}

//根據輸入的year, month以及offset印出月歷
int printMonthCalendar(int year, int month, int offset) {
	//12個月各月的天數 
	int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	//如果是閏年,2月就多加1天變成29天 
	days[1] += isLeapYear(year);
	//計算這個月第一天是星期幾 
	int weekday = getWeekday(year, month, 1, offset);
	//開始印出月歷 
	int i, count; 
	printf(" SUN MON TUE WED THU FRI SAT\n");
	//印出第一週的空白 
	for (i=0; i<weekday; i++) {
		printf("%4s", " ");
	}
	//印出每一天 
	for (i=1, count=weekday+1; i<=days[month-1]; i++, count++) {
		printf("%4d", i);
		//處理換行 
		if (count % 7 == 0) {
			printf("\n");
		}
	}
	//如果最後一天是星期六就不要再多印換行,以保持輸出的資料沒有多餘的空行 
	if ((count-1) %7 != 0) {
		printf("\n");
	}
	return 0;
} 

int main() {
	//輸入資料 
	int year, month, day, weekday;
	printf("輸入年月日(以空白分開): ");
	scanf("%d %d %d", &year, &month, &day);
	printf("輸入星期幾(0為星期日,1~6為星期一~六): ");
	scanf("%d", &weekday);
	//計算位移 
	int offset = weekday - getWeekday(year, month, day);
	
	//讓程式可以重複輸入資料 
	while (1) {
		printf("輸入年份和月份(輸入0 0以結束): ");
		scanf("%d %d", &year, &month);
		//輸入0 0就結束 
		if (!year & !month) {
			break;
		}
		//印出月歷 
		printMonthCalendar(year, month, offset);
	}
	return 0;
}

程式的執行結果,使用者介面按照題目的範例去仿製: 

文章內容僅提供技術分享,如有錯誤還請不吝指教。