Towers of Hanoi for Python

Author https://travis-ci.org/sys-git/towers.svg?branch=master https://coveralls.io/repos/github/sys-git/towers/badge.svg Documentation Status https://badge.fury.io/py/towers.svg https://img.shields.io/pypi/l/towers.svg https://img.shields.io/pypi/wheel/towers.svg https://img.shields.io/pypi/pyversions/towers.svg https://img.shields.io/pypi/status/towers.svg Updates Python 3

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 a TypeError).

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)
__bool__()[source]

A Towers is considered True if it’s state is completed.

Return type:bool
__call__()[source]

Run the towers. Convenience method.

Raises:See Towers.move_tower().
__contains__(x)[source]

Does this Towers contain the given Rod.

Parameters:x (Rod) – The Rod to find.
Return type:bool
__copy__()[source]

Return a shallow copy of this instance.

Return type:Towers
__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
__init__(height=1, rods=None, moves=0, verbose=False)[source]
Parameters:
  • height (int) – The height of the towers (ie: max number of disks each one rod can hold).
  • rods (Rods) – An existing Rods instance to use with this Towers (the heights must match).
  • moves (int) – The number of moves already taken.
  • verbose – True=enable verbose logging mode.
__iter__()[source]

Run the towers, yielding Move instances.

__len__()[source]

Determine how many Rod’s this Towers contains.

Return type:int
__nonzero__()[source]

A Towers is considered non-zero if it’s state is completed.

Return type:bool
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.
end_rod

Retrieve the end Rod for this towers.

Return type:Rod
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:
  • start (Rod) – The Rod to remove the Disk from.
  • end (Rod) – The Rods to move the Disk to.
move_tower(height, start, end, tmp)[source]

Move the stack of Disks on a Rod.

Parameters:
  • height (int) – The height of the Disk to move.
  • start (Rod) – The Rod to move the Disk from.
  • end (Rod) – The Rod to move the Disk to.
  • tmp (Rod) – The intermediary Rod to use when moving the Disk.
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 of Disk on a Rod).
Return type:int
start_rod

Retrieve the start Rod for this towers.

Return type:Rod
tmp_rod

Retrieve the temporary Rod for this towers.

Return type:Rod
to_json()[source]

Return a json serializable representation of this instance.

Return type:object
validate()[source]

Perform self validation.

Raises:
validate_end()[source]

Validate the end conditions for this towers.

Raises:
validate_start()[source]

Validate the start conditions for this towers

Raises:
verbose

Obtain this instance’s verbose flag.

Return type:bool

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:
  • start (Rod) – The rod containing the disks at their start position.
  • end (Rod) – The rod containing the disks at their end position.
  • tmp (Rod) – The intermediary rod.
  • height (int) – The height of the tower.
Raises:
__bool__()[source]

A Rods is considered True if it contains any disks on any rods.

Return type:bool
__copy__()[source]

Return a shallow copy of this instance.

Return type:Rods
__deepcopy__(*a)[source]

Return a deep copy of this instance.

Return type:Rods
__iter__()[source]

Iterate over all the rods.

Return type:Rod
__len__()[source]

Obtain the number of Rods.

Return type:int
__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
to_json()[source]

Return a json serializable representation of this instance.

Return type:object
validate()[source]

Perform self validation.

Raises:

Rod

Note

A tower that contains Disks.

class towers.core.rod.Rod[source]

A single tower containing disks.

__bool__()[source]

A Rod is considered True if it contains any disks.

Return type:bool
__copy__()[source]

Return a shallow copy of this instance.

Return type:Rod
__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
__iter__()[source]

Iterate over all the disks in this rod.

Return type:Disk
__len__() <==> len(x)[source]
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:

Rod

Raises:

See Rod.validate.

__nonzero__()[source]

A Rod is considered non-zero if it contains any disks.

Return type:bool
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__.
pop()[source]

Pop the top most disk from this rod and return it

Return type:Disk
to_json()[source]

Return a json serializable representation of this instance.

Return type:object
validate()[source]

Perform self validation.

Raises:

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 a Rod.
Return type:

Disk

Raises:
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__.
to_json()[source]

Return a json serializable representation of this instance.

Return type:object
validate()[source]

Perform self validation

Raises:
width

Obtain the width of the disk

Return type:int

Errors and Utils

Any error explicitly raised by towers is defined here.

exception towers.core.errors.InvalidRod(rod)[source]
__init__(rod)[source]
Parameters:rod (object) – The Rod which is invalid.
exception towers.core.errors.InvalidRods(rods)[source]
__init__(rods)[source]
Parameters:rods (object) – The Rods which are invalid
exception towers.core.errors.InvalidRodHeight(rod, max_height)[source]
__init__(rod, max_height)[source]
Parameters:
  • rod (Rod) – The Rod which has an invalid height.
  • max_height (int) – The max allowed height of the Rod.
exception towers.core.errors.DuplicateDisk(rod, disk_width)[source]

A duplicate disk was found on a tower.

__init__(rod, disk_width)[source]
Parameters:
  • rod (Rod) – The duplicate Rod.
  • disk_width (int) – The width of the Disk.
exception towers.core.errors.CorruptRod(rod, disk)[source]

A Rod with an invalid stack of disks was found.

__init__(rod, disk)[source]
Parameters:
  • rod (Rod) – The Rod which is corrupt.
  • disk (int) – A Disk which sits directly atop a smaller Disk.
exception towers.core.errors.InvalidStartingConditions(rods, moves)[source]

The Rods for the towers are not in the correct starting state.

__init__(rods, moves)[source]
Parameters:
  • rods (Rod) – The Rod’s.
  • moves (int) – Total number of moves already made (should be zero).
exception towers.core.errors.InvalidEndingConditions(rods)[source]

The Rod’s for the towers are not in the correct ending state.

__init__(rods)[source]
Parameters:rods (Rod) – The Rod’s.
exception towers.core.errors.InvalidTowerHeight(height)[source]

The height of the Tower is invalid.

__init__(height)[source]
Parameters:height (int) – The invalid height.
exception towers.core.errors.InvalidDiskPosition(position, height)[source]

The position of the Disk is invalid.

__init__(position, height)[source]
Parameters:
  • position (int) – The invalid position on the Rod.
  • height (int) – The height.
exception towers.core.errors.InvalidMoves(moves)[source]

An invalid number of moves.

__init__(moves)[source]
Parameters:moves (int) – The invalid moves.

Note

Main towers.core.utils.Serializable is used by all main classes: Towers, Rods, Rod, Disk

class towers.core.utils.Serializable[source]

A mixin which shows that a class is serializable.

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 from.
to_json()[source]

Return a json serializable representation of this instance.

Return type:object

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:
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.

class towers.core.moves.Move[source]
Parameters:
  • disk (Disk) – The disk that will be moved.
  • start (Rod) – The state of the start_rod prior to the move.
  • end (Rod) – The state of the end_rod prior to the move.
  • moves (int) – The number of moves prior to the move.

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

Installation

Instructions can be found here

Contributions

Guidelines can be found here

Authors can be found here

Indices and tables