def test_make_teams_single_2v2_large_pool(player_factory):
    """
    When we have a large number of players all with similar ratings, we want
    teams to be formed by putting players with the same rating on the same team.
    """

    # Large enough so the test is unlikely to pass by chance
    num = 40

    searches = [
        Search([player_factory(random.uniform(950, 1050), 10, name=f"p{i}")])
        for i in range(num)
    ]
    searches += [
        Search([player_factory(random.uniform(450, 550), 10, name=f"p{i}")])
        for i in range(num)
    ]
    matched, non_matched = algorithm.make_teams_from_single(searches, size=2)

    assert matched != []
    assert non_matched == []

    for search in matched:
        p1, p2 = search.players
        p1_mean, _ = p1.ratings[RatingType.LADDER_1V1]
        p2_mean, _ = p2.ratings[RatingType.LADDER_1V1]
        #
        assert math.fabs(p1_mean - p2_mean) <= 100
Example #2
0
async def test_cancel_twice(ladder_service: LadderService, player_factory):
    p1 = player_factory('Dostya',
                        player_id=1,
                        ladder_rating=(1500, 500),
                        ladder_games=0)
    p2 = player_factory('Brackman',
                        player_id=2,
                        ladder_rating=(2000, 500),
                        ladder_games=0)

    search = Search([p1])
    search2 = Search([p2])

    await ladder_service.start_search(p1, search, 'ladder1v1')
    await ladder_service.start_search(p2, search2, 'ladder1v1')

    searches = ladder_service._cancel_existing_searches(p1)
    assert search.is_cancelled
    assert searches == [search]
    assert not search2.is_cancelled

    searches = ladder_service._cancel_existing_searches(p1)
    assert searches == []

    searches = ladder_service._cancel_existing_searches(p2)
    assert search2.is_cancelled
    assert searches == [search2]
def test_make_teams_single_2v2_small_pool(player_factory):
    """
    When we have a small number of players, we want teams to be formed by
    distributing players of equal skill to different teams so that we can
    maximize the chances of getting a match.
    """

    # Try a bunch of times so it is unlikely to pass by chance
    for _ in range(20):
        searches = [
            Search([player_factory(random.gauss(1000, 5), 10, name=f"p{i}")])
            for i in range(2)
        ]
        searches += [
            Search([player_factory(random.gauss(500, 5), 10, name=f"r{i}")])
            for i in range(2)
        ]
        matched, non_matched = algorithm.make_teams_from_single(searches,
                                                                size=2)

        assert matched != []
        assert non_matched == []

        for search in matched:
            p1, p2 = search.players
            # Order doesn't matter
            if p1.ratings[RatingType.LADDER_1V1][0] > 900:
                assert p2.ratings[RatingType.LADDER_1V1][0] < 600
            else:
                assert p1.ratings[RatingType.LADDER_1V1][0] < 600
                assert p2.ratings[RatingType.LADDER_1V1][0] > 900
Example #4
0
async def test_queue_mid_cancel(matchmaker_queue,
                                matchmaker_players_all_match):
    # Turn list of players into map from ids to players.
    _, p1, p2, p3, _ = matchmaker_players_all_match
    (s1, s2, s3) = (Search([p1]), Search([p2]), Search([p3]))
    asyncio.create_task(matchmaker_queue.search(s1))
    asyncio.create_task(matchmaker_queue.search(s2))
    s1.cancel()

    async def find_matches():
        await asyncio.sleep(0.01)
        await matchmaker_queue.find_matches()

    try:
        await asyncio.gather(
            asyncio.wait_for(matchmaker_queue.search(s3), 0.1),
            asyncio.create_task(find_matches()))
    except CancelledError:
        pass

    assert not s1.is_matched
    assert s2.is_matched
    assert s3.is_matched
    assert len(matchmaker_queue._queue) == 0
    matchmaker_queue.on_match_found.assert_called_once_with(
        s2, s3, matchmaker_queue)
