Documentation
¶
Overview ¶
Package tournoi — moteur de tournoi de backgammon fondé sur un journal d'événements.
Intégration dans un logiciel hôte (Go, même processus) ¶
L'hôte conserve le journal (tournoi.Journal, un tableau JSON) et l'état courant peut être reconstruit à tout moment par Replay. Boucle type côté serveur :
cfg := tournoi.Config{Name: "Open", Phases: []tournoi.PhaseConfig{
{Kind: tournoi.KindSwissLives, Length: 7, Target: 16}, // suisse 2 vies continu, bascule à Σvies = 16
{Kind: tournoi.KindLivesBracket, Length: 9, FinalLength: 11}, // tableau à exemptions
}}
st, created, _ := tournoi.New(cfg, seed, time.Now())
journal := tournoi.Journal{created}
// inscriptions
ev := tournoi.Event{Kind: tournoi.EvPlayerAdded, Time: time.Now(), Player: &p}
st.Apply(ev); journal = append(journal, ev)
// boucle du TD
for _, a := range st.Propose() { // « lancer P3 contre P8 en 7 points, table 4 », etc.
ev, _ := st.EventFromAction(a, time.Now()) // le TD confirme
st.Apply(ev); journal = append(journal, ev)
}
// résultat saisi par le TD
ev = tournoi.ResultEvent("M12", "P3", 7, 4, time.Now())
st.Apply(ev); journal = append(journal, ev)
Corrections : ajouter un événement EvResultCorrected (jamais modifier le journal) ; l'état est recalculé et State.Warnings signale ce qui n'est plus cohérent (par exemple un match de tableau joué par le mauvais joueur). Forfaits : EvPlayerWithdrawn. Reprise après panne : Replay(journal).
Affichage : le paquet render fournit les composants HTML/SVG (arbres, tableau des vies, matchs en cours, classement, page complète). Prévision de fin : sim.Forecast(journal, now, K, …). Import de joueurs : players.FromCSV.
Règles pures : le paquet rules porte la dotation, la prévision de fin (temps de jeu, jour, fin après les pauses) et la feuille d'appariements en fonctions sans état ni E/S ; les méthodes de State, sim et render qui les appliquent en sont des enveloppes. Un hôte qui tient son propre état les appelle directement ; State.RulesMatches et Config.BreakIntervals en donnent les entrées depuis un State.
Déterminisme : Propose dépend seulement du journal (graine + nombre d'événements) ; le contenu des tirages est écrit dans les événements EvDraw, donc rejouer un journal ne dépend pas de l'algorithme d'appariement.
Package tournoi est un moteur de tournoi de backgammon fondé sur un journal d'événements.
L'hôte (le logiciel web) conserve la liste ordonnée des événements ; Replay reconstruit l'état ; Propose indique au directeur de tournoi (TD) quoi faire maintenant ; chaque décision du TD devient un événement. Aucun départage : les formats reposent sur les vies, les tableaux et les poules, avec barrages si nécessaire.
Index ¶
- Constants
- func New(cfg Config, seed int64, now time.Time) (*State, Event, error)
- func PhaseName(p PhaseConfig) string
- func Prizes(ranking []Rank, prizes []float64) map[PlayerID]float64
- func SectionName(name string) string
- type Absence
- type Action
- type ActionKind
- type Clock
- type Config
- type ConfigRefusal
- type Draw
- type Event
- func CancelEvent(id MatchID, now time.Time) Event
- func ConfigChangedEvent(cfg Config, now time.Time) Event
- func CorrectionEvent(id MatchID, winner PlayerID, scoreA, scoreB int, now time.Time) Event
- func ForfeitEvent(id MatchID, winner PlayerID, now time.Time) Event
- func LengthChangedEvent(phase, length int, now time.Time) Event
- func NoteEvent(text string, now time.Time) Event
- func PlayerAddedAtSlotEvent(p Player, slot Slot, now time.Time) Event
- func PlayerAddedEvent(p Player, now time.Time) Event
- func PlayerAvailableEvent(id PlayerID, now time.Time) Event
- func PlayerUnavailableEvent(id PlayerID, until time.Time, now time.Time) Event
- func PlayerUnavailableUntilRoundEvent(id PlayerID, round int, now time.Time) Event
- func PlayerUpdatedEvent(p Player, now time.Time) Event
- func PlayerWithdrawnAfterCurrentEvent(id PlayerID, now time.Time) Event
- func PlayerWithdrawnEvent(id PlayerID, now time.Time) Event
- func ReopenedEvent(now time.Time) Event
- func RepechageEvent(phase int, section string, withdrawn, replacement PlayerID, now time.Time) Event
- func ResultEvent(id MatchID, winner PlayerID, scoreA, scoreB int, now time.Time) Event
- func TableChangedEvent(id MatchID, table int, now time.Time) Event
- type EventKind
- type External
- type GMatch
- type Info
- type InfoCode
- type Journal
- type Label
- type LabelKind
- type Match
- type MatchID
- type MatchStatus
- type Note
- type NoteKind
- type PhaseConfig
- type PhaseState
- type Player
- type PlayerID
- type PlayerStatus
- type PrizePool
- type PrizeScale
- type Rank
- type ReasonCode
- type Retention
- type Section
- type Slot
- type Src
- type State
- func (s *State) Apply(ev Event) error
- func (s *State) CheckConfig(next Config) error
- func (s *State) ClockAt(now time.Time, start time.Time) Clock
- func (s *State) Distributable() float64
- func (s *State) EventFromAction(a Action, now time.Time) (Event, error)
- func (s *State) Expected(n int) time.Duration
- func (s *State) FreeSlots() []Slot
- func (s *State) Pool() float64
- func (s *State) PrizeAmounts(section string) []float64
- func (s *State) Propose() []Action
- func (s *State) ProposeAt(now time.Time) []Action
- func (s *State) ProposeWith(now time.Time, ext External) []Action
- func (s *State) Ranking() []Rank
- func (s *State) RulesMatches() []rules.Match
- func (s *State) RulesPhase(i int) *rules.Phase
- func (s *State) Running() []*Match
- func (s *State) SectionPrizes(section string) map[PlayerID]float64
- func (s *State) SectionRanking(name string) []Rank
- func (s *State) SlowMatches(now time.Time, facteur float64) []*Match
- func (s *State) StandingsCSV() []byte
- func (s *State) StatusOf(p PlayerID) PlayerStatus
- func (s *State) Statuses() []PlayerStatus
- func (s *State) Step(evs ...Event) ([]Action, error)
- type StatusKind
- type TableRule
- type Tables
- type TimeRange
- type Warning
- type WarningCode
Constants ¶
const ( KindSwissLives = "swiss_lives" // suisse à vies (continu ou par rondes) KindLivesBracket = "lives_bracket" // tableau à exemptions : 2 vies = exempt du 1er tour KindGSL = "gsl" // blocs de groupes GSL (2 vies) KindBracket = "bracket" // élimination simple, consolante, dernière chance, double élimination KindRoundRobin = "round_robin" // poules toutes rondes puis qualification (barrage si égalité) )
Kinds de phases.
const ( RefusalRemoved = "removed" // la configuration retire une phase déjà ouverte RefusalFinished = "finished" // la phase est terminée RefusalDrawn = "drawn" // le tirage de la phase est fait RefusalStarted = "started" // des matchs de la phase sont lancés )
Raisons d'un ConfigRefusal.
const JournalVersion = 2
JournalVersion est la version du format du journal écrite dans chaque nouvel événement. 0 (champ absent) désigne les journaux antérieurs aux codes structurés, toujours rejouables. 2 : config_changed ne peut plus changer les options de construction d'un tableau déjà tiré (consolante, dernière chance, réconciliation, recharge, têtes de série) ; un événement de version 1 qui le faisait reste accepté, sans effet, comme il l'a été.
const PrizeSectionAll = "all"
PrizeSectionAll est la clé de la dotation du classement GÉNÉRAL, celui que Ranking renvoie. Ce n'est pas un nom de section — aucune section ne s'appelle ainsi — mais la place réservée, dans la même carte, à la dotation d'un tournoi qui n'a pas de tableau (un suisse, par exemple).
const SeedingRating = rules.SeedingRating
SeedingRating : placement classique par cote d'entrée (1 contre 16, 2 contre 15…).
Variables ¶
This section is empty.
Functions ¶
func PhaseName ¶
func PhaseName(p PhaseConfig) string
PhaseName rend le nom d'une phase : celui que le TD a saisi, sinon le défaut du format. Validate ne remplit plus Name, pour qu'un hôte multilingue puisse fabriquer le sien.
func Prizes ¶
Prizes répartit une dotation par place sur un classement avec ex æquo : les joueurs classés à la même place se partagent les prix des places qu'ils occupent (rules.SharePrizes).
func SectionName ¶
SectionName rend le nom interne d'une section en français. Exportée parce que le paquet render en a besoin : un nom de section est un identifiant, et le traduire est le travail du Labeler de l'hôte — French() délègue ici.
Types ¶
type Absence ¶
type Absence struct {
Until time.Time `json:"until,omitempty"` // heure de retour ; zéro = pas d'échéance horaire
Round int `json:"round,omitempty"` // suisse par rondes : ronde de retour
Phase int `json:"phase"` // phase où elle a été déclarée (Round n'y vaut que là)
}
Absence est une indisponibilité déclarée.
type Action ¶
type Action struct {
Kind ActionKind `json:"kind"`
Phase int `json:"phase"`
Section string `json:"section,omitempty"`
Label Label `json:"label,omitempty"`
Round int `json:"round,omitempty"` // ronde suisse (0 = sans objet) ; remplace la relecture du libellé
Key string `json:"key,omitempty"`
Match MatchID `json:"match,omitempty"` // cancel_match : le match à annuler
A PlayerID `json:"a,omitempty"`
B PlayerID `json:"b,omitempty"`
Length int `json:"length,omitempty"`
Table int `json:"table,omitempty"`
Draw *Draw `json:"draw,omitempty"`
Reason ReasonCode `json:"reason,omitempty"`
Until time.Time `json:"until,omitempty"` // waiting_batch : échéance du prochain lot
// Warn signale ce que le moteur a remarqué sur CETTE proposition sans rien bloquer — la
// fin attendue tombe pendant une pause, par exemple. Le TD décide (voir horaires.go).
Warn WarningCode `json:"warn,omitempty"`
}
Action est une proposition du moteur ; le TD la confirme en ajoutant l'événement correspondant (voir Action.Event).
type ActionKind ¶
type ActionKind string
ActionKind est le type d'une action proposée au TD.
const ( ActStartMatch ActionKind = "start_match" // lancer un match ActBye ActionKind = "bye" // donner un bye (ronde synchrone) ActDraw ActionKind = "draw" // tirer un tableau / des groupes (le tirage est joint) ActNextPhase ActionKind = "next_phase" // passer à la phase suivante ActFinish ActionKind = "finish" // clore le tournoi ActWait ActionKind = "wait" // rien à faire : attendre la fin de matchs en cours // ActCancelMatch : annuler un match devenu incohérent après une correction (reparation.go). // Comme toute action, elle est PROPOSÉE : rien n'est annulé d'office. ActCancelMatch ActionKind = "cancel_match" // ActRepechage : un qualifié de poule s'est retiré avant le tirage de la phase suivante ; // le suivant de sa poule (B) peut prendre sa place (A). Proposée, jamais imposée : sans // confirmation, la place devient une exemption (repechage.go). ActRepechage ActionKind = "repechage" )
type Clock ¶
type Clock struct {
Played int `json:"played"`
Running int `json:"running"`
Elapsed time.Duration `json:"elapsed"`
AvgMatch time.Duration `json:"avg_match"` // durée moyenne observée des matchs terminés
AvgPerPt time.Duration `json:"avg_per_pt"` // durée moyenne observée par point
}
Clock résume l'avancement : matchs joués, en cours, temps écoulé.
type Config ¶
type Config struct {
Name string `json:"name"`
Phases []PhaseConfig `json:"phases"`
MinPerPoint float64 `json:"min_per_point,omitempty"` // durée moyenne d'un point (minutes), défaut 8
Tables Tables `json:"tables,omitempty"` // les tables de la salle (tables.go)
// Prizes : droit d'entrée, retenue d'organisation et barème par section (prizes.go). La
// forme ancienne — une simple liste de montants — reste lue et devient le barème du
// classement général.
Prizes PrizePool `json:"prizes,omitempty"`
// Breaks : les pauses programmées de la journée (repas, remise des prix). Rien n'est
// bloqué : une proposition dont le match rencontrerait une pause porte l'avertissement
// WarnEndsInBreak, et le directeur décide (horaires.go).
Breaks []TimeRange `json:"breaks,omitempty"`
}
Config décrit un tournoi : une suite de phases.
func ParseConfig ¶
ParseConfig lit une configuration JSON et la valide.
func (Config) BreakIntervals ¶ added in v0.6.0
BreakIntervals : les pauses déclarées, telles que rules.AfterBreaks et rules.EstimatedEnd les lisent.
type ConfigRefusal ¶
type ConfigRefusal struct {
Phase int `json:"phase"`
Field string `json:"field"` // champ JSON de PhaseConfig ("kind", "consolation"…) ; "phases" pour un retrait
Reason string `json:"reason"` // RefusalRemoved, RefusalFinished, RefusalDrawn, RefusalStarted
From string `json:"from,omitempty"` // kind : l'ancien format
To string `json:"to,omitempty"` // kind : le nouveau format
Opened int `json:"opened,omitempty"` // removed : le nombre de phases déjà ouvertes
}
ConfigRefusal est le refus d'une configuration : la phase, le champ, et la raison — un CODE, comme tout ce qui sort du moteur. Error() en donne le rendu français, pour la console.
func (*ConfigRefusal) Error ¶
func (r *ConfigRefusal) Error() string
type Draw ¶
type Draw struct {
Slots []PlayerID `json:"slots,omitempty"` // tableau : places du premier tour (BYE = exemption)
Groups [][]PlayerID `json:"groups,omitempty"` // groupes (GSL, poules)
Lives map[PlayerID]int `json:"lives,omitempty"` // vies à l'entrée (information)
}
Draw est le résultat d'un tirage (placement dans un tableau ou composition de groupes), matérialisé dans le journal pour que le rejeu ne dépende pas de l'algorithme.
type Event ¶
type Event struct {
Seq int `json:"seq"`
Version int `json:"version,omitempty"` // format du journal ; 0 = avant les codes structurés
Kind EventKind `json:"kind"`
Time time.Time `json:"time"`
Config *Config `json:"config,omitempty"`
Seed int64 `json:"seed,omitempty"`
Player *Player `json:"player,omitempty"`
ID PlayerID `json:"player_id,omitempty"`
MatchID MatchID `json:"match_id,omitempty"`
Phase int `json:"phase,omitempty"`
Section string `json:"section,omitempty"`
Label Label `json:"label,omitempty"`
Round int `json:"round,omitempty"`
Key string `json:"key,omitempty"`
A PlayerID `json:"a,omitempty"`
B PlayerID `json:"b,omitempty"`
Length int `json:"length,omitempty"`
Table int `json:"table,omitempty"`
Winner PlayerID `json:"winner,omitempty"`
ScoreA int `json:"score_a,omitempty"`
ScoreB int `json:"score_b,omitempty"`
Forfeit bool `json:"forfeit,omitempty"`
AfterCurrent bool `json:"after_current,omitempty"` // retrait différé : le joueur finit son match
Draw *Draw `json:"draw,omitempty"`
Text string `json:"text,omitempty"`
// Slot : sur player_added, la clé de la place d'exemption qu'un retardataire vient prendre
// dans un tableau déjà tiré (voir retardataire.go). Vide pour une inscription ordinaire.
Slot string `json:"slot,omitempty"`
// Until : sur player_unavailable, l'heure à laquelle le joueur redevient disponible.
Until *time.Time `json:"until,omitempty"`
}
Event est une entrée du journal. Les champs inutiles pour un type restent vides.
func CancelEvent ¶
CancelEvent : annulation d'un match lancé par erreur.
func ConfigChangedEvent ¶
ConfigChangedEvent : nouvelle configuration du tournoi, ENTIÈRE. Le moteur la valide et refuse ce qui changerait le format d'une phase commencée ou terminée, ou retirerait une phase ouverte (reconfig.go). Tout le reste est admis : la bascule, les longueurs à venir, les tables, les pauses, la dotation, une phase ajoutée après la phase courante.
EvLengthChanged reste lu pour les journaux existants ; il n'est plus le seul moyen de changer une longueur.
func CorrectionEvent ¶
CorrectionEvent : correction du résultat d'un match déjà terminé. Le journal n'est jamais modifié : la correction est un événement de plus, et l'état est recalculé.
func ForfeitEvent ¶
ForfeitEvent : un joueur ne se présente pas pour CE match, sans quitter le tournoi. Il suit ensuite le chemin d'un perdant ordinaire (la consolante, par exemple).
func LengthChangedEvent ¶
LengthChangedEvent : nouvelle longueur pour les matchs à venir d'une phase.
func PlayerAddedAtSlotEvent ¶
PlayerAddedAtSlotEvent : inscription d'un retardataire sur une place d'exemption libre d'un tableau déjà tiré (State.FreeSlots les énumère). Le tirage n'est pas refait : la place est occupée là où elle est. Une place déjà jouée est refusée par Apply.
func PlayerAddedEvent ¶
PlayerAddedEvent : inscription d'un joueur.
func PlayerAvailableEvent ¶
PlayerAvailableEvent : l'indisponibilité du joueur est levée, quelle qu'elle soit.
func PlayerUnavailableEvent ¶
PlayerUnavailableEvent : le joueur est indisponible jusqu'à until — il joue dans une autre épreuve, il est parti dîner, il n'arrive que demain. Il n'est plus apparié, et ne perd rien : ni vie, ni rang, ni place. until nul = jusqu'à PlayerAvailableEvent.
func PlayerUnavailableUntilRoundEvent ¶
PlayerUnavailableUntilRoundEvent : suisse par rondes, le joueur est absent jusqu'à la ronde round, où il est de nouveau apparié. L'indisponibilité tombe aussi au passage de phase.
func PlayerUpdatedEvent ¶
PlayerUpdatedEvent : correction de la fiche d'un joueur déjà inscrit — nom, club, cote. La fiche est ENTIÈRE, comme la configuration de config_changed : ce qui est écrit est le résultat. Rien d'autre ne change : un retiré reste retiré, ses vies, ses matchs et sa place dans les phases sont intacts. Un identifiant inconnu est refusé : inscrire, c'est PlayerAddedEvent.
player_added sur un identifiant connu reste lu comme avant (mise à jour de la fiche ET réinscription d'un retiré) : c'était le seul chemin des journaux antérieurs, et c'est toujours celui du retour d'un joueur retiré.
func PlayerWithdrawnAfterCurrentEvent ¶
PlayerWithdrawnAfterCurrentEvent : retrait différé. Le joueur n'est plus apparié, mais le match qu'il joue va à son terme — le cas de qui doit partir à 18 h.
func PlayerWithdrawnEvent ¶
PlayerWithdrawnEvent : retrait immédiat d'un joueur. Ses matchs en cours sont perdus par forfait, et ses matchs de graphe non lancés aussi.
func ReopenedEvent ¶
ReopenedEvent : un tournoi clos est rouvert, parce qu'un résultat était faux. Le classement final est effacé et sera recalculé à la clôture suivante — le journal, lui, garde tout.
func RepechageEvent ¶
func RepechageEvent(phase int, section string, withdrawn, replacement PlayerID, now time.Time) Event
RepechageEvent : dans la poule section de la phase phase, replacement prend la place du qualifié withdrawn, retiré avant le tirage de la phase suivante. C'est l'événement que produit EventFromAction sur une ActRepechage ; le construire à la main sert au TD qui choisit un autre joueur de la poule que celui proposé (entre ex æquo, par exemple).
func ResultEvent ¶
ResultEvent construit l'événement de résultat d'un match.
func TableChangedEvent ¶
TableChangedEvent : un match en cours change de table (bruit, lumière, retransmission).
type EventKind ¶
type EventKind string
EventKind est le type d'un événement du journal.
const ( EvCreated EventKind = "created" // Config, Seed EvPlayerAdded EventKind = "player_added" // Player EvPlayerWithdrawn EventKind = "player_withdrawn" // Player.ID ; AfterCurrent = finit son match EvPlayerUpdated EventKind = "player_updated" // Player : la fiche ENTIÈRE corrigée, l'état du joueur intact // EvPlayerUnavailable : ID ; Until (heure de retour) ou Round (ronde de retour), ou aucun des // deux (jusqu'à player_available). Le joueur n'est plus apparié, sans rien perdre. EvPlayerAvailable EventKind = "player_available" // ID : l'indisponibilité est levée EvMatchStarted EventKind = "match_started" // MatchID, Phase, Section, Label, Key, A, B, Length, Table EvResult EventKind = "result" // MatchID, Winner, ScoreA, ScoreB, Forfeit EvResultCorrected EventKind = "result_corrected" // idem, remplace le résultat précédent EvMatchCancelled EventKind = "match_cancelled" // MatchID (match lancé par erreur) EvBye EventKind = "bye" // Phase, Player, Label EvDraw EventKind = "draw" // Phase, Section, Draw EvNextPhase EventKind = "next_phase" // passage à la phase suivante EvRepechage EventKind = "repechage" // Phase, Section (poule), A (qualifié retiré), B (repêché) EvLengthChanged EventKind = "length_changed" // Phase, Length (matchs futurs de la phase) EvConfigChanged EventKind = "config_changed" // Config (la configuration ENTIÈRE, voir reconfig.go) EvReopened EventKind = "reopened" // le tournoi clos est rouvert ; Final sera recalculé EvTableChanged EventKind = "table_changed" // MatchID, Table (match en cours déplacé) EvFinished EventKind = "finished" EvNote EventKind = "note" // Text (annotation libre du TD) )
type External ¶
type External struct {
// BusyTables : tables occupées hors de ce tournoi. L'attribution les saute ; une proposition
// qui ne trouve plus de table attend (ReasonWaitingTable) au lieu de collisionner.
BusyTables []int `json:"busy_tables,omitempty"`
// BusyPlayers : joueurs de CE tournoi (ses PlayerID ; l'hôte traduit ceux de l'autre
// épreuve) qui jouent en ce moment ailleurs. Au suisse et en barrage ils ne sont pas
// appariés, et la file porte une attente ReasonPlayerBusy par joueur ; dans un graphe, où la
// place est fixée, leur match reste proposé, sans table, avec cette raison. Un identifiant
// inconnu est ignoré.
BusyPlayers []PlayerID `json:"busy_players,omitempty"`
}
External décrit ce que l'hôte sait de la salle et que le journal de CE tournoi ignore : les tables où joue, en ce moment, une autre épreuve dirigée à côté, et les joueurs de ce tournoi qui y jouent. Ce n'est pas un événement : l'occupation par l'extérieur change à chaque match de l'autre épreuve, elle n'appartient pas à l'histoire de celle-ci, et le rejeu n'en a pas besoin — le match_started confirmé porte, lui, la table et les joueurs effectivement pris.
type GMatch ¶
type GMatch struct {
Key string `json:"key"`
Label Label `json:"label,omitempty"`
Length int `json:"length"`
Src [2]Src `json:"src"`
Players [2]PlayerID `json:"players"`
MatchID MatchID `json:"match_id,omitempty"`
Winner PlayerID `json:"winner,omitempty"`
Loser PlayerID `json:"loser,omitempty"`
Done bool `json:"done"`
Walkover bool `json:"walkover,omitempty"`
Skipped bool `json:"skipped,omitempty"` // match conditionnel non joué (recharge)
CondFrom int `json:"cond_from,omitempty"` // index du match dont dépend l'existence (recharge)
CondSide int `json:"cond_side,omitempty"` // le match existe si le vainqueur de CondFrom est son joueur CondSide
Cond bool `json:"cond,omitempty"`
}
GMatch est un match d'un graphe : ses deux places viennent de joueurs fixés ou d'autres matchs.
type Info ¶
type Info struct {
Code InfoCode `json:"code"`
Player PlayerID `json:"player,omitempty"`
Phase int `json:"phase,omitempty"`
Section string `json:"section,omitempty"`
Label Label `json:"label,omitempty"`
}
Info est une information destinée au TD : un code et de quoi la situer.
type InfoCode ¶
type InfoCode string
InfoCode est le code d'une information : ni une incohérence à corriger, ni une action à confirmer, mais un fait que le TD doit voir — le sort d'un joueur inscrit qui ne joue encore nulle part.
const ( // InfoEntersAt : le joueur entrera là. Phase et Section (avec le libellé) disent où. InfoEntersAt InfoCode = "enters_at" // InfoNoEntry : le joueur est inscrit mais rien ne l'admet — aucune place d'exemption // libre, aucune phase à venir ouverte à tous. Le dire vaut mieux que le laisser disparaître // de l'affichage. InfoNoEntry InfoCode = "no_entry" )
type Label ¶
type Label struct {
Kind LabelKind `json:"kind,omitempty"`
N int `json:"n,omitempty"` // ronde, tour, bloc, nombre de places, de poules
Losses int `json:"losses,omitempty"` // suisse continu : groupe de défaites
Match int `json:"match,omitempty"` // suisse continu : n-ième match du joueur
Section string `json:"section,omitempty"` // nom interne de la section concernée
Text string `json:"text,omitempty"` // seul texte admis : ce que le TD a lui-même saisi
Players int `json:"players,omitempty"` // barrage : joueurs à départager
Spots int `json:"spots,omitempty"` // barrage : places à attribuer
Sub *Label `json:"sub,omitempty"`
}
Label est un libellé structuré. Les champs inutiles pour un code restent vides ; Sub compose un libellé dans un autre (« Bloc 2, groupe B : match décisif »).
func (*Label) UnmarshalJSON ¶
UnmarshalJSON accepte les deux formes d'un libellé : la structure (journaux à partir de la version 1) et la chaîne des journaux antérieurs, conservée telle quelle dans Text pour que rien ne soit perdu. upgrade (events.go) la convertit en code quand elle est reconnaissable.
type LabelKind ¶
type LabelKind string
LabelKind est le code d'un libellé de match, de tirage ou de phase.
const ( LabelNone LabelKind = "" // Suisse LabelSwissGroup LabelKind = LabelKind(rules.LabelSwissGroup) // Losses, Match : « 1 défaite, match 3 » LabelRound LabelKind = LabelKind(rules.LabelRound) // N : « Ronde 3 » LabelRematch LabelKind = LabelKind(rules.LabelRematch) LabelCrossed LabelKind = LabelKind(rules.LabelCrossed) // match croisé de secours // Tableaux LabelBracketRound LabelKind = LabelKind(rules.LabelBracketRound) // N : « Tour 2 » LabelFinal LabelKind = LabelKind(rules.LabelFinal) LabelSemiFinal LabelKind = LabelKind(rules.LabelSemiFinal) LabelQuarterFinal LabelKind = LabelKind(rules.LabelQuarterFinal) LabelMainDraw LabelKind = LabelKind(rules.LabelMainDraw) // Sub : « Principal, quart de finale » LabelConsolationRound LabelKind = LabelKind(rules.LabelConsolationRound) LabelConsolationFinal LabelKind = LabelKind(rules.LabelConsolationFinal) LabelLastChance LabelKind = LabelKind(rules.LabelLastChance) // Sub facultatif LabelGrandFinal LabelKind = LabelKind(rules.LabelGrandFinal) LabelGrandFinalRecharge LabelKind = LabelKind(rules.LabelGrandFinalRecharge) // GSL LabelOpening LabelKind = LabelKind(rules.LabelOpening) LabelWinnersMatch LabelKind = LabelKind(rules.LabelWinnersMatch) LabelLosersMatch LabelKind = LabelKind(rules.LabelLosersMatch) LabelDecider LabelKind = LabelKind(rules.LabelDecider) LabelSingleMatch LabelKind = LabelKind(rules.LabelSingleMatch) LabelSingleElim LabelKind = LabelKind(rules.LabelSingleElim) LabelInBlock LabelKind = LabelKind(rules.LabelInBlock) // N = bloc, Section, Sub // Poules LabelPoolRound LabelKind = LabelKind(rules.LabelPoolRound) // N LabelInSection LabelKind = LabelKind(rules.LabelInSection) // Section, Sub LabelBarrage LabelKind = LabelKind(rules.LabelBarrage) // Section LabelBarrageCross LabelKind = LabelKind(rules.LabelBarrageCross) LabelDrawPools LabelKind = LabelKind(rules.LabelDrawPools) // N = nombre de poules LabelDrawBarrage LabelKind = LabelKind(rules.LabelDrawBarrage) // Section, Players, Spots // LabelRepechage : repêchage proposé dans la poule Section ; Players = nombre de candidats // ex æquo (1 : un seul suivant ; davantage : le TD choisit, voir repechage.go). LabelRepechage LabelKind = "repechage" LabelDrawBracket LabelKind = LabelKind(rules.LabelDrawBracket) // N = places LabelDrawBlock LabelKind = LabelKind(rules.LabelDrawBlock) // N = bloc, Groups LabelPhase LabelKind = LabelKind(rules.LabelPhase) // Phase : le nom vient de la configuration LabelPoolName LabelKind = "pool_name" // Text : la lettre de la poule LabelBarrageName LabelKind = "barrage_name" // Sub = LabelPoolName LabelSectionMain LabelKind = "section_main" LabelSectionConso LabelKind = "section_conso" LabelSectionLast LabelKind = "section_last" LabelSectionFinals LabelKind = "section_finals" )
type Match ¶
type Match struct {
ID MatchID `json:"id"`
Phase int `json:"phase"`
Section string `json:"section,omitempty"` // identifiant : "main", "conso", "poule:A"…
Label Label `json:"label,omitempty"` // libellé structuré (codes.go)
Key string `json:"key,omitempty"` // clé interne (position dans un graphe de matchs)
Round int `json:"round,omitempty"` // ronde suisse (0 = sans objet)
A PlayerID `json:"a"`
B PlayerID `json:"b"`
Length int `json:"length"`
Table int `json:"table,omitempty"`
Status MatchStatus `json:"status"`
Start time.Time `json:"start"`
End time.Time `json:"end,omitempty"`
Winner PlayerID `json:"winner,omitempty"`
ScoreA int `json:"score_a,omitempty"`
ScoreB int `json:"score_b,omitempty"`
Forfeit bool `json:"forfeit,omitempty"`
}
Match est un match lancé (ou terminé) entre deux joueurs.
type MatchStatus ¶
type MatchStatus string
MatchStatus est l'état d'un match.
const ( Running MatchStatus = "running" Finished MatchStatus = "finished" Cancelled MatchStatus = "cancelled" )
type Note ¶
type Note struct {
Kind NoteKind `json:"kind,omitempty"`
Wins int `json:"wins,omitempty"`
Losses int `json:"losses,omitempty"`
Lives int `json:"lives,omitempty"`
Section string `json:"section,omitempty"`
Qualified bool `json:"qualified,omitempty"`
Sub *Label `json:"sub,omitempty"`
}
Note est la note de classement d'un joueur : un code et ses paramètres, jamais une phrase.
type NoteKind ¶
type NoteKind string
NoteKind est le code d'une note de classement.
const ( NoteNone NoteKind = "" NoteWinner NoteKind = NoteKind(rules.NoteWinner) NoteFinalist NoteKind = NoteKind(rules.NoteFinalist) NoteAlive NoteKind = NoteKind(rules.NoteAlive) // Lives NoteRecord NoteKind = NoteKind(rules.NoteRecord) // Wins, Losses NoteForfeit NoteKind = NoteKind(rules.NoteForfeit) // match perdu par forfait (classement d'une section) ; journaux antérieurs : retiré NoteWithdrawn NoteKind = NoteKind(rules.NoteWithdrawn) // retiré, classé sur son parcours : Wins, Losses, Lives ; tableau : Section + Sub ; poule : Section + Wins NoteRunning NoteKind = NoteKind(rules.NoteRunning) // encore en course, tableau non terminé NoteAwaitingDraw NoteKind = NoteKind(rules.NoteAwaitingDraw) // tableau pas encore tiré NoteUnranked NoteKind = NoteKind(rules.NoteUnranked) // aucune sortie enregistrée NoteSectionExit NoteKind = NoteKind(rules.NoteSectionExit) // Section + Sub : sorti de cette section là — pas forcément éliminé (State.Statuses) NoteSectionWinner NoteKind = NoteKind(rules.NoteSectionWinner) // Section NotePoolRecord NoteKind = NoteKind(rules.NotePoolRecord) // Section, Wins, Qualified )
type PhaseConfig ¶
type PhaseConfig struct {
Kind string `json:"kind"`
Name string `json:"name,omitempty"`
Lives int `json:"lives,omitempty"` // swiss_lives : nombre de vies (défaut 2)
Length int `json:"length"` // longueur des matchs (points)
FinalLength int `json:"final_length,omitempty"` // longueur de la finale (tableaux), 0 = Length
// Lengths donne la longueur tour par tour d'un tableau, DU DERNIER TOUR VERS LE PREMIER
// (« 15, 13, 11, 9 » = finale en 15, demies en 13, quarts en 11, reste en 9). L'ordre est
// celui dans lequel un organisateur annonce son tournoi, et il ne dépend pas de la taille
// du tableau : la même liste sert un tableau de 16 et un tableau de 64, où elle allonge les
// quatre derniers tours. Une liste plus courte que le tableau retombe sur Length.
Lengths []int `json:"lengths,omitempty"`
// LengthLate allonge les matchs de la fin d'un suisse, quand il ne reste plus que
// LateThreshold joueurs en vie ou moins. Les deux vont ensemble : l'un sans l'autre ne fait
// rien. Un changement de longueur décidé à la main par le TD (EvLengthChanged) l'emporte.
LengthLate int `json:"length_late,omitempty"`
LateThreshold int `json:"late_threshold,omitempty"`
// BatchMinutes : micro-rondes d'un suisse continu. Les joueurs libres attendent l'échéance,
// puis tous ceux d'un même groupe de défaites sont appariés d'un coup. 0 = appariement au
// fil de l'eau. L'échéance est dérivée du journal (horaires.go), jamais stockée à part.
BatchMinutes int `json:"batch_minutes,omitempty"`
Mode string `json:"mode,omitempty"` // swiss_lives : "continuous" (défaut) ou "rounds"
Pairing string `json:"pairing,omitempty"` // swiss_lives : "random" (défaut) ou "wins"
AvoidClubs bool `json:"avoid_clubs,omitempty"` // éviter les joueurs du même club quand c'est possible
AllowRematch bool `json:"allow_rematch,omitempty"`
Target int `json:"target,omitempty"` // swiss_lives / gsl : figer quand la somme des vies vaut Target (puissance de 2)
Consolation bool `json:"consolation,omitempty"` // bracket : consolante progressive (perdants du tableau principal)
LastChance bool `json:"last_chance,omitempty"` // bracket : dernière chance (perdants de la consolante)
Reconciliation bool `json:"reconciliation,omitempty"` // bracket : le vainqueur de la consolante joue le vainqueur du principal (double élimination)
Recharge bool `json:"recharge,omitempty"` // bracket : en double élimination, le vainqueur du principal doit être battu deux fois
GroupSize int `json:"group_size,omitempty"` // round_robin : taille des poules (défaut 4)
Qualifiers int `json:"qualifiers,omitempty"` // round_robin : qualifiés par poule (défaut 2)
Entry string `json:"entry,omitempty"` // "survivors" (défaut : joueurs encore en vie de la phase précédente), "all", "top:N"
// Seeding place les joueurs d'un tableau par cote au lieu de les tirer au hasard :
// "" (défaut) ou SeedingRating. Le défaut VIDE est un choix de conception et non un oubli —
// l'étude conclut « pas de têtes de série protégées », c'est la culture actuelle du
// backgammon. Voir seeding.go.
Seeding string `json:"seeding,omitempty"`
}
PhaseConfig paramètre une phase. Les champs inutiles pour un type sont ignorés.
type PhaseState ¶
type PhaseState struct {
Index int `json:"index"`
Cfg PhaseConfig `json:"cfg"`
Entrants []PlayerID `json:"entrants"`
Lives map[PlayerID]int `json:"lives"` // vies à l'entrée de la phase
Losses map[PlayerID]int `json:"losses"`
Wins map[PlayerID]int `json:"wins"`
Byes map[PlayerID]int `json:"byes"`
Opponents map[PlayerID][]PlayerID `json:"opponents"`
ElimOrder []PlayerID `json:"elim_order"` // ordre d'élimination
Round int `json:"round"` // rondes synchrones / blocs
// Roster : suisse par rondes, les joueurs appelés à la ronde Round, relevés au premier
// événement de la ronde (match ou bye). La ronde reste ouverte tant que l'un d'eux n'y est
// pas engagé : ses appariements restent proposés (phase_swiss.go).
Roster []PlayerID `json:"roster,omitempty"`
// ByeRounds : les rondes où le joueur a reçu un bye (suisse par rondes).
ByeRounds map[PlayerID][]int `json:"bye_rounds,omitempty"`
Drawn bool `json:"drawn"`
Done bool `json:"done"`
Sections []*Section `json:"sections,omitempty"`
Length int `json:"length"` // longueur courante des matchs
Started bool `json:"started"`
// Repechages : poules, qualifié retiré → joueur repêché à sa place (repechage.go).
Repechages map[PlayerID]PlayerID `json:"repechages,omitempty"`
}
PhaseState est l'état d'une phase.
type Player ¶
type Player struct {
ID PlayerID `json:"id"`
Name string `json:"name"`
Club string `json:"club,omitempty"`
Rating float64 `json:"rating,omitempty"` // PR (plus bas = meilleur) ; 0 = inconnu
}
Player décrit un joueur inscrit.
type PlayerID ¶
type PlayerID string
PlayerID identifie un joueur ; fourni par l'hôte.
const BYE PlayerID = "BYE"
BYE est l'identifiant réservé d'une place vide dans un tableau (exemption).
type PlayerStatus ¶
type PlayerStatus struct {
Player PlayerID `json:"player"`
Kind StatusKind `json:"kind"`
// Phase : la phase dont parle le statut — en cours (en jeu, exempté), à venir (qualifié,
// indécis), dernière jouée (éliminé, retiré, vainqueur).
Phase int `json:"phase,omitempty"`
Section string `json:"section,omitempty"`
Round int `json:"round,omitempty"`
Label Label `json:"label,omitempty"`
}
PlayerStatus est le statut d'un joueur : un code et de quoi le situer, jamais une phrase.
func (PlayerStatus) String ¶
func (p PlayerStatus) String() string
String rend le statut d'un joueur en français (« est-ce que je joue ? »), sans son nom. Les phases sont numérotées à partir de 1 : leur nom est dans la configuration, que l'hôte a.
type PrizePool ¶
type PrizePool struct {
EntryFee float64 `json:"entry_fee,omitempty"` // droit d'entrée par inscrit
Retention Retention `json:"retention,omitempty"`
Sections map[string]PrizeScale `json:"sections,omitempty"` // clé : PrizeSectionAll, "main", "conso"…
}
PrizePool décrit la dotation entière d'un tournoi.
func (PrizePool) SectionNames ¶
SectionNames : les sections dotées, dans un ordre stable (le classement général d'abord).
func (*PrizePool) UnmarshalJSON ¶
UnmarshalJSON accepte les deux formes : la liste de montants des configurations d'avant les sections (`"prizes": [100, 60, 40]`), qui devient la dotation du classement général, et la structure. Un journal existant se relit donc sans être réécrit.
type PrizeScale ¶
type PrizeScale struct {
Percents []float64 `json:"percents,omitempty"` // % du pool distribuable, place par place
Amounts []float64 `json:"amounts,omitempty"` // montants fixes, place par place
}
PrizeScale est la dotation d'une section : des pourcentages du pool distribuable, ou des montants fixes. Les deux ensemble n'ont pas de sens ; Amounts l'emporte, et Validate le dit.
type Rank ¶
type Rank struct {
Player PlayerID `json:"player"`
Rank int `json:"rank"`
Note Note `json:"note,omitempty"` // note structurée (codes.go)
}
Rank est une place au classement ; les ex æquo partagent le même Rank.
type ReasonCode ¶
type ReasonCode string
ReasonCode dit pourquoi le moteur ne propose rien à faire.
const ( ReasonNone ReasonCode = "" ReasonMatchesRunning ReasonCode = "matches_running" ReasonNoPairing ReasonCode = "no_pairing" ReasonWaitingBatch ReasonCode = "waiting_batch" ReasonWaitingTable ReasonCode = "waiting_table" // (A = le joueur, Until ou Round = son retour) dans un suisse ; sur la proposition de match // d'un graphe, qui reste dans la file sans table. ReasonPlayerUnavailable ReasonCode = "player_unavailable" // ReasonPlayerBusy : un joueur joue en ce moment dans une autre épreuve de la salle // (External.BusyPlayers). Sur une attente (A = le joueur) dans un suisse ; sur la proposition // de match d'un graphe, qui reste dans la file sans table. Jamais écrit au journal. ReasonPlayerBusy ReasonCode = "player_busy" )
func (ReasonCode) String ¶
func (r ReasonCode) String() string
String rend une raison d'attente en français.
type Retention ¶
type Retention struct {
Amount float64 `json:"amount,omitempty"`
Percent float64 `json:"percent,omitempty"`
}
Retention est ce que l'organisation garde avant de distribuer : un montant, un pourcentage du pool, ou les deux (le pourcentage s'applique au pool brut, puis le montant s'en retranche).
type Section ¶
type Section struct {
Name string `json:"name"`
Kind string `json:"kind"` // secMain, secConso, secLast, secGrandFinal, secKindGSL, secKindSE, secKindPool, secKindBarrage
Group int `json:"group,omitempty"`
Block int `json:"block,omitempty"`
Matches []GMatch `json:"matches"`
Rounds [][]int `json:"rounds,omitempty"` // indices de matchs par tour (affichage)
Players []PlayerID `json:"players,omitempty"` // barrage : joueurs concernés (appariement dynamique)
Spots int `json:"spots,omitempty"` // barrage : nombre de places à attribuer
}
Section est un graphe de matchs dont les places se remplissent par les résultats (tableau, groupe GSL, poule, barrage).
type Slot ¶
type Slot struct {
Phase int `json:"phase"`
Section string `json:"section"`
Key string `json:"key"`
Label Label `json:"label,omitempty"`
}
Slot est une place d'exemption libre : un côté d'un match de graphe dont la source est un BYE fixe, dans un tour que personne n'a commencé à jouer. C'est ce qu'un hôte propose au TD quand un joueur se présente en retard.
type Src ¶
type Src struct {
Player PlayerID `json:"player,omitempty"`
From int `json:"from"`
Section string `json:"section,omitempty"`
Loser bool `json:"loser,omitempty"`
}
Src est l'origine d'une place : un joueur, ou le vainqueur/perdant d'un match (index dans la section Section, ou la même section si vide).
type State ¶
type State struct {
Config Config `json:"config"`
Seed int64 `json:"seed"`
Players map[PlayerID]*Player `json:"players"`
Order []PlayerID `json:"order"` // ordre d'inscription
Withdrawn map[PlayerID]bool `json:"withdrawn,omitempty"`
// WithdrawAfter : retraits différés. Le joueur a demandé à partir mais finit le match qu'il
// joue ; il n'est plus apparié (il est occupé), et le retrait devient effectif dès que ce
// match est terminé. Un retrait différé sans match en cours est un retrait immédiat.
WithdrawAfter map[PlayerID]bool `json:"withdraw_after,omitempty"`
Matches map[MatchID]*Match `json:"matches"`
MatchOrder []MatchID `json:"match_order"`
Phases []*PhaseState `json:"phases"`
Current int `json:"current"` // index de la phase en cours (-1 avant création)
Finished bool `json:"finished"`
Final []Rank `json:"final,omitempty"`
NEvents int `json:"n_events"`
Last time.Time `json:"last"`
Warnings []Warning `json:"warnings,omitempty"`
// Infos : les inscrits qui ne jouent encore nulle part et où ils entreront (retardataire.go).
// Dérivées de l'état à chaque événement, jamais accumulées.
Infos []Info `json:"infos,omitempty"`
// Revived : joueurs qu'une correction a rendus à la vie dans un suisse, jusqu'à ce qu'ils
// rejouent (WarnCorrectionRevives).
Revived map[PlayerID]bool `json:"revived,omitempty"`
// player_available, par l'heure ou par la ronde de retour (absence.go).
Unavailable map[PlayerID]Absence `json:"unavailable,omitempty"`
// contains filtered or unexported fields
}
State est l'état complet d'un tournoi, reconstruit à partir du journal.
func (*State) CheckConfig ¶
CheckConfig dit si next pourrait remplacer la configuration courante, sans rien appliquer : la prévisualisation d'un formulaire de réglages. Le refus est un *ConfigRefusal (ou l'erreur de Validate). Il applique les règles d'aujourd'hui, celles d'un config_changed de la version courante du journal.
func (*State) Distributable ¶
Distributable : ce qui reste à distribuer après la retenue d'organisation.
func (*State) EventFromAction ¶
EventFromAction construit l'événement qui confirme une action proposée. Pour ActStartMatch, l'identifiant de match est attribué par le moteur (prochain numéro).
func (*State) FreeSlots ¶
FreeSlots énumère les places d'exemption qu'un retardataire peut encore prendre, dans l'ordre du tableau. L'hôte les propose au TD ; la place choisie voyage dans l'événement d'inscription (PlayerAddedAtSlotEvent).
func (*State) Pool ¶
Pool : le pool brut, droit d'entrée fois nombre d'inscrits.
Tous les inscrits comptent, y compris ceux qui se sont retirés : ils ont payé. Un forfait n'est pas un remboursement, et le moteur n'a pas à en décider.
func (*State) PrizeAmounts ¶
PrizeAmounts : les montants place par place d'une section, arrondis à l'unité (rules.PlaceAmounts).
Les pourcentages d'une affiche ne tombent presque jamais juste : 50/30/20 % de 432 € font 216, 129,60 et 86,40. Chaque place est payée à l'unité — personne ne paie en centimes à une table de tournoi — par la méthode du plus fort reste : 216, 129 et 86 tronqués, puis l'euro qui manque à la plus grande partie décimale, 0,60, d'où 216/130/86. La somme distribuée égale exactement le pool après retenue, aucun prix n'est négatif, et un barème décroissant donne des prix décroissants.
Des montants fixes (Amounts) ne sont ni arrondis ni ajustés : ils sont ce que l'organisateur a écrit. Une section sans dotation : nil.
func (*State) Propose ¶
Propose renvoie les actions à effectuer maintenant. Le TD en confirme tout ou partie ; chaque confirmation devient un événement (voir State.EventFromAction). Déterministe pour un journal donné.
« Maintenant » est ici l'horodatage du dernier événement du journal : le moteur n'a pas d'horloge, et ne va pas s'en inventer une. Un hôte qui affiche un compte à rebours ou qui veut les avertissements de pause à sa propre heure appelle ProposeAt.
func (*State) ProposeAt ¶
ProposeAt est Propose à une heure donnée. Elle ne change que ce qui dépend du temps : les micro-rondes (l'échéance du prochain lot) et les pauses (la fin attendue d'un match proposé). Le reste — appariements, tirages, passage de phase — ne dépend que du journal.
Le rejeu n'en est pas affecté : ce qui est rejoué, ce sont les événements, pas les propositions. Deux hôtes dont les horloges diffèrent proposent les mêmes matchs, à des instants différents.
func (*State) ProposeWith ¶
ProposeWith est ProposeAt avec ce que l'hôte sait de l'extérieur (External). L'attribution des tables et la disponibilité des joueurs en dépendent ; les tirages et passages de phase restent fonction du seul journal.
func (*State) Ranking ¶
Ranking renvoie le classement général courant : la phase en cours d'abord, puis les phases précédentes (joueurs éliminés plus tôt classés derrière), ex æquo conservés (rules.MergeRankings sur les rules.Rank de chaque phase).
func (*State) RulesMatches ¶ added in v0.6.0
RulesMatches : les matchs de l'état, dans l'ordre de lancement, tels que les règles pures les lisent. C'est l'entrée de rules.PlayingTime, rules.PaceAt, rules.Batches et rules.PairingSheet pour un hôte qui tient un State ; chaque ligne porte son libellé (Label), celui qu'une feuille imprime.
func (*State) RulesPhase ¶ added in v0.7.0
RulesPhase : l'instantané de la phase i tel que rules le lit (rules.Pair, rules.Rank, rules.RemainingMatches), pour un hôte qui tient un State et veut appeler les règles lui-même. nil si la phase n'existe pas. Les joueurs appariables d'un suisse (Free) sont ceux de l'instant du dernier événement.
func (*State) SectionPrizes ¶
SectionPrizes : ce que chaque joueur d'une section touche, ex æquo partagés.
func (*State) SectionRanking ¶
SectionRanking : le classement propre d'une section (main, conso, last, gf, un groupe GSL, une poule), et non le classement général du tournoi.
Une consolante a ses propres prix, donc son propre classement : celui de ses joueurs, par tour atteint DANS CETTE SECTION. Le classement général mélange les sections par priorité (un vainqueur de consolante passe derrière un demi-finaliste du principal) ; ici on ne regarde que la section, et le vainqueur de la consolante est premier de la consolante.
Enveloppe de rules.RankSection. La section est cherchée de la dernière phase vers la première : c'est la plus récente qui porte ce nom qui compte, un tournoi pouvant enchaîner deux tableaux.
func (*State) SlowMatches ¶
SlowMatches : matchs en cours qui dépassent `facteur` fois leur durée attendue.
func (*State) StandingsCSV ¶
StandingsCSV exporte le classement, une section par bloc.
La première colonne dit à quel classement la ligne appartient : « all » pour le classement général, puis l'identifiant de chaque section dotée (« main », « conso »…). Les blocs sont contigus et se lisent dans un tableur comme des tableaux séparés ; un hôte qui n'en veut qu'un filtre sur la colonne.
Les sections apparaissent parce qu'elles ont une DOTATION : sortir le classement de chaque groupe GSL d'un tournoi de cent joueurs noierait la feuille que le TD affiche au mur.
func (*State) StatusOf ¶
func (s *State) StatusOf(p PlayerID) PlayerStatus
StatusOf donne le statut d'un joueur. Un identifiant inconnu est « non engagé ».
func (*State) Statuses ¶
func (s *State) Statuses() []PlayerStatus
Statuses donne le statut de chaque inscrit, dans l'ordre d'inscription. Rien avant la création du tournoi.
type StatusKind ¶
type StatusKind string
StatusKind est le code du statut d'un joueur.
const ( // StatusPlaying : encore en course dans la phase en cours. Dans un tableau, Section, Round // et Label situent son prochain match. StatusPlaying StatusKind = "playing" // StatusBye : exempté — ne joue pas maintenant et entre plus tard. Tableau : il n'a encore // joué aucun match de la phase et le tirage (ou un forfait) l'a avancé jusqu'au match situé // par Section, Round (tour de la section, à partir de 1) et Label. Suisse par rondes : bye de // la ronde en cours ; il rejoue à la ronde Round (Label = LabelRound). StatusBye StatusKind = "bye" // StatusQualified : entre dans la phase Phase — la phase en cours est terminée et il fait // partie de ceux qui passent, ou le passage est fait et la phase n'est ni tirée ni commencée. // Un repêché (N26) est qualifié ; le retiré qu'il remplace ne l'est pas. StatusQualified StatusKind = "qualified" // StatusUndecided : son sort dans la phase Phase n'est pas encore fixé. Soit son parcours // dans la phase en cours est terminé mais Phase prend les N premiers (entrée top:N), connus à // la fin seulement ; soit il est candidat à un repêchage proposé que le TD n'a pas tranché. StatusUndecided StatusKind = "undecided" // StatusEliminated : plus aucun match à jouer dans le tournoi. Phase : la dernière phase // où il est entré. StatusEliminated StatusKind = "eliminated" // StatusWinner : la dernière phase est terminée (ou le tournoi clos) et il est premier. StatusWinner StatusKind = "winner" // StatusWithdrawn : retiré. Phase : la dernière phase où il est entré. Prime sur tout le // reste : un qualifié retiré n'est pas qualifié. StatusWithdrawn StatusKind = "withdrawn" // StatusNotEntered : inscrit, engagé dans aucune phase (un retardataire) ; State.Infos dit // où il entrera. StatusNotEntered StatusKind = "not_entered" )
type TableRule ¶
type TableRule struct {
Table int `json:"table"`
Section string `json:"section,omitempty"` // identifiant de section (main, conso, poule:A…)
Phase int `json:"phase,omitempty"` // index de phase ; 0 = toutes
AllPhases bool `json:"all_phases,omitempty"`
}
TableRule réserve une table à une section ou à une phase. Une réservation vide des deux côtés ne réserve rien.
type Tables ¶
type Tables struct {
Count int `json:"count,omitempty"`
Reserved []TableRule `json:"reserved,omitempty"` // retransmission, table d'honneur
}
Tables décrit les tables de la salle. Count = 0 signifie « illimité » : le moteur numérote alors sans borne, ce qui reste utile pour une simulation.
func (Tables) AvailableFor ¶
AvailableFor : la table n peut accueillir un match de cette section et de cette phase. Une table réservée n'accueille que ce pour quoi elle est réservée ; les autres tables sont libres.
func (*Tables) UnmarshalJSON ¶
UnmarshalJSON accepte les deux formes : le nombre des configurations d'avant les exceptions, et la structure. Une configuration écrite `"tables": 12` reste donc lisible.
type TimeRange ¶
TimeRange est un créneau de la journée : le repas, la remise des prix, la fermeture de la salle. Start incluse, End exclue.
type Warning ¶
type Warning struct {
Code WarningCode `json:"code"`
Match MatchID `json:"match,omitempty"`
Section string `json:"section,omitempty"`
Label Label `json:"label,omitempty"`
A PlayerID `json:"a,omitempty"`
B PlayerID `json:"b,omitempty"`
ExpectedA PlayerID `json:"expected_a,omitempty"`
ExpectedB PlayerID `json:"expected_b,omitempty"`
Length int `json:"length,omitempty"`
ScoreA int `json:"score_a,omitempty"`
ScoreB int `json:"score_b,omitempty"`
Player PlayerID `json:"player,omitempty"` // correction_* : le joueur concerné
Table int `json:"table,omitempty"` // table_shared : la table disputée
Other MatchID `json:"other,omitempty"` // table_shared : l'autre match sur la table
}
Warning est une incohérence : un code et de quoi la situer. Rien n'est bloqué par un avertissement — le TD décide (voir README, « le moteur propose, le TD décide »).
type WarningCode ¶
type WarningCode string
WarningCode est le code d'une incohérence signalée par le moteur.
const ( // WarnBracketWrongPlayers : un match de graphe a été joué par d'autres joueurs que ceux // que la place attendait (typiquement après la correction d'un résultat antérieur). WarnBracketWrongPlayers WarningCode = "bracket_wrong_players" // WarnScoreOverLength : un score dépasse la longueur annoncée du match. WarnScoreOverLength WarningCode = "score_over_length" // WarnEndsInBreak : la fin attendue d'un match proposé tombe dans une pause. WarnEndsInBreak WarningCode = "ends_in_break" // WarnSlowMatch : un match en cours dépasse la durée attendue. WarnSlowMatch WarningCode = "slow_match" // déplacement qui l'a produit a été accepté : le moteur avertit, il ne bloque pas. // L'avertissement tombe dès que l'un des deux matchs se termine ou change de table. WarnTableShared WarningCode = "table_shared" // WarnCorrectionEliminatesRunning : dans un suisse, une correction (ou une annulation) a fait // tomber à 0 vie un joueur (Player) qui joue en ce moment le match Match. L'annulation de ce // match est proposée (cancel_match). Dérivé : tombe quand le match finit ou est annulé. WarnCorrectionEliminatesRunning WarningCode = "correction_eliminates_running" // WarnCorrectionRevives : dans un suisse, une correction (ou une annulation) a rendu une vie à // un joueur (Player) qu'elle avait éliminé. Il redevient appariable ; l'avertissement reste // jusqu'à ce qu'il rejoue, ou qu'il soit de nouveau éliminé. WarnCorrectionRevives WarningCode = "correction_revives" )
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
tournoi-demo
command
tournoi-demo : joue un tournoi fictif avec le moteur et écrit le journal, la page d'affichage et les SVG dans un dossier ; ou rejoue un journal existant et affiche ce que le TD doit faire.
|
tournoi-demo : joue un tournoi fictif avec le moteur et écrit le journal, la page d'affichage et les SVG dans un dossier ; ou rejoue un journal existant et affiche ce que le TD doit faire. |
|
tournoi-td
command
tournoi-td : console interactive de direction de tournoi pour tester le moteur à la main.
|
tournoi-td : console interactive de direction de tournoi pour tester le moteur à la main. |
|
internal
|
|
|
dores
Package dores décrit les fichiers dorés des règles pures (rules/testdata) : leur forme JSON, leur lecture et leur réécriture.
|
Package dores décrit les fichiers dorés des règles pures (rules/testdata) : leur forme JSON, leur lecture et leur réécriture. |
|
Package players : import léger de listes de joueurs (CSV HelloAsso, FFBG, tableur).
|
Package players : import léger de listes de joueurs (CSV HelloAsso, FFBG, tableur). |
|
Package render produit des composants d'affichage (SVG, HTML) à partir d'un état de tournoi : arbres de tableaux, tableau des vies, appariements en cours, grille des tables, feuille d'appariements imprimable, classement, et une page autonome qui les rassemble.
|
Package render produit des composants d'affichage (SVG, HTML) à partir d'un état de tournoi : arbres de tableaux, tableau des vies, appariements en cours, grille des tables, feuille d'appariements imprimable, classement, et une page autonome qui les rassemble. |
|
Package rules porte les règles de tournoi en fonctions pures : sans état, sans entrée ni sortie, sans horloge — l'instant et la graine sont des arguments — et sans autre dépendance que la bibliothèque standard.
|
Package rules porte les règles de tournoi en fonctions pures : sans état, sans entrée ni sortie, sans horloge — l'instant et la graine sont des arguments — et sans autre dépendance que la bibliothèque standard. |
|
Package sim joue des tournois fictifs avec le moteur tournoi : résultats tirés au sort selon les PR, durées de match aléatoires.
|
Package sim joue des tournois fictifs avec le moteur tournoi : résultats tirés au sort selon les PR, durées de match aléatoires. |