このディレクトリの索引
http://hibari.2ch.net/test/read.cgi/tech/1301553333/680
#  1]授業単元:プログラミング 
#  [2]問題文:自己参照型構造体を用いて、以下の処理をするプログラムを作成せよ。 
#   
#  正の数入力→連結リストを辿り、初めて入力された数ならばカウンタを1増やす。同じ数が続けて入力されたらその数のカウンタをさらに1増やす。 
#  負の数入力→負の数の絶対値と同じ回数入力された数のデータを削除(例えば、-3を入力し、それ以前に14が3回入力されていたら、それを削除) 
#  0を入力→データを出力して終了。 
#   
#  データ出力→終了の流れはどうにかなりましたが、それ以外で上手い発想が思いつきません。 
#   
#  http://ime.nu/codepad.org/yayuXIUa 
#   
#  期限は明日までです。 
# 
# 

正の数入力後連結リストを辿り、初めて入力された数ならばカウンタを1増やす。負の数入力後負の数の絶対値と同じ回数入力された数のデータを削除0を入力後データを出力して終了 :-
        数入力(_数),
        連結リストとカウンタを更新していく(_数,[],0,_連結リスト,_カウンタ),
        データを出力して終了(_連結リスト,_カウンタ),!.

連結リストとカウンタを更新していく(_数,L_1,_カウンタ_1,L,_カウンタ) :-
        負の数が入力されたら負の数の絶対値と同じ回数入力された数のデータを削除して連結リストの最後に0を加える(_数,L_1,_カウンタ_1,L,_カウンタ),!.
連結リストとカウンタを更新していく(_数,L_1,_カウンタ_1,L,_カウンタ) :-
        初めて入力された数ならばカウンタを1増やす(_数,L_1,_カウンタ_1,L_2,_カウンタ_2),
        数入力(_数_2),
        連結リストとカウンタを更新していく(_数_2,L_2,_カウンタ_3,L,_カウンタ).
連結リストとカウンタを更新していく(_数,L_1,_カウンタ_1,L,_カウンタ) :-
        \+(初めて入力された数ならばカウンタを1増やす(_数,L_1,_カウンタ_1,L,_カウンタ)),        
        数入力(_数_2),
        連結リストの最後に数を追加(_数,L_1,L_2),
        連結リストとカウンタを更新していく(_数_2,L_2,_カウンタ_1,L,_カウンタ).

データを出力して終了(_連結リスト,_カウンタ) :-
        writef('実行後の連結リストは %t です\nその時点のカウンタは %t です\n',[_連結リスト,_カウンタ]),!.

負の数が入力されたら負の数の絶対値と同じ回数入力された数のデータを削除して連結リストの最後に0を加える(_負の数,L_1,_カウンタ_1,L_2,_カウンタ_2) :-
        _負の数 < 0,
        _負の数の絶対値 is abs(_負の数),
        負の数の絶対値と同じ回数入力された数のデータを削除(_負の数の絶対値,L_1,L_3),
        連結リストの最後に0を加える(L3,L2),!.

連結リストの最後に0を加える(L3,L2) :-
        append(L_3,[0],L_2),!.

負の数の絶対値と同じ回数入力された数のデータを削除(_負の数の絶対値,L_1,L_2) :-
        既に入力された重複しない数ならびを得る(L_1,_数ならび),
        削除する数を選択する(_負の数の絶対値,_数ならび,L_1,_削除する数候補),
        連結リストからデータを削除(_削除する数候補,L_1,L_2).

既に入力された重複しない数ならびを得る(L_1,_数ならび) :-
        findsetof(_数,append(_,[_数|_],L_1),_数ならび),!.

削除する数を選択する(_負の数の絶対値,_数ならび,L_1,_削除する数候補) :-
        findall(_数,(
                         append(_,[_数|_],_数ならび),

                         負の数の絶対値に要素数が一致する数(_負の数の絶対値,L_1,_数)),
                _削除する数候補),!.

負の数の絶対値に要素数が一致する数(_負の数の絶対値,L_1,_数) :-
        count(append(_,[_数|_],L_1),_負の数の絶対値)),!.

連結リストからデータを削除([],L,L) :- !.
連結リストからデータを削除([_数|R],L_1,L) :-
        ならびから削除(_数,L_1,L_2),
        連結リストからデータを削除(R,L_2,L).

ならびから削除(_,[],[]) :- !.
ならびから削除(_削除する要素,[_削除する要素|_残り対象ならび],_削除されたならび) :-
        ならびから削除(_削除する要素,_残り対象ならび,_削除されたならび),!.
ならびから削除(_削除する要素,[_要素|_残り対象ならび],[_要素|_残り削除ならび]) :-
        ならびから削除(_削除する要素,_残り対象ならび,_残り削除ならび),!.

初めて入力された数ならばカウンタを1増やす(_数,L_1,_カウンタ_1,L_2,_カウンタ_3) :-
        \+(append(_,[_数|_],L_1)),
        _カウンタ_2 is _カウンタ_1 + 1,
        同じ数が続けて入力されたらその数のカウンタをさらに1増やす(_数,L_1,_カウンタ_2,_カウンタ_3),
        連結リストの最後に数を追加(_数,L_1,L_2),!.

同じ数が続けて入力されたらその数のカウンタをさらに1増やす(_数,L_1,_カウンタ_1,_カウンタ_2) :-
        last(L_1,_数),
        _カウンタ_2 is _カウンタ_1 + 1,!.
同じ数が続けて入力されたらその数のカウンタをさらに1増やす(_,_,_カウンタ_1,_カウンタ_1).

連結リストの最後に数を追加(_数,L_1,L_2) :-
        append(L_1,[_数],L_2).

数入力(_数) :-
        write('数を入力してください : '),
        get_line(Line),
        数入力診断(Line,_数),!.
数入力(_数) :- 数入力(_数).

数入力診断(Line,_数) :-
        atom_to_term(Line,_数,_),
        number(_数),!.
数入力診断(Line,_数) :-
        writef('入力された %t からは数値が得られません。再入力をお願いします\n',[Line]),
        fail.