about summary refs log tree commit diff stats
path: root/resources/solutions/DFS-01.fornax
blob: 438e7e1bc3c9395dc634f0288662df71155470dd (plain) (blame)
1
2
3
4
5
6
7
rows:3 cols:3
.#......$
!-@......$
-#.@....$
-#.-@...$
-#.--@..$
|-#.---..@
>200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
/*
  Some general utilities in Picat.
  Others have been moved to the modules basic, math, sys, etc.
  by Hakan Kjellerstrand and Neng-Fa Zhou.
*/

module util.

% array_matrix_to_list(A) = array_matrix_to_list(A).
% array_matrix_to_list_matrix(A) = array_matrix_to_list_matrix(A).
% chunks_of(L,N) = chunks_of(L,N).
% columns(Matrix) = columns(Matrix).
% diagonal1(Matrix) = diagonal1(Matrix).
% diagonal2(Matrix) = diagonal2(Matrix).
% drop(L,N) = drop(L,N).
% find(String, SubString, From, To) => find(String, SubString, From, To).
% find_first_of(Compound,Pattern) = find_first_of(Compound,Pattern).
% find_ignore_case(String, SubString, From, To) => find_ignore_case(String, SubString, From, To).
% find_last_of(Compound,Pattern) = find_last_of(Compound,Pattern).
% join(S) = join(S).
% join(S, Seperator) = join(S, Seperator).
% list_matrix_to_array_matrix(L) = list_matrix_to_array_matrix(L).
% lstrip(L) = lstrip(L," \t\n\r").
% lstrip(L,Chars) = lstrip(L,Chars).
% matrix_multi(A,B) = matrix_multi(A,B).
% nextto(X,Y,List) => nextto(X,Y,List).
% permutation(Xs,Ys) => permutation(Xs,Ys).
% permutations(Xs) = permutations(Xs).
% power_set(Set) = power_set(Set).
% replace(Term,Old,New) = replace(Term,Old,New).
% replace_at(Compound,I,NewArg) = replace_at(Compound,I,NewArg).
% rows(Matrix) = rows(Matrix).
% rstrip(L) = rstrip(L," \t\n\r").
% rstrip(L,Chars) = rstrip(L,Chars).
% split(Str) = split(Str).
% split(Str,Seperators) = split(Str,Seperators).
% strip(L) = strip(L," \t\n\r").
% strip(L,Chars) = strip(L,Chars).
% take(L,N) = take(L,N).
% transpose(Matrix) = transpose(Matrix).

%
% Convert a 2D array to a list
%
array_matrix_to_list(A) = L =>
    NRows = A.length,
    NCols = A[1].length,
    L = [A[I,J] : I in 1..NRows, J in 1..NCols].

% Convert a 2D array to a 2D matrix of lists
array_matrix_to_list_matrix(A) = L =>
    L = [A[I].to_list() : I in 1..A.length].

% Convert a 2D list matrix to a 2D array matrix
list_matrix_to_array_matrix(L) = A =>
    bp.list_matrix_to_array_matrix(L,A).

%
% Join a list of strings with a join character.
% Res = join(String,JoinChar)
%
join(S) = join(S," ").

join(S, JoinAtm) = Res, atom(JoinAtm) => 
    join_aux(S, JoinAtm.to_string(), Res).
join(S,JoinStr) = Res, string(JoinStr) => 
    join_aux(S,JoinStr,Res).
join(S,JoinStr) = _Res => 
    handle_exception($string_or_atom_expected(JoinStr), $join(S,JoinStr)).

private
join_aux([],_JoinStr,Res)  => Res = [].
join_aux([W|Str],JoinStr,Res)  => 
    once(append(W,Res1,Res)),
    (Str == [] -> 
    Res2 = Res1
    ;
        once(append(JoinStr,Res2,Res1))
    ),
    join_aux(Str,JoinStr,Res2).

%%%%
% replace occurrences of Old in T (a variable or an atomic value) by New
replace(T,Old,New) = Res =>
    replace_aux(T,Old,New,Res).
    
replace_aux(Old,Old,New,Res) => Res = New.
replace_aux(T,Old,New,Res), atomic(T) => Res = T.
replace_aux(T,Old,New,Res), var(T) => Res = T.    
replace_aux([H|T],Old,New,Res) =>
    Res = [NH|NT],
    replace_aux(H,Old,New,NH), 
    replace_aux(T,Old,New,NT).
