このディレクトリの索引
% [1] 授業単元:C言語演習課題
% http://kansai2channeler.hp.infoseek.co.jp/cgi-bin/joyful/img/9422.txt
% 問題
% 年と月を「YYYY/MM」と入力し、入力された月のカレンダーを表示しなさい。
%
% 1752年10月以前、及び10000年1月以降はエラーを返す。
% 
% 出力形式は以下のとおり
% ・1行目は該当月の1日が月曜日でなければ、前月の最終月曜日から表示。
% ・該当月の最終日が日曜日でなければ、翌月の第1日曜日まで表示。
% ・6行目の表示が必要ない場合は表示しない。
%
% うるう年判定は以下のとおり
% ・年が4で割り切れる年はうるう年。
% ・年が100で割り切れる年はうるう年でない。
% ・年が400で割り切れる年はうるう年である。
% 
% [出力例]
% 年月日を入力:2009/07
% 
% 月 火 水 木 金 土 日
% 29 30 01 02 03 04 05
% 06 07 08 09 10 11 12
% 13 14 15 16 17 18 19
% 20 21 22 23 24 25 26
% 27 28 29 30 31 01 02

課題のカレンダー(_年/_月) :-
    not((_年/_月 >= 1752/10,_年/_月 =< 10000/1)),
    write('エラー: 入力された年月は範囲を逸脱しています\n'),!.
課題のカレンダー(_年/_月) :-
    _年/_月 @=< 2009/6,!,
    曜日検索(_日付,_曜日,2009/6/13,土曜),
    _日付=_年/_月/1,
    課題のカレンダー表示(_日付,_曜日).
課題のカレンダー(_年/_月) :-
    _年/_月 @>= 2009/6,!,
    曜日検索(2009/6/13,土曜,_日付,_曜日),
    _日付=_年/_月/1,
    課題のカレンダー表示(_日付,_曜日).

課題のカレンダー表示(_年/_月/_日,月曜) :-
    日付候補を得る(_年/_月/_日,_年/_月/_日,月曜,_日付整数ならび),
    課題のカレンダー見出し表示,
    課題のカレンダー週表示(_日付整数ならび).

課題のカレンダー表示(_年/_月/_日,_曜日) :-
    not(_曜日=月曜),
    前週の月曜日(_年/_月/_日,_曜日,_前週の月曜日),
    日付候補を得る(_年/_月/_日,_前週の月曜日,月曜,_日付整数ならび),
    課題のカレンダー見出し表示,
    課題のカレンダー週表示(_日付整数ならび).

前週の月曜日(_年/_月/_日,_曜日,_前週の月曜日) :-
    曜日検索(_前週の月曜日,_前週の曜日,_年/_月/_日,_曜日),
    _前週の曜日 = 月曜,!.

日付候補を得る(_年/_月/_日,_起点日付,_曜日,_日付整数ならび) :-
    findall(_日付,( 曜日(_起点日付,_曜日,_日付2,_),(_日付2=_年2/_月2/7,_年2/_月2 @> _年/_月,!,fail;true)),_日付整数ならび).

課題のカレンダー週表示(_日付整数ならび) :-
    n個組(7,_日付整数ならび,_7個組),
    月曜から日曜までヘッドゼロサプライで表示(_7個組).

月曜から日曜までヘッドゼロサプライで表示([_年/_月/_日]) :-
    ヘッドゼロサプライ(2,_日,_日付文字列),
    write_formatted('%t\n',[_日文字列]),!.
月曜から日曜までヘッドゼロサプライで表示([_年/_月/_日|R]) :-
    ヘッドゼロサプライ(2,_日,_日付文字列),
    write_formatted('%t ',[_日付文字列]),
    月曜から日曜までヘッドゼロサプライで表示(R).

課題のカレンダー見出し表示 :-
    write_formatted('月 火 水 木 金 土 日\n').

曜日検索(_日付,_曜日,_今日,_今日の曜日) :-
    var(_日付),
    var(_曜日),
    前日・今日(_日付,_曜日,_今日,_今日の曜日).
