Exercise: Prototype
This exercise puts the Prototype pattern into code.
Scenario
You are building a game enemy system. Pre-configured Enemy templates — called prototypes — are registered once with their stats. When the game needs a new enemy, it clones a prototype rather than constructing from scratch. The critical constraint: each clone must be fully independent, so adding an ability to a clone must not affect the original prototype or any sibling clone. The mutable abilities list is what makes this constraint interesting.
Commands
The program reads a list of commands, one per line. Commands that produce output print exactly one line.
| Command | Behavior | Output |
|---|---|---|
["register", name, hp, ability] | Store a prototype Enemy named name with hp hit points and an initial abilities list of [ability] | (none) |
["clone", proto, newname] | Create a new enemy newname by deep-copying the prototype proto; store the clone | "Cloned <newname> from <proto>", or "Unknown prototype: <proto>" if proto does not exist |
["addability", name, ability] | Append ability to the enemy named name (prototype or clone); unknown name is silently ignored | (none) |
["show", name] | Print the enemy's current state | "<name>: <hp> HP [<abilities joined by ', '>]", or "<name> not found" if unknown |
7 register goblin 100 slash clone goblin goblin_elite addability goblin_elite fireball show goblin show goblin_elite clone unknown x show ghost
Cloned goblin_elite from goblin goblin: 100 HP [slash] goblin_elite: 100 HP [slash, fireball] Unknown prototype: unknown ghost not found
After registering the goblin prototype with 100 HP and the ability slash, we clone it into goblin_elite. The clone starts with the same HP and a copy of the abilities list. Adding fireball to goblin_elite only touches the clone's list — the original goblin still shows only slash, proving the copy is independent. Cloning the nonexistent unknown prototype and showing the nonexistent ghost each produce the appropriate error messages.
Your task
Implement Enemy.clone() so it returns a deep copy — a new Enemy with the given name, the same HP, and an independent copy of the abilities list. The registry, dispatcher, and all other Enemy fields are already provided.