The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Games::Tournament::Swiss::Bracket - Players with same/similar scores pairable with each other

SYNOPSIS

    $tourney = Games::Tournament::Swiss>new($rounds, \@entrants);
    @rankedPlayers = $tourney->assignPairingNumbers;
    @firstbrackets = $t->formBrackets;
    ...
    $tourney->collectCards(@games);
    @scores = $tourney->updateScores($round);
    @groups = $tourney->formBrackets;

DESCRIPTION

In a Swiss tournament, in each round contestants are paired with other players with the same, or similar, scores. These contestants are grouped into a score group (bracket) in the process of deciding who plays who.

The concept of immigration control is applied to impose order on the players floating in and out of these score brackets. That is, floating is like flying. I pulled back on this metaphor. It was probably overengineering.

METHODS

new

 $group = Games::Tournament::Swiss::Bracket->new( score => 7.5, members => [ $a, $b, $c ], remainderof => $largergroup )

members is a reference to a list of Games::Tournament::Contestant::Swiss objects. The order is important. If the score group includes floaters, these members' scores will not be the same as $group->score. Such a heterogenous group is paired in two parts--first the downfloaters, and then the homogeneous remainder group. Remainder groups can be recognized by the existence of a 'remainderof' key that links them to the group they came from. Some members may also float down from a remainder group. Each bracket needs a score to determine the right order they will be paired in. The number, from 1 to the total number of brackets, reflects that order. A3

natives

 @floaters = $group->natives

Returns those members who were in this bracket originally, as that was their birthright, their scores being all the same. One is a native of only one bracket, and you cannot change this status except XXX EVEN by naturalization.

citizens

 @floaters = $group->citizens

Returns those members who belong to this bracket. These members don't include those have just floated in, even though this floating status may be permanent. One is a citizen of only one bracket, and you cannot change this status except by naturalization.

naturalize

 $citizen = $group->naturalize($foreigner)

Gives members who are resident, but not citizens, ie immigrants, having been floated here from other brackets, the same status as natives, making them indistinguishable from them. This will fail if the player is not resident or not an immigrant. Returns the player with their new status.

immigrants

 @floaters = @{$group->immigrants}

Returns those members who are foreigners, having been floated here from other brackets. At any one point a player may or may not be a foreigner. But if they are, they only can be a foreigner in one bracket.

downFloaters

 @floaters = $group->downFloaters

Returns those members downfloated here from higher brackets.

upFloaters

 @s1 = $group->upFloaters

Returns those members upfloated from the next bracket.

residents

        $pairables = $bracket->residents

Returns the members includeable in pairing procedures for this bracket because they haven't been floated out, or because they have been floated in. That is, they are not an emigrant. At any one point, a player is resident in one and only one bracket, unless they are in transit. At some other point, they may be a resident of another bracket.

emigrants

        $bracket->emigrants($member)
        $gone = $bracket->emigrants

Sets whether this citizen will not be included in pairing of this bracket. That is whether they have been floated to another bracket for pairing there. Gets all such members. A player may or may not be an emigrant. They can only stop being an emigrant if they move back to their native bracket. To do this, they have to be processed by 'entry'.

exit

        $bracket->exit($player)

Removes $player from the list of members of the bracket. They are now in the air. So make sure they enter another bracket.

entry

        $bracket->entry($native)
        $bracket->entry($foreigner)

Registers $foreigner as a resident (and was removing $native from the list of emigrants of this bracket, because they have returned from another bracket as in C12, 13).

reentry

        $bracket->reentry($member)

Removes this native (presumably) member from the list of emigrants of this bracket, because they have returned from another bracket as in C12, 13. Returns undef, if $member wasn't an emigrant. Otherwise returns the updated list of emigrants.

dissolved

 $group->dissolved(1)
 $s1 = $group->s1($players)
 $s1 = $group->s1

Dissolve a bracket, so it is no longer independent, its affairs being controlled by some other group:

s1

 $group->s1
 $s1 = $group->s1($players)
 $s1 = $group->s1

Getter/setter of the p players in the top half of a homogeneous bracket, or the p downFloaters in a heterogeneous bracket, as an array. A6

s2

 $s2 = $group->s2

Getter/Setter of the players in a homogeneous or a heterogeneous bracket who aren't in S1. A6

