オフラインどう書く第16回問題・CodeIQ(境界線の長さ)の解答

どう書く第16回問題と、同じ出題者の類題CodeIQ（境界線の長さ）の解答です。

どう書く第16回問題

問題はこちら
http://nabetani.sakura.ne.jp/hena/ord16boseg/

最初Juliaで解きました。
隣の升を比較するのに、bit演算や加減算もありますが、
Juliaでは10進数をn進数の文字列に変換する機能がありますので、文字の異同で比較します。
まず'0'で埋めた7x7の配列sqを作り、8進数を2進数の文字列に変換し、該当の升に入れます。
線分の長さごとの数を入れる配列ansを用意します。ans[i]に長さiの線分の数をいれます。
長さの変数の初期値を0にし、隣の升の文字を比較し、違えば、値を1増やし、次に行きます。
隣の文字が同じなら、変数の値が0でなければその数に該当するansの値を1増やし、
変数の値を0にして次に行きます。最後の列の升は同じ文字'0'になるようにしてあります。
これを縦横それぞれ５回ずつ繰り返し、合計を答えとします。

```Julia
#Julia v 1.0,1.4
str="0 	060276724276 	6,2,1,1,0,1
1 	770175454177 	2,3,0,3,1,0
2 	743733377170 	9,3,1,0,0,0
3 	724212121273 	5,2,1,1,1,1
4 	100000000000 	3,0,0,0,0,0
5 	000002000000 	4,0,0,0,0,0
6 	003622223600 	0,4,0,4,0,0
7 	520073737070 	8,3,1,1,0,0
8 	770077007700 	0,0,0,0,0,5
9 	555555555514 	2,0,0,0,2,2
10 	764252427600 	4,0,4,0,2,0
11 	774555554177 	3,3,1,3,0,0
12 	674574754557 	11,5,0,1,0,0
13 	000000000000 	0,0,0,0,0,0
14 	777777777777 	0,0,0,0,0,0
15 	774377777577 	6,0,2,0,0,0
16 	070777777777 	0,1,1,0,0,0
17 	373737373737 	0,0,0,0,0,1
18 	603260327725 	30,0,0,0,0,0
19 	466331144663 	30,0,0,0,0,0
20 	000000000242 	3,2,0,0,0,0
21 	567656043772 	18,2,1,0,0,0
22 	200763012420 	15,4,1,0,0,0
23 	400101140052 	14,3,0,0,0,0
24 	764767476476 	13,2,0,1,0,0
25 	001110140110 	12,2,1,0,0,0
26 	765405076527 	16,3,0,1,0,0
27 	377323370373 	8,4,2,0,0,0
28 	250541131216 	11,5,2,0,0,0
29 	744165741476 	12,3,2,0,0,0
30 	042101000300 	10,3,0,0,0,0
31 	002004554101 	11,3,1,0,0,0
32 	371707762706 	15,1,1,0,0,0
33 	130371310175 	7,3,1,2,0,0
34 	212537003613 	13,2,1,1,1,0
35 	157700063411 	15,3,0,0,0,1
36 	011500036007 	6,7,1,0,0,0
37 	743113313517 	17,2,1,0,0,0
38 	174105270405 	13,3,1,1,0,0
39 	427272200311 	13,3,2,0,0,0
40 	725370332237 	12,5,1,1,0,0
41 	005640420046 	12,1,3,0,0,0
42 	700350001101 	14,3,1,0,0,0
43 	577627744076 	16,1,1,1,0,0
44 	620332232007 	10,4,2,1,0,0
45 	260406401000 	15,1,1,0,0,0
46 	737272723276 	5,0,0,0,3,0
47 	000400040444 	7,0,2,0,0,0
48 	370222002177 	13,2,2,0,0,0
49 	372236024656 	9,3,2,0,1,0
50 	276131137003 	11,6,2,0,0,0
51 	742134007240 	13,4,2,0,0,0
52 	777721775571 	13,1,2,0,0,0
53 	700301232233 	11,2,3,0,0,0"

function solve(sq)
    hl,vl=0,0
    ans=zeros(Int8,6)
    for i in 1:5
        for j in 1:7
            if sq[i,j] != sq[i+1,j]
                hl=hl+1
            elseif hl>0
                ans[hl]=ans[hl]+1
                hl=0
            end
            if sq[j,i] != sq[j,i+1]
                vl=vl+1
            elseif vl>0
                ans[vl]=ans[vl]+1
                vl=0
            end
        end
    end
    return ans
end

function main()
    str1=split(str,"\n")
    for s in str1
        sq=fill('0',7,7)
        s1=split(s," ")
        s1[2]=strip(s1[2])
        for (i,m) in enumerate(s1[2])
            sn=string(parse(Int,m),base=2)
            for j in 1:length(sn)
                sq[div(i+1,2),3*(1-mod(i,2))-j+4]=reverse(sn)[j]
            end
        end
        res=solve(sq)
        ans=join(res,",")
        if ans==strip(s1[3])
            sel="pass"
        else
            sel="fail"
        end
        print(sel," ",ans,"\n")
    end
end

@time main()
```
Prolog
Juliaから移しました。
tenton/4で10進数からn進数のリストに変換されますので、数字を比較します。
solve1/2で入力値を二つずつまとめて二進数にし一つのリストにして最後に0を加え、
同じことを6回行って、リスト6個のリストを作っています。
最後にsolve/2に戻って7つの0からなるリストを加えています。
solve2/2で比較する二つの列を決めています。
solve3/4で実際に比較しています。nth0でインデックスを0から使えますので、
隣の数字の値が同じ時には、nth0(N1,R1,X,R2),X1 is X+1,nth0(N1,R,X1,R2)で、
ansに相当するリストR1のN1番目の値を1増やしてRとします。N1は現在の長さの変数です。
最初縦方向の長さを調べ、更にtrans/2でリストの行列を転置して、横方向の長さを調べます。
solveのRのヘッドを除いて文字列に直したものが答えです。

