{"slug": "solving-a-chess-puzzle-with-grok-4-5", "title": "Solving a chess puzzle with Grok 4.5", "summary": "Grok 4.5 successfully generated SWI Prolog and Lean 4 code to solve a chess puzzle: placing five white queens and three black queens on a 5×5 board so that no queen of one color attacks a queen of another color. The Prolog code ran correctly on the first attempt, enumerating all eight solutions, while the Lean 4 code ran correctly on the third iteration, which the author notes is better than previous experiences with Claude.", "body_md": "I’ve written several posts about using Claude or ChatGPT to generate Prolog or Lean code to solve a chess puzzle. I didn’t think Grok would be up to the task, though I didn’t try it. I’ve heard good things about Grok 4.5, so I gave it a shot. It did great.\n\nHere’s the problem, a variation on the *n*-queens problem formulated by Martin Gardner.\n\nCan you place five white queens and three black queens on a 5 × 5 board so that no queen of one color attacks a queen of another color?\n\nHere’s the prompt I have Grok 4.5.\n\nGenerate SWI Prolog code to solve the following chess puzzle. On a 5 by 5 chessboard, place 5 white queens and 3 black queens so that no queen is attacking a queen of the other color. Have the code enumerate all solutions.\n\nThe code ran correctly, giving all eight solutions.\n\nI then asked Grok\n\nNow generate Lean 4 code to solve the same puzzle.\n\nThe code did not run on the first or second attempts but ran correctly on the third iteration. That’s better than I’ve seen before. It’s not an apples-to-apples comparison, but it has usually taken many iterations with Claude before Lean code would run.\n\n## Solutions\n\nThere are eight solutions, each being a flip or a rotation of one fundamental solution. Here’s a representative.\n\n## SWI Prolog code\n\n```\n:- use_module(library(clpfd)).\n\n%% Enumerate all ways to place 5 white queens and 3 black queens\n%% on a 5x5 board so that no queen attacks a queen of the opposite colour.\n%% Same-colour queens are allowed to attack each other.\n%%\n%% Positions are numbered 1..25 in row-major order:\n%%   1  2  3  4  5\n%%   6  7  8  9 10\n%%  11 12 13 14 15\n%%  16 17 18 19 20\n%%  21 22 23 24 25\n\nsolve :-\n    solution(Whites, Blacks),\n    print_solution(Whites, Blacks),\n    fail.\nsolve :-\n    writeln('No more solutions.').\n\nsolution(Whites, Blacks) :-\n    length(Whites, 5),\n    length(Blacks, 3),\n    append(Whites, Blacks, All),\n    All ins 1..25,\n    all_distinct(All),\n    % canonical order so each set of positions is generated once\n    Whites = [W1,W2,W3,W4,W5],\n    W1 #< W2, W2 #< W3, W3 #< W4, W4 #< W5,\n    Blacks = [B1,B2,B3],\n    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 ')\n                      ; memberchk(Pos, Blacks) -> write('B ')\n                      ; write('. ')\n                      )\n                    )),\n             nl )),\n    nl.\n```\n\n## Lean 4 code\n\n```\n-- Lean 4 solution for the 5×5 black-and-white queens puzzle.\n-- 5 white queens + 3 black queens; no opposite-colour attacks.\n\ndef absDiff (a b : Nat) : Nat :=\n  if a ≥ b then a - b else b - a\n\ndef attacks (p q : Nat × Nat) : Bool :=\n  p.1 == q.1 || p.2 == q.2 || absDiff p.1 q.1 == absDiff p.2 q.2\n\n/-- All 25 squares (0-based, row-major). -/\ndef allPositions : List (Nat × Nat) :=\n  (List.range 5).flatMap fun r =>\n    (List.range 5).map fun c => (r, c)\n\n/-- Combinations of length exactly `k` (order-preserving). -/\ndef combinations {α : Type} : Nat → List α → List (List α)\n  | 0,     _      => [[]]\n  | _,     []     => []\n  | k + 1, x::ys  =>\n      (combinations k ys).map (fun zs => x :: zs) ++\n      combinations (k + 1) ys\n\ndef isAttackedBy (pos : Nat × Nat) (queens : List (Nat × Nat)) : Bool :=\n  queens.any (fun q => attacks q pos)\n\n/-- Every solution as a pair (white squares, black squares). -/\ndef solve : List (List (Nat × Nat) × List (Nat × Nat)) :=\n  (combinations 3 allPositions).foldl (fun acc blacks =>\n    let forbidden := allPositions.filter fun p =>\n      blacks.contains p || isAttackedBy p blacks\n    let available := allPositions.filter fun p =>\n      !(forbidden.contains p)\n    acc ++ (combinations 5 available).map fun whites => (whites, blacks)\n  ) []\n\n/-- Pretty-print one board. -/\ndef printBoard (whites blacks : List (Nat × Nat)) : IO Unit := do\n  for r in List.range 5 do\n    let mut row := \"\"\n    for c in List.range 5 do\n      let p := (r, c)\n      row := row ++\n        (if whites.contains p then \"W \"\n         else if blacks.contains p then \"B \"\n         else \". \")\n    IO.println row\n  IO.println \"\"\n\n/-- Enumerate and display every solution. -/\ndef main : IO Unit := do\n  let sols := solve\n  IO.println s!\"Found {sols.length} solutions.\\n\"\n  for p in (List.range sols.length).zip sols do\n    let i := p.1\n    let (whites, blacks) := p.2\n    IO.println s!\"Solution {i + 1}:\"\n    printBoard whites blacks\n\n#eval main\n```\n\n", "url": "https://wpnews.pro/news/solving-a-chess-puzzle-with-grok-4-5", "canonical_source": "https://www.johndcook.com/blog/2026/07/20/grok-chess/", "published_at": "2026-07-20 14:33:31+00:00", "updated_at": "2026-07-20 14:53:57.876971+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools"], "entities": ["Grok 4.5", "Claude", "ChatGPT", "Martin Gardner", "SWI Prolog", "Lean 4"], "alternates": {"html": "https://wpnews.pro/news/solving-a-chess-puzzle-with-grok-4-5", "markdown": "https://wpnews.pro/news/solving-a-chess-puzzle-with-grok-4-5.md", "text": "https://wpnews.pro/news/solving-a-chess-puzzle-with-grok-4-5.txt", "jsonld": "https://wpnews.pro/news/solving-a-chess-puzzle-with-grok-4-5.jsonld"}}