Пример #1
0
def test_simple_graph_generation():
    game = Game('test')
    start = Waypoint(game.graph, 'start')
    end = Waypoint(game.graph, 'end')
    start.add_destination(end)
    assert len(game.graph.nodes) == 2
    assert len(game.graph.edges) == 1
    assert not game.start_is_set()
Пример #2
0
def test_adding_task_adds_path():
    game = Game('test')
    start = Waypoint(game.graph, 'start')
    end = Waypoint(game.graph, 'end')
    task = Task(end, 'test description', 'test text', 'answer')
    start.add_task(task)
    game.set_start(start)
    assert len(game.graph.nodes) == 2
    assert len(game.graph.edges) == 1
    assert game.start_is_set()
Пример #3
0
def test_npc_interaction():
    """
      start
        |
        w1 <- dialog becomes available
        |
        end
    """
    game = Game('test')
    start = Waypoint(game.graph, 'start')
    w1 = Waypoint(game.graph, 'w1')
    end = Waypoint(game.graph, 'end')
    start.add_destination(w1)
    w1.add_destination(end)
    game.set_start(start)
    npc_dialog = Dialog()
    ds = Mail(npc_dialog.graph, 'test subject', 'test body')
    with pytest.raises(PlayerStateException):
        NonPlayableCharacter('test', 'npc', npc_dialog)
    npc_dialog.set_start(ds)
    npc_dialog.start.waypoints.append(w1)
    game.add_non_playable_character(NonPlayableCharacter('test', 'npc', npc_dialog))
    instance = game.create_new_game()
    instance.add_player(Player('test', 'player'), 'testy', 'mctestpants')
    assert len(instance.npc_states) == 1
    assert ds not in [k for k, _ in instance.player_states[0].inventory.values()]
    interactions = instance.player_states[0].move_to(w1)
    assert len(interactions.keys()) == 1 and len(interactions.values()) == 1
Пример #4
0
def test_serialize_deserialize(game):
    js = json.dumps(game.start, cls=MarugotoEncoder)
    s = json.loads(js, cls=MarugotoDecoder)
    assert game.start == s
    wp = Waypoint(game.graph, 'test with task')
    task = Task(None, 'test task', 'some task')
    wp.add_task(task)
    jst = json.dumps(wp, cls=MarugotoEncoder)
    st = json.loads(jst, cls=MarugotoDecoder)
    assert wp == st
    assert task.id == st.tasks[0]
Пример #5
0
def test_npc_required_response():
    """
      start
        |
        w1 <- dialog becomes available
        |
        end <- blocked till dialog in phase 2 (ds2)
    """
    game = Game('test')
    start = Waypoint(game.graph, 'start')
    w1 = Waypoint(game.graph, 'w1')
    end = Waypoint(game.graph, 'end')
    game.set_start(start)
    npc_dialog = Dialog()
    ds1 = Mail(npc_dialog.graph, 'test subject 1', 'test body 1')
    ds1.waypoints.append(w1)
    start.add_destination(w1)
    npc_dialog.set_start(ds1)
    ds2 = Mail(npc_dialog.graph, 'test subject 2', 'test body 2', items=['test item'], destination=end)
    ds1.add_follow_up(ds2, end)
    w1.add_interaction(ds2)
    npc = NonPlayableCharacter('test', 'npc', npc_dialog)
    game.add_non_playable_character(npc)
    instance = game.create_new_game()
    instance.add_player(Player('test', 'player'), 'testy', 'mctestpants')
    assert len(instance.player_states[0].available_moves()) == 1
    interactions = instance.player_states[0].move_to(w1)
    assert len(instance.player_states[0].available_moves()) == 0
    npc_instance = next(iter([n for n in instance.npc_states if n == npc]), None)
    if not npc_instance:
        assert fail('could not find npc instance in game instance')
    assert len(instance.player_states[0].inventory) == 0
    npc_instance.update_player_dialog(instance.player_states[0], interactions[npc], 'mail response')
    assert len(instance.player_states[0].inventory) == 1
    assert len(instance.player_states[0].available_moves()) == 1
    assert instance.player_states[0].move_to(end)