```Prolog
%swi-Prolog  version 7.4.2
%start.
%:-initialization(start).   % ideone

tenton(0,_,L,R):-
     length(L,N),N1 is 3-N,length(L1,N1),maplist(=(0),L1),append(L1,L,R),!.
tenton(X,B,L,RL):-
     X1 is X div B,R1 is X rem B,tenton(X1,B,[R1|L],RL).

tenton1(S,R):-atom_number(S,X),tenton(X,2,[],R).

add(X,L,R):-R=[X|L].

trans([H],R):-length(H,N),length(L,N),maplist(=([]),L),maplist(add,H,L,R).
trans([H|T],R):-trans(T,R1),maplist(add,H,R1,R).

solve3([[],[]],_,R,R).
solve3([[H1|T1],[H2|T2]],N1,R1,FR):-
     (H1=:=H2->(nth0(N1,R1,X,R2),X1 is X+1,nth0(N1,R,X1,R2),N=0);(N is N1+1,R=R1)),
     solve3([T1,T2],N,R,FR).
     
solve2([_,_],[0,0,0,0,0,0,0]).
solve2([H1,H2|T],R):-
     solve2([H2|T],R1),solve3([H1,H2],0,[0,0,0,0,0,0,0],R2),maplist(plus,R1,R2,R).

solve1([],[]).
solve1([H1,H2|T],R):-
     solve1(T,R1),maplist(tenton1,[H1,H2],L),flatten(L,L1),
     append(L1,[0],L2),append([L2],R1,R).

solve(L,R):-
     solve1(L,L1),append(L1,[[0,0,0,0,0,0,0]],L2),solve2(L2,R1),
     trans(L2,L3),solve2(L3,R2),maplist(plus,R1,R2,R).

start:-str(S),split_string(S,"\n","",L),pre(L),!.

pre([]).
pre([H|T]):-
     split_string(H,"\s","\s",[_,B,C]),atom_chars(B,L),solve(L,R),disp(R,C),pre(T).

disp(R,C):-
     R=[_|T],atomics_to_string(T,",",S),(S==C->Str=" pass";Str=" fail"),
     write(Str),write(" "),writeln(S->C).

str("0  060276724276    6,2,1,1,0,1
1       770175454177    2,3,0,3,1,0
2       743733377170    9,3,1,0,0,0
3       724212121273    5,2,1,1,1,1
4       100000000000    3,0,0,0,0,0
5       000002000000    4,0,0,0,0,0
6       003622223600    0,4,0,4,0,0
7       520073737070    8,3,1,1,0,0
8       770077007700    0,0,0,0,0,5
9       555555555514    2,0,0,0,2,2
10      764252427600    4,0,4,0,2,0
11      774555554177    3,3,1,3,0,0
12      674574754557    11,5,0,1,0,0
13      000000000000    0,0,0,0,0,0
14      777777777777    0,0,0,0,0,0
15      774377777577    6,0,2,0,0,0
16      070777777777    0,1,1,0,0,0
17      373737373737    0,0,0,0,0,1
18      603260327725    30,0,0,0,0,0
19      466331144663    30,0,0,0,0,0
20      000000000242    3,2,0,0,0,0
21      567656043772    18,2,1,0,0,0
22      200763012420    15,4,1,0,0,0
23      400101140052    14,3,0,0,0,0
24      764767476476    13,2,0,1,0,0
25      001110140110    12,2,1,0,0,0
26      765405076527    16,3,0,1,0,0
27      377323370373    8,4,2,0,0,0
28      250541131216    11,5,2,0,0,0
29      744165741476    12,3,2,0,0,0
30      042101000300    10,3,0,0,0,0
31      002004554101    11,3,1,0,0,0
32      371707762706    15,1,1,0,0,0
33      130371310175    7,3,1,2,0,0
34      212537003613    13,2,1,1,1,0
35      157700063411    15,3,0,0,0,1
36      011500036007    6,7,1,0,0,0
37      743113313517    17,2,1,0,0,0
38      174105270405    13,3,1,1,0,0
39      427272200311    13,3,2,0,0,0
40      725370332237    12,5,1,1,0,0
41      005640420046    12,1,3,0,0,0
42      700350001101    14,3,1,0,0,0
43      577627744076    16,1,1,1,0,0
44      620332232007    10,4,2,1,0,0
45      260406401000    15,1,1,0,0,0
46      737272723276    5,0,0,0,3,0
47      000400040444    7,0,2,0,0,0
48      370222002177    13,2,2,0,0,0
49      372236024656    9,3,2,0,1,0
50      276131137003    11,6,2,0,0,0
51      742134007240    13,4,2,0,0,0
52      777721775571    13,1,2,0,0,0
53      700301232233    11,2,3,0,0,0").
```

