{"record":{"id":"51350f350c8227d8","repo":"coding-horror/basic-computer-games","slug":"you-can-t-place-a-larger-disk-on-top-of-a-smaller","errorCode":null,"errorMessage":"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE, IT MIGHT CRUSH IT!","messagePattern":"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE, IT MIGHT CRUSH IT!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"90_Tower/python/tower.py","lineNumber":31,"sourceCode":"        print(f\"[ {self.size()} ]\")\n\n\nclass Tower:\n    def __init__(self) -> None:\n        self.__disks: List[Disk] = []\n\n    def empty(self) -> bool:\n        return len(self.__disks) == 0\n\n    def top(self) -> Optional[Disk]:\n        return None if self.empty() else self.__disks[-1]\n\n    def add(self, disk: Disk) -> None:\n        if not self.empty():\n            t = self.top()\n            assert t is not None  # cannot happen as it's not empty\n            if disk.size() > t.size():\n                raise Exception(\n                    \"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE, IT MIGHT CRUSH IT!\"\n                )\n        self.__disks.append(disk)\n\n    def pop(self) -> Disk:\n        if self.empty():\n            raise Exception(\"empty pop\")\n        return self.__disks.pop()\n\n    def print(self) -> None:\n        r = f'Needle: [{\", \".join([str(x.size()) for x in self.__disks])}]'\n        print(r)\n\n\nclass Game:\n    def __init__(self) -> None:\n        # use fewer sizes to make debugging easier\n        # self.__sizes = [3, 5, 7]  # ,9,11,13,15]","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/90_Tower/python/tower.py#L13-L49","documentation":"Raised as a generic Exception by Tower.add() in the Tower-of-Hanoi game when the disk being added is larger than the disk currently on top of the needle. This enforces the core rule of Tower of Hanoi (no larger disk may rest on a smaller one). It fires in take_turn() after the player picks a source disk and a destination needle (tower.py:107-121).","triggerScenarios":"Player selects a disk and tries to place it on a needle whose top disk is smaller; e.g. moving disk size 9 onto a needle topped by size 3. Triggered via the take_turn flow after which_disk()/which_tower() input.","commonSituations":"An illegal move in the game; a programmatic solver invoking Tower.add without checking sizes; the game's own move logic being called with an out-of-order disk.","solutions":["Choose a destination needle that is empty or whose top disk is larger than the moved disk.","Wrap the move in a check comparing disk.size() to to_tower.top() before calling add.","Catch the Exception in take_turn and re-prompt the player for a valid needle (the game already validates disk/tower selection but add is the final guard)."],"exampleFix":"# before\ndisk = from_tower.pop()\nto_tower.add(disk)  # raises if disk bigger than top\n\n# after: validate before moving\ndisk = from_tower.pop()\nif not to_tower.empty() and disk.size() > to_tower.top().size():\n    from_tower.add(disk)  # undo\n    print(\"ILLEGAL MOVE. LARGER DISK CAN'T GO ON SMALLER ONE.\")\nelse:\n    to_tower.add(disk)","handlingStrategy":"validation","validationCode":"# Python: check before calling Tower.add\ndef can_place(to_tower, disk):\n    return to_tower.empty() or disk.size() <= to_tower.top().size()\n\nif can_place(to_tower, disk):\n    to_tower.add(disk)\nelse:\n    print(\"Illegal move.\")","typeGuard":"from typing import Optional\ndef is_valid_move(to_tower: 'Tower', disk: 'Disk') -> bool:\n    top: Optional[Disk] = to_tower.top()\n    return top is None or disk.size() <= top.size()","tryCatchPattern":"# Catch in take_turn and re-prompt the player\ntry:\n    to_tower.add(disk)\nexcept Exception:\n    from_tower.add(disk)  # undo pop\n    print(\"ILLEGAL MOVE. TRY AGAIN.\")","preventionTips":["Always compare disk.size() against the destination's top before adding.","Validate moves at the game-loop level so add() is the last line of defense, not the first.","Use a custom exception class instead of bare Exception for clearer handling."],"tags":["python","game-logic","rule-violation","tower-of-hanoi"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}