I’ve written a number of posts about utilizing Claude or ChatGPT to generate Prolog or Lean code to unravel a chess puzzle. I didn’t assume Grok can be as much as the duty, although I didn’t strive it. I’ve heard good issues about Grok 4.5, so I gave it a shot. It did nice.
Right here’s the issue, a variation on the n-queens downside formulated by Martin Gardner.
Are you able to place 5 white queens and three black queens on a 5 × 5 board in order that no queen of 1 colour assaults a queen of one other colour?
Right here’s the immediate I’ve Grok 4.5.
Generate SWI Prolog code to unravel the next chess puzzle. On a 5 by 5 chessboard, place 5 white queens and three black queens in order that no queen is attacking a queen of the opposite colour. Have the code enumerate all options.
The code ran appropriately, giving all eight options.
I then requested Grok
Now generate Lean 4 code to unravel the identical puzzle.
The code didn’t run on the primary or second makes an attempt however ran appropriately on the third iteration. That’s higher than I’ve seen earlier than. It’s not an apples-to-apples comparability, but it surely has normally taken many iterations with Claude earlier than Lean code would run.
Options
There are eight options, every being a flip or a rotation of 1 elementary answer. Right here’s a consultant.
SWI Prolog code
:- use_module(library(clpfd)).
%% Enumerate all methods to put 5 white queens and three black queens
%% on a 5x5 board in order that no queen assaults a queen of the alternative color.
%% Similar-colour queens are allowed to assault one another.
%%
%% 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
clear up :-
answer(Whites, Blacks),
print_solution(Whites, Blacks),
fail.
clear up :-
writeln('No extra options.').
answer(Whites, Blacks) :-
size(Whites, 5),
size(Blacks, 3),
append(Whites, Blacks, All),
All ins 1..25,
all_distinct(All),
% canonical order so every set of positions is generated as soon as
Whites = [W1,W2,W3,W4,W5],
W1 #< W2, W2 #< W3, W3 #< W4, W4 #< W5,
Blacks = [B1,B2,B3],
B1 #< B2, B2 #< B3, % each black is secure from each white maplist(safe_from_all(Whites), Blacks), label(All). safe_from_all(Whites, Black) :- maplist(no_attack(Black), Whites). %% Two queens do *not* assault one another. 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, % completely different row C1 #= C2, % completely different column abs(R1-R2) #= abs(C1-C2). % completely 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 code
-- Lean 4 answer for the 5×5 black-and-white queens puzzle.
-- 5 white queens + 3 black queens; no opposite-colour assaults.
def absDiff (a b : Nat) : Nat :=
if a ≥ b then a - b else b - a
def assaults (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 : Checklist (Nat × Nat) :=
(Checklist.vary 5).flatMap enjoyable r =>
(Checklist.vary 5).map enjoyable c => (r, c)
/-- Mixtures of size precisely `ok` (order-preserving). -/
def mixtures {α : Kind} : Nat → Checklist α → Checklist (Checklist α)
| 0, _ => [[]]
| _, [] => []
| ok + 1, x::ys =>
(mixtures ok ys).map (enjoyable zs => x :: zs) ++
mixtures (ok + 1) ys
def isAttackedBy (pos : Nat × Nat) (queens : Checklist (Nat × Nat)) : Bool :=
queens.any (enjoyable q => assaults q pos)
/-- Each answer as a pair (white squares, black squares). -/
def clear up : Checklist (Checklist (Nat × Nat) × Checklist (Nat × Nat)) :=
(mixtures 3 allPositions).foldl (enjoyable acc blacks =>
let forbidden := allPositions.filter enjoyable p =>
blacks.comprises p || isAttackedBy p blacks
let out there := allPositions.filter enjoyable p =>
!(forbidden.comprises p)
acc ++ (mixtures 5 out there).map enjoyable whites => (whites, blacks)
) []
/-- Fairly-print one board. -/
def printBoard (whites blacks : Checklist (Nat × Nat)) : IO Unit := do
for r in Checklist.vary 5 do
let mut row := ""
for c in Checklist.vary 5 do
let p := (r, c)
row := row ++
(if whites.comprises p then "W "
else if blacks.comprises p then "B "
else ". ")
IO.println row
IO.println ""
/-- Enumerate and show each answer. -/
def fundamental : IO Unit := do
let sols := clear up
IO.println s!"Discovered {sols.size} options.n"
for p in (Checklist.vary sols.size).zip sols do
let i := p.1
let (whites, blacks) := p.2
IO.println s!"Answer {i + 1}:"
printBoard whites blacks
#eval fundamental