Example #5
0
async def test_cancel_twice(ladder_service: LadderService):
    p1 = mock.create_autospec(Player('Dostya', id=1))
    p1.ladder_rating = (1500, 500)
    p1.numGames = 0

    p2 = mock.create_autospec(Player('Brackman', id=1))
    p2.ladder_rating = (2000, 50)
    p2.numGames = 0

    search = Search([p1])
    search2 = Search([p2])

    ladder_service.start_search(p1, search, 'ladder1v1')
    ladder_service.start_search(p2, search2, 'ladder1v1')

    searches = ladder_service._cancel_existing_searches(p1)
    assert search.is_cancelled
    assert searches == [search]
    assert not search2.is_cancelled

    searches = ladder_service._cancel_existing_searches(p1)
    assert searches == []

    searches = ladder_service._cancel_existing_searches(p2)
    assert search2.is_cancelled
    assert searches == [search2]
Example #6
0
async def test_queue_mid_cancel(mocker, player_service, matchmaker_queue,
                                matchmaker_players_all_match):
    # Turn list of players into map from ids to players.
    player_service.players = dict(
        map(lambda x: (x.id, x), list(matchmaker_players_all_match)))
    p0, p1, p2, p3, _ = matchmaker_players_all_match
    (s1, s2, s3) = (Search([p1]), Search([p2]), Search([p3]))
    asyncio.ensure_future(matchmaker_queue.search(s1))
    asyncio.ensure_future(matchmaker_queue.search(s2))
    s1.cancel()

    async def find_matches():
        await asyncio.sleep(0.01)
        matchmaker_queue.find_matches()

    try:
        await asyncio.gather(
            asyncio.wait_for(matchmaker_queue.search(s3), 0.1),
            asyncio.ensure_future(find_matches()))
    except CancelledError:
        pass

    assert not s1.is_matched
    assert s2.is_matched
    assert s3.is_matched
    assert len(matchmaker_queue) == 0
Example #7
0
def test_unmatched_newbies_do_not_forcefully_match_teams(p):
    newbie = Search([p(1500, 500, ladder_games=0)])
    team = Search([p(1500, 100), p(1500, 100)])

    searches = [newbie, team]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 0
Example #8
0
def test_unmatched_newbies_do_notforcefully_match_top_players(p):
    newbie = Search([p(1500, 500, ladder_games=0)])
    top_player = Search([p(2500, 10, ladder_games=100)])

    searches = [newbie, top_player]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 0
Example #9
0
def test_unmatched_newbies_forcefully_match_pros(p):
    newbie = Search([p(1500, 500, ladder_games=0)])
    pro = Search([p(1400, 10, ladder_games=100)])

    searches = [newbie, pro]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 2
Example #10
0
async def test_search_await(mocker, loop, matchmaker_players):
    p1, p2, _, _, _, _ = matchmaker_players
    s1, s2 = Search([p1]), Search([p2])
    assert not s1.matches_with(s2)
    await_coro = asyncio.ensure_future(s1.await_match())
    s1.match(s2)
    await asyncio.wait_for(await_coro, 1)
    assert await_coro.done()
Example #11
0
def test_search_await(mocker, loop, matchmaker_players):
    p1, p2, _, _, _ = matchmaker_players
    s1, s2 = Search(p1), Search(p2)
    assert not s1.matches_with(s2)
    await_coro = asyncio. async (s1.await_match())
    s1.match(s2)
    yield from asyncio.wait_for(await_coro, 1)
    assert await_coro.done()
Example #12
0
def test_combined_search_attributes(matchmaker_players):
    p1, p2, p3, _, _, _ = matchmaker_players
    search = CombinedSearch(Search([p1, p2]), Search([p3]))
    assert search.players == [p1, p2, p3]
    assert search.raw_ratings == [
        p1.ratings[RatingType.LADDER_1V1], p2.ratings[RatingType.LADDER_1V1],
        p3.ratings[RatingType.LADDER_1V1]
    ]
