オフラインどう書くF03とCodeIQ(ダブルテトロミノ)の解答

類題といえるかどうかわかりませんが、同じ出題者の問題でパターンマッチで解いた二題です。

F03の問題
問題はこちら->http://nabetani.sakura.ne.jp/hena/ordf03triom/

member関数2つでも解けそうですが、簡単なパターンマッチで解きました。
アルファベットが10列5行のフィールドの左上の領域にあるとし、二次元配列を一次元配列に変換し、
トリオミノを0から始まる昇順の数字のリストで表し、問題の領域も、
ソートして最小値が0になるよう調整して、トリオミノのリストとパターンマッチさせます。

```Prolog
%SWI-Prolog version 7.4.2,7.6.4
%start.
%:-initialization(start).  %ideone

p("J",[0,9,10]).
p("L",[0,10,11]).
p("T",[0,1,11]).
p("R",[0,1,10]).
p("I",[0,10,20]).
p("B",[0,1,2]).

ston(S,N):-atom_codes(S,N1),N2 is N1-97,N is (N2 mod 5)+(N2 div 5)*10. %5をかけるのは不可
 
find(L,R):-sort(L,[H|T]),X is 0-H,maplist(plus(X),T,T1),p(R,[0|T1]),!.
find(_,"-").
 
solve(L,R):-maplist(ston,L,L1),find(L1,R).
 
start:-str(S),split_string(S,"\s\n","\s",L),pre(L).

pre([]).
pre([_,B,Q|T]):-atom_chars(B,L),solve(L,R),disp(R,Q),pre(T).

disp(R,A):-(A==R->Str=" pass ";Str=" fail "),write(Str),writeln(R).
 
 str("0         cba     B
1       yam     -
2       aaa     -
3       def     -
4       gga     -
5       bbf     -
6       gmh     T
7       mhn     L
8       dea     -
9       mrn     R
10      hcm     I
11      mno     B
12      snr     J
13      xnn     -
14      nnl     -
15      kop     -
16      ejd     T
17      txy     J
18      pvu     L
19      baf     R
20      hhc     -
21      ono     -
22      wxv     B
23      bdc     B
24      ojt     I
25      fkp     I       ").
```

ダブルテトロミノ
問題とテストケースにおいてお世話になりました。解答例も載っています。
->https://blog.goo.ne.jp/r-de-r/e/1520ccb1b3004934ccdcf0698db98db3

二回パターンマッチをするのですが、一回目のパターンマッチで、
マッチした部分に値が入ることを利用しています。

makef/2とinp/3で、黒い升を変数にし周囲を1にした10x10のフィールドを作ります。
rot/4はテトロミノを回転させて得られるすべてのピースを求めます。
makeup/2は回転、反転して得られるすべてのピースを求めます。
count/2で二つのテトロミノをパターンマッチさせます。
pat/3をで2回使っていますが、すでに置いたピースとパターンマッチすることを避けるため、
ピースに当てはめる数字を変えています。
are/2でフィールドのパターンマッチする範囲の上端を下げつつare1/2を呼び出します。
are1でフィールドのパターンマッチする部分の左端をずらしながらare2/2を呼びます。
are2の最初の行がテトロミノの上端とパターンマッチ成功すれば、下の行でも続けます。
findallでパターンマッチ成功した組み合わせをすべて集めます。
パターンマッチをする関数areは
以前はテトロミノの占める矩形と同じ大きさの矩形を作って調べるコードでしたが、
appendを使ったコードを書いてみました。
append(H1,_,H2)でH2の先頭からの要素がH1であるときにパターンマッチするとともに、
H2のその部分が変数の場合はH1に束縛され値を持ちます。

```Prolog
%SWI-Prolog version 7.4.2,7.6.4
%start.
%:-initialization(start).  %ideone

pat("I",X,[[X,X,X,X]]).
pat("L",X,[[X,_,_],[X,X,X]]).
pat("O",X,[[X,X],[X,X]]).
pat("S",X,[[_,X,X],[X,X,_]]).
pat("T",X,[[X,X,X],[_,X,_]]).

rotate(L,L1):-L=[H|T],maplist([A,B]>>(B=[A]),H,H1),foldl(apall,T,H1,L1).   %90度回転
apall([],[],[]).
apall([H1|T1],[H2|T2],R):-apall(T1,T2,R1),H3=[H1|H2],R=[H3|R1].

rot(0,_,L,L):-!.     %member/2を使うとL1の変数がR1の中のリストの変数に束縛されてしまう
rot(N,L,R1,R):-N1 is N-1,rotate(L,L1),R2=[L1|R1],rot(N1,L1,R2,R).

makep(L,R):-rot(4,L,[L],R1),reverse(L,L1),rot(4,L1,[L1|R1],R).   %patを回転

delh([_|T],T).

are(_,[[]|_]):-fail.
are(L2,L):-are1(L2,L)->true;(maplist(delh,L,L1),are(L2,L1)).

are1(_,[]):-fail.
are1(L2,[H|T]):-are2(L2,[H|T])->true;are1(L2,T).

are2([],_):-!.
are2([H1|T1],[H2|T2]):-append(H1,_,H2),!,are2(T1,T2).

makef(0,[]).
makef(N,R):-N1 is N-1,makef(N1,R1),length(L,10),R=[L|R1].

count(L,R):-
     pat(R1,2,L1),count1(L,L1), %Lの値が自然に変わる
     pat(R2,3,L2),R1=<R2,count1(L,L2),% すでに置いたピースとパターンマッチすることを避ける
     msort([R1,R2],R3),concat_atom(R3,R).

count1(L,L1):-makep(L1,L10),sort(L10,L11),member(L12,L11),are(L12,L).

inp(_,_,-1).  %黒升以外を1にする
inp(L1,DL,X):-
     X1 is X-1,inp(L1,DL,X1),inp(L1,DL,X,9).

inp(_,_,_,-1).
inp(L1,DL,X,Y):-
     Y1 is Y-1,inp(L1,DL,X,Y1),atom_number(SX,X),atom_number(SY,Y),
     (member([SX,SY],DL)->true;(nth0(X,L1,L2),nth0(Y,L2,1))).

solve(L,R):-
     makef(10,L1),inp(L1,L,9),findall(R1,count(L1,R1),R2),
     (R2=[]->R="-";(sort(R2,R3),atomics_to_string(R3,",",R))),!.

start:-
     f(S,A),atomics_to_string(L,"\s",S),maplist(atom_chars,L,L1),
     solve(L1,R),disp(R,A),fail.
start.

disp(R,A):-(R==A->Str=" pass ";Str=" fail "),write(Str),writeln(R).

f("56 37 36 55 35 46 45 47","LO,LS").
f("70 07 44 34 98 11 00 32","-").
f("63 60 67 65 64 62 61 66","II").
f("65 46 45 66 54 44 64 56","LL").
f("34 46 36 47 33 44 35 45","II,SS,TT").
f("85 75 76 84 83 73 86 74","II,LL,OO").
f("67 76 77 78 68 69 58 57","LT,ST").
f("44 45 34 55 43 35 33 56","LO,LS").
f("55 46 66 45 44 57 54 56","LT,OT").
f("43 24 35 33 34 32 23 44","SS,TT").
f("20 10 12 21 03 22 13 11","LL,OS").
f("53 54 75 45 55 35 65 56","-").
f("88 89 86 87 78 68 99 79","-").
f("28 37 25 38 35 47 46 36","SS").
f("94 93 01 03 02 91 92 04","II").

```