I managed to resolve a bug in a program today which was obvious in retrospect, but raised my Prolog enlightenment quite a bit.
The problem starts with a chess program written as part of Stanford University’s General Game Playing course which I discovered via Coursera a few years ago. (The course is still available at General Game Playing - Notes).
I really enjoyed the course, and I think General Game Playing would have got a lot more traction if the instructor, Professor Michael Genesereth, had simply used Prolog instead of his own invented Lisp-style language called kif.
I was under the impression one could simply transliterate kif into prolog, leading me into the following trap.
The original kif predicate to say a player could move a piece to block a checking move by a queen or a rook (the exact same problem cropped up in the queen or bishop predicate) looked like this:
; Block rook threat (rook or queen)
(<= (legal ?player (move ?piece ?u ?v ?x ?y))
(true (control ?player))
(or (true (check ?player rook ?tx ?ty))
(true (check ?player queen ?tx ?ty)))
(not (occupied_by_player ?x ?y ?player))
(piece_owner_type ?piece ?player ?ptype)
(distinct ?ptype king)
(piece_owner_type ?king ?player king)
(true (cell ?kx ?ky ?king))
(legal2 ?player (move ?piece ?u ?v ?x ?y))
(blocks_rook_threat ?x ?y ?tx ?ty ?kx ?ky)
(not (threatened_with_capture ?player ?tx ?ty ?kx ?ky ?u ?v)) ; (u,v) is location moved from -- ignore it
)
My “interpreter” tansliterated it into this:
% Block rook threat (rook or queen)
legal(Player, move(Piece, U, V, X, Y)) :-
true(control(Player)),
(true(check(Player, rook, Tx, Ty)) ; true(check(Player, queen, Tx, Ty))),
\+occupied_by_player(X, Y, Player),
piece_owner_type(Piece, Player, Ptype),
dif(Ptype, king),
piece_owner_type(King, Player, king),
true(cell(Kx, Ky, King)),
legal2(Player, move(Piece, U, V, X, Y)),
blocks_rook_threat(X, Y, Tx, Ty, Kx, Ky),
\+threatened_with_capture(Player, Tx, Ty, Kx, Ky, U, V).
It took me a couple of hours to figure out why my game player using the mechanically translated kif rules would not allow players to make blocking moves.
Fixing this simply involved moving one line of code. I’ll leave that here as a chess puzzle for readers.