Example #13
0
async def test_search_await(matchmaker_players):
    p1, p2, _, _, _, _ = matchmaker_players
    s1, s2 = Search([p1]), Search([p2])
    assert not s1.matches_with(s2)
    await_coro = asyncio.create_task(s1.await_match())
    s1.match(s2)
    await asyncio.wait_for(await_coro, 1)
    assert await_coro.done()
def test_remove_isolated(player_factory):
    s1 = Search([player_factory(1500, 64, ladder_games=20)])
    s2 = Search([player_factory(1500, 63, ladder_games=20)])
    s3 = Search([player_factory(1600, 75, ladder_games=50)])
    ranks = add_graph_edge_weights({s1: [s3], s2: [], s3: [s1]})

    algorithm._MatchingGraph.remove_isolated(ranks)

    assert ranks == add_graph_edge_weights({s1: [s3], s3: [s1]})
def test_matchmaker_random_only(player_factory):
    newbie1 = Search([player_factory(1550, 500, ladder_games=1)])
    newbie2 = Search([player_factory(200, 400, ladder_games=9)])

    searches = (newbie1, newbie2)
    match_pairs = algorithm.make_matches(searches)
    match_sets = [set(pair) for pair in match_pairs]

    assert {newbie1, newbie2} in match_sets
def test_unmatched_newbies_do_not_forcefully_match_top_players(player_factory):
    newbie = Search([player_factory(1500, 500, ladder_games=0)])
    top_player = Search([player_factory(2500, 10, ladder_games=100)])
    top_player.register_failed_matching_attempt()

    searches = [newbie, top_player]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 0
def test_remove_isolated_2(player_factory):
    s1 = Search([player_factory(1500, 64, ladder_games=20)])
    s2 = Search([player_factory(1500, 63, ladder_games=20)])
    s3 = Search([player_factory(1600, 75, ladder_games=50)])
    ranks = {s1: [], s2: [], s3: []}

    algorithm._MatchingGraph.remove_isolated(ranks)

    assert ranks == {}
def test_match_graph_will_not_include_matches_below_threshold_quality(
        player_factory, build_func):
    s1 = Search([player_factory(1500, 500)])
    s2 = Search([player_factory(2000, 300)])
    searches = [s1, s2]

    ranks = build_func(searches)

    assert ranks == {s1: [], s2: []}
Example #19
0
def test_newbies_are_forcefully_matched_with_newbies(p):
    newbie1 = Search([p(0, 500, ladder_games=9)])
    newbie2 = Search([p(1500, 500, ladder_games=9)])
    pro = Search([p(1500, 10, ladder_games=100)])

    searches = [newbie1, pro, newbie2]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert matches[newbie1] == newbie2
    assert matches[newbie2] == newbie1
Example #20
0
def test_search_quality_equivalence(player_factory, rating1, rating2):
    p1 = player_factory("Player1",
                        ladder_rating=rating1,
                        with_lobby_connection=False)
    p2 = player_factory("Player2",
                        ladder_rating=rating2,
                        with_lobby_connection=False)
    s1 = Search([p1])
    s2 = Search([p2])
    assert s1.quality_with(s2) == s2.quality_with(s1)
Example #21
0
def unmatched_newbie_teams_do_not_forcefully_match_pros(p):
    newbie_team = Search(
        [p(1500, 500, ladder_games=0),
         p(1500, 500, ladder_games=0)])
    pro = Search([p(1800, 10, ladder_games=100)])

    searches = [newbie_team, pro]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 0
Example #22
0
def test_odd_number_of_unmatched_newbies(p):
    newbie1 = Search([p(-250, 500, ladder_games=9)])
    newbie2 = Search([p(750, 500, ladder_games=9)])
    newbie3 = Search([p(1500, 500, ladder_games=9)])
    pro = Search([p(1500, 10, ladder_games=100)])

    searches = [newbie1, pro, newbie2, newbie3]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 4