resetS12

 $group->resetS12

Resetter of S1 and S2 to the original members, ranked before exchanges in C8. A6

resetShuffler

    $previous->entry($_) for @returnees;
    $previous->resetShuffler;
    return C7;

Take precautions to prevent transposing players who are no longer in the bracket in S2, or to make sure they ARE transposed, when finding a different pairing, before returning from C10,12,13 (C11?). Do this by resetting S1 and S2. Don't use this in the wrong place. We don't want to try the same pairing twice.

p

 $tables = $group->p

Half the number of players in a homogeneous bracket, rounded down to the next lowest integer. Or the number of down floaters in a heterogeneous bracket. Also the number of players in S1, and thus the number of pairings in the pair group. If there are more downfloaters than original members, half the number of players. (See A1,2)A6

bigGroupP

 $tables = $group->bigGroupP

Half the number of players in a big bracket (group), rounded down to the next lowest integer. Sometimes the number of pairs in a combined bracket, particularly, a heterogeneous bracket and its remainder group is needed. In such cases, p will be just the number of downfloated players, which is not what we want. In a non-heterogeneous bracket, bigGroupP will be the same as p. See C11

pprime

 $tables = $group->pprime

p is half the number of players in a bracket, but we may have to accept fewer pairings than this number if suitable opponents cannot be found for players, up to the point where p=0. pprime sets/gets this real p number. A8

bigGroupPprime

 $tables = $group->bigGroupPprime

bigGroupP is half the number of players in a heterogeneous bracket and its remainder group, but we may have to accept fewer pairings than this number if suitable opponents cannot be found for players, up to the point where no players are paired. bigGroupPprime sets/gets this real p number for the combined groups/brackets. A8

q

 $tables = $group->q

Number of players in the score bracket divided by 2 and then rounded up. In a homogeneous group with an even number of players, this is the same as p. A8

x

 $tables = $group->x

Sets the number, ranging from zero to p, of matches in the score bracket in which players will have their preferences unsatisfied. A8

bigGroupX

 $tables = $group->bigGroupX

x is okay for a homogeneous group, uncombined with other groups, but in the case of groups that are interacting to form joined brackets, or in that of a heterogeneous bracket and a remainder group, we need a bigGroupX to tell us how many matches in the total number, ranging from zero to bigGroupP, of matches in the score bracket(s) will have players with unsatisfied preferences. A8

bigGroupXprime

 $tables = $group->bigGroupXprime

xprime is a revised upper limit on matches where preferences are not satisfied, but in the case of a combined bracket (in particular, a heterogeneous bracket and a remainder group) we need a figure for the total number of preference-violating matches over the 2 sections, because the distribution of such matches may change. bigGroupXprime sets/gets this total x number. A8

xprime

 $tables = $group->xprime

x is the lower limit on matches where preferences are not satisfied, but the number of such undesirable matches may be increased if suitable opponents cannot be found for players, up to the point where only players with Absolute preferences have their preferences satisfied. xprime sets/gets this real x number. A8

floatCheckWaive

 $tables = $group->floatCheckWaive

There is an ordered sequence in which the checks of compliance with the Relative Criteria B5,6 restriction on recurring floats are relaxed in C9,10. The order is 1. downfloats for players downfloated 2 rounds before, 2. downfloats for players downfloated in the previous round (in C9), 3. upfloats for players floated up 2 rounds before, 4. upfloats for players floated up in the previous round (for players paired with opponents from a higher bracket in a heterogeneous bracket, in C10). (It appears levels are being skipped, eg from B6Down to B6Up or from All to B6Down.) Finally, although it is not explicitly stated, all float checks must be dropped and pairings considered again, before reducing the number of pairs made in the bracket. (This is not entirely correct.) This method sets/gets the float check waive level at the moment. All criteria below that level should be checked for compliance. The possible values in order are 'None', 'B6Down', 'B5Down', 'B6Up', 'B5Up', 'All'. TODO Should there be some way of not requiring the caller to know how to use this method and what the levels are.

hetero

        $group->hetero

