C++で指定した年のカレンダーを出力する方法
この記事では、ある年を入力として受け取り、その年のカレンダーをコンソールに出力するC++プログラムを紹介します。
年間カレンダーには、1月から12月までのすべての月と、各月の日付が表示されます。ここでは、指定した年のカレンダー全体を出力するプログラムを段階的に作成していきます。
カレンダーを生成するためには、主に次の2つの計算が必要になります。
1. 特定の月の日数を求める
まず、各月が何日あるかを正しく把握する必要があります。
- 31日の月: 1月、3月、5月、7月、8月、10月、12月
- 30日の月: 4月、6月、9月、11月
- 2月: 平年は28日、うるう年は29日
うるう年の判定は、「400で割り切れる年」、または「4で割り切れ、かつ100で割り切れない年」という一般的なルールに基づいて行います。
2. 月の開始曜日を求める
年と月の情報から、毎月1日が何曜日であるかを計算します。この開始曜日によって、カレンダーの1行目に挿入すべき空白(インデント)の数が決まります。
サンプルプログラム
それでは、実際に2019年のカレンダーを出力するプログラムを見てみましょう。
#include<iostream>
using namespace std;
int dayNumber(int day, int month, int year){
static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
year -= month < 3;
return ( year + year/4 - year/100 + year/400 + t[month-1] + day) % 7;
}
string getMonthName(int monthNumber){
string months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
return (months[monthNumber]);
}
int numberOfDays (int monthNumber, int year){
switch(monthNumber){
case 0 :
case 2 :
case 4 :
case 6 :
case 7 :
case 9 :
case 11: return(31);
break;
case 1 :
if (year % 400 == 0 || (year % 4 == 0 && year %100 != 0))
return (29);
else
return (28);
break;
case 3 :
case 5 :
case 8 :
case 10 : return(30);
break;
}
}
void printCalendar(int year){
cout<<"\t\t\t Calendar - Year "<<year;
int days;
int current = dayNumber (1, 1, year);
for (int i = 0; i < 12; i++){
days = numberOfDays (i, year);
cout<<endl<<"\t\t ----X----"<<getMonthName (i).c_str()<<"----X---- \t\t"<<endl;
cout<<" Sun Mon Tue Wed Thu Fri Sat \n";
int k;
for (k = 0; k < current; k++)
cout<<"\t";
for (int j = 1; j <= days; j++){
printf("%5d", j);
if (++k > 6){
k = 0;
cout<<endl;
}
}
if (k)
cout<<endl;
current = k;
}
return;
}
int main(){
int year = 2019;
printCalendar(year);
return (0);
}
出力結果
Calendar - Year 2019
----X----January----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
----X----February----X----
Sun Mon Tue Wed Thu Fri Sat
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28
----X----March----X----
Sun Mon Tue Wed Thu Fri Sat
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
----X----April----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
----X----May----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
----X----June----X----
Sun Mon Tue Wed Thu Fri Sat
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
----X----July----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
----X----August----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
----X----September----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
----X----October----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
----X----November----X----
Sun Mon Tue Wed Thu Fri Sat
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
----X----December----X----
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
プログラムのポイント
- dayNumber関数: 「サカモトのアルゴリズム」と呼ばれる手法を用い、指定した日付の曜日(0=日曜〜6=土曜)を高速に算出します。
- getMonthName関数: 月番号に対応する英語の月名を返します。
- numberOfDays関数: 月ごとの日数を、うるう年の判定も含めて返します。
- printCalendar関数: 各月の開始曜日分だけタブで空白を空け、printfの書式指定「%5d」で日付を右揃えに整列させながら出力します。週が変わるたびに改行し、前の月の終了曜日を次の月の開始位置として引き継ぐのがポイントです。
この仕組みを理解すれば、main関数のyear変数を変更するだけで、任意の西暦年の年間カレンダーを生成できるようになります。ぜひ自分の環境でコンパイルして、動作を確認してみてください。
-
C++で始点から終点までのすべての経路を出力する方法|深さ優先探索(DFS)による実装
この記事では、有向グラフが与えられたときに、始点(ソース)から終点(デスティネーション)までのすべての経路を出力する問題を、C++で解く方法を解説します。有向グラフとは?有向グラフとは、各辺に向きが定められており、頂点Aから頂点Bへと一方向に進むことができるグラフのことです。逆向き(BからA)には、対応する逆向きの辺が存在しない限り移動できません。問題の例具体例を使って問題を理解しましょう。下図のようなグラフを考えます。始点を「K」、終点を「P」とした場合の出力は次のようになります。出力:K -> T -> Y -> A -> P K -> T -> Y -
-
C++で非連結グラフに対するBFS(幅優先探索)を実装する方法
非連結グラフとは非連結グラフ(disconnected graph)とは、グラフ内の1つ以上の頂点が他の頂点と辺でつながっておらず、どこかの頂点から出発しても到達できない頂点が存在するグラフのことです。このようなグラフは、複数の「連結成分(connected component)」に分かれている状態と捉えることができます。通常のBFSでは不十分な理由単純な幅優先探索(BFS: Breadth First Search)が正しく機能するのは、グラフが連結している場合、すなわちグラフ内のすべての頂点がある1つの頂点から到達できる場合だけです。非連結グラフでは、開始頂点から到達できない頂点が必ず存在