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()
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()
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
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]
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)
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
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()
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
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]