Пример #6
0
    def object_hook(obj):
        if '_type' not in obj:
            return obj
        if obj['_type'] == 'Waypoint':
            waypoint = Waypoint(
                nx.DiGraph(), obj['title'], obj['description'],
                obj['time_limit'], obj['money_limit'],
                obj['budget_modification'],
                [json.loads(i, cls=MarugotoDecoder) for i in obj['items']]
                if 'items' in obj and obj['items'] else None,
                obj['timer_visible'],
                json.loads(obj['level'], cls=MarugotoDecoder))
            waypoint.id = UUID(obj['_key'])
            if 'items' in obj and obj['items']:
                for i in obj['items']:
                    waypoint.items.append(json.loads(i, cls=MarugotoDecoder))
            for t in obj['tasks']:
                waypoint.tasks.append(UUID(t))
            for i in obj['interactions']:
                waypoint.interactions.append(UUID(i))
            return waypoint
        if obj['_type'] == 'Level':
            icon = base64.decodebytes(obj['icon']) if obj['icon'] else None
            return Level(obj['title'], icon)
        if obj['_type'] == 'Task':
            media = base64.decodebytes(obj['media']) if obj['media'] else None
            task = Task(
                None, obj['description'], obj['text'], obj['solution'], media,
                [json.loads(i, cls=MarugotoDecoder) for i in obj['items']] if
                'items' in obj and obj['items'] else None, obj['time_limit'],
                obj['money_limit'], obj['budget_modification'], obj['ratio'],
                obj['days'], obj['offset'])
            task.id = UUID(obj['_key'])
            if obj['destination']:
                task.destination = UUID(obj['destination'])
            return task
        if obj['_type'] == 'Dialog':
            dialog = Dialog()
            dialog.start = UUID(obj['start'])
            dialog.id = UUID(obj['_key'])
            return dialog
        if obj['_type'] == 'Mail':
            mail = Mail(
                nx.DiGraph(), obj['subject'], obj['body'], obj['description'],
                obj['time_limit'], obj['money_limit'],
                obj['budget_modification'],
                [json.loads(i, cls=MarugotoDecoder) for i in obj['items']]
                if 'items' in obj and obj['items'] else None)
            mail.id = UUID(obj['_key'])
            if obj['destination']:
                mail.destination = UUID(obj['destination'])
            if obj['task']:
                mail.task = UUID(obj['task'])
            for w in obj['waypoints']:
                mail.waypoints.append(UUID(w))
            return mail
        if obj['_type'] == 'Speech':
            speech = Speech(
                nx.DiGraph(), obj['content'], obj['description'],
                obj['time_limit'], obj['money_limit'],
                obj['budget_modification'],
                [json.loads(i, cls=MarugotoDecoder) for i in obj['items']]
                if 'items' in obj and obj['items'] else None)
            speech.id = UUID(obj['_key'])
            if obj['destination']:
                speech.destination = UUID(obj['destination'])
            if obj['task']:
                speech.task = UUID(obj['task'])
            for w in obj['waypoints']:
                speech.waypoints.append(UUID(w))
            return speech
        if obj['_type'] == 'Game':
            game = Game(obj['title'])
            game.image = base64.decodebytes(
                obj['image']) if obj['image'] else None
            game.energy = obj['energy']
            game.start = UUID(obj['start'])
            return game
        if obj['_type'] == 'GameInstance':
            game_instance = GameInstance(
                json.loads(obj['game'], cls=MarugotoDecoder), obj['name'],
                json.loads(obj['game_master'], cls=MarugotoDecoder),
                strptime(obj['starts_at'], '%Y-%m-%d %H-%M-%S-%f')
                if obj['starts_at'] else None,
                strptime(obj['ends_at'], '%Y-%m-%d %H-%M-%S-%f')
                if obj['ends_at'] else None)
            game_instance.created_at = strptime(obj['created_at'],
                                                '%Y-%m-%d %H-%M-%S-%f')
            game_instance.id = UUID(obj['_key'])
            if obj['players']:
                for player in obj['players']:
                    game_instance.player_states.append(
                        json.loads(player, cls=MarugotoDecoder))
            if obj['npcs']:
                for npc in obj['npcs']:
                    game_instance.npc_states.append(
                        json.loads(npc, cls=MarugotoDecoder))
            return game_instance
        if obj['_type'] == 'Player':
            player = Player(obj['mail'], obj['password'])
            player.id = UUID(obj['_key'])
            return player
        if obj['_type'] == 'PlayerState':
            player_state = PlayerState(
                json.loads(obj['player'], cls=MarugotoDecoder), obj['first'],
                obj['last'], None, obj['budget'])
            player_state.energy = obj['energy']
            for waypoint in obj['path']:
                player_state.path.append(
                    json.loads(waypoint, cls=MarugotoDecoder))

            for npc, interactions in obj['dialogs'].items():
                player_state.dialogs[npc] = [(strptime(i['stamp'],
                                                       '%Y-%m-%d %H-%M-%S-%f'),
                                              json.loads(i['interaction'],
                                                         cls=MarugotoDecoder),
                                              i['response'])
                                             for i in interactions]
            for stamp, kvs in obj['inventory']:
                player_state.inventory[strptime(stamp,
                                                '%Y-%m-%d %H-%M-%S-%f')] = [
                                                    (k['key'],
                                                     json.loads(v['value']))
                                                    for k, v in kvs
                                                ]
            return player_state
        if obj['_type'] == 'NonPlayableCharacterState':
            npc = NonPlayableCharacterState(
                obj['first'], obj['last'], None,
                json.loads(obj['dialog'], cls=MarugotoDecoder),
                obj['salutation'], obj['mail'],
                base64.decodebytes(obj['image']) if obj['image'] else None)

            for player, interactions in obj['paths'].items():
                npc.paths[json.loads(player, cls=MarugotoDecoder)] = [
                    (strptime(i['stamp'], '%Y-%m-%d %H-%M-%S-%f'),
                     json.loads(i['interaction'], cls=MarugotoDecoder))
                    for i in interactions
                ]
            return npc
        if obj['_type'] == 'UUID':
            return UUID(obj['value'])
        if obj['_type'] == 'STAMP':
            return strptime(obj['value'], '%Y-%m-%d %H-%M-%S-%f')
        return obj