replace_aux(T,Old,New,Res) =>
    Res = new_struct(T.name,T.length),
    foreach(I in 1 .. T.length) 
        replace_aux(T[I],Old,New,Res[I]) 
    end.

%%%%
% return a copy of the compound value, replacing the Ith argument by NewVal
replace_at(List,I,NewVal) = NewList, integer(I), list(List) =>
    replace_list_at(List,I,NewVal,NewList,ErrorFlag),
    (var(ErrorFlag) -> true; handle_exception($domain_error(I), $replace_at)).
replace_at(Struct,I,NewVal) = NewStruct, integer(I), struct(Struct) =>
    Arity = len(Struct),
    (I >= 1, I =< Arity ->
    NewStruct = new_struct(Struct.name,Arity),
    foreach(J in 1 .. Arity) 
            (J == I ->
            NewStruct[J] = NewVal
        ;
            NewStruct[J] = Struct[J]
        )
    end
    ;
        handle_exception($domain_error(I), $replace_at)
    ).

private
replace_list_at([_|List],1,NewVal,NewList,_ErrorFlag) => NewList = [NewVal|List].
replace_list_at([E|List],I,NewVal,NewList,ErrorFlag) =>
    NewList = [E|NewList1],
    replace_list_at(List,I-1,NewVal,NewList1,ErrorFlag).
replace_list_at(_,_,_,_,ErrorFlag) => ErrorFlag = 1.

% match a string
%   find(String, SubString,From,To)
%
% (If we want to have multiple results it must be a predicate,
%  not a function.)
find(String, SubString, From, To) =>
    SubLen = SubString.length,
    bp.append(Pre,SubString,_,String),
    From = Pre.length+1,
    To = From+SubLen-1.

% Case insensitive match
find_ignore_case(String, SubString, From, To) =>
    String2 = String.to_lowercase(),
    SubString2 = SubString.to_lowercase(),
    find(String2,SubString2,From,To).

%%%%
% searches for the first argument that unifies with Pattern and returns the argument's index
find_first_of(List,Pattern) = Index, list(List) =>
    find_list_first_of(List,Pattern,1,Index).
find_first_of(Struct,Pattern) = Index, struct(Struct) =>
    find_struct_first_of(Struct,Pattern,1, len(Struct), Index).
find_first_of(Struct,_Pattern) = _ =>
    handle_exception($compound_expected(Struct), find_first_of).

find_list_first_of([],_Pattern,_CurIndex,Index) => Index = -1.
find_list_first_of([E|L],Pattern,CurIndex,Index), E != Pattern =>  % not unifiable
    find_list_first_of(L,Pattern,CurIndex+1,Index).
find_list_first_of(_L,_Pattern,CurIndex,Index) => Index = CurIndex.

find_struct_first_of(_Struct,_Pattern,CurIndex,Arity,Index), CurIndex > Arity => Index = -1.
find_struct_first_of(Struct,Pattern,CurIndex,Arity,Index), Struct[CurIndex] != Pattern =>  % not unifiable
    find_struct_first_of(Struct,Pattern,CurIndex+1,Arity,Index).
find_struct_first_of(_,_,CurIndex,_Arity,Index) => Index = CurIndex.

%%%%
% searches for the last argument that unifies with Pattern and returns the argument's index
find_last_of(List,Pattern) = Index, list(List) =>
    find_list_last_of(List,Pattern,1,-1,Index).
find_last_of(Struct,Pattern) = Index, struct(Struct) =>
    find_struct_last_of(Struct,Pattern, len(Struct), Index).
find_last_of(Struct,_) = _ =>
    handle_exception($compound_expected(Struct), find_last_of).

find_list_last_of([],_Pattern,_CurIndex,Index0,Index) => Index = Index0.
find_list_last_of([E|L],Pattern,CurIndex,Index0,Index), E != Pattern =>  % not unifiable
    find_list_last_of(L,Pattern,CurIndex+1,Index0,Index).
find_list_last_of([_|L],Pattern,CurIndex,_Index0,Index) =>
    find_list_last_of(L,Pattern,CurIndex+1,CurIndex,Index).

find_struct_last_of(_Struct,_Pattern,0,Index) => Index = -1.
find_struct_last_of(Struct,Pattern,CurIndex,Index), Struct[CurIndex] != Pattern =>  % not unifiable
    find_struct_last_of(Struct,Pattern,CurIndex-1,Index).
find_struct_last_of(_,_,CurIndex,Index) => Index = CurIndex.

