{
  "name": "codegen-state-machine",
  "description": "Implement a finite state machine from a specification",
  "dataset": "terminal-bench-local",
  "difficulty": "medium",
  "instruction": "Create a file called fsm.py that implements a configurable finite state machine. The class StateMachine should support:\n\n1. __init__(self, initial_state: str) — set the starting state\n2. add_transition(self, from_state: str, event: str, to_state: str, action=None) — register a transition. action is an optional callable that receives (from_state, event, to_state)\n3. handle(self, event: str) -> str — process an event, execute the transition action if any, move to the new state, return the new state. Raise ValueError if no transition exists for current state + event.\n4. current_state (property) — return the current state\n5. reset(self) — return to initial state\n6. can_handle(self, event: str) -> bool — return True if a transition exists for the current state + event\n7. get_transitions(self, state: str) -> list[str] — return list of events that can be handled from the given state, sorted alphabetically",
  "setup_files": {
    "test_fsm.py": "import sys\nfrom fsm import StateMachine\n\npassed = 0\nfailed = 0\n\ndef check(desc, got, expected):\n    global passed, failed\n    if got == expected:\n        passed += 1\n    else:\n        print(f\"FAIL {desc}: got {got}, expected {expected}\")\n        failed += 1\n\n# Build a turnstile FSM\nsm = StateMachine('locked')\nlog = []\nsm.add_transition('locked', 'coin', 'unlocked', lambda f,e,t: log.append(f'paid: {f}->{t}'))\nsm.add_transition('unlocked', 'push', 'locked', lambda f,e,t: log.append(f'entered: {f}->{t}'))\nsm.add_transition('locked', 'push', 'locked')  # no action\nsm.add_transition('unlocked', 'coin', 'unlocked')  # extra coin\n\ncheck('initial state', sm.current_state, 'locked')\ncheck('can handle coin', sm.can_handle('coin'), True)\ncheck('can handle push', sm.can_handle('push'), True)\ncheck('cannot handle invalid', sm.can_handle('kick'), False)\n\n# Transitions\nresult = sm.handle('coin')\ncheck('after coin', result, 'unlocked')\ncheck('current after coin', sm.current_state, 'unlocked')\ncheck('action logged', log[-1], 'paid: locked->unlocked')\n\nresult = sm.handle('push')\ncheck('after push', result, 'locked')\ncheck('action logged 2', log[-1], 'entered: unlocked->locked')\n\n# Push while locked (no-op transition)\nsm.handle('push')\ncheck('push while locked', sm.current_state, 'locked')\n\n# Reset\nsm.handle('coin')\ncheck('before reset', sm.current_state, 'unlocked')\nsm.reset()\ncheck('after reset', sm.current_state, 'locked')\n\n# ValueError for invalid event\ntry:\n    sm.handle('kick')\n    check('invalid raises', False, True)  # should not reach\nexcept ValueError:\n    passed += 1\n\n# get_transitions\ntransitions = sm.get_transitions('locked')\ncheck('locked transitions', transitions, ['coin', 'push'])\ntransitions = sm.get_transitions('unlocked')\ncheck('unlocked transitions', transitions, ['coin', 'push'])\ncheck('unknown state transitions', sm.get_transitions('broken'), [])\n\n# Build a more complex FSM: traffic light\ntl = StateMachine('red')\ntl.add_transition('red', 'timer', 'green')\ntl.add_transition('green', 'timer', 'yellow')\ntl.add_transition('yellow', 'timer', 'red')\ntl.add_transition('red', 'emergency', 'red')\ntl.add_transition('green', 'emergency', 'red')\ntl.add_transition('yellow', 'emergency', 'red')\n\ntl.handle('timer')\ncheck('traffic green', tl.current_state, 'green')\ntl.handle('timer')\ncheck('traffic yellow', tl.current_state, 'yellow')\ntl.handle('emergency')\ncheck('traffic emergency', tl.current_state, 'red')\n\nprint(f\"{passed}/{passed+failed} tests passed\")\nif failed > 0:\n    sys.exit(1)\n"
  },
  "verify": "cd $BENCH_WORK_DIR && python3 test_fsm.py",
  "timeout": 240000,
  "tags": ["code-generation", "python", "from-spec", "design-pattern"]
}
