Source code for towers.core.disk

#!/usr/bin/env python
# -*- coding: latin-1 -*-
#
# @module towers.core.disk
# @version 0.1
# @copyright (c) 2017-present Francis Horsman.

import json
from collections import namedtuple

import six

from .errors import InvalidDiskPosition
from .utils import Serializable
from .validation import Validatable, validate_height

__all__ = ['Disk']


[docs]class Disk(namedtuple('Disk', ('original_position', 'height')), Validatable, Serializable): """ An immutable representation of a sized disk that sits on a `Rod`. """
[docs] def __new__(cls, original_position, height=1): """ :param int original_position: The position on the `Rod` that this disks originally sat. Zero = The bottom of the `Rod`. :param int height: The maximum position of this :class:`Disk` on a :class:`Rod`. :rtype: :class:`Disk` :raises InvalidTowerHeight: The height of the tower is invalid. :raises InvalidDiskPosition: The position of the disk is invalid. """ self = super(Disk, cls).__new__( cls, original_position, height, ) self.validate() return self
[docs] def to_json(self): """ Return a json serializable representation of this instance. :rtype: object """ return { 'original_position': self.original_position, 'height': self.height, }
@classmethod
[docs] def from_json(cls, d): """ Return a class instance from a json serializable representation. :param str|dict d: The json or decoded-json from which to create a new instance. :rtype: :class:`Disk` :raises: See :class:`Disk.__new__`. """ if isinstance(d, six.string_types): d = json.loads(d) return cls( original_position=d.pop('original_position'), height=d.pop('height'), )
@property def width(self): """ Obtain the width of the disk :rtype: int """ return self.height - self.original_position
[docs] def validate(self): """ Perform self validation :raises InvalidTowerHeight: The height of the tower is invalid. :raises InvalidDiskPosition: The position of the disk is invalid. """ validate_height(self.height) if (self.original_position < 0) or (self.original_position >= self.height): raise InvalidDiskPosition(self.original_position, self.height)
def __str__(self): return 'Disk({original_position})'.format( original_position=self.original_position) def __repr__(self): return '{original_position}'.format( original_position='*' * self.width)