Closed TheYoBots closed 1 year ago
I'm trying to understand the goal of this feature. To take your example, if your bot plays a wide variety of time controls in standard chess, what's the problem with playing a wide variety of time controls for variants? For example, in the case of the opening books, these are separated by variant because using the wrong book could result in illegal moves being chosen.
So, the only reason I want my bot to play 25+1 (for example) is so that it doesn't have a provisional classical rating. But when it comes to variants, I'd rather not play long games when it doesn't matter what time control you are playing a variant, so maybe I just want to play an 8+1 in variants.
+1 would like this too
Just mentioning that this is supported by the feature described in https://github.com/lichess-bot-devs/lichess-bot/pull/493#issuecomment-1175459973, which I have implemented in my fork.
This gives maximal flexibility, at the cost of making things somewhat complex. Note however that adding this feature now would result in even more complexity as when it was originally proposed, since in the meantime another way of randomly choosing between multiple time controls has been added.
So that ship has probably sailed, but maybe it can still serve as a reference (e.g. for the implementation).
A note on the design suggested by @TheYoBots: The change should be backwards compatible, which adds some implementation complexity. Specifically, how would a config in the existing format be handled? If there is no standard
, chess960
etc. key in the matchmaking section, it internally treats it as having an entry for each supported variant, each with the same time control settings?
How's this for an idea? Instead of trying to stuff all of this complexity into a single configuration file, the user creates multiple configuration files and lichess-bot can rotate between them on some interval. The meta-config file would look like this:
rotation_interval:
games: 100
time: 180 # minutes
configurations:
- config.standard.yml
- config.variants.yml
- config.standard.no_books.yml
- config.casual.bullet.yml
- ...
The rotation_interval
section specifies how often lichess-bot restarts with the next configuration file, looping through the list in the order given. Here, it's after 100 games or 3 hours, whichever comes first. A missing value defaults to infinity. Then, the configurations
section contains the list of configuration files. The user would start lichess-bot with python3 lichess-bot.py --multiconfig meta.config.py
.
With this setup, anything in a user's configuration file--not just matchmaking time controls--can be specialized for whatever purpose. The configurations files might even belong to different bot accounts.
Note: Some care would have to be taken with correspondence games to make sure that they continue with the same configuration file.
I don't think restarting often to change config using a meta-config file is the best option. Instead, simply reading the next config in the list instead of the previous one would be better. But what if a game is in play? Will the next config in the list be called immediately or wait for the game to finish?
Would it be possible to make the line dynamic and adhere to the meta-config without using the --config
arg?
https://github.com/lichess-bot-devs/lichess-bot/blob/bf41362351b97e01df35d51a0427b5b68315d1dd/lichess-bot.py#L966
Why do I feel this only increases the complexity?
I prefer the idea by mheinzel. We can add random time controls inside each random time control. Example:
matchmaking:
allow_matchmaking: true
challenge_timeout: 30
challenge_variant: "standard"
challenge_mode: "rated"
challenge_initial_time:
- 60
- 120
challenge_increment:
- 1
- 2
opponent_min_rating: 1000
opponent_max_rating: 2000
challenges:
# Keep all settings from the top level
- challenge_name: "standard"
# Override time control
- challenge_name: "Rapid"
challenge_initial_time:
- 5
- 10
challenge_increment:
- 0
- 1
- 2
- 3
- challenge_name: "Classical"
challenge_initial_time:
- 1800
- 3600
challenge_increment: 30
- challenge_name: "Chess960"
challenge_variant: "chess960"
challenge_initial_time: 60
challenge_increment: 1
- challenge_name: "Atomic"
challenge_variant: "atomic"
This uses both the current setup and the idea by mheinzel.
I think something that could be more workable looks like this:
matchmaking:
allow_matchmaking: true
challenge_timeout: 30
challenge_variant: "standard"
challenge_mode: "rated"
challenge_initial_time:
- 60
- 120
challenge_increment:
- 1
- 2
opponent_min_rating: 1000
opponent_max_rating: 2000
challenge_overrides:
Rapid:
challenge_initial_time:
- 5
- 10
challenge_increment:
- 0
- 1
- 2
- 3
Classical:
challenge_initial_time:
- 1800
- 3600
challenge_increment: 30
Chess960:
challenge_variant: "chess960"
challenge_initial_time: 60
challenge_increment: 1
Atomic:
challenge_variant: "atomic"
The names of the subsections under challenge_overrides:
don't matter. They are just keys for lookup. Then, in Matchmaking.choose_opponent()
:
def choose_opponent(self):
challenge_override = random.choice(list(self.matchmaking_cfg.challenge_overrides.keys()) + [None])
this_matchup_cfg = self.override_cfg(challenge_override)
The method override_cfg()
creates a new matchmaking configuration with the configuration from the randomly chosen key by making the appropriate replacements in self.matchmaking_cfg
. If None
is chosen, the default configuration is used unchanged.
So would matchmaking_overrides
ignore these options?
challenge_variant: "standard"
challenge_mode: "rated"
challenge_initial_time:
- 60
- 120
challenge_increment:
- 1
- 2
If it does then why does that section even have to be there. And doesn't this simply just lead to the same thing I initially proposed?
matchmaking: allow_matchmaking: false # Set it to 'true' to challenge other bots. challenge_timeout: 30 # Create a challenge after being idle for 'challenge_timeout' minutes. The minimum is 1 minute. # opponent_min_rating: 600 # Opponents rating should be above this value (600 is the minimum rating in lichess). # opponent_max_rating: 4000 # Opponents rating should be below this value (4000 is the maximum rating in lichess). opponent_rating_difference: 300 # The maximum difference in rating between the bot's rating and opponent's rating. opponent_allow_tos_violation: false # Set to 'true' to allow challenging bots that violated the Lichess Terms of Service. challenge_mode: "random" # Set it to the mode in which challenges are sent. Possible options are 'casual', 'rated' and 'random'. challenge_filter: none # If a bot declines a challenge, do not issue a similar challenge to that bot. Possible options are 'none', 'coarse', and 'fine'. standard: challenge_initial_time: # Initial time in seconds of the challenge (to be chosen at random). - 60 - 180 challenge_increment: # Increment in seconds of the challenge (to be chosen at random). - 1 - 2 # challenge_days: # Days for correspondence challenge (to be chosen at random). # - 1 # - 2 # chess960: # challenge_initial_time: # - 60 # - 180 # challenge_increment: # - 1 # - 2 # challenge_days: # - 1 # - 2 # etc. # Use the same pattern for 'giveaway' (antichess), 'crazyhouse', 'horde', 'kingofthehill', 'racingkings' and '3check' as well.
It will override them only if they exist inside the section. These are the defaults, so they don't have to be copy and pasted to every section.
matchmaking:
allow_matchmaking: true
challenge_timeout: 30
challenge_variant: "standard"
challenge_mode: "rated"
challenge_initial_time:
- 60
- 120
challenge_increment:
- 1
- 2
opponent_min_rating: 1000
opponent_max_rating: 2000
challenge_overrides:
Atomic:
challenge_variant: "atomic"
challenge_mode: "casual"
Chess960:
challenge_variant: "chess960"
challenge_initial_time: 60
challenge_increment: 1
With the above config, Atomic
will use the default time controls and min/max ratings (as specified in the main section of the matchmaking config), while Chess960
will use a different time control, but the default game mode and min/max ratings.
In your config this will corrspond to:
standard:
challenge_initial_time: # Initial time in seconds of the challenge (to be chosen at random).
- 60
- 180
challenge_increment: # Increment in seconds of the challenge (to be chosen at random).
- 1
- 2
challenge_mode: "rated"
opponent_min_rating: 1000
opponent_max_rating: 2000
atomic:
challenge_mode: "caual"
challenge_initial_time: # Initial time in seconds of the challenge (to be chosen at random).
- 60
- 180
challenge_increment: # Increment in seconds of the challenge (to be chosen at random).
- 1
- 2
opponent_min_rating: 1000
opponent_max_rating: 2000
chess960:
challenge_initial_time: # Initial time in seconds of the challenge (to be chosen at random).
- 60
challenge_increment: # Increment in seconds of the challenge (to be chosen at random).
- 1
challenge_mode: "rated"
opponent_min_rating: 1000
opponent_max_rating: 2000
The first config will lead to less repetition. Another advantage to the first config is that names don't mean anything. One can add two or move sections for the same time control/variant. For example:
challenge_overrides:
Bullet2:
challenge_mode: "casual"
Bullet3:
opponent_min_rating: 2000
This way the bot has a 2/3 chance of playing rated.
Is your feature request related to a problem? Please describe. It isn't completely related to a problem. But I though the matchmaking feature would be more useful if for different variants I could set different time controls. For example, I want to play various time controls in standard chess so that I don't have a provisional rating in different "standard game types" (like bullet, blitz, rapid, classical). But for variants I don't want to challenge other opponents in these same time controls, I just need a single time control per variant
Describe the solution you'd like So I'd suggest something similar to what is done for adding opening books. where for each variant I can choose different time controls to challenge opponents. These options could remain the same for all variants:
and then for respective variants, the initial time and increment could be changed:
Additional context So I suppose this is how I would want the matchmaking config to be: