Solution Code for the "Spinout" Puzzle

As part of a programming languages course I teach, I have developed a Prolog program for solving the 1980’s puzzle “Spinout” (from “Binary Arts”). Here is my code for anybody who might be interested:

% Spinout Puzzle Solver
% Author: M. Q. Rieck 
% Last updated: Spring 2020 

% This is my solution to the Prolog progrmamming project 
% I assigned in CS 135, at Drake U. in Spring 2020. 

% A function to create a list on N ones (representing 
% vertical knobs/dials on the puzzle)
initList(0,[]). 
initList(N,[H|T]) :- 
   N > 0, 
   M is N-1,
   H is 1,
   initList(M,T).

% Display the configuration of knobs/dials corresponding 
% to a list of zeros and ones (i.e. bits)
showConfig0([]).
showConfig0([H|T]) :- 
   showConfig0(T), 
   ((H is 0, format(' -'));
   (H is 1, format(' |'))).
showConfig(L) :- 
   format('Configuration:   '),
   showConfig0(L), nl, nl. 

% Change one of the bits in a list of bits
changeBit([],_,[]). 
changeBit([H|T],0,[H1|T]) :-
   H1 is 1-H.
changeBit([H|T],N,[H|T1]) :-
   N > 0, 
   M is N-1, 
   changeBit(T,M,T1).

% Turn a specified knob/dial, numbering the knobs from 
% right to left, beginning with zero. Actually, alter the
% list of bits representing the configuration of knobs, by
% changing the bit in a specified position of the bit list. 
turn(N,T,L,L1,StartCount,EndCount) :-
    EndCount is StartCount+1,
    (T is 0; T is 1),
    write('Step '),
    write(EndCount),
    write(': Turn knob '),
    write(N),
    ((T is 0, write(' horizontally.'));
     (T is 1, write(' vertically.'))),
    nl,
    changeBit(L,N,L1),
    showConfig(L1).

% Assume that the rightmost knobs/dials are vertical 
% (so the corresponding initial bits in the list are ones), 
% make allowable step-by-step changes so as to cause 
% these knobs/dials to become horizontal (so the 
% corresponding bits are all changed to zeros)
moveHor(0,StartList,StartList,StartCount,StartCount).
moveHor(1,StartList,EndList,StartCount,EndCount) :-
    turn(0,0,StartList,EndList,StartCount,EndCount).
moveHor(N,StartList,EndList,StartCount,EndCount) :-
    N > 1,
    M is N-1,
    P is N-2,
    moveHor(P,StartList,L1,StartCount,Count1),
    turn(M,0,L1,L2,Count1,Count2),
    moveVer(P,L2,L3,Count2,Count3),
    moveHor(M,L3,EndList,Count3,EndCount).

% Assume that the rightmost knobs/dials are horizontal 
% (so the corresponding initial bits in the list are zeros), 
% make allowable step-by-step changes so as to cause 
% these knobs/dials to become vertical (so the
% corresponding bits are all changed to ones)
moveVer(0,StartList,StartList,StartCount,StartCount).
moveVer(1,StartList,EndList,StartCount,EndCount) :-
    turn(0,1,StartList,EndList,StartCount,EndCount).
moveVer(N,StartList,EndList,StartCount,EndCount) :-
    N > 1,
    M is N-1,
    P is N-2,
    moveVer(M,StartList,L1,StartCount,Count1),
    moveHor(P,L1,L2,Count1,Count2),
    turn(M,1,L2,L3,Count2,Count3),
    moveVer(P,L3,EndList,Count3,EndCount).

% Demonstrate the solution to the Spinout puzzle, using 
% N knobs/dials. Do this by first creating and displaying 
% the initial configuration of all vertical knobs/dials, 
% and then invoking the functon moveHor to change them 
% all to the horizonal position. 
spinout(N) :- nl, 
    initList(N,List),
    showConfig(List),  
    moveHor(N,List,_,0,_), 
    !.
1 Like