/********************************************************************
Program: 萬年曆
Version: 1.3
File: HK0214D.cpp HomeWork_02 1.4 Description
compiler: Turbo c++ 3.0
Author: 龍龍 (Dick Guan) B86506057
Date: 11/6/1997
Description:
已知:
西元一年一月一日為 Sat
1752為特殊的一年(曆法上有點兒更改)
1752之前為四年一閏
1752之9月只有19天 (1.2.14.15.......)沒有3~13號
1752以後之閏年規則為:是4的倍數,不是100的倍數而是400的倍數
ex. 1800不是閏年(100的倍數)但2000是閏年(因是400的倍數)
思考:
利用我們的星期是連續的,且是七個一循環
假設使用者輸入year年month月,我們可寫個函數
算出由西元元年一月一日至year年month月1日共隔了幾天
(當然,必須再寫個函數用來判定這一連下來的年有無閏年(1752前後不一樣判定法)
或是特殊的1752年9月___只有19天!!!)
將結果加上6(因為一年一月一日是Sat),再將結果除以7
所得結果即為year年month月1日是星期幾
研析:
1年1月1日是Sat
2年1月1日是Sum 加1
3年1月1日是Mon 加1
4年1月1日是Tue 加1
5年1月1日是Thu 加2....!!!
有沒有發覺,如果當年不是閏年,則下一年的同一天其星期數會加一天,
閏年則加兩天
因為 365(沒有閏年) / 7 ......1
366(閏年) / 7 ......2
so.....................可藉此特性來算出
由1年1月1日至year年1月1日累計了多少天(而不是多少個365或366天)
這樣比較快的 :>
********************************************************************/
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
enum {Sum, Mon, Tue, Wed, Thu, Fri, Sat};
enum {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
enum {Normal_Feb=1, Leap_Feb=2, Special_Sep=5};
const char *Month[] = {"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};
//const char *Week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
int Month_Days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int Special_Day[12][32];
void display_calendar(int year, int month, int first_day, int x, int y, int
color);
int find_day(int year, int month, int day);
int leap(int year);
void input_data(int &year, int &month, int &start_month);
void set_special_day(void);
void main(void)
{
const int x_skip_space = 24;
const int y_skip_space = 10;
int year;
int month;
int day = 1; // default day = 1
int first_day;
int start_month;
int color;
set_special_day();
do{
input_data(year, month, start_month);
for(int i=0; i<6; i++)
{
if(start_month == month)
color = WHITE;
else
color = LIGHTGRAY;
first_day = find_day(year, start_month, day);
display_calendar(year, start_month++, first_day,
(i%3)*x_skip_space+1, (i/3)*y_skip_space+3, color);
// 下行為恢復一般二月份的正常天數
Month_Days[Feb] = 28;
}
printf("\nContinue..? [Y/N] :");
}while(toupper(getch()) == 'Y');
}
void input_data(int &year, int &month, int &start_month)
{
do{
clrscr();
printf("Please Input the year and the month : ");
scanf("%d %d", &year, &month);
if(year>0 && month>0 && month<13)
break;
printf("Input error...!!!\n");
getch();
}while(1);
month--; // Because array starts at 0 , not 1
start_month = ((month>=6) ? Jul : Jan);
}
void set_special_day(void)
{
Special_Day[Jan][1] = 1;
Special_Day[Feb][14] = 1;
Special_Day[Aug][8] = 1;
Special_Day[Sep][28] = 1;
Special_Day[Oct][10] = 1;
Special_Day[Oct][25] = 1;
Special_Day[Oct][31] = 1;
Special_Day[Nov][4] = 1; // my birthday
Special_Day[Nov][12] = 1;
Special_Day[Dec][25] = 1;
}
/************************************************************************
Function: display_calendar(int year, int month, int first_day)
用來顯示月曆,需注意1752年9月
又顯示方式可利用一個迴圈由1號至月底
並設一個變數day來代表是星期幾
當day遞增至星期六時,將day改為星期日(即為數值上的0)並執行換行程式
************************************************************************/
void display_calendar(int year, int month, int first_day, int x, int y, int
color)
{
int number;
int day = first_day;
int flag = 0; /*判斷旗標,判斷是否為1752/9*/
if(year == 1752 && month == Sep) flag = 1;
textcolor(color);
gotoxy(x, y);
cprintf(" %4d %s\n",year, Month[month]);
gotoxy(x, ++y);
cprintf(" Su Mo Tu We Th Fr Sa\n");
gotoxy(x+first_day*3, ++y);
/*依續由1號至月底(Month_Days[month])跑下來
flag是用來檢查特例的1752/9用*/
for (number=1; number<=Month_Days[month]; number++)
{
if(flag)
if(number > 2 && number < 14)
continue; /*因1752/9沒有3~13所以跳過*/
if(day==Sum) textcolor(LIGHTRED);
else if(day==Sat) textcolor(LIGHTBLUE);
if(Special_Day[month][number]) textcolor(YELLOW);
cprintf("%3d",number); /*以四格為單位位移量*/
day++; /*星期數遞增*/
textcolor(color);
if(day > Sat) /*如超過Sat,則還原為Sum,且換行*/
{
day = Sum;
gotoxy(x, ++y);
}
}
printf("\n");
}
/***************************************************************************
Function: int find_day(int year, int month, int day)
回傳值為year年month月day日是星期幾
在此題中,day已內設為1(參考main中)
*****************************************************************************/
int find_day(int year, int month, int day)
{
long delta_days = Sat;
int first_day;
int i = 1;
for(; i < year; i++)
delta_days += leap(i);
/*算出由西元一年一月一日至(year-1)年所累計的天數*/
/*以下為再算出year年的年初至month月1日所經過的天數
其中,先判斷year年是否為閏年
接著判斷是否為怪怪的1752
第三部分則為將值加起來囉*/
if(leap(year) == Leap_Feb)
Month_Days[Feb] = 29;
if(year == 1752)
{
Month_Days[Feb] = 29; /*小心!1752年亦是閏年唷...!!*/
Month_Days[Sep] = 19;
}
for(i=0; i<(month); i++)
delta_days += Month_Days[i];
Month_Days[Sep] = 30;
/*以下四行可不加,因此程式還可用來求year年month月day日是星期幾
if的那一段是因為1752年9月沒有3~13號,所以要特別的計算*/
if(year == 1752 && month == Sep && day > 13)
delta_days += day-12;
else
delta_days += day-1;
/*除以7,可得星期幾*/
first_day = (int)(delta_days % 7);
return(first_day);
}
/*****************************************************************************
Function: int leap(int year)
用來判斷year年是否為閏年(要分1752年前後)或是特殊的1752年9月
****************************************************************************/
int leap(int year)
{
if(year > 1752)
{
if(year%4 == 0 && (year%100 != 0 || year%400 == 0))
return(Leap_Feb);
}
else if(year < 1752)
{
if(year%4 == 0)
return(Leap_Feb);
}
else if(year == 1752)
{
return(Special_Sep);
/*Special_Sep = 5, 因為1752年是閏年,但9月只有19天(少11天)
so... 1752年為 [365(一般) + 1(閏年) - 11(9月)]除以7餘5囉..^_^
*/
}
return(Normal_Feb);
}
--
龍龍
你是一位聰明人嗎?如果是,你該記住,你的聰明是跟那些人學來的,
然後在適當的地點,適當的時間,輕輕的對那人說:這是你教我的。
聲音要輕,而且只告訴他一個人。
摘錄自"牧羊少年奇幻之旅"
--
※ 發信站: 批踢踢實業坊(ptt.twbbs.org)
◆ From: DickG.m5.ntu.edu