Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- hanoi_recursive_counter = 0
- def __validate_hanoi_input(
- n: int,
- source: str,
- mid: str,
- dest: str) -> None:
- """
- Function whose job is to validate the inputs passed onto the hanoi functions. Raises an appropriate error if the
- inputs are not right.
- :param n: The current move number.
- :param source: The name of the first peg.
- :param mid: The name of the second peg.
- :param dest: The name of the third peg.
- :return: None
- """
- if not isinstance(n, int):
- raise TypeError('Expected an int, but got {} instead.'.format(type(n).__name__))
- if n <= 0:
- raise ValueError('n must be greater than zero, but got {} instead.'.format(n))
- for i, param in enumerate((source, mid, dest), start=2):
- if not isinstance(param, str):
- raise TypeError('Argument {} must be a string, but got {} instead.'.format(i, type(param).__name__))
- def __get_disc_move_msg(
- move_num: int,
- disc: int,
- source: str,
- dest: str) -> str:
- """
- Function whose job is to generate and return a move message given the move number, disc, source and destination peg.
- :param move_num: The current move number.
- :param disc: The disc to be moved value.
- :param source: The name of the peg to be moved from.
- :param dest: The name of peg to be moved to.
- :return: A string with the generated move message.
- """
- return '{}. Move disc {} from {} -> {}\n'.format(move_num, disc, source, dest)
- def hanoi_iterative(
- n: int,
- source: str = 'A',
- mid: str = 'B',
- dest: str = 'C') -> str:
- """
- An iterative way of solving the Tower of Hanoi problem. The basic rules the program follows are as such:
- 1. In odd-numbered moves, the smallest disk (1) is moved to the right or left, depending on whether n is odd
- (left) or even (right).
- 2. In even-numbered moves, the only possible move is made that doesn't involve the smallest disk (1).
- 3. A larger disk is not placed on top of a smaller one.
- :param n: The number of discs used.
- :param source: (Optional) The name of the first peg.
- :param mid: (Optional) The name of the second peg.
- :param dest: (Optional) The name of the destination or initially third peg.
- :return: A list containing all (2^n - 1) number of move messages.
- """
- __validate_hanoi_input(n, source, mid, dest)
- result = ''
- discs_dict = {0: source, 1: mid, 2: dest}
- pegs = [{x for x in range(1, n + 1)}, set(), set()]
- is_n_odd = -1 if n % 2 == 0 else 1
- smallest_disc_loc = 0
- for x in range(1, 2 ** n):
- if x % 2 == 1:
- dest = (smallest_disc_loc - is_n_odd) % 3
- pegs[smallest_disc_loc].remove(1)
- pegs[dest].add(1)
- result += __get_disc_move_msg(
- x,
- 1,
- discs_dict[smallest_disc_loc],
- discs_dict[dest])
- smallest_disc_loc = dest
- continue
- non_smallest_disc_locs = {j: pegs[j] for j in range(len(pegs)) if j != smallest_disc_loc}
- first_non_smallest_peg_loc, second_non_smallest_peg_loc = non_smallest_disc_locs.keys()
- first_peg, second_peg = list(non_smallest_disc_locs.values())
- if not bool(first_peg):
- second_peg_smallest_disc = min(second_peg)
- pegs[second_non_smallest_peg_loc].remove(second_peg_smallest_disc)
- pegs[first_non_smallest_peg_loc].add(second_peg_smallest_disc)
- result += __get_disc_move_msg(
- x,
- second_peg_smallest_disc,
- discs_dict[second_non_smallest_peg_loc],
- discs_dict[first_non_smallest_peg_loc])
- elif not bool(second_peg):
- first_peg_smallest_disc = min(first_peg)
- pegs[first_non_smallest_peg_loc].remove(first_peg_smallest_disc)
- pegs[second_non_smallest_peg_loc].add(first_peg_smallest_disc)
- result += __get_disc_move_msg(
- x,
- first_peg_smallest_disc,
- discs_dict[first_non_smallest_peg_loc],
- discs_dict[second_non_smallest_peg_loc])
- else:
- first_peg_min, second_peg_min = min(first_peg), min(second_peg)
- if first_peg_min < second_peg_min:
- pegs[first_non_smallest_peg_loc].remove(first_peg_min)
- pegs[second_non_smallest_peg_loc].add(first_peg_min)
- result += __get_disc_move_msg(
- x,
- first_peg_min,
- discs_dict[first_non_smallest_peg_loc],
- discs_dict[second_non_smallest_peg_loc])
- continue
- pegs[second_non_smallest_peg_loc].remove(second_peg_min)
- pegs[first_non_smallest_peg_loc].add(second_peg_min)
- result += __get_disc_move_msg(
- x,
- second_peg_min,
- discs_dict[second_non_smallest_peg_loc],
- discs_dict[first_non_smallest_peg_loc])
- return result
- def hanoi_recursive(
- n: int,
- source: str = 'A',
- mid: str = 'B',
- dest: str = 'C') -> str:
- """
- The classic way of solving the Tower of Hanoi problem recursively. The idea is that to move n discs from peg A to
- peg C, you need to move n-1 discs from peg A to peg B, then move disc number n (which is the largest among them)
- from peg A to peg C, and finally move the remaining n-1 discs from peg B to peg C.
- :param n: The number of discs used.
- :param source: (Optional) The name of the first peg.
- :param mid: (Optional) The name of the second peg.
- :param dest: (Optional) The name of the destination or initially third peg.
- :return: A string containing all (2^n - 1) number of move messages seperated by newline (\n).
- """
- def _hanoi_recursive(
- _n: int,
- _source: str,
- _mid: str,
- _dest: str) -> str:
- global hanoi_recursive_counter
- if _n == 1:
- hanoi_recursive_counter += 1
- return __get_disc_move_msg(
- hanoi_recursive_counter,
- 1,
- _source,
- _dest)
- return (
- _hanoi_recursive(_n - 1, _source, _dest, _mid) +
- __get_disc_move_msg(hanoi_recursive_counter := hanoi_recursive_counter + 1, _n, _source, _dest) +
- _hanoi_recursive(_n - 1, _mid, _source, _dest)
- )
- __validate_hanoi_input(n, source, mid, dest)
- global hanoi_recursive_counter
- hanoi_recursive_counter = 0
- return _hanoi_recursive(n, source, mid, dest)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement