Search code examples
prologinstantiation-error

Arguments are not sufficiently instantiated


I have an assignment in which I have to solve the battleships puzzle using Prolog. My current solution goes over the entire field and places a piece of boat on the coordinates it is currently on. If no part of the boat is allowed there (I only look at the sums of boat pieces which are given.) it places some water.

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).

The line above is what you call. The first argument is the field with a ~ for water an _ for unknown and everything else is a part of a boat. The second argument is the sum of pieces of boat in each column, the third argument is the same but for the rows. The fourth argument is the size of the boats and the final argument is where I should put the result.

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).

Solving the problem like this will start in the upper right corner and go left and down to fill in the field. However when backtracking is needed because it got stuck it fails. Using this example an x will be placed on position (0,3) which is wrong. When we reach the end of the row we find another piece of boat and figure out that something is wrong. Her we go back to where we placed the x. It should now put an ~ there but instead it tells me:

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

I only have some basic knowledge of Prolog and couldn't figure out what was wrong.

Any help would be appreciated and I hope the question is somewhat clear.


Solution

  • In second clause of fillRow/2 you have this line:

    replace(Columns, ColumnIndex, C2, NewColumns),
    

    There ColumnIndex is a singleton, which means that nowhere else in the code you use it any way. For example: you don't set it to any value. That's why in 2nd clause of replace/4 you have error in this line:

    Index > 0,
    

    Because Index is equivalent to ColumnIndex, then Index is not set (not sufficiently instantiated) and comparison is impossible. Thus, an error.