このディレクトリの索引
#  出典: プログラムのお題スレ Part4 #38
#  
#  標準入力から与えられたフォーマットを元に年齢を求めて出力せよ
#  標準入力から以下の形式で与えられます
#  YYYY/MM/dd
#  
#  年齢は誕生日の前日に歳を重ねることに注意せよ。4/1生まれの場合は3/31に歳が増えることになる。 

'標準入力から与えられたフォーマットを元に年齢を求めて出力せよ
標準入力から以下の形式で与えられます
YYYY/MM/dd

年齢は誕生日の前日に歳を重ねることに注意せよ。4/1生まれの場合は3/31に歳が増えることになる。' :-
        '標準入力から与えられたフォーマット(YYYY/MM/dd)を元に'(_年,_月,_日),
        '年齢を求めて(年齢は誕生日の前日に歳を重ねることに注意せよ。4/1生まれの場合は3/31に歳が増えることになる)'(_年,_月,_日,_年齢),
        出力せよ(_年齢).

'標準入力から与えられたフォーマット(YYYY/MM/dd)を元に'(_年,_月,_日) :-
        get_line(_文字列),
        read_term_from_atom(_文字列,_年/_月/_日,[]).

'年齢を求めて(年齢は誕生日の前日に歳を重ねることに注意せよ。4/1生まれの場合は3/31に歳が増えることになる)'(_年,_月,_日,_年齢) :-
        date(date(_今日_年,_今日_月,_今日_日)),
        誕生日の前日(_今日_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日),
        '年齢を計算する(年齢は誕生日の前日に歳を重ねることに注意せよ)'(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢).

誕生日の前日(_年,_月,1,_前日_年,_前日_月,_前日_日) :-
        誕生日の前月と月末日を得る(_年,_月,1,_前日_年,_前日_月,_前日_日).
誕生日の前日(_年,_月,_日,_年,_月,_前日_日) :-
        \+(_日 = 1),
        succ(_前日_日,_日).

誕生日の前月と月末日を得る(_誕生日の年,1,1,_誕生日の前年,12,31) :-
        succ(_誕生日の前年,_誕生日の年).
誕生日の前月と月末日を得る(_年,3,1,_年,2,_誕生日の前月末日) :-
        '3月1日はうるう年であるか否かで誕生日の前月末日が変わる'(_年,_誕生日の前月末日).
誕生日の前月と月末日を得る(_年,_誕生日の月,1,_年,_誕生日の前月,30) :-
        '誕生日の前月が小の月(2月を除く)'(_誕生日の月,_誕生日の前月).
誕生日の前月と月末日を得る(_年,_誕生日の月,1,_年,_誕生日の前月,31) :-
        '誕生日の前月が大の月(12月を除く)'(_誕生日の月,_誕生日の前月).

'3月1日はうるう年であるか否かで誕生日の前月末日が変わる'(_年,29) :-
        うるう年(_年).
'3月1日はうるう年であるか否かで誕生日の前月末日が変わる'(_年,28) :-
        \+(うるう年(_年)).

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

'誕生日の前月が小の月(2月を除く)'(_誕生日の月,_誕生日の前月) :-
        succ(_誕生日の前月,_誕生日の月),
        member(_誕生日の前月,[4,6,9,11]).

'誕生日の前月が大の月(12月を除く)'(_誕生日の月,_誕生日の前月) :-
        succ(_誕生日の前月,_誕生日の月),
        member(_誕生日の前月,[1,3,5,7,8,10]).


'年齢を計算する(年齢は誕生日の前日に歳を重ねることに注意せよ)'(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢) :-
        まだ誕生日の前日になっていない(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢).
'年齢を計算する(年齢は誕生日の前日に歳を重ねることに注意せよ)'(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢) :-
        既に誕生日の前日を過ぎている(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢).

まだ誕生日の前日になっていない(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢)  :-
        _月 < _誕生日の前日_月,
        _年齢 is _誕生日の前日の年 - _年 - 1.
まだ誕生日の前日になっていない(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢)  :-
        _月 = _誕生日の前日_月,
        _日 < _誕生日の前日の日,
        _年齢 is _誕生日の前日_年 - _年 - 1.

既に誕生日の前日を過ぎている(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢) :-
        _月 > _誕生日の前日_月,
        _年齢 is _誕生日の前日の年 - _年.
既に誕生日の前日を過ぎている(_年,_月,_日,_誕生日の前日_年,_誕生日の前日_月,_誕生日の前日_日,_年齢) :-
        _月 = _誕生日の前日_月,
        _日 >= _誕生日の前日_日,
        _年齢 is _誕生日の前日_年 - _年.

出力せよ(_年齢) :-
        writef('%t歳です\n',[_年齢]).