def test_get_all_possible_attacks_or_moves(): world = P.World(P.Map.load('maps/mini.json'), ['one', 'two', 'three'], has_neutral=False) # territory 0 1 2 3 4 5 world.owners = [1, 0, 1, 2, 1, 1] world.armies = [5, 2, 2, 2, 1, 3] assert set(P.get_all_possible_attacks(P.PlayerState(world, 1))) == { P.Attack(from_, to, count) for from_, to, count in [ (0, 1, 4), (2, 1, 1), (2, 3, 1), (5, 3, 2), ] } assert set(P.get_all_possible_moves(P.PlayerState(world, 1))) == { P.Move(from_, to, count) for from_, to, count in [ (0, 2, 4), (2, 0, 1), (5, 4, 2), ] }
def test_reinforce_error(): map_ = P.Map.load('maps/tiny3.json') world = P.World(map_, ['p0', 'p1', 'neutral'], has_neutral=True) world.armies = [1, 1, 1] world.owners = [0, 0, 1] agent_0 = um.Mock(__str__=um.Mock(return_value='BadMockAgent')) state_0 = P.PlayerState(world, 0) # redeem C = P.Card state_0.cards = [C(2, 0), C(2, 1), C(1, 2)] agent_0.redeem = um.Mock(return_value=[C(2, 0), C(2, 1), C(2, 2)]) # card not owned with pytest.raises(ValueError) as e: list(P._reinforce(agent_0, state_0, um.Mock())) assert 'redeem' in str(e) and 'BadMockAgent' in str(e) agent_0.redeem = um.Mock(return_value=[C(2, 0), C(2, 1), C(1, 2)]) # not a matching set with pytest.raises(ValueError) as e: list(P._reinforce(agent_0, state_0, um.Mock())) assert 'redeem' in str(e) and 'BadMockAgent' in str(e) state_0.cards = [C(2, 0), C(2, 1), C(1, 2), C(1, 0), C(0, 1), C(0, 2)] agent_0.redeem = um.Mock(return_value=None) # fail to redeem with 6 cards with pytest.raises(ValueError) as e: list(P._reinforce(agent_0, state_0, um.Mock())) assert 'redeem' in str(e) and 'BadMockAgent' in str(e) assert '6' in str(e) and '5' in str(e) # reinforce state_0.cards = [] agent_0.redeem = um.Mock(return_value=None) agent_0.reinforce = um.Mock(return_value={2: 3}) # enemy territory with pytest.raises(ValueError) as e: list(P._reinforce(agent_0, state_0, um.Mock())) assert 'reinforce' in str(e) and 'BadMockAgent' in str(e) and '2' in str(e) agent_0.reinforce = um.Mock(return_value={ 0: 2, 1: 2 }) # selected the wrong number of reinforcements with pytest.raises(ValueError) as e: list(P._reinforce(agent_0, state_0, um.Mock())) assert 'reinforce' in str(e) and 'BadMockAgent' in str(e) assert '4' in str(e) and '3' in str(e) agent_0.reinforce = um.Mock(return_value={ 0: 5, 1: -2 }) # negative number of reinforcements with pytest.raises(ValueError) as e: list(P._reinforce(agent_0, state_0, um.Mock())) assert 'reinforce' in str(e) and 'BadMockAgent' in str(e) assert '-2' in str(e)
def test_attack_and_move_error(): map_ = P.Map.load('maps/tiny4.json') # disconnect (0, 2), so that there can be a "not connected" error map_.edges[0].remove(2) map_.edges[2].remove(0) world = P.World(map_, ['p0', 'p1', 'neutral'], has_neutral=True) world.armies = [5, 5, 3, 5] world.owners = [0, 0, 1, 1] agents = [um.Mock(), um.Mock(), None] states = [ P.PlayerState(world, 0), P.PlayerState(world, 1), P.PlayerState(world, 2) ] agents_and_states = list(zip(agents, states)) rand = um.Mock() for action in [ P.Attack(0, 1, 2), # attacking from enemy P.Attack(2, 3, 2), # attacking to friendly P.Attack(2, 1, 3), # attacking with too many units P.Attack(2, 0, 2), # attacking to disconnected territory P.Attack(2, 1, 0), # attacking with 0 or negative units P.Move(2, 1, 2), # moving to enemy P.Move(1, 2, 2), # moving from enemy P.Move(2, 3, 3), # moving too many units P.Move(2, 3, 0) ]: # moving 0 or negative units agents[1].act = um.Mock(return_value=action) with pytest.raises(ValueError) as e: list( P._attack_and_move(agents[1], states[1], um.Mock(), agents_and_states, rand)) assert str(action) in str(e) # sanity check that a correct attack & move are indeed possible agents[1].act = um.Mock(side_effect=[P.Attack(2, 1, 2), P.Move(3, 2, 4)]) rand.choices = um.Mock(return_value=[(2, 0)]) # attacker loses assert len( list( P._attack_and_move(agents[1], states[1], um.Mock(), agents_and_states, rand))) == 2 assert len(states[1].cards) == 0, "didn't earn a card" assert world.armies == [5, 5, 5, 1] assert world.owners == [0, 0, 1, 1]
def test_attack_and_move(): map_ = P.Map.load('maps/tiny3.json') world = P.World(map_, ['p0', 'p1', 'neutral'], has_neutral=True) world.owners = [0, 1, 2] world.armies = [5, 2, 1] agents = [um.Mock(), um.Mock(), None] states = [ P.PlayerState(world, 0), P.PlayerState(world, 1, cards=[P.Card(2, 2)]), P.PlayerState(world, 2) ] agents_and_states = list(zip(agents, states)) deck = um.Mock() rand = um.Mock() # 1. Don't take any action - no card earnt agents[0].act = um.Mock(return_value=None) events = list( P._attack_and_move(agents[0], states[0], deck, agents_and_states, rand)) assert events == [ P.Event(agents[0], states[0], 'act', dict(earned_card=False), None) ] assert len(states[0].cards) == 0, 'no cards earnt' # 2. Attack (knock out Neutral) then Move agents[0].act = um.Mock(side_effect=[P.Attack(0, 2, 3), P.Move(2, 0, 1)]) rand.choices = um.Mock(return_value=[(0, 1)]) events = list( P._attack_and_move(agents[0], states[0], deck, agents_and_states, rand)) assert events == [ P.Event(agents[0], states[0], 'act', dict(earned_card=False), P.Attack(0, 2, 3)), P.Event(agents[0], states[0], 'act', dict(earned_card=True), P.Move(2, 0, 1)) ] assert len(states[0].cards) == 1, 'earnt a card' assert world.owners == [0, 1, 0] assert world.armies == [3, 2, 2] # dice rolls alternatives, probabilities = rand.choices.call_args[0] assert alternatives == ((0, 1), (1, 0)) np.testing.assert_almost_equal(probabilities, [855 / 1296, 441 / 1296]) # 3. Attack (knock out other player, claim their cards), win agents[0].act = um.Mock(return_value=P.Attack(0, 1, 2)) rand.choices = um.Mock(return_value=[(0, 2)]) with pytest.raises(P._GameOverException): list( P._attack_and_move(agents[0], states[0], deck, agents_and_states, rand)) assert world.owners == [0, 0, 0] assert world.armies == [1, 2, 2] # dice rolls alternatives, probabilities = rand.choices.call_args[0] assert alternatives == ((0, 2), (1, 1), (2, 0)) np.testing.assert_almost_equal(probabilities, [295 / 1296, 420 / 1296, 581 / 1296]) # cards assert len( states[0].cards ) == 2, 'conquered a card (haven\'t earnt one as the game ended too soon)' assert P.Card(2, 2) in states[0].cards assert len(states[1].cards) == 0, 'conquered = lost card' assert world.n_cards == [2, 0, 0]
def test_reinforce(): map_ = P.Map.load('maps/quad.json') tid = map_.territory_names.index C = P.Card deck = um.Mock() # Set up the world world = P.World(map_, ['p0', 'p1', 'p2'], has_neutral=False) for i in range(map_.n_territories): world.armies[i] = 1 world.owners[i] = 2 world.owners[tid('A4')] = 0 world.owners[tid('B4')] = 1 agent_0 = um.Mock() state_0 = P.PlayerState(world, 0) # 1. Minimum territory reinforcements, no continents, no sets agent_0.reinforce = um.Mock(return_value={tid('A4'): 3}) events = list(P._reinforce(agent_0, state_0, deck)) assert events == [ P.Event(agent_0, state_0, 'reinforce', dict(count=3), {tid('A4'): 3}) ] assert world.armies[tid('A4')] == 1 + 3 assert world.sets_redeemed == 0 # 2. Minimum territory, no continents, declaring a set cards = [ C(0, tid('B1')), C(1, tid('B2')), C(2, tid('B3')), C(2, tid('B4')) ] cards_to_redeem = [cards[0], cards[1], cards[3]] state_0.cards = cards.copy() world.n_cards[0] = len(cards) agent_0.redeem = um.Mock(return_value=cards_to_redeem.copy()) agent_0.reinforce = um.Mock(return_value={tid('A4'): 7}) # 3 (territory) + 4 (set) events = list(P._reinforce(agent_0, state_0, deck)) assert events == [ P.Event(agent_0, state_0, 'redeem', {}, cards_to_redeem.copy()), P.Event(agent_0, state_0, 'reinforce', dict(count=7), {tid('A4'): 7}) ] assert world.armies[tid('A4')] == 4 + 7 assert world.sets_redeemed == 1 assert world.n_cards[0] == 1 assert state_0.cards == [C(2, tid('B3'))] deck.redeem.assert_called_with(cards_to_redeem) # 3. Multiple territory, multiple continents, declaring a set agent_2 = um.Mock() cards = [C(2, tid('A2')), C(2, tid('A3')), C(2, tid('A4'))] state_2 = P.PlayerState(world, 2, cards=cards) world.n_cards[2] = len(state_2.cards) agent_2.redeem = um.Mock(return_value=cards.copy()) # Need to make 17 reinforcements: 6 (=18/3, territory) + 6 (set) + 5 (=2+3, continents) reinforcements = {tid('A3'): 11, tid('B5'): 6} agent_2.reinforce = um.Mock(return_value=reinforcements) events = list(P._reinforce(agent_2, state_2, deck)) assert events == [ P.Event(agent_2, state_2, 'redeem', {}, cards.copy()), P.Event(agent_2, state_2, 'reinforce', dict(count=17), reinforcements) ] assert world.armies[tid( 'A4')] == 11, 'matches set but not owned, so unchanged' assert world.armies[tid('A2')] == 3, 'bonus armies' assert world.armies[tid( 'A3')] == 1 + 2 + 11, 'bonus armies & reinforcements' assert world.armies[tid('B5')] == 1 + 6, 'reinforcements' assert world.sets_redeemed == 2 assert world.n_cards[2] == 0 assert state_2.cards == [] deck.redeem.assert_called_with(cards)
def _make_world(map_, agents): world = P.World(map_, [str(a) for a in agents], isinstance(agents[-1], P._NeutralAgent)) return world, [(agent, P.PlayerState(world, n)) for n, agent in enumerate(agents)]