このディレクトリの索引
#  
#  20×20のボックスの中からある文字列を取り出すプログラムを書いて!
#  
#  かたやん印刷所では、いまの時代においてもグーテンベルグ印刷にこだわって印刷をしています。
#  グーテンベルグ印刷とは、活版(活字を組み合わせて作った版)で印刷する方法です。(Wikipedia)
#  
#  かたやん印刷所の所長かたやんは、使った活字を元の場所に戻さないので、
#  いつも活字を入れているボックスはぐちゃぐちゃで、
#  ほしい活字をすぐに見つけ出すことができません。
#  
#  そこで見かねた印刷所の副所長エミーは、活字を入れているボックスビデオで撮影し、
#  画像解析し、ボックスのどこにどの活字があるかを解析し、
#  ほしい文字列の活字がどこにあるか瞬時にみつけだすプログラミングを作ることにしました。
#  
#  現状の状態のボックスは以下のようになっています。
#  
#  
#  6×6のボックスの中から"PRO, PROGRAMMER"という活字を探し出したいです。
#  カンマやスペースは1つの活字としてカウントします。
#  ですので、今回は文字13個、カンマ1個、スペース1個の合計15個の活字が必要です。
#  一度使った活字は2回使うことはできません。
#  
#  活字の場所は、(縦番号,横番号)で表すと以下のような順番で活字を取り出すことができます。
#  縦番号は上から下の方向に、横番号は左から右の方向に、1から数えます。
#  1,4 = P
#  2,1 = R
#  1,6 = O
#  5,2 = ,
#  5,4 = space
#  2,2 = P
#  3,4 = R
#  4,5 = O
#  5,1 = G
#  4,3 = R
#  1,1 = A
#  2,5 = M
#  6,1 = M
#  2,4 = E
#  6,6 = R
#  
#  
#  上記の例では、例えば"P"という文字が2回でてきますが、(1,4)と(2,2)にある"P"はどちらを先につかってもかまいません。
#  また場所の特定は1つのみ記述すればよいです。すべての場所番号を書く必要はありません。
#  
#  画像解析したボックスのデータはCSVで出力されます。
#  ボックスのデータを使ってほしい文字列を作るための活字の在り処を探しだしてください。
#  
#  ■資料
#  gutenberg.zip
#  zipファイルを解凍すると以下のファイルが入っています。
#  
#  gutenberg.csv
#  このボックスから"STAY HUNGRY, STAY FOOLISH"という活字を取り出してください。
#  文字21個、カンマ1個、スペース3個で、合計25個の活字が必要です。
#  
#  answer.txt
#  解答用テキストファイルです。
#  
#  ■解答方法
#  解答用テキストファイル(answer.txt)を完成させ、アップロードしてください。
#  ※解答用テキストファイル(answer.txt)以外のファイル形式(zipなど)をアップロードした場合は評価対象外となります。
#  

'20×20のボックスの生成'  :-
        open('gutenberg.csv',read,Instream),
        '20×20のボックスの生成'(Instream,_20掛ける20のボックス),
        close(Instream),
        assertz('20×20のボックス'(_20掛ける20のボックス)).

'20×20のボックスの生成'(Instream,[]) :-
        at_end_of_stream(Instream),!.
'20×20のボックスの生成'(Instream,[L|R]) :-
        get_line(Instream,Line),
        split(Line,['\t'],L),
        '20×20のボックスの生成'(Instream,R).

'20×20のボックスの中からある文字列を取り出す'(_ある文字列,_20掛ける20のボックス) :-
        atom_chars(_ある文字列,_文字ならび),
        '20×20のボックスの中からある文字列を取り出す'(_文字ならび,_20掛ける20のボックス,L),
        解の表示(L).

'20×20のボックスの中からある文字列を取り出す'([],_20掛ける20のボックス,[]) :- !.
'20×20のボックスの中からある文字列を取り出す'([_文字|_残り文字ならび],_20掛ける20のボックス_1,[[_文字,_行目,_列目]|R]) :-
        ある文字を取り出す(_文字,_20掛ける20のボックス_1,1,_列目,_20掛ける20のボックス_2),
        '20×20のボックスの中からある文字列を取り出す'(_残り文字ならび,_20掛ける20のボックス_2,R).

