Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add max simultaneous games per user option #1061

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ challenge: # Incoming challenges.
# recent_bot_challenge_age: 60 # Maximum age of a bot challenge to be considered recent in seconds
# max_recent_bot_challenges: 2 # Maximum number of recent challenges that can be accepted from the same bot
bullet_requires_increment: false # Require that bullet game challenges from bots have a non-zero increment
max_simultaneous_games_per_user: 5 # Maximum number of simultaneous games with the same user

greeting:
# Optional substitution keywords (include curly braces):
Expand Down
1 change: 1 addition & 0 deletions lib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ def insert_default_values(CONFIG: CONFIG_DICT_TYPE) -> None:
set_config_default(CONFIG, "challenge", key="min_days", default=1)
set_config_default(CONFIG, "challenge", key="block_list", default=[], force_empty_values=True)
set_config_default(CONFIG, "challenge", key="allow_list", default=[], force_empty_values=True)
set_config_default(CONFIG, "challenge", key="max_simultaneous_games_per_user", default=5)
set_config_default(CONFIG, "correspondence", key="checkin_period", default=600)
set_config_default(CONFIG, "correspondence", key="move_time", default=60, force_empty_values=True)
set_config_default(CONFIG, "correspondence", key="disconnect_time", default=300)
Expand Down
5 changes: 4 additions & 1 deletion lib/lichess_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from http.client import RemoteDisconnected
from queue import Empty
from multiprocessing.pool import Pool
from collections import Counter
from typing import Optional, Union, TypedDict, cast
from types import FrameType
MULTIPROCESSING_LIST_TYPE = MutableSequence[model.Challenge]
Expand Down Expand Up @@ -614,7 +615,9 @@ def handle_challenge(event: EventType, li: LICHESS_TYPE, challenge_queue: MULTIP
if chlng.from_self:
return

is_supported, decline_reason = chlng.is_supported(challenge_config, recent_bot_challenges)
players_with_active_games = Counter(game["opponent"]["username"] for game in li.get_ongoing_games())

is_supported, decline_reason = chlng.is_supported(challenge_config, recent_bot_challenges, players_with_active_games)
if is_supported:
challenge_queue.append(chlng)
sort_challenges(challenge_queue, challenge_config)
Expand Down
8 changes: 5 additions & 3 deletions lib/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from enum import Enum
from lib.timer import Timer, msec, seconds, sec_str, to_msec, to_seconds, years
from lib.config import Configuration
from collections import defaultdict
from collections import defaultdict, Counter
from lib.types import UserProfileType, ChallengeType, GameEventType, PlayerType

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -91,8 +91,8 @@ def decline_due_to(self, requirement_met: bool, decline_reason: str) -> str:
"""
return "" if requirement_met else decline_reason

def is_supported(self, config: Configuration,
recent_bot_challenges: defaultdict[str, list[Timer]]) -> tuple[bool, str]:
def is_supported(self, config: Configuration, recent_bot_challenges: defaultdict[str, list[Timer]],
players_with_active_games: Counter[str]) -> tuple[bool, str]:
"""Whether the challenge is supported."""
try:
if self.from_self:
Expand All @@ -109,6 +109,8 @@ def is_supported(self, config: Configuration,
or self.decline_due_to(self.challenger.name not in config.block_list, "generic")
or self.decline_due_to(self.challenger.name in allowed_opponents, "generic")
or self.decline_due_to(self.is_supported_recent(config, recent_bot_challenges), "later")
or self.decline_due_to(players_with_active_games[self.challenger.name]
< config.max_simultaneous_games_per_user, "later")
or self.decline_due_to(is_supported_extra(self), "generic"))

return not decline_reason, decline_reason
Expand Down
6 changes: 3 additions & 3 deletions test_bot/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from lib import model
import yaml
from lib import config
from collections import defaultdict
from collections import defaultdict, Counter
from lib.timer import Timer
from lib.types import ChallengeType, UserProfileType, GameEventType, PlayerType

Expand Down Expand Up @@ -52,10 +52,10 @@ def test_challenge() -> None:
assert challenge_model.speed == "bullet"
assert challenge_model.time_control["show"] == "1.5+1"
assert challenge_model.color == "white"
assert challenge_model.is_supported(configuration, recent_challenges) == (True, "")
assert challenge_model.is_supported(configuration, recent_challenges, Counter()) == (True, "")

CONFIG["challenge"]["min_base"] = 120
assert challenge_model.is_supported(configuration, recent_challenges) == (False, "timeControl")
assert challenge_model.is_supported(configuration, recent_challenges, Counter()) == (False, "timeControl")


def test_game() -> None:
Expand Down
1 change: 1 addition & 0 deletions wiki/Configure-lichess-bot.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ will precede the `go` command to start thinking with `sd 5`. The other `go_comma
- `allow_list`: An indented list of usernames from which challenges are exclusively accepted. A challenge from a user not on this list is declined. If this option is not present or empty, any user's challenge may be accepted.
- `recent_bot_challenge_age`: Maximum age of a bot challenge to be considered recent in seconds
- `max_recent_bot_challenges`: Maximum number of recent challenges that can be accepted from the same bot
- `max_simultaneous_games_per_user`: Maximum number of games that can be played simultaneously with the same user

## Greeting
- `greeting`: Send messages via chat to the bot's opponent. The string `{me}` will be replaced by the bot's lichess account name. The string `{opponent}` will be replaced by the opponent's lichess account name. Any other word between curly brackets will be removed. If you want to put a curly bracket in the message, use two: `{{` or `}}`.
Expand Down
Loading