Exemple #1
0
class Adventure:
    def __init__(self, gamedata, testclass=Tests, actionclass=Actions):
        data = GameData(gamedata)
        self.controls = data.controls

        self.state = State(data)
        self.tests = testclass(self.state)
        self.actions = actionclass(self.state, self.tests)

        self.game_over = False

    def start_game(self):
        """Run any actions that occur before the first turn."""
        return self.do_actions("before_game")

    def do_command(self, command):
        """Start a new turn with the given command, run any actions,
        and return any resulting messages. End the game if the gameover
        flag has been set."""
        self.state.start_turn(command)
        messages = []

        for stage in ("before_turn", "during_turn", "after_turn"):
            messages += self.do_actions(stage)

            if self.game_over:
                messages += self.do_actions("after_game")
                break

        return messages

    def get_control_actions(self, control):
        """Run each set of tests for this control, and if all tests are true
        for any set of tests, return the 'then' actions, otherwise 'else'."""

        def test_is_true(test):
            # return opposite if test is preceded by a bang
            neg, test = (True, test[1:]) if test[0] == "!" else (False, test)

            method, args = test.split()[0], test.split()[1:]
            return getattr(self.tests, method)(*args) ^ neg

        results = (
            control["then"]
            if not control["if"] or any(all(test_is_true(test) for test in cond) for cond in control["if"])
            else control["else"]
        )

        actions = []

        for result in results:
            if isinstance(result, dict):
                # run tests for this control and return its actions
                actions.extend(self.get_control_actions(result))
            else:
                # return the actions
                action, args = result.split()[0], result.split()[1:]
                actions.append((action, args))

        return actions

    def do_actions(self, stage):
        """Evaluate each of the controls, run any actions and return
        any messages. End execution if 'done', end game if 'gameover'."""
        actions = itertools.chain(*[self.get_control_actions(control) for control in self.controls.get(stage, [])])
        messages = []

        for action, args in actions:
            if action == "done":
                # end execution of actions
                break
            elif action == "gameover":
                # end execution of actions and end the game
                self.game_over = True
                break
            elif action == "replace":
                # replace the input command and restart execution
                self.state.current_turn.replace_command(" ".join(args))
                return self.do_actions(stage)

            # treat name=value args as keyword args
            pargs, kwargs = [], {}
            for arg in args:
                if "=" in arg:
                    kwargs.update([arg.split("=", 1)])
                else:
                    pargs.append(arg)

            msgs = getattr(self.actions, action)(*pargs, **kwargs)
            if isinstance(msgs, basestring):
                messages.append(msgs)
            elif msgs is not None:
                messages.extend(msgs)

        return messages