Skip to content

Commit

Permalink
Update based on Lexon feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
jauggy committed Oct 17, 2024
1 parent c66d479 commit 14d06db
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 26 deletions.
1 change: 0 additions & 1 deletion lib/teiserver/account/libs/relationship_lib.ex
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ defmodule Teiserver.Account.RelationshipLib do

@spec check_block_status(T.userid(), [T.userid()]) :: :ok | :blocking | :blocked
def check_block_status(userid, userid_list) do
user = Account.get_user_by_id(userid)
userid_count = Enum.count(userid_list) |> max(1)

block_count_needed = Config.get_site_config_cache("lobby.Block count to prevent join")
Expand Down
35 changes: 23 additions & 12 deletions lib/teiserver/battle/balance/brute_force_avoid.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ defmodule Teiserver.Battle.Balance.BruteForceAvoid do
This is not a balance algorithm that is callable players. It's a lib that can be used by another balance algorithm.
"""
alias Teiserver.Config
alias Teiserver.Battle.Balance.BruteForceAvoidTypes, as: BF
require Integer

@max_team_diff 14
# Parties will be split if team diff is too large. It either uses absolute value or percentage
# See get_max_team_diff function below for full details
@max_team_diff_abs 10
@max_team_diff_importance 10000
@party_importance 1000
@avoid_importance 10
Expand All @@ -33,9 +36,7 @@ defmodule Teiserver.Battle.Balance.BruteForceAvoid do
# Go through every possibility and get the combination with the lowest score
result =
Enum.map(combos, fn x ->
get_players_from_indexes(x, players_with_index)
end)
|> Enum.map(fn team ->
team = get_players_from_indexes(x, players_with_index)
result = score_combo(team, players, avoids, parties)
Map.put(result, :first_team, team)
end)
Expand All @@ -61,16 +62,29 @@ defmodule Teiserver.Battle.Balance.BruteForceAvoid do
Teiserver.Helper.CombinationsHelper.get_combinations(num_players)
end

# Parties/avoids will be ignored if the team rating diff is too large
# This function returns the allowed team difference
# By default, it is either 10 rating points or 5% of a single team rating - whichever is larger
defp get_max_team_diff(total_lobby_rating, num_teams) do
# This value is 10% in dev but 5% in production. Can be adjusted by Admin
percentage_of_team = Config.get_site_config_cache("teiserver.Max deviation") / 100
max(total_lobby_rating / num_teams * percentage_of_team, @max_team_diff_abs)
end

@spec score_combo([BF.player()], [BF.player()], [[number()]], [[number()]]) :: any()
def score_combo(first_team, all_players, avoids, parties) do
first_team_rating = get_team_rating(first_team)
both_team_rating = get_team_rating(all_players)
rating_diff_penalty = abs(both_team_rating - first_team_rating * 2)
num_teams = 2

max_team_diff_penalty =
cond do
rating_diff_penalty > @max_team_diff -> @max_team_diff_importance
true -> 0
rating_diff_penalty > get_max_team_diff(both_team_rating, num_teams) ->
@max_team_diff_importance

true ->
0
end

# If max_team_diff_penalty is non zero don't even bother calculating avoid and party penalty
Expand All @@ -97,12 +111,9 @@ defmodule Teiserver.Battle.Balance.BruteForceAvoid do
end

def get_players_from_indexes(player_indexes, players_with_index) do
Enum.filter(players_with_index, fn {_player, index} ->
Enum.member?(player_indexes, index)
end)
|> Enum.map(fn {player, _index} ->
player
end)
players_with_index
|> Enum.filter(fn {_player, index} -> index in player_indexes end)
|> Enum.map(fn {player, _index} -> player end)
end

def count_broken_parties(first_team, parties) do
Expand Down
11 changes: 6 additions & 5 deletions lib/teiserver/battle/balance/respect_avoids.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ defmodule Teiserver.Battle.Balance.RespectAvoids do
# The lowest uncertainty rank 0 player at the time of writing this is 6.65
@high_uncertainty 6.65
@splitter "------------------------------------------------------"
@per_player_avoid_limit 2

@doc """
Main entry point used by balance_lib
Expand Down Expand Up @@ -451,20 +452,17 @@ defmodule Teiserver.Battle.Balance.RespectAvoids do

@spec get_avoids([any()], number(), boolean()) :: [String.t()]
def get_avoids(player_ids, lobby_max_avoids, debug_mode? \\ false) do
# The max number of avoids per player to pull from db
player_limit = 2

cond do
debug_mode? ->
RelationshipLib.get_lobby_avoids(player_ids, lobby_max_avoids, player_limit)
RelationshipLib.get_lobby_avoids(player_ids, lobby_max_avoids, @per_player_avoid_limit)

true ->
avoid_min_hours = get_avoid_delay()

RelationshipLib.get_lobby_avoids(
player_ids,
lobby_max_avoids,
player_limit,
@per_player_avoid_limit,
avoid_min_hours
)
end
Expand Down Expand Up @@ -524,6 +522,9 @@ defmodule Teiserver.Battle.Balance.RespectAvoids do
end

def is_newish_player?(rank, uncertainty) do
# It is possible that someone has high uncertainty due to
# playing unranked, playing PvE, or playing a different game mode e.g. 1v1
# If they have many hours i.e. chev 4 = 100 hours, we will not consider them newish
uncertainty >= @high_uncertainty && rank <= 2
end
end
12 changes: 5 additions & 7 deletions lib/teiserver/battle/libs/balance_lib.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Teiserver.Battle.BalanceLib do
@moduledoc """
A set of functions related to balance, if you are looking to see how balance is implemented this is the place. Ratings are calculated via Teiserver.Game.MatchRatingLib and are used here. Please note ratings and balance are two very different things and complaints about imbalanced games need to be correct in addressing balance vs ratings.
"""
alias Teiserver.{Account, Config}
alias Teiserver.{Account, Config, CacheUser}
alias Teiserver.Data.Types, as: T
alias Teiserver.Battle.Balance.BalanceTypes, as: BT
alias Teiserver.Game.MatchRatingLib
Expand Down Expand Up @@ -637,12 +637,10 @@ defmodule Teiserver.Battle.BalanceLib do
{rating, uncertainty} = get_user_rating_value_uncertainty_pair(userid, rating_type_id)
rating = fuzz_rating(rating, fuzz_multiplier)

# Get stats data
# Potentially adjust ratings based on os_global_adjust
stats_data = Account.get_user_stat_data(userid)
adjustment = int_parse(stats_data["os_global_adjust"])
rating = rating + adjustment
rank = Map.get(stats_data, "rank", 0)
# Get rank of user using the Role method
# If we change the method for chevron icons, we stil want to use this method as it is based on playtime
# This could be improved by using playtime to pass into the balance algorithm instead of rank
rank = CacheUser.calculate_rank(userid, "Role")

# This call will go to db or cache
# The cache for users is :users
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@
<Fontawesome.icon icon={Teiserver.Account.RelationshipLib.icon_avoid()} style="regular" />
</h4>
<div :if={@show_help} class="help-box">
In addition to the effects of ignoring; if enough players in a lobby are avoiding someone they will not be able to become a player themselves. They will still be able to spectate though.
In addition to the effects of ignoring; if you avoid someone, there's less chance the balance algorithm will place you on the same team. However, avoids will be broken if the algorithm cannot balance teams fairly. This feature is still under development.
</div>
<.table id="avoids-table" table_class="table-sm" rows={@avoids}>
<:col :let={avoid} label="Name"><%= avoid.to_user.name %></:col>
Expand Down

0 comments on commit 14d06db

Please sign in to comment.