0

Prolog を使用して戦艦のパズルを解かなければならない課題があります。私の現在の解決策は、フィールド全体に行き、現在の座標にボートを配置します。ボートの一部がそこに許可されていない場合 (与えられたボートのピースの合計だけを見ています)、水を配置します。

example(X) :-
   battleship(
       [
        [n,_,'~',_,_,_,_,n],
        [_,_,n,'~',_,o,_,_],
        ['~','~',_,'~',_,_,_,s],
        [_,'~',x,'~',_,_,'~','~'],
        [_,_,_,'~',_,_,n,_],
        [_,_,_,'~',_,_,_,_],
        [_,_,_,x,_,'~',_,_],
        [_,_,_,_,_,_,_,_]
       ],
       [5,0,5,1,2,1,2,4],[2,4,2,3,2,1,4,2],[4,3,2,1],X).

上の行はあなたが呼ぶものです。最初の引数は~for water と_for unknown のフィールドで、それ以外はすべてボートの一部です。2 番目の引数は、各列のボートのピースの合計です。3 番目の引数は同じですが、行についてです。4 番目の引数はボートのサイズで、最後の引数は結果を格納する場所です。

battleship(Grid, Columns, Rows, Ships, Result) :-
    print(Result),
    fillField(Grid, Columns, Rows, Ships, Result).

fillField(Grid, Columns, Rows, Ships, Result) :-
    fillRows(Grid, Columns, Rows, Ships, Result, 0).

fillRows(Grid, Columns, Rows, Ships, Result, RowIndex) :-
    length(Grid, Length),
    RowIndex >= Length,
    print(Grid), print('\n'),
    print('Done\n').

fillRows(Grid, Columns, Rows, Ships, Result, RowIndex) :-
    length(Grid, Length),
    RowIndex < Length,
    fillRow(Grid, Columns, Rows, Ships, Result, RowIndex, 0),
    NextRow is RowIndex + 1,
    fillRows(Grid, Columns, Rows, Ships, Result, NextRow).

fillRow(Grid, Columns, Rows, Ships, Result, RowIndex, ElemIndex) :-
    print(Grid),print('\n'),
    length(Grid, Length),
    ElemIndex >= Length.

fillRow(Grid, Columns, Rows, Ships, Result, RowIndex, ElemIndex) :-
    length(Grid, Length),
    ElemIndex < Length,
    isLegalShip(Grid, RowIndex, ElemIndex),
    nth0(RowIndex, Rows, R1),
    R2 is R1 - 1,
    R2 >= 0,
    replace(Rows, RowIndex, R2, NewRows),
    nth0(ElemIndex, Columns, C1),
    C2 is C1 - 1,
    C2 >= 0,
    replace(Columns, ColumnIndex, C2, NewColumns),
    NextElem is ElemIndex + 1,
    fillRow(Grid, NewColumns, NewRows, Ships, Result, RowIndex, NextElem).

fillRow(Grid, Columns, Rows, Ships, Result, RowIndex, ElemIndex) :-
    length(Grid, Length),
    ElemIndex < Length,
    isSea(Grid, RowIndex, ElemIndex),
    NextElem is ElemIndex + 1,
    fillRow(Grid, Columns, Rows, Ships, Result, RowIndex, NextElem).


isLegalShip(Grid, RowIndex, ElemIndex) :-
    nth0(RowIndex, Grid, Row),
    nth0(ElemIndex, Row, Element),
    isShip(Element).    

replace([_|Tail], 0, Value, [Value|Tail]).
replace([Head|Tail], Index, Value, [Head|R]):- 
    Index > 0, 
    NextIndex is Index - 1, 
    replace(Tail, NextIndex, Value, R).

isSea(Grid, RowIndex, ElemIndex) :-
    nth0(RowIndex, Grid, Row),
    nth0(ElemIndex, Row, '~').
isShip(x).
isShip(o).
isShip(e).
isShip(s).
isShip(w).
isShip(n).

このように問題を解くと、右上隅から始まり、左下に移動してフィールドが埋められます。ただし、スタックしたためにバックトラックが必要な場合は失敗します。この例を使用すると、間違っxた位置に配置され(0,3)ます。列の終わりに到達すると、別のボートを見つけ、何かがおかしいことに気づきます。彼女は私たちが置いた場所に戻りxます。そこに配置する必要~がありますが、代わりに次のように表示されます。

ERROR: >/2: Arguments are not sufficiently instantiated
Exception: (13) fillRow([[n, ~, ~, _G907, _G910, _G913, _G916|...], [_G925, _G928, n, ~, _G937, o|...], [~, ~, _G958, ~, _G964|...], [_G979, ~, x, ~|...], [_G1006, _G1009, _G1012|...], [_G1033, _G1036|...], [_G1060|...], [...|...]], [4, 0, 5, 1, 2, 1, 2, 4], [1, 4, 2, 3, 2, 1, 4, 2], [4, 3, 2, 1], _G828, 0, 3) ? creep
Exception: (10) fillRow([[n, _G901, ~, _G907, _G910, _G913, _G916|...], [_G925, _G928, n, ~, _G937, o|...], [~, ~, _G958, ~, _G964|...], [_G979, ~, x, ~|...], [_G1006, _G1009, _G1012|...], [_G1033, _G1036|...], [_G1060|...], [...|...]], [5, 0, 5, 1, 2, 1, 2, 4], [2, 4, 2, 3, 2, 1, 4, 2], [4, 3, 2, 1], _G828, 0, 0) ? creep

私は Prolog の基本的な知識しか持っておらず、何が問題なのかわかりませんでした。

質問がある程度明確になることを願っています。

4

1 に答える 1

3

あなたの2番目の句には、次のfillRow/2行があります:

replace(Columns, ColumnIndex, C2, NewColumns),

ColumnIndexシングルトンがあります。これは、コード内の他の場所でそれを使用しないことを意味します。例: どの値にも設定しません。そのため、2 番目の節で次のreplace/4行にエラーがあります。

Index > 0,

Indexは と同等であるため、ColumnIndexIndex設定されておらず (十分にインスタンス化されていません)、比較は不可能です。したがって、エラー。

于 2014-05-16T14:23:19.323 に答える