Gets (but doesn't set) whether this group is heterogeneous, ie includes players who have been downfloated from a higher score group, or upfloated from a lower score group, or if it is homogeneous, ie every player has the same score. A group where half or more of the members have come from a higher bracket is regarded as homogeneous. We use the scores of the players, rather than a floating flag.

trueHetero

        $group->trueHetero

Gets whether this group is really heterogeneous, ie includes players with different scores, because they been downfloated from a higher score group, or upfloated from a lower score group, even if it is being treated as homogeneous. A group where half or more of the members have come from a higher bracket is regarded as homogeneous, but it is really heterogeneous.

c7shuffler

        $nextS2 = $bracket->c7shuffler($firstmismatch)
        if ( @nextS2 compatible )
        {
            create match cards;
        }

Gets the next permutation of the second-half players in D1 transposition counting order, as used in C7, that will not have the same incompatible player in the bad position found in the present transposition. If you get an illegal modulus error, check your $firstmismatch is a possible value.

c7iterator

        $next = $bracket->c7iterator
        while ( my @s2 = &$next )
        {
            create match cards unless this permutation is incompatible;
        }

DEPRECATED Creates an iterator for the permutation of the second-half players in D1 transposition counting order, as used in C7. Only as many players as are in S1 can be matched, so we get only the permutations of all the p-length combinations of members of S2. Deprecated because if C1 or C6 finds a player in a certain position in S2 should not be paired with the player in the corresponding position in S1, we need to be able to skip ahead to the next permutation where a different player is in that position.

c8iterator

        $next = $bracket->c8iterator
        while ( my @members = &$next )
        {
            next if grep {$incompat{$s1[$_]}{$s2[$_]}} 0..$p-1);
        }

Creates an iterator for the exchange of @s1 and @s2 players in D2 order, as used in C8. Exchanges are performed in order of the difference between the pairing numbers of the players exchanged. If the difference is equal, the exchange with the lowest player is to be performed first. XXX Only as many players as in S1 can be matched, so does this mean some exchanges don't have an effect? I don't understand the description when there are an odd number of players. There appears to be a bug with only 3 players. 1 and 2 should be swapped, I think. I think the order of exchanges of 2 players each may also have some small inconsistencies with the FIDE order.

score

        $group->score

Gets/sets the score of the score group.

number

        $group->number

Gets/sets the bracket's number, a number from 1 to the number of separate brackets, remainder groups and bye groups in the tournament. Don't use this number for anything important.

badpair

        $group->badpair

Gets/sets the badpair, the position, counting from zero, of the first pair in S1 and S2 for which pairing failed in a previous attempt in C6. This is the first position at which the next ordering of S2 will differ from the previous one. All orderings between these two orderings will not result in a criteria-compliant pairing.

members

        $group->members

Gets/sets the members of the score group as an anonymous array of player objects. The order of this array is important. The first half is paired with the second half.

c8swapper

        $pairing->c8swapper

Gets/sets an iterator through the different exchanges of players in the two halves of the bracket.

_floatCheck

        %b65TestResults = _floatCheck( \@testee, $checkLevels );

Takes a list representing the pairing of a bracket (see the description for _getNonPaired), and the various up- and down-float check levels. Returns an anonymous hash with keys: (a) 'badpos', the first element of the list responsible for violation of B6 or 5, if there was a violation of any of the levels, (b) 'passer', an anonymous array of the same form as \@testee, if there was no violation of any of the levels, and (c) 'message', a string noting the reason why the pairing is in violation of B6 or 5, and the id of the player involved. If there are multiple violations, the most important one is/should be returned.

_getNonPaired

        $bracket->_getNonPaired([$alekhine,$uwe],undef,[$deepblue,$yournewnike])

Takes a list representing the pairing of S1 and S2. Each element of the list is either a 2-element anonymous array ref (an accepted pair of players), or undef (a rejected pair.) Returns an array of the same form, but with the accepted player items replaced by undef and the undef items replaced by the pairs rejected. If there are more players in S2 than S1, those players are represented as [undef,$player].

AUTHOR

Dr Bean, <drbean, followed by the at mark (@), cpan, then a dot, and finally, org>

BUGS

Please report any bugs or feature requests to bug-games-tournament-swiss at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Games-Tournament-Swiss. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Games::Tournament::Swiss::Bracket

You can also look for information at:

ACKNOWLEDGEMENTS

See http://www.fide.com/official/handbook.asp?level=C04 for the FIDE's Swiss rules.

COPYRIGHT & LICENSE

Copyright 2006 Dr Bean, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.