CodeIQ:境界の長さ

問題とサンプルはこちらのお世話になりました。
https://sw-logic.com/Portfolio/Programing/CodeIQ/3133.php

Juliaで解きました。
隣の升を比較するところが同じな類題です。
16進数を10進数に変換しさらに2進数の文字列に変換しています。
条件別に加算をしていくだけですので、二次元の配列は作らずに、
文字列をつないで計算で位置を求めてみました。
文字列を作るときに桁数が足りないところは'0'を追加しました。
テストケースがサンプルしかありませんが、複雑な問題ではありませんので、
多分大丈夫だと思います。

```Julia
#Julia v 1.0,1.4
inp=[["f7","8f","44","7a","e6","8f","20","af"],["ff","bc","94","fc","89","a3","45","23"]]
out=[[16,17,11,12],[10,15,12,13]]

function solve(x)
    gr,re,ye,bl=0,0,0,0
    for i in 1:7,j in 1:8
        if x[j+(i-1)*8] != x[j+i*8]
           if x[j+(i-1)*8]=='1'
               gr+=1
            else
               re+=1
            end
        end
        if x[i+(j-1)*8] != x[i+1+(j-1)*8]
            if x[i+(j-1)*8]=='1'
   
              ye+=1
           else
              bl+=1
          end
        end
    end
    return [re,gr,bl,ye]
end

function main()
    for i in 1:2
        x=""
        for j in 1:8
           y=string(parse(Int32, inp[i][j],base= 16),base=2)
           n=8-length(y)
                y="0"^n*y
           x=x*y
        end
        res=solve(x)
        if res==out[i]
          sel="pass"
        else
          sel="fail"
        end
        print(sel," ",res,"\n")
     end
end

@time main()
```