This repository has been archived on 2023-04-18. You can view files and clone it, but cannot push or open issues or pull requests.
iaj/TP1/Prolog/main.pl
2023-03-01 02:28:50 +01:00

84 lines
2.6 KiB
Prolog

% Read a file with the puzzle and return the initial state of the game
read_board(Filename, Board) :-
open(Filename, read, Stream),
read_lines(Stream, Lines),
maplist(atom_chars, Board, Lines).
read_lines(Stream, []) :-
at_end_of_stream(Stream).
read_lines(Stream, [Line|Lines]) :-
\+ at_end_of_stream(Stream),
read_line(Stream, Line),
read_lines(Stream, Lines).
read_line(Stream, Line) :-
read_line_to_codes(Stream, Codes),
maplist(char_code, Line, Codes).
% Solve the Sokoban puzzle using DFS
sokoban(Board, Moves, Solution) :-
solved(Board),
Solution = Board,
Moves = [].
sokoban(Board, Moves, Solution) :-
move(Board, Dir, NewBoard),
\+ member(NewBoard, Moves),
sokoban(NewBoard, [NewBoard|Moves], Solution1),
Solution = [Dir|Solution1].
% Check if the board is solved (all boxes are on targets)
solved(Board) :-
findall(Box, (member(Box, Board), member($, Box)), Boxes),
findall(Target, (member(Target, Board), member(., Target)), Targets),
subset(Boxes, Targets).
% Find the position of the player on the board
player(Board, row(Row), col(Col)) :-
nth0(Row, Board, RowList),
nth0(Col, RowList, '1').
% Find the cell at the given row and column
cell(Board, row(Row), col(Col), Cell) :-
nth0(Row, Board, RowList),
nth0(Col, RowList, Cell).
% Move the player in the given direction
% If the player pushes a box, move the box as well
move(Board, Dir, NewBoard) :-
player(Board, row(Row), col(Col)),
cell(Board, row(NewRow), col(NewCol), Cell),
direction(Dir, dRow, dCol),
NewRow is Row + dRow,
NewCol is Col + dCol,
(
Cell = ' ' ; Cell = '.',
replace(Board, Row, Col, ' ', Board1),
replace(Board1, NewRow, NewCol, '1', NewBoard)
;
Cell = '$' ; Cell = '*',
cell(Board, row(NewRow2), col(NewCol2), Cell2),
NewRow2 is NewRow + dRow,
NewCol2 is NewCol + dCol,
(Cell2 = ' ' ; Cell2 = '.'),
replace(Board, Row, Col, ' ', Board1),
replace(Board1, NewRow, NewCol, '1', Board2),
replace(Board2, NewRow2, NewCol2, '$', NewBoard)
).
% Replace an element at the given row and column
replace(List, Row, Col, NewElem, NewList) :-
nth0(Row, List, RowList),
nth0(Col, RowList, _, RestRow),
nth0(Col, NewRow, NewElem, RestRow),
nth0(Row, NewList, NewRow, RestList).
% Define the directions
direction(up, -1, 0).
direction(down, 1, 0).
direction(left, 0, -1).
direction(right, 0, 1).
% Example usage
solve_sokoban(Filename, Solution) :-
read_board(Filename, Board),
sokoban(Board, [Board], Solution).