Пример #7
0
def test_identify_player_path():
    """
    start
      |
      w1
      |  <- task answer required before transition becomes available
      w2
      |
      end
    """
    game = Game('test')
    start = Waypoint(game.graph, 'start')
    w1 = Waypoint(game.graph, 'w1')
    w2 = Waypoint(game.graph, 'w2', items=['some item'])
    end = Waypoint(game.graph, 'end')
    start.add_destination(w1)
    task = Task(w2, 'test description', 'test text', 'answer')
    w1.add_task(task)
    w2.add_destination(end)
    game.set_start(start)
    instance = game.create_new_game()
    player = Player('test', 'player')
    instance.add_player(player, 'testy', 'mctestpants')
    assert len(instance.player_states[0].path) == 1
    assert instance.player_states[0].path[0][1] == start
    assert w1 in instance.player_states[0].available_moves()
    assert w2 in instance.player_states[0].available_path()
    # not allowed to skip to end
    with pytest.raises(PlayerIllegalMoveException):
        instance.player_states[0].move_to(end)
    instance.player_states[0].move_to(w1)
    # no backsies
    with pytest.raises(PlayerIllegalMoveException):
        instance.player_states[0].move_to(start)
    # w2 is blocked from w1
    with pytest.raises(PlayerIllegalMoveException):
        instance.player_states[0].move_to(w2)
    answer = 'answer'
    assert len(instance.player_states[0].inventory) == 0
    instance.player_states[0].move_to(w2, answer)
    assert not instance.player_states[0].is_finished()
    assert len(instance.player_states[0].inventory) == 1
    instance.player_states[0].move_to(end)
    assert instance.player_states[0].current_position() == end
    assert instance.player_states[0].is_finished()
Пример #8
0
def game():
    """
                  start  (path with dialog)
                  /   \
               w1 (m1) w2 (d1)
                  \   /
                   knot1
                 /  |  \
                w3  w4 w5  <- with task t1,t2,t3
                \   |
                  end <- task from dialog td1
    :return: game with described graph
    """
    #TODO, check interaction model in waypoint
    dialog = Dialog()
    dialog_start = Mail(dialog.graph, 'start sub', 'start body')
    m1 = Mail(dialog.graph, 'second sub', 'second body')
    td1 = Task(None, 'some task 1', 'some task', 'some solution')
    d1 = Speech(dialog.graph, 'content', task=td1)

    game = Game('test')
    start = Waypoint(game.graph, 'start')
    w1 = Waypoint(game.graph, 'w1')
    w2 = Waypoint(game.graph, 'w2')
    knot = Waypoint(game.graph, 'knot')
    w3 = Waypoint(game.graph, 'w3')
    t1 = Task(w3, 'some task 1', 'some task')
    w4 = Waypoint(game.graph, 'w4')
    t2 = Task(w4, 'some task 2', 'some task')
    w5 = Waypoint(game.graph, 'w5')
    t3 = Task(w5, 'some task 3', 'some task')
    end = Waypoint(game.graph, 'end')
    start.add_destination(w1, 1.1)
    start.add_destination(w2)
    w1.add_destination(knot)
    w2.add_destination(knot)
    knot.add_task(t1)
    knot.add_task(t2)
    knot.add_task(t3)
    w3.add_destination(end)
    w4.add_destination(end)
    game.set_start(start)

    dialog_end = Speech(dialog.graph, 'next content', destination=end)
    dialog.set_start(dialog_start)
    dialog_start.add_follow_up(d1)
    dialog_start.add_follow_up(m1)
    dialog_start.waypoints.append(start)
    d1.add_follow_up(dialog_end, None)

    game.add_non_playable_character(NonPlayableCharacter(
        'bob', 'test', dialog))

    return game
Пример #9
0
def test_create_and_delete_game(wait_for_api, create_clean_db, client):
    # create our game
    game = Game('test')
    start = Waypoint(game.graph, 'start')
    w1 = Waypoint(game.graph, 'w1')
    w2 = Waypoint(game.graph, 'w2', items=['some item'])
    end = Waypoint(game.graph, 'end')
    start.add_destination(w1)
    task = Task(w2, 'test description', 'test text', 'answer')
    w1.add_task(task)
    w2.add_destination(end)
    game.set_start(start)
    # create user
    lg = client.post(
        f"{ROOT_URL}/register", json=default_account
    )
    assert lg.status_code == 201
    token = json.loads(lg.data)
    # convert it to an API object
    game_data = generate_api_game(game)
    lg = client.post(
        f"{ROOT_URL}/games", json=game_data, headers={'X-TOKEN': token}
    )
    assert lg.status_code == 201
    lg = client.get(
        f"{ROOT_URL}/games"
    )
    assert lg.status_code == 200
    assert game.title in [g['title'] for g in lg.data]