# - - - - - c l a s s P u z z l e
class Puzzle(object):
'''Represents a Kriss Kross puzzle and solving mechanism.
Exports:
Puzzle ( inFile ):
[ inFile is a readable file ->
if inFile contains a valid puzzle file ->
return a new Puzzle instance representing that file
else ->
raise SyntaxError ]
Exported attributes:
.inFile: [ as passed to constructor, read-only ]
.size:
[ the count of rows and columns in the puzzle, as a
Coords instance ]
Exported methods:
.show():
[ return the current state of the puzzle, in the same
format as the input framework, as a multi-line string ]
.whatCell ( coord ):
[ coord is a Coord instance ->
if there is a cell at coord ->
return the Cell instance at that location
else -> return None ]
.genCells(): [ generate the cells in self, in ascending order ]
.whatSlots ( coord ):
[ coord is a Coord instance ->
generate all the slots that contain coord, as
Slot instances, if any ]
.scan ( j, isV ):
[ (isV is 0 for horizontal, 1 for vertical) and
(j is a valid index for dimension isV) ->
generate the coordinates of row or column j as
a sequence of Coord instances ]
.nSlots():
[ returns the number of slots in self ]
.genSolutions():
[ generate a sequence of Puzzle instances representing
the solutions to self, if any ]
In addition to a WordBank instance that
manages the word choices, two internal data structures
manage the collections of cells and slots. Both are
dictionaries to allow random access.
State/Invariants:
.__wordBank:
[ a WordBank instance representing the word list and
the state of solution ]
.__cellMap:
[ a dictionary whose keys are (row, column) tuples
representing the coordinates in self where characters
can go, and the associated value is a Cell instance
representing what is at that coordinate ]
.__slotMap:
[ a dictionary whose keys are (row, column, isV),
where (row, column) is the location of the first position
in a slot in self and isV is 0 for horizontal, 1 for
vertical, and the associated value is a Slots
instance representing a slot with that origin and
orientation ]
The recursive algorithm needs to know the first slot and the successor for each slot.
.__firstSlot:
[ the first slot in self ]
.__slotSuccessor:
[ a dictionary whose keys are all the slots in self,
and each related value is the successor of that slot
in the sequence, or None for the last slot ]
'''
There is a subtle point about the indices in .__cellMap and .__slotMap.
Initially I was planning to use Coord
instances as the indices in .__cellMap.
However, if a piece of logic manufactured a different Coordinstance and
used it to index .__cellMap, it would get a
KeyError. Hence we use tuples to insure
that any two coordinates are treated the same.