C#で学ぶ!指カレンダーの使い方~従来の手順(3/4)
日付の範囲
日付として有効な範囲はグレゴリオ暦の$${1}$$年$${1}$$月$${1}$$日から$${9999}$$年$${12}$$月$${31}$$日まで(※)です. ただし, ユーザは与えられた日付に対して,
その年の$${1}$$月$${1}$$日の曜日を知っている.
その年が平年か閏年か分かる.
必要があります.
※:世界史において実際にグレゴリオ暦(新暦ともいう)が採用されたのは$${1582}$$年$${10}$$月$${15}$$日からです.
グレゴリオ暦の置閏法
上述のように, ユーザは日付の年が平年か閏年かを事前に知っておく必要があります. では, グレゴリオ暦ではその平年か閏年かを決めるルール(置閏法)がどんなものかというと, 次のようにはっきり決まっています.
グレゴリオ暦の置閏法:
日付の年数を$${Y}$$としたとき
$${Y}$$が$${4}$$で割り切れない.
$${Y}$$が$${4}$$で割り切れて, $${100}$$で割り切れない.
$${Y}$$が$${100}$$で割り切れて, $${400}$$で割り切れない.
$${Y}$$が$${400}$$で割り切れる.
の$${2}$$と$${4}$$の場合にはその年は閏年, $${1}$$と$${3}$$の場合にはその年は平年となります.
手順
従来の指カレンダーの手順はコードで表すと下記のようになります.
従来の指カレンダーの手順(C#による記述):
int Month = 12;
int Day = 31;
int number = 0;
int yubi = 0;
int january1st = 5;
bool isLeapYear = false;
// Calculation for "Month".
if (isLeapYear)
{
switch (Month)
{
case 1:yubi = 0; break;
case 2:yubi = 3; break;
case 3:yubi = 4; break;
case 4:yubi = 0; break;
case 5:yubi = 2; break;
case 6:yubi = 5; break;
case 7:yubi = 0; break;
case 8:yubi = 3; break;
case 9:yubi = 6; break;
case 10:yubi = 1; break;
case 11:yubi = 4; break;
case 12:yubi = 6; break;
}
} else
{
switch (Month)
{
case 1: yubi = 0; break;
case 2: yubi = 3; break;
case 3: yubi = 3; break;
case 4: yubi = 6; break;
case 5: yubi = 1; break;
case 6: yubi = 4; break;
case 7: yubi = 6; break;
case 8: yubi = 2; break;
case 9: yubi = 5; break;
case 10: yubi = 0; break;
case 11: yubi = 3; break;
case 12: yubi = 5; break;
}
}
// Calculation for "Day".
number = 1;
while (number + 7 <= Day) {number = number + 7;}
while (number + 1 <= Day) {number = number + 1; yubi = (yubi + 1) % 7;}
// Calculation for "january1st".
for (int i = 0; i < january1st; i++)
{
yubi = (yubi + 1) % 7;
}
始めに変数に対して設定を行ってから手順を実行してみてください. (コード内では与えられた日付が$${9999}$$年$${12}$$月$${31}$$日だったとして設定しています. )
すると最終的に$${yubi}$$という変数に計算結果($${0}$$から$${6}$$までの整数)が入力され, その値によって与えられた日付の曜日を求めることができます.
初期設定のしかた:
日付の月数, 日数をそれぞれ$${Month}$$, $${Day}$$に入力する($${1}$$~$${2}$$行目).
日付の年の$${1}$$月$${1}$$日の曜日に対応する数値を$${january1st}$$に入力する($${5}$$行目).
ただし, 曜日と数値の対応についてはやはり次のようにします.
$${isLeapYear}$$に対して, 日付の年が閏年なら$${true}$$, 平年なら$${false}$$を入力する($${6}$$行目).
yubiの計算について
コードでは変数$${yubi}$$には$${0}$$から$${6}$$までの整数が入力され, それが何度か更新されます. その更新する際に行っている入力や計算を, 指を使って行うのが指カレンダーの大きな特徴となっています. その詳しい方法については次の記事を参照してください。
指を使ったモジュラ計算(noteの記事)
3つのセクション
コードには$${3}$$つのセクションがあり, それぞれ$${Month}$$に関する計算($${9}$$~$${43}$$行目),
$${Day}$$に関する計算($${46}$$~$${48}$$行目),
$${january1st}$$に関する計算($${51}$$~$${54}$$行目)
を担当しています. これらのセクションの順番は入れ替えないでください.
Monthに関する計算
if~else文により, $${isLeapYear}$$が$${true}$$のとき, つまり日付が閏年のときは上のブロックが実行されます.
一方で, $${isLeapYear}$$が$${false}$$のとき, つまり日付が平年のときは下のブロックが実行されます.
いずれにしてもブロック内ではswitch文により評価対象の$${Month}$$がとりうる$${12}$$パターンの値(日付の各月に対応)それぞれについて, 決まった値により$${yubi}$$を更新させています.
(例:$${9999}$$年$${12}$$月$${31}$$日の場合)
平年で$${Month=12}$$なので$${yubi=5}$$.
Dayに関する計算
ここでは始めに$${number}$$という計算用の変数に$${1}$$を代入します. ちなみに, この$${number}$$については指で計算するとかはないので, シンプルに頭の中で計算を行います.
(例:$${9999}$$年$${12}$$月$${31}$$日の場合)
$${number=1}$$.
そして次にあるwhile文では$${number + 7 ≤ Day}$$という条件が成立する間ずっとブロック内の命令を繰り返し実行します. ブロック内では, $${number}$$を$${7}$$ずつ増加させるという計算を行います.
(例:$${9999}$$年$${12}$$月$${31}$$日の場合)
続くwhile文では$${number + 1 ≤ Day}$$という条件が成立する間ずっとブロック内の命令を繰り返し実行します. ブロック内では, $${number}$$を$${1}$$ずつ増加させると同時に, $${yubi}$$の値を更新させています.
(例:$${9999}$$年$${12}$$月$${31}$$日の場合)
january1stに関する計算
ここでは$${january1st}$$という変数が登場します. 上述のようにこの変数には日付の年の$${1}$$月$${1}$$日の曜日に対応する数値が格納されています.
(例:$${9999}$$年$${12}$$月$${31}$$日の場合)$${9999}$$年$${1}$$月$${1}$$日が金曜日であることから, $${january1st=5}$$.
そしてfor文により, $${january1st}$$の値の回数だけブロック内の命令を繰り返します. ブロック内では$${yubi}$$を更新させているので, つまりそれを$${january1st}$$の値の回数だけ繰り返すということになります.
(例:$${9999}$$年$${12}$$月$${31}$$日の場合)
$${january1st=5}$$なので命令を$${5}$$回実行する.
この記事が気に入ったらサポートをしてみませんか?