= Solution
Assume the board satisfies the <representation invariant>. Reject completed boards and occupied or out-of-range coordinates; testing membership in the empty component covers both coordinate failures.
``
finished :: Board -> Bool
finished (os,xs,es) = won os || won xs || null es
play :: Board -> Place -> Board
play b@(os,xs,es) q
| finished b = error "play: completed game"
| q `notElem` es = error "play: unavailable place"
| length os == length xs = (q:os,xs,rest)
| otherwise = (os,q:xs,rest)
where rest = filter (/=q) es
``
Here `won` is defined in part d. Moving one available coordinate into the appropriate occupied component preserves the <set partition> and the alternating-count rule. Checking completion first preserves the no-moves-after-a-win invariant.
Back to article page