In order to interpret a sporting tournament under the libtour
engine, one has to write a tournament definition in the predefined
format in the Scheme programming language.
The following three pieces of definition must be provided:
To make a tournament definition suitable for the libtour
engine, one has to write a file called `<tour-name>.scm' and put
it in a directory where libtour
will find it (for the
`tourcli' CLI client, see section Quick start). The file has to
define a Guile module, tour-defs <tour-name>
and export the
following variables:
<tour-name>:INFO
TITLE
key is required
<tour-name>:TEAMS
<tour-name>:TEAMS-FORMAT
<tour-name>:STAGES
<tour-name>:WINNERS
<tour-name>:SCHEDULE
<tour-name>:SCHEDULE-FORMAT
<tour-name>:SCHEDULE-DATE
<tour-name>:SCHEDULE-HOME
The definitions are usually split into several files. For instance, here is a partial content of `fifawc2002.scm':
(define-module (fifawc2002)) (use-modules ((fifawc2002_rules)) ((fifawc2002_teams) :renamer (symbol-prefix-proc 'fifawc2002:)) ((fifawc2002_schedule) :renamer (symbol-prefix-proc 'fifawc2002:))) ;; definitions of INFO, STAGES, WINNERS omitted (export fifawc2002:INFO fifawc2002:STAGES fifawc2002:WINNERS) (re-export fifawc2002:TEAMS fifawc2002:TEAM-FORMAT fifawc2002:SCHEDULE fifawc2002:SCHEDULE-FORMAT fifawc2002:SCHEDULE-DATE fifawc2002:SCHEDULE-HOME)
The following sections describe contents of the exported variables.
An associative list pointed to by the <tour-name>:TEAMS
variable binds global team IDs to the team descriptions.
<tour-name>:TEAMS : '(("<TEAM-GLOBAL-ID-1" <team-description-list>) ...)
<team-description-list>
is a list of strings as defined by the
<tour-name>:TEAM-FORMAT
variable. Only NAME
of teams
is required to be specified in <tour-name>:TEAM-FORMAT
, this
name will be returned as the team identifier in libtour
queries.
For instance, team definitions for the 2003 Ice Hockey WC included in
the libtour
distribution, contains the following (trimmed for
space):
(define ihwc2003:TEAMS '(("SVK" "Slovakia") ; "SVK" is a global team ID ("RUS" "Russia") ; "Russia" is a team name ; according to the TEAM-FORMAT ; definition below ("SWE" "Sweden") ...)) (define ihwc2003:TEAM-FORMAT '(NAME))
<tour-name>:STAGES
variable exported by the tournament module
contains a Scheme list where each list member describes one stage.
<tour-name>:STAGES : (<stage-definition> ...) <stage-definition>: ((ID . <string for the stage ID>) (NAME . <string for the stage name>) (STANDINGS-FIELDS . <standings-fields list>) (GAMERES-FIELDS . <gameres-fields list>) (RES-F . <game-result-interpretation-procedure>) (TEAMS . <teams-definition>) (GROUPS . <groups-definition>) (SUMMARY . <summary-definition>) (FILTERS . <filters-definition>)) (MAX-POINTS . <max-points-definition>))
The ID
string can be anything, by convention it is "S1" for
the first stage, "S2" for the second etc. The NAME
string
usually denotes what the stage is called, "Preliminary", or
"Quarterfinals".
MAX-POINTS
defines maximum number of points a team can get in a
game. If such information can be provided for this stage, the value
must be an integer greater than zero. If, on the other hand, maximum
points can't be defined, a false value #f
shoud be used.
The rest of the keys are described in the following subsections.
STANDINGS-FIELDS
defines a list of column (or field) names for a
team in a table of standings, like this:
'(GAMES WINS DRAWS LOSSES GOALS-FOR GOALS-AGAINST POINTS)
All the fields will contain integers. The following fields are
required to be present: GAMES
, and POINTS
GAMERES-FIELDS
denotes the fields for a game result. It consists
of a pair of lists, the names of the fields in the first and types of
the fields in the second. For instance, if a game results can be
described by three items, goals scored by the first team, goals scored
by the second team, and whether the game ended in overtime, the game
fields may be defined like following:
'((GF GA OT) int int bool)
int
and bool
are the only two supported types.
A Scheme procedure placed under the RES-F
key will be used by
libtour
for interpreting a game result. It expects an
associative list as the sole argument, whose keys are the same as
GAMERES-FIELDS
. For instance, for the GAMERES-FIELDS
shown
above and the game in which the first team lost 2 to 3 in regulation
time (OT is false), the argument will be
'((GF . 2) (GA . 3) (OT . 0))
The RES-F
procedure should return a pair of associative lists
that describe change of STANDINGS-FIELDS
for each of the
teams. Continuing our example, if a team is awarded two points for a
win, and zero for a loss, the procedure can return the following:
'( ;;; first team list ((GAMES . 1) ; increment game count by 1 (LOSSES . 1) ; increment loss count by 1 (GOALS-FOR . 2) ; first team scored 2 goals (GOALS-AGAINST . 3)) ; first team allowed 3 goals (GAMES . 1) ;;; second team list (WINS . 1) ; increment win count by 1 (GOALS-FOR . 3) (GOALS-AGAINST . 2) (POINTS . 2)) ; second team earned 2 points
The return lists may contain an association pair for any of the fields
found in the STANDINGS-FIELDS
list even if their values haven't
changed (such as (POINTS . 0)
for the first team).
Note that values of the POINTS
entry cannot exceed the value
defined in MAX-POINTS
for current stage (see section Stages definition).
mk-res-lists
helper procedure defined in the (libtour
common)
module (see section common module) is useful when creating a
resulting list.
The TEAMS
definition is an associative list with team IDs
local to stage (see section Structure of a tournament) as keys and
procedures of no argument (thunks) that return global team IDs when
called:
'(("TEAM-LOCAL-ID-1" . <thunk>) ...)
Team local IDs can be any strings, but it is convenient to give them
somewhat meaningful names. For the first stage of a tournament teams
are known in advance, therefore the TEAMS
list might look like
following:
`(("TEAM-LOCAL-ID-1" . ,(lambda () "TEAM-GLOBAL-ID-1")) ...)
For the following stages the thunk will be called after the previous stage is compete. Here is an example of specifying the team that took the first place in group "A" in the previous stage:
`("PREV-STAGE-A-1" . ,(lambda () <code to determine the real team ID>))
The thunk has to throw a Guile error if it cannot determine the global team ID.
The GROUPS
key in the stage definition list corresponds to an
associative list of group definitions.
<group-definitions>: (<group-definition> ...) <group-definition>: ((ID . <string for the group ID>) (NAME . <string for the group name>) (DESCRIPTION . <string for the group description>) ;; optional (G-TEAMS . <stage-local team-IDs list>) (FORMULA . <playing formula specification>) (G-CMP-F . <teams-comparison-procedure>) (G-GAME-HERE-F . <game-belongs-to-this-group-procedure-or-spec>))
Like for a stage, the ID
string can be anything unique, and
NAME
string usually describes what a group is, like "Group
A", or "Semifinal Pair 1". The DESCRIPTION
string is
optional and can contain some additional information about the group;
it is filled in by libtour
for filtered groups (see section Filtered groups).
The G-TEAMS
is a list of team IDs (local to the stage). Team
IDs for a group should be subset of the the keys in stage's
TEAMS
definition (see section Stage teams definition). A team may
belong to more than one group within a stage.
Group playing formula helps determine how many games should be played between the teams within a group and when the group becomes complete (see section Game results and formula). The following values are allowed for a formula definition:
'(ROUND <number>)
'(TEAM-GAMES <number>)
'(PLAYOFF <number>)
'(NONE)
The procedure defined under the G-CMP-F
key in the group
definition will be used by libtour
for sorting teams within
the group.
The procedure must accept five arguments: (1) tournament name, (2) stage ID, (3) group ID, and (4,5) team result lists of the two teams to be compared. The first three arguments are obvious. Each of the last two contains an associative list of team results (see section Standings and Game result fields definitions) plus a team ID (local to stage) association pair, for example:
'((GAMES . 10) ;; these are STANDINGS-FIELDS (WINS . 7) (DRAWS . 1) (LOSSES . 2) (GOALS-FOR . 22) (GOALS-AGAINST . 7) (POINTS . 15) (ID . "<TEAM-LOCAL-ID>")) ;; additional ID entry
The procedure must return 1
if the first team results are
higher than the second's, -1
if opposite, and 0
if the
teams appear to be equal.
An example of the sorting procedure below uses helper procedures from
module (libtour common)
(see section common module).
(define cmp-f (lambda (tour-name stage-id group-id t1 t2) (or ;; compare points (cmp-assoc-field-p 'POINTS t1 t2) ;; if points are equal, compare goal difference (cmp-assoc-field-diff-p 'GOALS-FOR 'GOALS-AGAINST t1 t2) ;; if goal differences are equal, see which team scored more (cmp-assoc-field-p 'GOALS-FOR t1 t2) ;; if equal, compare personal games for these two teams (cmp-two-teams-p c-tour-name stage-id (assoc-ref t1 'ID) (assoc-ref t2 'ID) ;; another cmp procedure cmp-prelim-stage-personal-f ;; consider only games between these two teams 'BOTH) 0))) ;; give up, the teams are equal
To determine if a game belongs to a given group, another Scheme
procedure should be supplied. For the two most common cases, however,
libtour
provides shortcuts so that a predefined Scheme symbol
can be given instead of a procedure.
'BOTH
'ANY
(lambda (game-alist) ...)
(#f . #f)
if none of the two teams' result should be
recorded in this group (and therefore the game does not belong to this
group), or one of (#t . #f)
, (#f . #t)
, (#t . #t)
if only the first, or only the second, or both teams' results
correspondingly should be recorded in this group.
If a procedure is supplied, it should expect a game associative list
and be in the format defined by the SCHEDULE-FORMAT
(see section Game schedule definition), for instance:
'((ID . 123) (DATE . "23.06.2003 15:00") (TEAM1 . "<TEAM-LOCAL-ID-1>") (TEAM2 . "<TEAM-LOCAL-ID-2>"))
As mentioned, the procedure should return a pair of boolean values.
A SUMMARY
entry controls creation of a summary group for a
stage (see section Summary group). If its value is #f
, no summary
group will be created. If it contains a procedure, a summary group
will be created for the stage, and this procedure will be used for
team comparison (like see section Teams comparison procedure) within this
group.
A FILTERS
entry in a stage definition defines what team and/or
game filters are aplicable to this stage (see section Filtered groups). It
contains an associative list with the following optional keys:
TEAM-FILTERS
, and GAME-FILTERS
; the values are lists of
filters:
((TEAM-FILTERS <team-filter-making-procedure> ...) (GAME-FILTERS <game-filter-making-procedure> ...))
If no filters can be applied, the list is empty.
Winners (or losers) are the teams that finished the tournament with some distinguishable result: won gold, or lost everything. Winners definition is very similar to the one for teams within a stage (see section Stage teams definition). The differences are:
#f
rather than throw error.
Here is an example of a Winners list:
(define <tour-name>:WINNERS '(("Gold" . <thunk>) ("Silver" . <thunk>) ("Bronze" . <thunk>)))
The <tour-name>:SCHEDULE
variable contains a list in the form:
'(<stage-list> ...) stage-list: ("stage-id" <entry> ...) entry: <game-definition> or <thunk>
where <game-definition>
is a list of string members defined in
tour-name:SCHEDULE-FORMAT
, and <thunk>
is a procedure of
no arguments that returns a list of <game-definition>
. The
<thunk>
list elements (if any) are run at the time the stage
changes its state from "uninitialized" to "ready".
A <game-definition>
may look like this:
'(("1" "31.05.02 20:30" "<place>" "<stage-local team ID 1>" "<stage-local team ID 2>"))
To allow loading stages with unknown schedule <entry>
members
are optional. Note, however, that a stage with no schedule can never
become "complete".
tour-name:SCHEDULE-FORMAT
variable defines the meaning of the
list members. For the preceding example it would be:
'(ID DATE TIME PLACE TEAM1 TEAM2)
Note that ID
, DATE
, TEAM1
, and
TEAM2
fields are mandatory, any other -- optional. Games are
not required to be sorted as the sorting is done internally by
libtour
.
Interestingly, you can also supply a game result along with the game's
schedule entry. If the game list contains more items than there is in
SCHEDULE-FORMAT
list, the rest is assumed to contain the game
result in the format according to GAMERES-FIELDS
. If the game
result specified in the schedule, the game will be read-only. This
obscure feature allows to implement carry-forward games but can also
be used for pre-setting game results in the schedule.
tour-name:SCHEDULE-DATE
variable should be provided. It is a
string that describes the format of the DATE
field in game
definitions. The format description style used is identical to the one
of UNIX strptime(3)
C function. For instance, a date
"2001-11-12 18:30"
would be have format "%Y-%m-%d %H:%M"
Please see the corresponding man page for details.
tour-name:SCHEDULE-HOME
variable notifies the position of the
home team in the game definitions. The following values
(integer
type) are permitted:
TEAM1
field is the home team
TEAM2
field is the home team
Go to the first, previous, next, last section, table of contents.