mirror of
https://gitlab.com/ddorn/tfjm-discord-bot.git
synced 2024-11-26 22:07:08 +00:00
🚧 new tirages working without save
This commit is contained in:
parent
cfdd55daa2
commit
dfc8176084
@ -1,5 +1,8 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import random
|
import random
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
from functools import wraps
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
@ -57,12 +60,14 @@ class Team:
|
|||||||
|
|
||||||
return "\n".join(f"`{n.rjust(width)}`: {v}" for n, v in info.items())
|
return "\n".join(f"`{n.rjust(width)}`: {v}" for n, v in info.items())
|
||||||
|
|
||||||
return f""" - Accepté: {self.accepted_problems[round]}
|
|
||||||
- Refusés: {", ".join(p[0] for p in self.rejected[round]) if self.rejected[round] else "aucun"}
|
#
|
||||||
- Coefficient: {self.coeff(round)}
|
# return f""" - Accepté: {self.accepted_problems[round]}
|
||||||
- Ordre au tirage: {self.tirage_order[round]}
|
# - Refusés: {", ".join(p[0] for p in self.rejected[round]) if self.rejected[round] else "aucun"}
|
||||||
- Ordre de passage: {self.passage_order[round]}
|
# - Coefficient: {self.coeff(round)}
|
||||||
"""
|
# - Ordre au tirage: {self.tirage_order[round]}
|
||||||
|
# - Ordre de passage: {self.passage_order[round]}
|
||||||
|
# """
|
||||||
|
|
||||||
|
|
||||||
class Poule:
|
class Poule:
|
||||||
@ -110,6 +115,9 @@ class BaseTirage:
|
|||||||
]
|
]
|
||||||
return await self.event(Event(trigram, random.choice(available)))
|
return await self.event(Event(trigram, random.choice(available)))
|
||||||
|
|
||||||
|
async def accept(self, trigram, yes: bool):
|
||||||
|
return await self.event(Event(trigram, yes))
|
||||||
|
|
||||||
async def next(self, typ, team=None):
|
async def next(self, typ, team=None):
|
||||||
while True:
|
while True:
|
||||||
event = await self.queue.get()
|
event = await self.queue.get()
|
||||||
@ -148,6 +156,7 @@ class BaseTirage:
|
|||||||
# TODO: avoid KeyError
|
# TODO: avoid KeyError
|
||||||
if dices[event.team] is None:
|
if dices[event.team] is None:
|
||||||
dices[event.team] = event.value
|
dices[event.team] = event.value
|
||||||
|
await self.info_dice(event.team, event.value)
|
||||||
else:
|
else:
|
||||||
await self.warn_twice(int)
|
await self.warn_twice(int)
|
||||||
|
|
||||||
@ -173,6 +182,9 @@ class BaseTirage:
|
|||||||
return poules
|
return poules
|
||||||
|
|
||||||
async def draw_poule(self, poule):
|
async def draw_poule(self, poule):
|
||||||
|
|
||||||
|
await self.start_draw_poule(poule)
|
||||||
|
|
||||||
# Trigrams in draw order
|
# Trigrams in draw order
|
||||||
trigrams = await self.draw_order(poule)
|
trigrams = await self.draw_order(poule)
|
||||||
|
|
||||||
@ -184,25 +196,27 @@ class BaseTirage:
|
|||||||
if team.accepted_problems[poule.rnd] is not None:
|
if team.accepted_problems[poule.rnd] is not None:
|
||||||
# The team already accepted a problem
|
# The team already accepted a problem
|
||||||
current += 1
|
current += 1
|
||||||
|
current %= len(teams)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Choose problem
|
# Choose problem
|
||||||
await self.start_select_pb(team)
|
await self.start_select_pb(team)
|
||||||
event = await self.next(str, team.name)
|
pevent = await self.next(str, team.name)
|
||||||
# TODO: Add check for already selected / taken by someone else
|
# TODO: Add check for already selected / taken by someone else
|
||||||
# This is not a bug for now, since it cannot happen yet
|
# This is not a bug for now, since it cannot happen yet
|
||||||
await self.info_draw_pb(team, event.value, rnd)
|
await self.info_draw_pb(team, pevent.value, poule.rnd)
|
||||||
|
|
||||||
# Accept it
|
# Accept it
|
||||||
accept = await self.next(bool, team.name)
|
accept = await self.next(bool, team.name)
|
||||||
if accept:
|
if accept.value:
|
||||||
team.accepted_problems[poule.rnd] = event.value
|
team.accepted_problems[poule.rnd] = pevent.value
|
||||||
await self.info_accepted(team, event.value)
|
await self.info_accepted(team, pevent.value)
|
||||||
else:
|
else:
|
||||||
await self.info_rejected(team, event.value, rnd=poule.rnd)
|
await self.info_rejected(team, pevent.value, rnd=poule.rnd)
|
||||||
team.rejected[poule.rnd].add(event.value)
|
team.rejected[poule.rnd].add(pevent.value)
|
||||||
|
|
||||||
current += 1
|
current += 1
|
||||||
|
current %= len(teams)
|
||||||
|
|
||||||
await self.annonce_poule(poule)
|
await self.annonce_poule(poule)
|
||||||
|
|
||||||
@ -212,7 +226,7 @@ class BaseTirage:
|
|||||||
teams = self.poules[poule]
|
teams = self.poules[poule]
|
||||||
dices = await self.get_dices(teams)
|
dices = await self.get_dices(teams)
|
||||||
|
|
||||||
order = sorted(self.teams, key=lambda t: dices[t], reverse=True)
|
order = sorted(teams, key=lambda t: dices[t], reverse=True)
|
||||||
|
|
||||||
await self.annonce_draw_order(order)
|
await self.annonce_draw_order(order)
|
||||||
return order
|
return order
|
||||||
@ -232,6 +246,9 @@ class BaseTirage:
|
|||||||
async def start_make_poule(self, rnd):
|
async def start_make_poule(self, rnd):
|
||||||
"""Called when it starts drawing the poules for round `rnd`"""
|
"""Called when it starts drawing the poules for round `rnd`"""
|
||||||
|
|
||||||
|
async def start_draw_poule(self, poule):
|
||||||
|
"""Called when we start a poule."""
|
||||||
|
|
||||||
async def start_draw_order(self, poule):
|
async def start_draw_order(self, poule):
|
||||||
"""Called when we start to draw the order."""
|
"""Called when we start to draw the order."""
|
||||||
|
|
||||||
@ -253,6 +270,9 @@ class BaseTirage:
|
|||||||
async def info_finish(self):
|
async def info_finish(self):
|
||||||
"""Called when the tirage has ended."""
|
"""Called when the tirage has ended."""
|
||||||
|
|
||||||
|
async def info_dice(self, team, dice):
|
||||||
|
"""Called on a dice roll."""
|
||||||
|
|
||||||
async def info_draw_pb(self, team, pb, rnd):
|
async def info_draw_pb(self, team, pb, rnd):
|
||||||
"""Called when a team draws a problem."""
|
"""Called when a team draws a problem."""
|
||||||
|
|
||||||
@ -262,3 +282,7 @@ class BaseTirage:
|
|||||||
async def info_rejected(self, team, pb, rnd):
|
async def info_rejected(self, team, pb, rnd):
|
||||||
"""Called when a team rejects a problem,
|
"""Called when a team rejects a problem,
|
||||||
before it is added to the rejected set."""
|
before it is added to the rejected set."""
|
||||||
|
|
||||||
|
|
||||||
|
def setup(_):
|
||||||
|
pass
|
||||||
|
@ -18,6 +18,7 @@ from src.constants import *
|
|||||||
from src.core import CustomBot
|
from src.core import CustomBot
|
||||||
|
|
||||||
COGS_SHORTCUTS = {
|
COGS_SHORTCUTS = {
|
||||||
|
"bt": "src.base_tirage",
|
||||||
"c": "src.constants",
|
"c": "src.constants",
|
||||||
"d": "tirages",
|
"d": "tirages",
|
||||||
"e": "errors",
|
"e": "errors",
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import random
|
import random
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
from collections import defaultdict, namedtuple
|
from collections import defaultdict, namedtuple
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
@ -15,7 +17,7 @@ from discord.ext import commands
|
|||||||
from discord.ext.commands import group, Cog, Context
|
from discord.ext.commands import group, Cog, Context
|
||||||
from discord.utils import get
|
from discord.utils import get
|
||||||
|
|
||||||
from src.base_tirage import BaseTirage
|
from src.base_tirage import BaseTirage, Event
|
||||||
from src.constants import *
|
from src.constants import *
|
||||||
from src.core import CustomBot
|
from src.core import CustomBot
|
||||||
from src.errors import TfjmError, UnwantedCommand
|
from src.errors import TfjmError, UnwantedCommand
|
||||||
@ -34,7 +36,7 @@ Record = namedtuple("Record", ["name", "pb", "penalite"])
|
|||||||
|
|
||||||
def delete_and_pm(f):
|
def delete_and_pm(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapper(self, *args, **kwargs):
|
async def wrapper(self, *args, **kwargs):
|
||||||
await self.ctx.message.delete()
|
await self.ctx.message.delete()
|
||||||
await self.ctx.author.send(
|
await self.ctx.author.send(
|
||||||
"J'ai supprimé ton message:\n> "
|
"J'ai supprimé ton message:\n> "
|
||||||
@ -47,6 +49,8 @@ def delete_and_pm(f):
|
|||||||
if msg:
|
if msg:
|
||||||
await self.ctx.author.send(f"Raison: {msg}")
|
await self.ctx.author.send(f"Raison: {msg}")
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def send_all(f):
|
def send_all(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
@ -57,12 +61,33 @@ def send_all(f):
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def safe(f):
|
||||||
|
@wraps(f)
|
||||||
|
async def wrapper(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
return await f(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_tb(e.__traceback__, file=sys.stderr)
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class DiscordTirage(BaseTirage):
|
class DiscordTirage(BaseTirage):
|
||||||
def __init__(self, ctx, *teams, fmt):
|
def __init__(self, ctx, *teams, fmt):
|
||||||
super(DiscordTirage, self).__init__(*teams, fmt=fmt)
|
super(DiscordTirage, self).__init__(*teams, fmt=fmt)
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
self.captain_mention = get(ctx.guild.roles, name=Role.CAPTAIN).mention
|
self.captain_mention = get(ctx.guild.roles, name=Role.CAPTAIN).mention
|
||||||
|
|
||||||
|
def team_for(self, author):
|
||||||
|
for team in self.teams:
|
||||||
|
if get(author.roles, name=team):
|
||||||
|
return team
|
||||||
|
return None
|
||||||
|
|
||||||
|
def mention(self, trigram):
|
||||||
|
return get(self.ctx.guild.roles, name=trigram).mention
|
||||||
|
|
||||||
def records(self, teams, rnd):
|
def records(self, teams, rnd):
|
||||||
"""Get the strings needed for show the tirage in a list of Records"""
|
"""Get the strings needed for show the tirage in a list of Records"""
|
||||||
|
|
||||||
@ -75,6 +100,36 @@ class DiscordTirage(BaseTirage):
|
|||||||
for team in teams
|
for team in teams
|
||||||
]
|
]
|
||||||
|
|
||||||
|
async def dice(self, ctx, n):
|
||||||
|
self.ctx = ctx
|
||||||
|
trigram = self.team_for(ctx.author)
|
||||||
|
|
||||||
|
if trigram is None:
|
||||||
|
await self.warn_wrong_team(None, None)
|
||||||
|
elif n == 100:
|
||||||
|
await super().dice(trigram)
|
||||||
|
else:
|
||||||
|
await self.warn_unwanted(int, int)
|
||||||
|
|
||||||
|
async def rproblem(self, ctx):
|
||||||
|
self.ctx = ctx
|
||||||
|
trigram = self.team_for(ctx.author)
|
||||||
|
|
||||||
|
if trigram is None:
|
||||||
|
await self.warn_wrong_team(None, None)
|
||||||
|
else:
|
||||||
|
await super().rproblem(trigram)
|
||||||
|
|
||||||
|
async def accept(self, ctx, yes):
|
||||||
|
self.ctx = ctx
|
||||||
|
trigram = self.team_for(ctx.author)
|
||||||
|
|
||||||
|
if trigram is None:
|
||||||
|
await self.warn_wrong_team(None, None)
|
||||||
|
else:
|
||||||
|
await super().accept(trigram, yes)
|
||||||
|
|
||||||
|
@safe
|
||||||
@delete_and_pm
|
@delete_and_pm
|
||||||
async def warn_unwanted(self, wanted: Type, got: Type):
|
async def warn_unwanted(self, wanted: Type, got: Type):
|
||||||
|
|
||||||
@ -91,6 +146,8 @@ class DiscordTirage(BaseTirage):
|
|||||||
else "Halte là ! Ce serait bien de tirer un problème d'abord... "
|
else "Halte là ! Ce serait bien de tirer un problème d'abord... "
|
||||||
"et peut-être qu'il te plaira :) ",
|
"et peut-être qu'il te plaira :) ",
|
||||||
(bool, int): "Il tirer un dé avec `!dice 100` d'abord.",
|
(bool, int): "Il tirer un dé avec `!dice 100` d'abord.",
|
||||||
|
(int, int): "Il faut lancer un dé à 100 faces.",
|
||||||
|
(str, str): f"'{got}' n'est pas un problème valide.",
|
||||||
}
|
}
|
||||||
|
|
||||||
reason = texts.get((type(got), wanted))
|
reason = texts.get((type(got), wanted))
|
||||||
@ -100,10 +157,12 @@ class DiscordTirage(BaseTirage):
|
|||||||
reason = "Je sais pas, le code ne devrait pas venir ici..."
|
reason = "Je sais pas, le code ne devrait pas venir ici..."
|
||||||
return reason
|
return reason
|
||||||
|
|
||||||
|
@safe
|
||||||
@delete_and_pm
|
@delete_and_pm
|
||||||
async def warn_wrong_team(self, expected, got):
|
async def warn_wrong_team(self, expected, got):
|
||||||
return "ce n'était pas à ton tour."
|
return "ce n'était pas à ton tour."
|
||||||
|
|
||||||
|
@safe
|
||||||
async def warn_colisions(self, collisions: List[str]):
|
async def warn_colisions(self, collisions: List[str]):
|
||||||
await self.ctx.send(
|
await self.ctx.send(
|
||||||
f"Les equipes {french_join(collisions)} ont fait le même résultat "
|
f"Les equipes {french_join(collisions)} ont fait le même résultat "
|
||||||
@ -111,6 +170,7 @@ class DiscordTirage(BaseTirage):
|
|||||||
"Le nouveau lancer effacera l'ancien."
|
"Le nouveau lancer effacera l'ancien."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@safe
|
||||||
@delete_and_pm
|
@delete_and_pm
|
||||||
async def warn_twice(self, typ: Type):
|
async def warn_twice(self, typ: Type):
|
||||||
|
|
||||||
@ -120,6 +180,7 @@ class DiscordTirage(BaseTirage):
|
|||||||
print("Weird, DiscordTirage.warn_twice was called with", typ)
|
print("Weird, DiscordTirage.warn_twice was called with", typ)
|
||||||
return "Je sais pas, le code ne devrait pas venir ici..."
|
return "Je sais pas, le code ne devrait pas venir ici..."
|
||||||
|
|
||||||
|
@safe
|
||||||
@send_all
|
@send_all
|
||||||
async def start_make_poule(self, rnd):
|
async def start_make_poule(self, rnd):
|
||||||
if rnd == 0:
|
if rnd == 0:
|
||||||
@ -135,50 +196,82 @@ class DiscordTirage(BaseTirage):
|
|||||||
f"afin de déterminer les poules du second tour."
|
f"afin de déterminer les poules du second tour."
|
||||||
)
|
)
|
||||||
|
|
||||||
async def start_draw_order(self, poule):
|
@safe
|
||||||
print(poule)
|
@send_all
|
||||||
|
async def start_draw_poule(self, poule):
|
||||||
|
yield (
|
||||||
|
f"Nous allons commencer le tirage pour la poule **{poule}** entre les "
|
||||||
|
f"équipes {french_join('**%s**' %p for p in self.poules[poule])}. Les autres équipes peuvent "
|
||||||
|
f"quitter le salon si elles le souhaitent et revenir quand elles seront mentionnées."
|
||||||
|
)
|
||||||
|
|
||||||
|
@safe
|
||||||
|
@send_all
|
||||||
|
async def start_draw_order(self, poule):
|
||||||
|
mentions = [self.mention(tri) for tri in self.poules[poule]]
|
||||||
|
yield (
|
||||||
|
f"Les capitaines de {french_join(mentions)}, vous pouvez à nouveau lancer un dé 100, "
|
||||||
|
f"qui déterminera l'ordre de tirage des problèmes. Le plus grand lancer tirera en premier "
|
||||||
|
f"les problèmes."
|
||||||
|
)
|
||||||
|
|
||||||
|
@safe
|
||||||
async def start_select_pb(self, team):
|
async def start_select_pb(self, team):
|
||||||
await self.ctx.send(f"C'est au tour de {team.mention} de choisir un problème.")
|
await self.ctx.send(f"C'est au tour de {team.mention} de choisir un problème.")
|
||||||
|
|
||||||
|
@safe
|
||||||
|
@send_all
|
||||||
async def annonce_poules(self, poules):
|
async def annonce_poules(self, poules):
|
||||||
print(poules)
|
first = "\n".join(
|
||||||
|
f"{p}: {french_join(t)}" for p, t in poules.items() if p.rnd == 0
|
||||||
|
)
|
||||||
|
second = "\n".join(
|
||||||
|
f"{p}: {french_join(t)}" for p, t in poules.items() if p.rnd == 1
|
||||||
|
)
|
||||||
|
yield (
|
||||||
|
f"Les poules sont donc, pour le premier tour :"
|
||||||
|
f"```{first}```\n"
|
||||||
|
f"Et pour le second tour :"
|
||||||
|
f"```{second}```"
|
||||||
|
)
|
||||||
|
|
||||||
|
@safe
|
||||||
@send_all
|
@send_all
|
||||||
async def annonce_draw_order(self, order):
|
async def annonce_draw_order(self, order):
|
||||||
order_str = "\n ".join(f"{i}) {tri}" for i, tri in enumerate(order))
|
order_str = "\n".join(f"{i+1}) {tri}" for i, tri in enumerate(order))
|
||||||
yield "L'ordre de tirage des problèmes pour ce tour est donc: \n" + order_str
|
yield f"L'ordre de tirage des problèmes pour ce tour est donc: ```{order_str}```"
|
||||||
|
|
||||||
|
@safe
|
||||||
async def annonce_poule(self, poule):
|
async def annonce_poule(self, poule):
|
||||||
teams = [self.teams[tri] for tri in self.poules[poule]]
|
teams = [self.teams[tri] for tri in self.poules[poule]]
|
||||||
|
|
||||||
if len(teams) == 3:
|
if len(teams) == 3:
|
||||||
table = """```
|
table = """```
|
||||||
+-----+---------+---------+---------+
|
+-----+---------+---------+---------+
|
||||||
| | Phase 1 | Phase 2 | Phase 3 |
|
| | Phase 1 | Phase 2 | Phase 3 |
|
||||||
| | Pb {0.pb} | Pb {1.pb} | Pb {2.pb} |
|
| | Pb {0.pb} | Pb {1.pb} | Pb {2.pb} |
|
||||||
+-----+---------+---------+---------+
|
+-----+---------+---------+---------+
|
||||||
| {0.name} | Déf | Rap | Opp |
|
| {0.name} | Déf | Rap | Opp |
|
||||||
+-----+---------+---------+---------+
|
+-----+---------+---------+---------+
|
||||||
| {1.name} | Opp | Déf | Rap |
|
| {1.name} | Opp | Déf | Rap |
|
||||||
+-----+---------+---------+---------+
|
+-----+---------+---------+---------+
|
||||||
| {2.name} | Rap | Opp | Déf |
|
| {2.name} | Rap | Opp | Déf |
|
||||||
+-----+---------+---------+---------+
|
+-----+---------+---------+---------+
|
||||||
```"""
|
```"""
|
||||||
else:
|
else:
|
||||||
table = """```
|
table = """```
|
||||||
+-----+---------+---------+---------+---------+
|
+-----+---------+---------+---------+---------+
|
||||||
| | Phase 1 | Phase 2 | Phase 3 | Phase 4 |
|
| | Phase 1 | Phase 2 | Phase 3 | Phase 4 |
|
||||||
| | Pb {0.pb} | Pb {1.pb} | Pb {2.pb} | Pb {3.pb} |
|
| | Pb {0.pb} | Pb {1.pb} | Pb {2.pb} | Pb {3.pb} |
|
||||||
+-----+---------+---------+---------+---------+
|
+-----+---------+---------+---------+---------+
|
||||||
| {0.name} | Déf | | Rap | Opp |
|
| {0.name} | Déf | | Rap | Opp |
|
||||||
+-----+---------+---------+---------+---------+
|
+-----+---------+---------+---------+---------+
|
||||||
| {1.name} | Opp | Déf | | Rap |
|
| {1.name} | Opp | Déf | | Rap |
|
||||||
+-----+---------+---------+---------+---------+
|
+-----+---------+---------+---------+---------+
|
||||||
| {2.name} | Rap | Opp | Déf | |
|
| {2.name} | Rap | Opp | Déf | |
|
||||||
+-----+---------+---------+---------+---------+
|
+-----+---------+---------+---------+---------+
|
||||||
| {3.name} | | Rap | Opp | Déf |
|
| {3.name} | | Rap | Opp | Déf |
|
||||||
+-----+---------+---------+---------+---------+
|
+-----+---------+---------+---------+---------+
|
||||||
```"""
|
```"""
|
||||||
|
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
@ -205,6 +298,7 @@ class DiscordTirage(BaseTirage):
|
|||||||
|
|
||||||
await self.ctx.send(embed=embed)
|
await self.ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@safe
|
||||||
@send_all
|
@send_all
|
||||||
async def info_start(self):
|
async def info_start(self):
|
||||||
yield (
|
yield (
|
||||||
@ -225,6 +319,7 @@ class DiscordTirage(BaseTirage):
|
|||||||
"l'ordre de tirage pour le tour et les problèmes."
|
"l'ordre de tirage pour le tour et les problèmes."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@safe
|
||||||
@send_all
|
@send_all
|
||||||
async def info_finish(self):
|
async def info_finish(self):
|
||||||
yield "Le tirage est fini, merci à tout le monde !"
|
yield "Le tirage est fini, merci à tout le monde !"
|
||||||
@ -235,9 +330,19 @@ class DiscordTirage(BaseTirage):
|
|||||||
# TODO: Save it
|
# TODO: Save it
|
||||||
# TODO: make them available with the api
|
# TODO: make them available with the api
|
||||||
|
|
||||||
|
@safe
|
||||||
|
@send_all
|
||||||
|
async def info_dice(self, team, dice):
|
||||||
|
yield f"L'équipe {team} a lancé un... {dice} :game_die:"
|
||||||
|
|
||||||
|
@safe
|
||||||
|
@send_all
|
||||||
async def info_draw_pb(self, team, pb, rnd):
|
async def info_draw_pb(self, team, pb, rnd):
|
||||||
|
|
||||||
|
yield (f"L'équipe {self.mention(team.name)} a tiré... **{pb}**")
|
||||||
|
|
||||||
if pb in team.rejected[rnd]:
|
if pb in team.rejected[rnd]:
|
||||||
await self.ctx.send(
|
yield (
|
||||||
f"Vous avez déjà refusé **{pb}**, "
|
f"Vous avez déjà refusé **{pb}**, "
|
||||||
f"vous pouvez le refuser à nouveau (`!non`) et "
|
f"vous pouvez le refuser à nouveau (`!non`) et "
|
||||||
f"tirer immédiatement un nouveau problème "
|
f"tirer immédiatement un nouveau problème "
|
||||||
@ -245,19 +350,20 @@ class DiscordTirage(BaseTirage):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if len(team.rejected[rnd]) >= MAX_REFUSE:
|
if len(team.rejected[rnd]) >= MAX_REFUSE:
|
||||||
await self.ctx.send(
|
yield (
|
||||||
f"Vous pouvez accepter ou refuser **{pb}** "
|
f"Vous pouvez accepter ou refuser **{pb}** "
|
||||||
f"mais si vous choisissez de le refuser, il y "
|
f"mais si vous choisissez de le refuser, il y "
|
||||||
f"aura une pénalité de 0.5 sur le multiplicateur du "
|
f"aura une pénalité de 0.5 sur le multiplicateur du "
|
||||||
f"défenseur."
|
f"défenseur."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await self.ctx.send(
|
yield (
|
||||||
f"Vous pouvez accepter (`!oui`) ou refuser (`!non`) **{pb}**. "
|
f"Vous pouvez l'accepter (`!oui`) ou le refuser (`!non`). "
|
||||||
f"Il reste {MAX_REFUSE - len(team.rejected[rnd])} refus sans pénalité "
|
f"Il reste {MAX_REFUSE - len(team.rejected[rnd])} refus sans pénalité "
|
||||||
f"pour {team.mention}."
|
f"pour {team.mention}."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@safe
|
||||||
async def info_accepted(self, team, pb):
|
async def info_accepted(self, team, pb):
|
||||||
await self.ctx.send(
|
await self.ctx.send(
|
||||||
f"L'équipe {team.mention} a accepté "
|
f"L'équipe {team.mention} a accepté "
|
||||||
@ -265,6 +371,7 @@ class DiscordTirage(BaseTirage):
|
|||||||
f"ne peuvent plus l'accepter."
|
f"ne peuvent plus l'accepter."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@safe
|
||||||
async def info_rejected(self, team, pb, rnd):
|
async def info_rejected(self, team, pb, rnd):
|
||||||
msg = f"{team.mention} a refusé **{pb}** "
|
msg = f"{team.mention} a refusé **{pb}** "
|
||||||
if pb in team.rejected[rnd]:
|
if pb in team.rejected[rnd]:
|
||||||
@ -274,152 +381,7 @@ class DiscordTirage(BaseTirage):
|
|||||||
await self.ctx.send(msg)
|
await self.ctx.send(msg)
|
||||||
|
|
||||||
|
|
||||||
class Tirage(yaml.YAMLObject):
|
class TiragePhase:
|
||||||
yaml_tag = "Tirage"
|
|
||||||
|
|
||||||
def __init__(self, ctx, channel, teams):
|
|
||||||
assert len(teams) in (3, 4)
|
|
||||||
|
|
||||||
self.channel: int = channel
|
|
||||||
self.teams = [Team(team) for team in teams]
|
|
||||||
self.phase = TirageOrderPhase(self, round=0)
|
|
||||||
|
|
||||||
async def update_phase(self, ctx):
|
|
||||||
if self.phase.finished():
|
|
||||||
next_class = await self.phase.next(ctx)
|
|
||||||
|
|
||||||
if next_class is None:
|
|
||||||
await self.end(ctx)
|
|
||||||
else:
|
|
||||||
# Continue on the same round.
|
|
||||||
# If a Phase wants to change the round
|
|
||||||
# it needs to change its own round.
|
|
||||||
self.phase = next_class(self, self.phase.round)
|
|
||||||
await self.phase.start(ctx)
|
|
||||||
|
|
||||||
async def end(self, ctx):
|
|
||||||
self.phase = None
|
|
||||||
if False:
|
|
||||||
# Allow everyone to send messages again
|
|
||||||
send = discord.PermissionOverwrite() # reset
|
|
||||||
await ctx.channel.edit(overwrites={ctx.guild.default_role: send})
|
|
||||||
|
|
||||||
tl = {}
|
|
||||||
if File.TIRAGES.exists():
|
|
||||||
with open(File.TIRAGES) as f:
|
|
||||||
tl = yaml.load(f)
|
|
||||||
else:
|
|
||||||
File.TIRAGES.touch()
|
|
||||||
|
|
||||||
key = max(0, *tl.keys()) + 1
|
|
||||||
tl[key] = self
|
|
||||||
with open(File.TIRAGES, "w") as f:
|
|
||||||
yaml.dump(tl, f)
|
|
||||||
|
|
||||||
await ctx.send(
|
|
||||||
f"A tout moment, ce rapport peut " f"être envoyé avec `!draw show {key}`"
|
|
||||||
)
|
|
||||||
|
|
||||||
from src.tfjm_discord_bot import tirages
|
|
||||||
|
|
||||||
if self.channel in tirages:
|
|
||||||
del tirages[self.channel]
|
|
||||||
|
|
||||||
async def show_tex(self, ctx):
|
|
||||||
if len(self.teams) == 3:
|
|
||||||
table = r"""
|
|
||||||
\begin{{table}}[]
|
|
||||||
\begin{{tabular}}{{|c|c|c|c|}}
|
|
||||||
\hline
|
|
||||||
& Phase 1 - {0.pb} & Phase 2 - {1.pb} & Phase {2.pb} \\\\ \hline
|
|
||||||
{0.name} & Déf & Rap & Opp \\ \hline
|
|
||||||
{1.name} & Opp & Déf & Rap \\ \hline
|
|
||||||
{2.name} & Rap & Opp & Déf \\ \hline
|
|
||||||
\end{{tabular}}
|
|
||||||
\end{{table}}
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
table = r"""
|
|
||||||
\begin{{table}}[]
|
|
||||||
\begin{{tabular}}{{|c|c|c|c|c|}}
|
|
||||||
\hline
|
|
||||||
& Phase 1 - {0.pb} & Phase 2 - {1.pb} & Phase 3 - {2.pb} & Phase 4 - {3.pb} \\\\ \hline
|
|
||||||
{0.name} & Déf & & Rap & Opp \\ \hline
|
|
||||||
{1.name} & Opp & Déf & & Rap \\ \hline
|
|
||||||
{2.name} & Rap & Opp & Déf & \\ \hline
|
|
||||||
{3.name} & & Rap & Opp & Déf \\ \hline
|
|
||||||
\end{{tabular}}
|
|
||||||
\end{{table}}
|
|
||||||
"""
|
|
||||||
msg = ",tex "
|
|
||||||
for i in (0, 1):
|
|
||||||
msg += rf"\section{{ {ROUND_NAMES[i].capitalize()} }}"
|
|
||||||
msg += table.format(*self.records(i))
|
|
||||||
await ctx.send(msg)
|
|
||||||
|
|
||||||
|
|
||||||
class Phase:
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class OrderPhase(Phase):
|
|
||||||
def __init__(self, tirage, round, name, order_name, reverse=False):
|
|
||||||
super().__init__(tirage, round)
|
|
||||||
self.name = name
|
|
||||||
self.reverse = reverse
|
|
||||||
self.order_name = order_name
|
|
||||||
|
|
||||||
def order_for(self, team):
|
|
||||||
return getattr(team, self.order_name)[self.round]
|
|
||||||
|
|
||||||
def set_order_for(self, team, order):
|
|
||||||
getattr(team, self.order_name)[self.round] = order
|
|
||||||
|
|
||||||
async def dice(self, ctx, author, dice):
|
|
||||||
team = self.team_for(author)
|
|
||||||
|
|
||||||
if self.order_for(team) is None:
|
|
||||||
self.set_order_for(team, dice)
|
|
||||||
await ctx.send(f"L'équipe {team.mention} a obtenu... **{dice}**")
|
|
||||||
else:
|
|
||||||
raise UnwantedCommand("tu as déjà lancé un dé !")
|
|
||||||
|
|
||||||
def finished(self) -> bool:
|
|
||||||
return all(self.order_for(team) is not None for team in self.teams)
|
|
||||||
|
|
||||||
async def next(self, ctx) -> "Type[Phase]":
|
|
||||||
orders = [self.order_for(team) for team in self.teams]
|
|
||||||
if len(set(orders)) == len(orders):
|
|
||||||
# All dice are different: good
|
|
||||||
self.teams.sort(key=self.order_for, reverse=self.reverse)
|
|
||||||
await ctx.send(
|
|
||||||
f"L'ordre {self.name} pour ce tour est donc :\n"
|
|
||||||
" - "
|
|
||||||
+ "\n - ".join(
|
|
||||||
f"{team.mention} ({self.order_for(team)})" for team in self.teams
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return self.NEXT
|
|
||||||
else:
|
|
||||||
# Find dice that are the same
|
|
||||||
count = defaultdict(list)
|
|
||||||
for team in self.teams:
|
|
||||||
count[self.order_for(team)].append(team)
|
|
||||||
|
|
||||||
re_do = []
|
|
||||||
for teams in count.values():
|
|
||||||
if len(teams) > 1:
|
|
||||||
re_do.extend(teams)
|
|
||||||
|
|
||||||
teams_str = ", ".join(team.mention for team in re_do)
|
|
||||||
|
|
||||||
for team in re_do:
|
|
||||||
self.set_order_for(team, None)
|
|
||||||
# We need to do this phase again.
|
|
||||||
return self.__class__
|
|
||||||
|
|
||||||
|
|
||||||
class TiragePhase(Phase):
|
|
||||||
"""The phase where captains accept or refuse random problems."""
|
"""The phase where captains accept or refuse random problems."""
|
||||||
|
|
||||||
def __init__(self, tirage, round=0):
|
def __init__(self, tirage, round=0):
|
||||||
@ -654,6 +616,15 @@ class TirageCog(Cog, name="Tirages"):
|
|||||||
dice = random.randint(1, n)
|
dice = random.randint(1, n)
|
||||||
return f"{ctx.author.mention} : {Emoji.DICE} {dice}"
|
return f"{ctx.author.mention} : {Emoji.DICE} {dice}"
|
||||||
|
|
||||||
|
@commands.command(name="dice-all", aliases=["da"], hidden=True)
|
||||||
|
@commands.has_role(Role.DEV)
|
||||||
|
async def dice_all_cmd(self, ctx, *teams):
|
||||||
|
channel = ctx.channel.id
|
||||||
|
if channel in self.tirages:
|
||||||
|
for t in teams:
|
||||||
|
d = random.randint(1, 100)
|
||||||
|
await self.tirages[channel].event(Event(t, d))
|
||||||
|
|
||||||
@commands.command(
|
@commands.command(
|
||||||
name="random-problem",
|
name="random-problem",
|
||||||
aliases=["rp", "problème-aléatoire", "probleme-aleatoire", "pa"],
|
aliases=["rp", "problème-aléatoire", "probleme-aleatoire", "pa"],
|
||||||
@ -663,7 +634,7 @@ class TirageCog(Cog, name="Tirages"):
|
|||||||
|
|
||||||
channel = ctx.channel.id
|
channel = ctx.channel.id
|
||||||
if channel in self.tirages:
|
if channel in self.tirages:
|
||||||
await self.tirages[channel].choose_problem(ctx)
|
await self.tirages[channel].rproblem(ctx)
|
||||||
else:
|
else:
|
||||||
problem = random.choice(PROBLEMS)
|
problem = random.choice(PROBLEMS)
|
||||||
await ctx.send(f"Le problème tiré est... **{problem}**")
|
await ctx.send(f"Le problème tiré est... **{problem}**")
|
||||||
@ -712,7 +683,7 @@ class TirageCog(Cog, name="Tirages"):
|
|||||||
name="start", usage="équipe1 équipe2 équipe3 (équipe4)",
|
name="start", usage="équipe1 équipe2 équipe3 (équipe4)",
|
||||||
)
|
)
|
||||||
@commands.has_any_role(*Role.ORGAS)
|
@commands.has_any_role(*Role.ORGAS)
|
||||||
async def start(self, ctx: Context, *teams: discord.Role):
|
async def start(self, ctx: Context, fmt, *teams: discord.Role):
|
||||||
"""
|
"""
|
||||||
(orga) Commence un tirage avec 3 ou 4 équipes.
|
(orga) Commence un tirage avec 3 ou 4 équipes.
|
||||||
|
|
||||||
@ -730,28 +701,25 @@ class TirageCog(Cog, name="Tirages"):
|
|||||||
"il est possible d'en commencer un autre sur une autre channel."
|
"il est possible d'en commencer un autre sur une autre channel."
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(teams) not in (3, 4):
|
try:
|
||||||
|
fmt = list(map(int, fmt.split("+")))
|
||||||
|
except ValueError:
|
||||||
raise TfjmError(
|
raise TfjmError(
|
||||||
"Il faut 3 ou 4 équipes pour un tirage. "
|
"Le premier argument doit être le format du tournoi, "
|
||||||
"Exemple: `!draw start @AAA @BBB @CCC`"
|
"par exemple `3+3` pour deux poules à trois équipes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not set(fmt).issubset({3, 4}):
|
||||||
|
raise TfjmError("Seuls les poules à 3 ou 4 équipes sont suportées.")
|
||||||
|
|
||||||
# Here all data should be valid
|
# Here all data should be valid
|
||||||
|
|
||||||
# Prevent everyone from writing except Capitaines, Orga, CNO, Benevole
|
self.tirages[channel_id] = DiscordTirage(ctx, *teams, fmt=fmt)
|
||||||
if False:
|
await self.tirages[channel_id].run()
|
||||||
read = discord.PermissionOverwrite(send_messages=False)
|
|
||||||
send = discord.PermissionOverwrite(send_messages=True)
|
|
||||||
r = lambda role_name: get(ctx.guild.roles, name=role_name)
|
|
||||||
overwrites = {
|
|
||||||
ctx.guild.default_role: read,
|
|
||||||
r(Role.CAPTAIN): send,
|
|
||||||
r(Role.BENEVOLE): send,
|
|
||||||
}
|
|
||||||
await channel.edit(overwrites=overwrites)
|
|
||||||
|
|
||||||
self.tirages[channel_id] = Tirage(ctx, channel_id, teams)
|
if self.tirages[channel_id]:
|
||||||
await self.tirages[channel_id].phase.start(ctx)
|
# Check if aborted in an other way
|
||||||
|
del self.tirages[channel_id]
|
||||||
|
|
||||||
@draw_group.command(name="abort")
|
@draw_group.command(name="abort")
|
||||||
@commands.has_any_role(*Role.ORGAS)
|
@commands.has_any_role(*Role.ORGAS)
|
||||||
@ -768,32 +736,32 @@ class TirageCog(Cog, name="Tirages"):
|
|||||||
if channel_id in self.tirages:
|
if channel_id in self.tirages:
|
||||||
print(self.tirages, channel_id)
|
print(self.tirages, channel_id)
|
||||||
print(self.tirages[channel_id])
|
print(self.tirages[channel_id])
|
||||||
|
del self.tirages[channel_id]
|
||||||
await self.tirages[channel_id].end(ctx)
|
|
||||||
await ctx.send("Le tirage est annulé.")
|
await ctx.send("Le tirage est annulé.")
|
||||||
else:
|
else:
|
||||||
await ctx.send("Il n'y a pas de tirage en cours.")
|
await ctx.send("Il n'y a pas de tirage en cours.")
|
||||||
|
|
||||||
@draw_group.command(name="skip", aliases=["s"])
|
#
|
||||||
@commands.has_role(Role.DEV)
|
# @draw_group.command(name="skip", aliases=["s"])
|
||||||
async def draw_skip(self, ctx, *teams: discord.Role):
|
# @commands.has_role(Role.DEV)
|
||||||
"""(dev) Passe certaines phases du tirage."""
|
# async def draw_skip(self, ctx, *teams: discord.Role):
|
||||||
channel = ctx.channel.id
|
# """(dev) Passe certaines phases du tirage."""
|
||||||
self.tirages[channel] = tirage = Tirage(ctx, channel, teams)
|
# channel = ctx.channel.id
|
||||||
|
# self.tirages[channel] = tirage = Tirage(ctx, channel, teams)
|
||||||
|
#
|
||||||
|
# tirage.phase = TiragePhase(tirage, round=1)
|
||||||
|
# for i, team in enumerate(tirage.teams):
|
||||||
|
# team.tirage_order = [i + 1, i + 1]
|
||||||
|
# team.passage_order = [i + 1, i + 1]
|
||||||
|
# team.accepted_problems = [PROBLEMS[i], PROBLEMS[-i - 1]]
|
||||||
|
# tirage.teams[0].rejected = [{PROBLEMS[3]}, set(PROBLEMS[4:8])]
|
||||||
|
# tirage.teams[1].rejected = [{PROBLEMS[7]}, set()]
|
||||||
|
#
|
||||||
|
# await ctx.send(f"Skipping to {tirage.phase.__class__.__name__}.")
|
||||||
|
# await tirage.phase.start(ctx)
|
||||||
|
# await tirage.update_phase(ctx)
|
||||||
|
|
||||||
tirage.phase = TiragePhase(tirage, round=1)
|
def get_tirages(self) -> Dict[int, BaseTirage]:
|
||||||
for i, team in enumerate(tirage.teams):
|
|
||||||
team.tirage_order = [i + 1, i + 1]
|
|
||||||
team.passage_order = [i + 1, i + 1]
|
|
||||||
team.accepted_problems = [PROBLEMS[i], PROBLEMS[-i - 1]]
|
|
||||||
tirage.teams[0].rejected = [{PROBLEMS[3]}, set(PROBLEMS[4:8])]
|
|
||||||
tirage.teams[1].rejected = [{PROBLEMS[7]}, set()]
|
|
||||||
|
|
||||||
await ctx.send(f"Skipping to {tirage.phase.__class__.__name__}.")
|
|
||||||
await tirage.phase.start(ctx)
|
|
||||||
await tirage.update_phase(ctx)
|
|
||||||
|
|
||||||
def get_tirages(self) -> Dict[int, Tirage]:
|
|
||||||
if not File.TIRAGES.exists():
|
if not File.TIRAGES.exists():
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@ -812,6 +780,7 @@ class TirageCog(Cog, name="Tirages"):
|
|||||||
`!draw show 42` - Affiche le tirage n°42
|
`!draw show 42` - Affiche le tirage n°42
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
return
|
||||||
tirages = self.get_tirages()
|
tirages = self.get_tirages()
|
||||||
|
|
||||||
if not tirages:
|
if not tirages:
|
||||||
|
@ -5,6 +5,7 @@ from discord.ext.commands import Bot
|
|||||||
|
|
||||||
|
|
||||||
def french_join(l):
|
def french_join(l):
|
||||||
|
l = list(l)
|
||||||
start = ", ".join(l[:-1])
|
start = ", ".join(l[:-1])
|
||||||
return f"{start} et {l[-1]}"
|
return f"{start} et {l[-1]}"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user