# contributed by mrfesol (Tomasz Wesolowski)


class HashTranspositionTable:
    """
    Base Class for various types of hashes
    """

    def __init__(self):
        self.modulo = 1024  # default value

    def before(self, key):
        """
        Returns initial value of hash.
        It's also the place where you can initialize some auxiliary variables
        """
        return 0

    def after(self, key, hash):
        """
        Returns final value of hash
        """
        return hash

    def get_hash(self, key, depth=0):
        """
        Recursively computes a hash
        """
        ret_hash = self.before(key)
        if type(key) is int:
            return self.hash_int(key)
        if type(key) is str and len(key) <= 1:
            return self.hash_char(key)
        for v in list(key):
            ret_hash = self.join(ret_hash, self.get_hash(v, depth + 1)) % self.modulo
        if depth == 0:
            ret_hash = self.after(key, ret_hash)
        return ret_hash

    def hash_int(self, number):
        """
        Returns hash for a number
        """
        return number

    def hash_char(self, string):
        """
        Returns hash for an one-letter string
        """
        return ord(string)

    def join(self, one, two):
        """
        Returns combined hash from two hashes
        one - existing (combined) hash so far
        two - hash of new element
        one = join(one, two)
        """
        return (one * two) % self.modulo