🤖 AI / ML
用 Grok 4.5 解决国际象棋难题Solving a chess puzzle with Grok 4.5
作者此前曾使用 Claude 或 ChatGPT 生成 Prolog 或 Lean 代码来解决国际象棋难题,但未对 Grok 抱有期望。在尝试 Grok 4.5 后,发现其表现出色,成功完成了代码生成与难题求解任务。
John
我写过几篇关于使用 Claude 或 ChatGPT 生成 Prolog 或 Lean 代码来解决国际象棋谜题的文章。我原本以为 Grok 无法胜任这项任务,尽管我并没有试过。我听说 Grok 4.5 表现不错,所以试了一下。结果它做得非常好。
问题是这样的,这是由 Martin Gardner 提出的 n 皇后问题的一个变体。
你能在 5 × 5 的棋盘上放置五个白皇后和三个黑皇后,使得没有任何一种颜色的皇后攻击另一种颜色的皇后吗?
这是我给 Grok 4.5 的提示词。
生成 SWI Prolog 代码来解决以下国际象棋谜题。在 5×5 的棋盘上,放置 5 个白皇后和 3 个黑皇后,使得没有任何皇后攻击另一种颜色的皇后。让代码枚举所有解。
代码运行正确,给出了全部八个解。
然后我问 Grok
现在生成 Lean 4 代码来解决同一个谜题。
代码在第一次和第二次尝试时未能运行,但在第三次迭代时运行正确。这比我以前见过的要好。虽然这不是绝对公平的比较,但通常 Claude 需要经过多次迭代才能让 Lean 代码运行起来。
解
共有八个解,每个解都是一个基本解的翻转或旋转。这里是一个代表性解。
:- use_module(library(clpfd)).
%% Enumerate all ways to place 5 white queens and 3 black queens
%% on a 5x5 board so that no queen attacks a queen of the opposite colour.
%% Same-colour queens are allowed to attack each other.
%%
%% Positions are numbered 1..25 in row-major order:
%% 1 2 3 4 5
%% 6 7 8 9 10
%% 11 12 13 14 15
%% 16 17 18 19 20
%% 21 22 23 24 25
solve :-
solution(Whites, Blacks),
print_solution(Whites, Blacks),
fail.
solve :-
writeln('No more solutions.').
solution(Whites, Blacks) :-
length(Whites, 5),
length(Blacks, 3),
append(Whites, Blacks, All),
All ins 1..25,
all_distinct(All),
% canonical order so each set of positions is generated once
Whites = [W1,W2,W3,W4,W5],
W1 #< W2, W2 #< W3, W3 #< W4, W4 #< W5,
Blacks = [B1,B2,B3],
B1 #< B2, B2 #< B3, % every black is safe from every white maplist(safe_from_all(Whites), Blacks), label(All). safe_from_all(Whites, Black) :- maplist(no_attack(Black), Whites). %% Two queens do *not* attack each other. no_attack(P, Q) :- R1 #= (P-1) div 5 + 1, C1 #= (P-1) mod 5 + 1, R2 #= (Q-1) div 5 + 1, C2 #= (Q-1) mod 5 + 1, R1 #\= R2, % different row C1 #\= C2, % different column abs(R1-R2) #\= abs(C1-C2). % different diagonal print_solution(Whites, Blacks) :- format('Whites: ~w~n', [Whites]), format('Blacks: ~w~n', [Blacks]), forall(between(1, 5, R), ( forall(between(1, 5, C), ( Pos is (R-1)*5 + C, ( memberchk(Pos, Whites) -> write('W ')
; memberchk(Pos, Blacks) -> write('B ')
; write('. ')
)
)),
nl )),
nl.Lean 4 代码
-- Lean 4 solution for the 5×5 black-and-white queens puzzle.
-- 5 white queens + 3 black queens; no opposite-colour attacks.
def absDiff (a b : Nat) : Nat :=
if a ≥ b then a - b else b - a
def attacks (p q : Nat × Nat) : Bool :=
p.1 == q.1 || p.2 == q.2 || absDiff p.1 q.1 == absDiff p.2 q.2
/-- All 25 squares (0-based, row-major). -/
def allPositions : List (Nat × Nat) :=
(List.range 5).flatMap fun r =>
(List.range 5).map fun c => (r, c)
/-- Combinations of length exactly `k` (order-preserving). -/
def combinations {α : Type} : Nat → List α → List (List α)
| 0, _ => [[]]
| _, [] => []
| k + 1, x::ys =>
(combinations k ys).map (fun zs => x :: zs) ++
combinations (k + 1) ys
def isAttackedBy (pos : Nat × Nat) (queens : List (Nat × Nat)) : Bool :=
queens.any (fun q => attacks q pos)
/-- Every solution as a pair (white squares, black squares). -/
def solve : List (List (Nat × Nat) × List (Nat × Nat)) :=
(combinations 3 allPositions).foldl (fun acc blacks =>
let forbidden := allPositions.filter fun p =>
blacks.contains p || isAttackedBy p blacks
let available := allPositions.filter fun p =>
!(forbidden.contains p)
acc ++ (combinations 5 available).map fun whites => (whites, blacks)
) []
/-- Pretty-print one board. -/
def printBoard (whites blacks : List (Nat × Nat)) : IO Unit := do
for r in List.range 5 do
let mut row := ""
for c in List.range 5 do
let p := (r, c)
row := row ++
(if whites.contains p then "W "
else if blacks.contains p then "B "
else ". ")
IO.println row
IO.println ""
/-- Enumerate and display every solution. -/
def main : IO Unit := do
let sols := solve
IO.println s!"Found {sols.length} solutions.\n"
for p in (List.range sols.length).zip sols do
let i := p.1
let (whites, blacks) := p.2
IO.println s!"Solution {i + 1}:"
printBoard whites blacks
#eval main需要完整排版与评论请前往来源站点阅读。