このディレクトリの索引
#  出題場所 :: http://toro.2ch.net/test/read.cgi/tech/1390525149/103
#  お題:与えられた年月のカレンダーを表示せよ。 
#   

'与えられた年月のカレンダーを表示せよ。'(_年,_月) :-
        カレンダー矩形(_年,_月,_カレンダー矩形),
        カレンダーを表示する(_年,_月,_カレンダー矩形).

カレンダー矩形(_年,_月,_カレンダー矩形) :-
        '1日の曜日を表す値'(_年,_月,_1日の曜日を表す値),
        月末日(_年,_月,_月末日),
        日付を埋めて週カレンダーならびを作る(_1日の曜日を表す値,_月末日,_カレンダー矩形).

'1日の曜日を表す値'(_年,_月,_曜日を表す値) :-
        'Zellerの公式を用いて曜日を表す値と曜日を得る'(_年,_月,1,_曜日を表す値,_).

'Zellerの公式'(_年,_月,_日,_曜日を表す値) :-
        _曜日を表す値 is (_年 + truncate(_年 / 4) - truncate(_年 / 100) + truncate(_年 / 400) + truncate((13 * _月 + 8) / 5) + _日) mod 7.


'Zellerの公式を用いて曜日を表す値と曜日を得る'(_年,_月,_日,_曜日を表す値,_曜日) :-
        'Zellerの公式では1月と2月はそれぞれ前年の13月と14月に変換して計算する'(_年,_月,_日,_曜日を表す値,_曜日).
'Zellerの公式を用いて曜日を表す値と曜日を得る'(_年,_月,_日,_曜日を表す値,_曜日) :-
        _月 > 2,
        'Zellerの公式'(_年,_月,_日,_曜日を表す値),
        'Zellerの公式で曜日を表す値と曜日'(_曜日を表す値,_曜日).

'Zellerの公式では1月と2月はそれぞれ前年の13月と14月に変換して計算する'(_年,_月,_日,_曜日を表す値,_曜日) :-
        _月 =< 2,
        _年_1 is _年 - 1,
        _月_2 is _月 + 12,
        'Zellerの公式を用いて曜日を表す値と曜日を得る'(_年_1,_月_2,_日,_曜日を表す値,_曜日).

'Zellerの公式で曜日を表す値と曜日'(0,日曜).
'Zellerの公式で曜日を表す値と曜日'(1,月曜).
'Zellerの公式で曜日を表す値と曜日'(2,火曜).
'Zellerの公式で曜日を表す値と曜日'(3,水曜).
'Zellerの公式で曜日を表す値と曜日'(4,木曜).
'Zellerの公式で曜日を表す値と曜日'(5,金曜).
'Zellerの公式で曜日を表す値と曜日'(6,土曜).

月末日(_年,2,29) :-
        うるう年(_年),!.
月末日(_年,2,28) :- !.
月末日(_,_月,31) :-
        member(_月,[1,3,5,7,8,10,12]).
月末日(_,_月,30) :-
        member(_月,[4,6,9,11]).

うるう年(_年) :-
        0 is _年 mod 400,!.
うるう年(_年) :-
        \+(0 is _年 mod 100),!.
うるう年(_年) :-
        0 is _年 mod 4.

日付を埋めて週カレンダーならびを作る(_1日の曜日を表す値,_月末日,_週カレンダーならび) :-
        日付を埋める(_1日の曜日を表す値,_月末日,_42日分の日枠),
        週ごとに折り返す(_42日分の日枠,_週カレンダーならび).

日付を埋める(_1日の曜日を表す値,_月末日,_42日分の日枠) :-
        findall(A,(
                    between(1,42,N),
                    _日付 is N - _1日の曜日を表す値,
                    日付か空白を選択(_日付,_月末日,A)),
                _42日分の日枠).

日付か空白を選択(_日付,_月末日,' ') :-
        _日付 < 0,!.
日付か空白を選択(_日付,_月末日,' ') :-
        _日付 > _月末日,!.
日付か空白を選択(_日付,_月末日,_日付).

週ごとに折り返す([],[]).
週ごとに折り返す([_1,_2,_3,_4,_5,_6,_7|R1],[[_1,_2,_3,_4,_5,_6,_7]|R2]) :-
        週ごとに折り返す(R1,R2).

カレンダーを表示する(_年,_月,_週カレンダーならび) :-
        カレンダーの年月を表示する(_年,_月),
        カレンダーの日付部を表示する(_週カレンダーならび).

カレンダーの年月を表示する(_年,_月) :-
        writef('\n%10R年%3R月     \n\n',[_年,_月]).

カレンダーの日付部を表示する([]) :- !.
カレンダーの日付部を表示する([_週カレンダー|R]) :-
        writef('%3R%3R%3R%3R%3R%3R%3R\n',_週カレンダー),
        カレンダーの日付部を表示する(R).