% A*B=C
matrix_multi(A,B) = C, array(A), array(B) =>   % A and B must be array matricies
    C = new_array(A.length,B[1].length),
    foreach(I in 1..A.length, J in 1..B[1].length)
        C[I, J] = sum([A[I,K]*B[K,J] : K in 1..A[1].length])
    end.

% nondet
permutation(Xs, Ys) => bp.permutation(Xs,Ys).

% generate permutations
permutations([]) = [[]].
permutations([H|T]) = [insert(P,I,H) : P in Ps, I in 1..P.length+1] => Ps = permutations(T).

%nonet
nextto(X,Y, List) => bp.nextto(X,Y,List).

% generate the power set
power_set([]) = [[]].
power_set([H|T]) = P1++P2 =>
    P1 = power_set(T),
    P2 = [[H|S] : S in P1].

%
% Split a string into tokens given some split chars
% List = split(String, Seperators)
%
split(Str) = split(Str," \t\n\r").   % use white spaces as the default set of separators

split(Str,Seperators) = Tokens =>
    bp.picat_split_string(Str,Seperators,Tokens).

lstrip(L) = lstrip(L," \t\n\r").

lstrip([],_Elms) = [].
lstrip([E|L],Elms) = NewL, membchk(E, Elms) => NewL = lstrip(L,Elms).
lstrip(L,_Elms) = NewL => NewL = L.

rstrip(L) = rstrip(L," \t\n\r").

rstrip(L, Elms) = L.reverse().lstrip(Elms).reverse().

strip(L) = strip(L," \t\n\r").

strip(L, Elms) = L.lstrip(Elms).rstrip(Elms).

%
% Transpose a 2D matrix
%
transpose(Matrix) = Transposed, array(Matrix) =>   % array matrix
    N = Matrix.length,
    M = Matrix[1].length,
    Transposed = new_array(M,N),
    foreach(I in 1..N, J in 1..M)
        Transposed[J,I] = Matrix[I,J]
    end.
transpose(Matrix) = Transposed =>   % assumed to be list matrix
    N = Matrix.length,
    M = Matrix[1].length,
    Transposed = [Mj : J in 1..M, Mj = [Matrix[I,J] : I in 1..N]].

%=============
% for matrices (inspired by B-Prolog's ^rows, ^columns, ^diag1, ^diag2)
%
% These should be put in util.pi since transpose/1 is used.

rows(M) = M, list(M)  => true.
rows(A) = Rows, array(A)  =>  NRows = A.length, Rows = [A[I] : I in 1..NRows].

columns(M) = [Column : Column in M.transpose()], list(M) => true.
columns(A) = [Column : Column in A.transpose()], array(A) => true.

diagonal1(M) = [M[I,I] : I in 1..M.length], list(M)  => true.
diagonal1(A) = [A[I,I] : I in 1..A.length], array(A)  => true.

diagonal2(M) = [M[I,M.length-I+1] : I in 1..M.length], list(M)  => true.
diagonal2(A) = [A[I,A.length-I+1] : I in 1..A.length], array(A)  => true.


%=============
% from Haskell prelude
%
take(L,N) = Taken, list(L), integer(N), take_aux(L,N,Taken) => true.

private
take_aux([H|T],N,Taken), N > 0 => Taken = [H|TakenR], take_aux(T,N-1,TakenR).
take_aux(_List,_N,Taken) => Taken = [].

drop(L,N) = Taken, list(L), integer(N), drop_aux(L,N,Taken) => true.

private
drop_aux([_|T],N,Taken), N > 0 => drop_aux(T,N-1,Taken).
drop_aux(L,_,Taken), list(L) => Taken = L.

chunks_of([],_N) = [].
chunks_of(L,N) = Chunks, list(L) =>
    Chunks = [Chunk|ChunksR],
    chunks_of(L,Chunk,0,N,ChunksR).

chunks_of([],Chunk,_,_,Chunks) => Chunk = [], Chunks = [].
chunks_of(L,Chunk,N,N,Chunks) =>
    Chunk = [],
    (L == [] ->
        Chunks = []
    ;
        Chunks = [NextChunk|ChunksR],
        chunks_of(L,NextChunk,0,N,ChunksR)
    ).
chunks_of([X|Xs],Chunk,Count,N,Chunks) =>
    Chunk = [X|ChunkR],
    chunks_of(Xs,ChunkR,Count+1,N,Chunks).