Example #23
0
def test_make_matches_will_not_match_low_quality_games(p):
    s1 = Search([p(100, 64, name='p1')])
    s2 = Search([p(2000, 64, name='p2')])

    searches = [s1, s2]

    matches = algorithm.make_matches(searches)

    assert (s1, s2) not in matches
    assert (s2, s1) not in matches
def test_make_matches_will_not_match_low_quality_games(player_factory):
    s1 = Search([player_factory(100, 64, name="p1")])
    s2 = Search([player_factory(2000, 64, name="p2")])

    searches = [s1, s2]

    matches = algorithm.make_matches(searches)

    assert (s1, s2) not in matches
    assert (s2, s1) not in matches
def test_odd_number_of_unmatched_newbies(player_factory):
    newbie1 = Search([player_factory(-250, 500, ladder_games=9)])
    newbie2 = Search([player_factory(750, 500, ladder_games=9)])
    newbie3 = Search([player_factory(1500, 500, ladder_games=9)])
    pro = Search([player_factory(1500, 10, ladder_games=100)])
    pro.register_failed_matching_attempt()

    searches = [newbie1, pro, newbie2, newbie3]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 4
def test_newbies_are_forcefully_matched_with_newbies(player_factory):
    newbie1 = Search([player_factory(0, 500, ladder_games=9)])
    newbie2 = Search([player_factory(1500, 500, ladder_games=9)])
    pro = Search([player_factory(1500, 10, ladder_games=100)])
    pro.register_failed_matching_attempt()

    searches = [newbie1, pro, newbie2]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert matches[newbie1] == newbie2
    assert matches[newbie2] == newbie1
def test_unmatched_newbies_forcefully_match_pros(player_factory):
    newbie = Search([player_factory(1500, 500, ladder_games=0)])
    pro = Search([player_factory(1400, 10, ladder_games=100)])

    searches = [newbie, pro]
    matches = algorithm.RandomlyMatchNewbies().find(searches)
    # No match if the pro is on their first attempt
    assert len(matches) == 0

    pro.register_failed_matching_attempt()
    matches = algorithm.RandomlyMatchNewbies().find(searches)
    assert len(matches) == 2
def unmatched_newbie_teams_do_not_forcefully_match_pros(player_factory):
    newbie_team = Search([
        player_factory(1500, 500, ladder_games=0),
        player_factory(1500, 500, ladder_games=0)
    ])
    pro = Search([player_factory(1800, 10, ladder_games=100)])
    pro.register_failed_matching_attempt()

    searches = [newbie_team, pro]
    matches = algorithm.RandomlyMatchNewbies().find(searches)

    assert len(matches) == 0
Example #29
0
async def test_queue_cancel(matchmaker_queue, matchmaker_players):
    # Turn list of players into map from ids to players.

    s1, s2 = Search([matchmaker_players[1]]), Search([matchmaker_players[2]])
    matchmaker_queue.push(s1)
    s1.cancel()
    try:
        await asyncio.wait_for(matchmaker_queue.search(s2), 0.01)
    except (TimeoutError, CancelledError):
        pass

    assert not s1.is_matched
    assert not s2.is_matched
Example #30
0
def test_newbie_detection(matchmaker_players):
    pro, joe, _, _, _, newbie = matchmaker_players
    pro_search = Search([pro])
    newbie_search = Search([newbie])
    newb_team_search = Search([joe, newbie])
    pro_team_search = Search([pro, joe])

    assert pro_search.has_newbie() is False
    assert pro_search.is_newbie(pro) is False
    assert newbie_search.has_newbie() is True
    assert newbie_search.is_newbie(newbie) is True
    assert newb_team_search.has_newbie() is True
    assert pro_team_search.has_newbie() is False