曜日検索(_日付,_曜日,_今日,_今日の曜日) :-
    var(_日付),
    var(_曜日),
    前日・今日(_前日,_前日の曜日,_今日,_今日の曜日),
    曜日検索(_日付,_曜日,_前日,_前日の曜日).
曜日検索(_今日,_今日の曜日,_日付,_曜日) :-
    var(_日付),
    var(_曜日),
    前日・今日(_今日,_今日の曜日,_日付,_曜日).
曜日検索(_今日,_今日の曜日,_日付,_曜日) :-
    var(_日付),
    var(_曜日),
    前日・今日(_今日,_今日の曜日,_翌日,_翌日の曜日),
    曜日検索(_翌日,_翌日の曜日,_日付,_曜日).

'曜日'(_日付,_曜日,_日付,_曜日) :-
    ! .
'曜日'(_日付1,_曜日1,_日付2,_曜日2) :-
    _日付1 @> _日付2,
    '前日・今日'(_日付3,_曜日3,_日付1,_曜日1),
    '曜日'(_日付3,_曜日3,_日付2,_曜日2) .
'曜日'(_日付1,_曜日1,_日付2,_曜日2) :-
    _日付1 @< _日付2,
    '前日・今日'(_日付1,_曜日1,_日付3,_曜日3),
    '曜日'(_日付3,_曜日3,_日付2,_曜日2) .

前日・今日(_前日の年/12/31,_前日の曜日,_年/1/1,_曜日) :-
    一つ違い(_前日の年,_年),
    曜日連鎖(_前日の曜日,_曜日),!.
前日・今日(_年/2/29,_前日の曜日,_年/3/1,_曜日) :-
    うるう年(_年),
    曜日連鎖(_前日の曜日,_曜日),!.
前日・今日(_年/2/28,_前日の曜日,_年/3/1,_曜日) :-
    not(うるう年(_年)),
    曜日連鎖(_前日の曜日,_曜日),!.
前日・今日(_年/_前月/30,_前日の曜日,_年/_月/1,_曜日) :-
    一つ違い(_前月,_月),
    member(_前月,[4,6,9,11]),
    曜日連鎖(_前日の曜日,_曜日),!.    
前日・今日(_年/_前月/31,_前日の曜日,_年/_月/1,_曜日) :-
    一つ違い(_前月,_月),
    member(_前月,[1,3,5,7,8,10,12]),
    曜日連鎖(_前日の曜日,_曜日),!.   
前日・今日(_年/_月/_前日,_前日の曜日,_年/_月/_日,_曜日) :-
    一つ違い(_前日,_日),
    曜日連鎖(_前日の曜日,_曜日),!.    

一つ違い(M,N) :-
    integer(M),!,
    N is M + 1.
一つ違い(M,N) :-
    integer(N),!,
    M is N - 1.

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

曜日連鎖(月曜,火曜).
曜日連鎖(火曜,水曜).
曜日連鎖(水曜,木曜).
曜日連鎖(木曜,金曜).
曜日連鎖(金曜,土曜).
曜日連鎖(土曜,日曜).
曜日連鎖(日曜,月曜).

n個組(N,L,X) :-
    length(X,N),
    append(X,L2,L3),
    append(L1,L3,L),
    length(L1,Len),
    0 is Len mod N.

ヘッドゼロサプライ(N桁,_整数,_ヘッドゼロ整数文字列) :-
    number_chars(_整数,_数字ならび),
    ヘッドゼロサプライ_1(N桁,_数字ならび,_ヘッドゼロ整数文字ならび),
    concat_atom(_ヘッドゼロ整数文字ならび,_ヘッドゼロ整数文字列),!. 

ヘッドゼロサプライ_1(N桁,L,L) :-
    length(L,N桁),!.
ヘッドゼロサプライ_1(N桁,L,['0'|R]) :-
    M桁 is N桁 - 1,
    ヘッドゼロサプライ_1(M桁,L,R).