Towers of Hanoi for Python¶
The `Towers of Hanoi` algorithm.
Towers¶
-
class
towers.core.towers.
Towers
(height=1, rods=None, moves=0, verbose=False)[source]¶ A representation of the towers including all logic.
-
class
JsonEncoder
(skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, encoding='utf-8', default=None)[source]¶ -
default
(obj)[source]¶ Implement this method in a subclass such that it returns a serializable object for
o
, or calls the base implementation (to raise aTypeError
).For example, to support arbitrary iterators, you could implement default like this:
def default(self, o): try: iterable = iter(o) except TypeError: pass else: return list(iterable) # Let the base class default method raise the TypeError return JSONEncoder.default(self, o)
-
-
__call__
()[source]¶ Run the towers. Convenience method.
Raises: See Towers.move_tower()
.
-
__contains__
(x)[source]¶ Does this
Towers
contain the givenRod
.Parameters: x (Rod) – The Rod
to find.Return type: bool
-
__deepcopy__
(*d)[source]¶ Return a deep copy of this instance.
Parameters: d (dict) – Memoisation dict. Return type: Towers
-
__enter__
()[source]¶ Context-Manager entry, validate our entry state for towers-start conditions.
Raises: See Towers.validate_start()
.
-
__eq__
(other)[source]¶ Compare Towers instances for equivalence.
Parameters: other (Towers) – The other Towers
to compare.Return type: bool
-
__exit__
(*args, **kwargs)[source]¶ Context-Manager exit, validate our exit state for towers-end conditions.
Raises: See Towers.validate_end()
.
-
__getitem__
(index)[source]¶ Get the
Rod
at the given index.Parameters: index (int) – The index to get the Rod
at.Return type: Rod
-
context
(**kwds)[source]¶ Create a temp context for performing moves. The state of this instance will be reset at context exit.
Parameters: - reset_on_success (bool) – Reset this instance’s state on exit from the context if no error occurred. Default = True.
- reset_on_error (bool) – Reset this instance’s state on exit from the context if an error occurred. Default = False.
-
classmethod
from_json
(d)[source]¶ Return a class instance from a json serializable representation.
Parameters: d (str|dict) – The json or decoded-json from which to create a new instance. Return type: Towers Raises: See Towers
.__new__.
-
height
¶ Obtain the height of the
Towers
(ie: max number of disks each one rod can hold).Return type: int
-
move_disk
(start, end)[source]¶ Move the Disk from one Rod to another.
Note: Generator, yields Move instances.
Parameters:
-
moves
¶ Determine how many moves have occurred so far.
Return type: int
-
static
moves_for_height
(height)[source]¶ Determine the max number of moves required to solve the puzzle for the given height
Parameters: height (int) – The height of the Rods
(number ofDisk
on aRod
).Return type: int
-
validate
()[source]¶ Perform self validation.
Raises: - InvalidTowerHeight – The height of the tower is invalid
- DuplicateDisk – This
Rod
already contains thisDisk
. - CorruptRod – A
Disk
is on top of aDisk
of smaller size.
-
validate_end
()[source]¶ Validate the end conditions for this towers.
Raises: - InvalidTowerHeight – The height of the tower is invalid
- DuplicateDisk – This
Rod
already contains thisDisk
. - CorruptRod – A
Disk
is on top of aDisk
of smaller size. - InvalidEndingConditions – End conditions are invalid.
-
validate_start
()[source]¶ Validate the start conditions for this towers
Raises: - InvalidTowerHeight – The height of the
Towers
is invalid - DuplicateDisk – This
Rod
already contains thisDisk
. - CorruptRod – A
Disk
is on top of aDisk
of smaller size. - InvalidStartingConditions – Initial conditions are invalid.
- InvalidTowerHeight – The height of the
-
verbose
¶ Obtain this instance’s verbose flag.
Return type: bool
-
class
Rods¶
Rods is a collection of Rod’s, one representing the start, end and intermediary rods for the tower.
-
class
towers.core.rods.
Rods
[source]¶ A collection of 3 Rod’s that form the Tower.
Parameters: Raises: - InvalidTowerHeight – The height of the tower is invalid.
- InvalidRod – A rod is not of expected type Rod.
- InvalidRodHeight – A rod height is inconsistent with the specified height.
- DuplicateDisk – A rod contains a duplicate disk
- CorruptRod – A disk is on top of a disk of smaller size on a Rod.
-
__bool__
()[source]¶ A Rods is considered True if it contains any disks on any rods.
Return type: bool
-
__nonzero__
()[source]¶ A Rods is considered non-zero if it contains any disks on any rods.
Return type: bool
-
classmethod
from_json
(d)[source]¶ Return a class instance from a json serializable representation.
Parameters: d (str|dict) – The json or decoded-json from which to create a new instance. Return type: Rods
Raises: See Rods
.__new__.
-
height
¶ Retrieve the height of the rods (ie: max number of disks each one can hold).
Return type: int
-
validate
()[source]¶ Perform self validation.
Raises: - DuplicateDisk – This rod already contains this disk
- CorruptRod – A disk is on top of a disk of smaller size.
Rod¶
Note
A tower that contains Disks.
-
class
towers.core.rod.
Rod
[source]¶ A single tower containing disks.
-
__deepcopy__
(*d)[source]¶ Return a deep copy of this instance.
Parameters: d (dict) – Memoisation dict. Return type: Rod
-
__eq__
(other)[source]¶ Compare Rod instances for equivalence.
Parameters: other (Rod) – Return type: bool
-
static
__new__
(cls, name, disks=None, height=0)[source]¶ Parameters: - name (str) – The name of the rod.
- disks (List[Disk]) – (optional) mutatable list of Disks.
- height (int) – The height of the rod.
Return type: Raises: See Rod.validate.
-
append
(disk, validate=True)[source]¶ Append the disk to this rod and optionally validate.
Parameters: - disk (Disk) – The disk to add to the top of our rod.
- validate (bool) – True=perform self validation.
-
classmethod
from_json
(d)[source]¶ Return a class instance from a json serializable representation.
Parameters: d (Union[str,dict]) – The json or decoded-json from which to create a new instance. Return type: Rod Raises: See Rod.__new__.
-
validate
()[source]¶ Perform self validation.
Raises: - DuplicateDisk – This rod already contains this disk
- CorruptRod – A disk is on top of a disk of smaller size.
- InvalidTowerHeight – The height of the tower is invalid.
- InvalidDiskPosition – The position of the disk is invalid.
-
Disk¶
A disk is a sized element on a Rod where: 1 <= size <= rod_height
-
class
towers.core.disk.
Disk
[source]¶ An immutable representation of a sized disk that sits on a Rod.
-
static
__new__
(cls, original_position, height=1)[source]¶ Parameters: - original_position (int) – The position on the Rod that this disks originally sat. Zero = The bottom of the Rod.
- height (int) – The maximum position of this
Disk
on aRod
.
Return type: Raises: - InvalidTowerHeight – The height of the tower is invalid.
- InvalidDiskPosition – The position of the disk is invalid.
-
classmethod
from_json
(d)[source]¶ Return a class instance from a json serializable representation.
Parameters: d (str|dict) – The json or decoded-json from which to create a new instance. Return type: Disk
Raises: See Disk.__new__
.
-
validate
()[source]¶ Perform self validation
Raises: - InvalidTowerHeight – The height of the tower is invalid.
- InvalidDiskPosition – The position of the disk is invalid.
-
width
¶ Obtain the width of the disk
Return type: int
-
static
Errors and Utils¶
Any error explicitly raised by towers is defined here.
-
exception
towers.core.errors.
DuplicateDisk
(rod, disk_width)[source]¶ A duplicate disk was found on a tower.
-
exception
towers.core.errors.
CorruptRod
(rod, disk)[source]¶ A
Rod
with an invalid stack of disks was found.
-
exception
towers.core.errors.
InvalidStartingConditions
(rods, moves)[source]¶ The
Rods
for the towers are not in the correct starting state.
-
exception
towers.core.errors.
InvalidEndingConditions
(rods)[source]¶ The
Rod
’s for the towers are not in the correct ending state.
-
exception
towers.core.errors.
InvalidTowerHeight
(height)[source]¶ The height of the
Tower
is invalid.
-
exception
towers.core.errors.
InvalidDiskPosition
(position, height)[source]¶ The position of the
Disk
is invalid.
Note
Main towers.core.utils.Serializable is used by all main classes: Towers, Rods, Rod, Disk
Validation¶
Note
These methods are used internally, but there’s no reason they can’t be used externally.
-
towers.core.validation.
validate_height
(height)[source]¶ Validate the height of a
Tower`s or :class:`Rod
.Parameters: height (int) – The height to validate. Raises: InvalidTowerHeight – The height of the Tower
is invalid.
-
towers.core.validation.
validate_rods
(rods)[source]¶ Validate the rods.
Parameters: rods (List[Rod]|None) – The
Rod
’s to validate.Raises: - InvalidRods – expecting type
Rods
. - DuplicateDisk – This
Rod
already contains thisDisk
- CorruptRod – A
Disk
is on top of aDisk
of smaller size.
- InvalidRods – expecting type
-
towers.core.validation.
validate_moves
(moves)[source]¶ Validate the number of moves.
Parameters: moves (int) – The moves count to validate. Raises: InvalidMoves – The number of moves is not an number or is less than zero.
Moves¶
Note
When the Towers is iterated over, a series of Move’s are yielded.
Example¶
>>> tower = Towers(height=3)
>>> print(tower)
Towers(Rods(3 - start([***, **, *]), end([]), tmp([])))
>>> print('moves required: {moves}'.format(moves=tower.moves_for_height(height)))
moves required: 7
>>> with tower:
... for i in tower:
... print(i)
Move(disk=*, start=Rod(name='start', disks=[***, **, *], height=3), end=Rod(name='end', disks=[], height=3), moves=0)
Move(disk=**, start=Rod(name='start', disks=[***, **], height=3), end=Rod(name='tmp', disks=[], height=3), moves=1)
Move(disk=*, start=Rod(name='end', disks=[*], height=3), end=Rod(name='tmp', disks=[**], height=3), moves=2)
Move(disk=***, start=Rod(name='start', disks=[***], height=3), end=Rod(name='end', disks=[], height=3), moves=3)
Move(disk=*, start=Rod(name='tmp', disks=[**, *], height=3), end=Rod(name='start', disks=[], height=3), moves=4)
Move(disk=**, start=Rod(name='tmp', disks=[**], height=3), end=Rod(name='end', disks=[***], height=3), moves=5)
Move(disk=*, start=Rod(name='start', disks=[*], height=3), end=Rod(name='end', disks=[***, **], height=3), moves=6)
>>> print(tower)
Towers(Rods(3 - start([]), end([***, **, *]), tmp([])))
>>> print('moves taken: {moves}'.format(moves=tower.moves))
moves taken: 7