Skip to content

Commit bff726f

Browse files
committed
Introduce a smart multiplier calculation
The matchmaking multiplier is calculated based on the online bots and the configured rating limits
1 parent 1e2e7fa commit bff726f

File tree

4 files changed

+51
-23
lines changed

4 files changed

+51
-23
lines changed

botli_dataclasses.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,11 @@ class Matchmaking_Type:
253253
rated: bool
254254
variant: Variant
255255
perf_type: Perf_Type
256-
multiplier: float
256+
config_multiplier: int | None
257+
multiplier: int
257258
weight: float
258-
min_rating_diff: int
259-
max_rating_diff: int
259+
min_rating_diff: int | None
260+
max_rating_diff: int | None
260261

261262
def __post_init__(self) -> None:
262263
self.estimated_game_duration = timedelta(seconds=max(self.initial_time, 3) * 1.33 + self.increment * 94.48)

config.yml.default

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ matchmaking:
170170
# rated: true # Whether matchmaking should play rated games. Default: true
171171
# variant: standard # Chess variant (https://lichess.org/variant) to challenge. Default: standard
172172
# weight: 100 # Weight with which this type is selected. Default: Types are played according to their time control.
173-
# multiplier: 15 # Multiplier for calculating timeouts in matchmaking. Default: 15 * number of configured performance types.
173+
# multiplier: 15 # Multiplier for calculating timeouts in matchmaking. Default: smart multiplier calculation.
174174
# min_rating_diff: 0 # Minimum rating distance to opponent. Default: 0
175175
# max_rating_diff: 300 # Maximum rating distance to opponent. Default: 10000
176176

matchmaking.py

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -126,19 +126,13 @@ def _get_matchmaking_types(self) -> list[Matchmaking_Type]:
126126
rated = True if type_config.rated is None else type_config.rated
127127
variant = Variant.STANDARD if type_config.variant is None else Variant(type_config.variant)
128128
perf_type = self._variant_to_perf_type(variant, initial_time, increment)
129-
multiplier = 15 if type_config.multiplier is None else type_config.multiplier
130129
weight = 1.0 if type_config.weight is None else type_config.weight
131-
min_rating_diff = 0 if type_config.min_rating_diff is None else type_config.min_rating_diff
132-
max_rating_diff = 10_000 if type_config.max_rating_diff is None else type_config.max_rating_diff
133130

134131
matchmaking_types.append(Matchmaking_Type(name, initial_time, increment, rated, variant,
135-
perf_type, multiplier, weight, min_rating_diff, max_rating_diff))
132+
perf_type, type_config.multiplier, -1, weight,
133+
type_config.min_rating_diff, type_config.max_rating_diff))
136134

137-
perf_type_count = len({matchmaking_type.perf_type for matchmaking_type in matchmaking_types})
138135
for matchmaking_type, type_config in zip(matchmaking_types, self.config.matchmaking.types.values()):
139-
if type_config.multiplier is None:
140-
matchmaking_type.multiplier *= perf_type_count
141-
142136
if type_config.weight is None:
143137
matchmaking_type.weight /= matchmaking_type.estimated_game_duration.total_seconds()
144138

@@ -147,14 +141,15 @@ def _get_matchmaking_types(self) -> list[Matchmaking_Type]:
147141
return matchmaking_types
148142

149143
async def _call_update(self) -> bool:
150-
if self.next_update <= datetime.now():
151-
print('Updating online bots and rankings ...')
152-
self.types.extend(self.suspended_types)
153-
self.suspended_types.clear()
154-
self.online_bots = await self._get_online_bots()
155-
return True
144+
if self.next_update > datetime.now():
145+
return False
156146

157-
return False
147+
print('Updating online bots and rankings ...')
148+
self.types.extend(self.suspended_types)
149+
self.suspended_types.clear()
150+
self.online_bots = await self._get_online_bots()
151+
self._set_multiplier()
152+
return True
158153

159154
async def _get_online_bots(self) -> list[Bot]:
160155
user_ratings = await self._get_user_ratings()
@@ -196,6 +191,36 @@ async def _get_user_ratings(self) -> dict[Perf_Type, int]:
196191

197192
return performances
198193

194+
def _set_multiplier(self) -> None:
195+
for matchmaking_type in self.types:
196+
if matchmaking_type.config_multiplier:
197+
matchmaking_type.multiplier = matchmaking_type.config_multiplier
198+
else:
199+
min_rating_diff = matchmaking_type.min_rating_diff if matchmaking_type.min_rating_diff else 0
200+
max_rating_diff = matchmaking_type.max_rating_diff if matchmaking_type.max_rating_diff else 600
201+
202+
bot_count = self._get_bot_count(matchmaking_type.perf_type, min_rating_diff, max_rating_diff)
203+
perf_type_count = len({matchmaking_type.perf_type for matchmaking_type in self.types})
204+
matchmaking_type.multiplier = bot_count * perf_type_count
205+
206+
def _get_bot_count(self, perf_type: Perf_Type, min_rating_diff: int, max_rating_diff: int) -> int:
207+
def bot_filter(bot: Bot) -> bool:
208+
if perf_type not in bot.rating_diffs:
209+
return False
210+
211+
if abs(bot.rating_diffs[perf_type]) > max_rating_diff:
212+
return False
213+
214+
if abs(bot.rating_diffs[perf_type]) < min_rating_diff:
215+
return False
216+
217+
if self.opponents.opponent_dict[bot.username][perf_type].multiplier > 1:
218+
return False
219+
220+
return True
221+
222+
return sum(map(bot_filter, self.online_bots))
223+
199224
def _variant_to_perf_type(self, variant: Variant, initial_time: int, increment: int) -> Perf_Type:
200225
if variant != Variant.STANDARD:
201226
return Perf_Type(variant)

opponents.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,13 @@ def bot_filter(bot: Bot) -> bool:
6969
if matchmaking_type.perf_type not in bot.rating_diffs:
7070
return False
7171

72-
if abs(bot.rating_diffs[matchmaking_type.perf_type]) > matchmaking_type.max_rating_diff:
73-
return False
72+
if matchmaking_type.max_rating_diff:
73+
if abs(bot.rating_diffs[matchmaking_type.perf_type]) > matchmaking_type.max_rating_diff:
74+
return False
7475

75-
if abs(bot.rating_diffs[matchmaking_type.perf_type]) < matchmaking_type.min_rating_diff:
76-
return False
76+
if matchmaking_type.min_rating_diff:
77+
if abs(bot.rating_diffs[matchmaking_type.perf_type]) < matchmaking_type.min_rating_diff:
78+
return False
7779

7880
return True
7981

0 commit comments

Comments
 (0)