🤖 AI / ML
Writing Prolog with ChatGPTWriting Prolog with ChatGPT
Writing Prolog with ChatGPT
John
几天前,我写了关于如何使用 Claude 编写 Prolog 代码来解决国际象棋谜题的文章。今天早上,我用 ChatGPT 尝试了一个类似国际象棋谜题。任务是将后、王、车、象和马放置在一个 4x4 的棋盘上,使得没有任何棋子互相攻击。
当然,解决国际象棋谜题并没有太大的市场需求,但解决本质上等同于逻辑谜题的现实问题却是有需求的。这些国际象棋谜题的实验表明,在 LLM 的辅助下编写 Prolog 代码可能会是一种不错的体验。Prolog 的语法可能有些古怪,但 LLM 能够很好地应对。而且由于 Prolog 已经存在了很长时间且变化不大,你可以预期 LLM 非常擅长生成这种语言的代码。 [1]
我给 ChatGPT 输入了以下提示词:
编写一个 SWI Prolog 程序来解决以下国际象棋谜题。将后、王、车、象和马放置在一个 4x4 的棋盘上,使得没有任何棋子互相攻击。打印出所有解。
它生成了一个 chess4.pl 文件(如下),我使用以下命令运行了它:
swipl -q -s chess4.pl -g solve -t halt程序找出了全部 16 种解:
Solution 1:
queen=1-2 king=2-4 rook=3-1 bishop=4-3 knight=4-4
. K . N
. . . B
Q . . .
. . R .
Solution 2:
queen=1-2 king=4-3 rook=2-4 bishop=3-1 knight=4-1
. R . .
. . . K
Q . . .
. . B N
...代码如下。
% chess4.pl
% Place queen, king, rook, bishop, and knight on a 4x4 board
% so that no piece attacks another.
:- use_module(library(lists)).
square(X-Y) :-
between(1, 4, X),
between(1, 4, Y).
solve :-
findall(Board, solution(Board), Boards),
print_solutions(Boards, 1),
length(Boards, Count),
format('Total solutions: ~d~n', [Count]).
solution(Board) :-
Pieces = [queen, king, rook, bishop, knight],
findall(S, square(S), Squares),
place_pieces(Pieces, Squares, Board),
safe(Board).
place_pieces([], _, []).
place_pieces([Piece | Pieces], Squares, [Piece-Square | Board]) :-
select(Square, Squares, RemainingSquares),
place_pieces(Pieces, RemainingSquares, Board).
safe(Board) :-
safe(Board, Board).
safe([], _).
safe([Piece-Square | Rest], Board) :-
forall(
member(OtherPiece-OtherSquare, Rest),
non_attacking(Piece-Square, OtherPiece-OtherSquare, Board)
),
safe(Rest, Board).
non_attacking(P1-S1, P2-S2, Board) :-
\+ attacks(P1, S1, S2, Board),
\+ attacks(P2, S2, S1, Board).
% Attack rules
attacks(king, X1-Y1, X2-Y2, _) :-
X1-Y1 \= X2-Y2,
DX is abs(X1 - X2),
DY is abs(Y1 - Y2),
DX =< 1,
DY =< 1. attacks(knight, X1-Y1, X2-Y2, _) :- DX is abs(X1 - X2), DY is abs(Y1 - Y2), ( DX =:= 1, DY =:= 2 ; DX =:= 2, DY =:= 1 ). attacks(rook, S1, S2, Board) :- same_rank_or_file(S1, S2), clear_line(S1, S2, Board). attacks(bishop, S1, S2, Board) :- same_diagonal(S1, S2), clear_line(S1, S2, Board). attacks(queen, S1, S2, Board) :- ( same_rank_or_file(S1, S2) ; same_diagonal(S1, S2) ), clear_line(S1, S2, Board). same_rank_or_file(X1-Y1, X2-Y2) :- ( X1 =:= X2 ; Y1 =:= Y2 ). same_diagonal(X1-Y1, X2-Y2) :- DX is abs(X1 - X2), DY is abs(Y1 - Y2), DX =:= DY. % For sliding pieces, make sure no piece blocks the path. clear_line(X1-Y1, X2-Y2, Board) :- step(X1, X2, SX), step(Y1, Y2, SY), NX is X1 + SX, NY is Y1 + SY, clear_path(NX-NY, X2-Y2, SX-SY, Board). clear_path(Target, Target, _, _) :- !. clear_path(X-Y, Target, SX-SY, Board) :- \+ occupied(X-Y, Board), NX is X + SX, NY is Y + SY, clear_path(NX-NY, Target, SX-SY, Board). step(A, B, 0) :- A =:= B. step(A, B, 1) :- B > A.
step(A, B, -1) :-
B < A.
occupied(Square, Board) :-
member(_-Square, Board).
% Printing
print_solutions([], _).
print_solutions([Board | Rest], N) :-
format('Solution ~d:~n', [N]),
print_coordinates(Board),
print_board(Board),
nl,
N1 is N + 1,
print_solutions(Rest, N1).
print_coordinates(Board) :-
member(queen-Q, Board),
member(king-K, Board),
member(rook-R, Board),
member(bishop-B, Board),
member(knight-N, Board),
format(' queen=~w king=~w rook=~w bishop=~w knight=~w~n',
[Q, K, R, B, N]).
print_board(Board) :-
forall(
between(1, 4, Row0),
(
Y is 5 - Row0,
forall(
between(1, 4, X),
(
piece_at(X-Y, Board, Symbol),
format('~w ', [Symbol])
)
),
nl
)
).
piece_at(Square, Board, Symbol) :-
member(Piece-Square, Board),
!,
piece_symbol(Piece, Symbol).
piece_at(_, _, '.').
piece_symbol(queen, 'Q').
piece_symbol(king, 'K').
piece_symbol(rook, 'R').
piece_symbol(bishop, 'B').
piece_symbol(knight, 'N').[1] 这个周末我尝试了生成 Prolog 和 Lean 代码,并且在使用 Prolog 时取得了更好的效果。遇到的问题其实不在于 Lean 本身,而在于 Mathlib 库。这个库经常被重构,这对于一门年轻的语言来说固然合情合理,但这确实让代码的生成和调试变得更加困难。
需要完整排版与评论请前往来源站点阅读。