ある文字を取り出す(_文字,[_行|R_1],_行目,_列目,[_行_2|R_1]) :-
        nth1(_列目,_行,_文字),
        行を更新する(_行,_列目,_行_2),!.
ある文字を取り出す(_文字,[_行|R_1],_行目,_列目,[_行|R_2]) :-
        _行目_2 is _行目 + 1,
        ある文字を取り出す(_文字,R_1,_行目_2,_列目,R_2).

行を更新する(_行,_列目,_行_2) :-
        length([_|L1],_列目),
        append(L1,[_|R],_行),
        append(L1,[''|R],_行_2),!.

解の表示(L) :-
        tell('ans.txt'),
        forall(member([_文字,_行目,_列目],L),writef('%t,%t,%t\n',[_文字,_行目,_列目])),
        told.

get_line(Stream,X) :-
        get_char(Stream,C),
        get_line_1(Stream,C,Chars),
        atom_chars(X,Chars).

get_line_1(Stream,'\n',[]) :- !.
get_line_1(Stream,end_of_file,[e,n,d,'_',o,f,'_',f,i,l,e]) :- !.
get_line_1(Stream,C,[C|R]) :-
        get_char(Stream,C2),
        get_line_1(Stream,C2,R).

get_line(X) :-
        get_char(C),
        get_line_1(C,Chars),
        atom_chars(X,Chars).

get_line_1('\n',[]) :- !.
get_line_1(end_of_file,[e,n,d,'_',o,f,'_',f,i,l,e]) :- !.
get_line_1(C,[C|R]) :-
        get_char(C2),
        get_line_1(C2,R).

split('',_,[],[]) :- !.
split(_文字列,_区切り文字列ならび,[_区切り文字列|R3],[_副文字列|R4]) :-
        副文字列を切り出す(_文字列,_区切り文字列ならび,_区切り文字列,_副文字列,_残り文字列),
        split(_残り文字列,_区切り文字列ならび,R3,R4).


副文字列を切り出す(_文字列,_区切り文字列ならび,_区切り文字列,_副文字列,_残り文字列) :-
        文字ならびとして切り出す(_文字列,_区切り文字列ならび,_区切り文字列,_切り出し文字ならび,_残り文字列),
        atomic_list_concat(_切り出し文字ならび,_副文字列),!.


文字ならびとして切り出す('',_,'',[],'') :- !.
文字ならびとして切り出す(_文字列,_区切り文字列ならび,_区切り文字列,[],_残り文字列) :-
        文字列の先頭は区切り文字列である(_文字列,_区切り文字列ならび,_区切り文字列,_残り文字列),!.
文字ならびとして切り出す(_文字列,_区切り文字列ならび,_区切り文字列,[_文字|R4],_残り文字列) :-
        一文字切り出す(_文字列,_文字,_残り文字列_2),
        文字ならびとして切り出す(_残り文字列_2,_区切り文字列ならび,_区切り文字列,R4,_残り文字列).


文字列の先頭は区切り文字列である(_文字列,_区切り文字列ならび,_区切り文字列,_残り文字列) :-
        member(_区切り文字列,_区切り文字列ならび),
        atom_length(_区切り文字列,_長さ),
        sub_atom(_文字列,0,_長さ,_残り文字数,_区切り文字列),
        sub_atom(_文字列,_,_残り文字数,0,_残り文字列),!.

一文字切り出す(_文字列,_文字,_残り文字列_2) :-
        sub_atom(_文字列,0,1,_,_文字),
        sub_atom(_文字列,1,_,0,_残り文字列_2).

:- '20×20のボックスの生成'(_CSVファイル).

:- '20×20のボックス'(_20掛ける20のボックス),
   '20×20のボックスの中からある文字列を取り出す'(_ある文字列,_20掛ける20のボックス).