Round-robin tournament schedule

From Rosetta Code
Revision as of 16:04, 15 November 2021 by SqrtNegInf (talk | contribs) (→‎{{header|Perl}}: more general)
Round-robin tournament schedule is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

A round-robin tournament is also known as an all-play-all-tournament; each participant plays every other participant once.

For N participants the number of rounds is N-1 if N is an even number. When there are an odd number of participants then each round one contestor has no opponent (AKA as a "bye"). The number of rounds is N in that case.

Task

Write a program that prints out a tournament schedule for 12 participants (represented by numbers 1 to 12).

See also


FreeBASIC

<lang freebasic>function nob( n as uinteger, i as uinteger, bye as boolean ) as string

   'helper function to allow byes to be printed intelligently
   dim as string pad
   if n > 9 then pad = " " else pad = ""
   if n = i and bye then 
       return pad+"B" 
   else 
       if i<10 then return pad + str(i) else return str(i)
   end if

end function

sub roundrob( byval n as uinteger )

   dim as boolean bye = false
   if n mod 2 = 1 then      'if there is an odd number of competitors
       bye = 1              'make note of this fact
       n += 1               'and treat the tournament as having one more competitor
   end if
   dim as uinteger schd(1 to n), r, i, temp1, temp2
   for i = 1 to n
       schd(i) =i           'initial population of the array with numbers 1-n
   next i
   for r = 1 to n-1
       print using "Round ##:   ";r;
       for i = 1 to n/2     'print the pairings according to the scheme
                            '1 2 3 4
                            '5 6 7 8
           print using "(& - &)  ";nob(n,schd(i),bye);nob(n,schd(i+n\2),bye);
       next i
       print
       'now move positions 2-n around clockwise
       temp1 = schd(n/2)    'need to track two temporary variables
       temp2 = schd(n/2+1)
       for i = n/2 to 3 step -1  'top row
           schd(i) = schd(i-1)
       next i
       for i = n/2+1 to n-1      'bottom row
           schd(i) = schd(i+1)
       next i
       schd(n) = temp1           'fill in the ones that "jumped" between rows
       schd(2) = temp2
   next r

end sub

print "Twelve teams" roundrob(12) print "Nine teams with byes" roundrob(9) </lang>

Output:

Twelve teams Round 1: ( 1 - 7) ( 2 - 8) ( 3 - 9) ( 4 - 10) ( 5 - 11) ( 6 - 12) Round 2: ( 1 - 8) ( 7 - 9) ( 2 - 10) ( 3 - 11) ( 4 - 12) ( 5 - 6) Round 3: ( 1 - 9) ( 8 - 10) ( 7 - 11) ( 2 - 12) ( 3 - 6) ( 4 - 5) Round 4: ( 1 - 10) ( 9 - 11) ( 8 - 12) ( 7 - 6) ( 2 - 5) ( 3 - 4) Round 5: ( 1 - 11) (10 - 12) ( 9 - 6) ( 8 - 5) ( 7 - 4) ( 2 - 3) Round 6: ( 1 - 12) (11 - 6) (10 - 5) ( 9 - 4) ( 8 - 3) ( 7 - 2) Round 7: ( 1 - 6) (12 - 5) (11 - 4) (10 - 3) ( 9 - 2) ( 8 - 7) Round 8: ( 1 - 5) ( 6 - 4) (12 - 3) (11 - 2) (10 - 7) ( 9 - 8) Round 9: ( 1 - 4) ( 5 - 3) ( 6 - 2) (12 - 7) (11 - 8) (10 - 9) Round 10: ( 1 - 3) ( 4 - 2) ( 5 - 7) ( 6 - 8) (12 - 9) (11 - 10) Round 11: ( 1 - 2) ( 3 - 7) ( 4 - 8) ( 5 - 9) ( 6 - 10) (12 - 11) Nine teams with byes Round 1: ( 1 - 6) ( 2 - 7) ( 3 - 8) ( 4 - 9) ( 5 - B) Round 2: ( 1 - 7) ( 6 - 8) ( 2 - 9) ( 3 - B) ( 4 - 5) Round 3: ( 1 - 8) ( 7 - 9) ( 6 - B) ( 2 - 5) ( 3 - 4) Round 4: ( 1 - 9) ( 8 - B) ( 7 - 5) ( 6 - 4) ( 2 - 3) Round 5: ( 1 - B) ( 9 - 5) ( 8 - 4) ( 7 - 3) ( 6 - 2) Round 6: ( 1 - 5) ( B - 4) ( 9 - 3) ( 8 - 2) ( 7 - 6) Round 7: ( 1 - 4) ( 5 - 3) ( B - 2) ( 9 - 6) ( 8 - 7) Round 8: ( 1 - 3) ( 4 - 2) ( 5 - 6) ( B - 7) ( 9 - 8) Round 9: ( 1 - 2) ( 3 - 6) ( 4 - 7) ( 5 - 8) ( B - 9)

Julia

<lang julia>""" https://rosettacode.org/mw/index.php?title=Round-robin_tournament_schedule """

function schurig(N, verbose = true)

   """ Taken from https://en.wikipedia.org/wiki/Round-robin_tournament
       #Original_construction_of_pairing_tables_by_Richard_Schurig_(1886) """
   nrows = isodd(N) ? N : N - 1
   ncols = (N + 1) ÷ 2
   players = mod1.(reshape(collect(1:nrows*ncols), ncols, nrows)', nrows)
   opponents = zero(players)
   table = [(0, 0) for _ in 1:nrows, _ in 1:ncols]
   for i in 1:nrows
       oldrow = i == nrows ? 1 : i + 1
       verbose && print("\n", rpad("Round $i:", 10))
       for j in 1:ncols
           oldcol = ncols - j + 1
           opponents[i, j] = players[oldrow, oldcol]
           j == 1 && (opponents[i, j] = iseven(N) ? N : 0)
           table[i, j] = (sort([players[i, j], opponents[i, j]])...,)
           if verbose
               s1, s2 = string.(table[i, j])
               print(rpad("($(s1 == "0" ? "Bye" : s1) - $s2)", 10))
           end
       end
   end
   return table

end

print("Schurig table for round robin with 12 players:") schurig(12) print("\n\nSchurig table for round robin with 7 players:") schurig(7)

</lang>

Output:
Schurig table for round robin with 12 players:
Round 1:  (1 - 12)  (2 - 11)  (3 - 10)  (4 - 9)   (5 - 8)   (6 - 7)   
Round 2:  (7 - 12)  (6 - 8)   (5 - 9)   (4 - 10)  (3 - 11)  (1 - 2)
Round 3:  (2 - 12)  (1 - 3)   (4 - 11)  (5 - 10)  (6 - 9)   (7 - 8)
Round 4:  (8 - 12)  (7 - 9)   (6 - 10)  (5 - 11)  (1 - 4)   (2 - 3)
Round 5:  (3 - 12)  (2 - 4)   (1 - 5)   (6 - 11)  (7 - 10)  (8 - 9)
Round 6:  (9 - 12)  (8 - 10)  (7 - 11)  (1 - 6)   (2 - 5)   (3 - 4)
Round 7:  (4 - 12)  (3 - 5)   (2 - 6)   (1 - 7)   (8 - 11)  (9 - 10)
Round 8:  (10 - 12) (9 - 11)  (1 - 8)   (2 - 7)   (3 - 6)   (4 - 5)
Round 9:  (5 - 12)  (4 - 6)   (3 - 7)   (2 - 8)   (1 - 9)   (10 - 11)
Round 10: (11 - 12) (1 - 10)  (2 - 9)   (3 - 8)   (4 - 7)   (5 - 6)
Round 11: (6 - 12)  (5 - 7)   (4 - 8)   (3 - 9)   (2 - 10)  (1 - 11)

Schurig table for round robin with 7 players:
Round 1:  (Bye - 1) (2 - 7)   (3 - 6)   (4 - 5)
Round 2:  (Bye - 5) (4 - 6)   (3 - 7)   (1 - 2)
Round 3:  (Bye - 2) (1 - 3)   (4 - 7)   (5 - 6)
Round 4:  (Bye - 6) (5 - 7)   (1 - 4)   (2 - 3)
Round 5:  (Bye - 3) (2 - 4)   (1 - 5)   (6 - 7)
Round 6:  (Bye - 7) (1 - 6)   (2 - 5)   (3 - 4)
Round 7:  (Bye - 4) (3 - 5)   (2 - 6)   (1 - 7)

Perl

<lang perl>#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/Round-robin_tournament_schedule use warnings;

my $n = 12; my @teams = 1 .. $n; for (1 .. $n-1)

 {
 @teams[0,$n-1,1..$n-2] = @teams;
 printf 'Round %2d:' . '%4d vs %2d'x($n/2) . "\n", $_, @teams[ map { $_, $n-1-$_} 0..($n/2)-1 ];
 }</lang>
Output:
Round  1:   1 vs 2    3 vs 12   4 vs 11   5 vs 10   6 vs 9    7 vs 8 
Round  2:   1 vs 3    4 vs 2    5 vs 12   6 vs 11   7 vs 10   8 vs 9 
Round  3:   1 vs 4    5 vs 3    6 vs 2    7 vs 12   8 vs 11   9 vs 10
Round  4:   1 vs 5    6 vs 4    7 vs 3    8 vs 2    9 vs 12  10 vs 11
Round  5:   1 vs 6    7 vs 5    8 vs 4    9 vs 3   10 vs 2   11 vs 12
Round  6:   1 vs 7    8 vs 6    9 vs 5   10 vs 4   11 vs 3   12 vs 2 
Round  7:   1 vs 8    9 vs 7   10 vs 6   11 vs 5   12 vs 4    2 vs 3 
Round  8:   1 vs 9   10 vs 8   11 vs 7   12 vs 6    2 vs 5    3 vs 4 
Round  9:   1 vs 10  11 vs 9   12 vs 8    2 vs 7    3 vs 6    4 vs 5 
Round 10:   1 vs 11  12 vs 10   2 vs 9    3 vs 8    4 vs 7    5 vs 6 
Round 11:   1 vs 12   2 vs 11   3 vs 10   4 vs 9    5 vs 8    6 vs 7 

Raku

<lang perl6>my @players = (1,0)[$_%2] .. $_ given 12; my $half = +@players div 2; my $round = 0;

loop {

   printf "Round %2d: %s\n", ++$round, "{ zip( @players[^$half], @players[$half..*].reverse ).map: { sprintf "(%2d vs %-2d)", |$_ } }";
   @players[1..*].=rotate(-1);
   last if [<] @players;

}</lang>

Output:
Round  1: ( 1 vs 12) ( 2 vs 11) ( 3 vs 10) ( 4 vs 9 ) ( 5 vs 8 ) ( 6 vs 7 )
Round  2: ( 1 vs 11) (12 vs 10) ( 2 vs 9 ) ( 3 vs 8 ) ( 4 vs 7 ) ( 5 vs 6 )
Round  3: ( 1 vs 10) (11 vs 9 ) (12 vs 8 ) ( 2 vs 7 ) ( 3 vs 6 ) ( 4 vs 5 )
Round  4: ( 1 vs 9 ) (10 vs 8 ) (11 vs 7 ) (12 vs 6 ) ( 2 vs 5 ) ( 3 vs 4 )
Round  5: ( 1 vs 8 ) ( 9 vs 7 ) (10 vs 6 ) (11 vs 5 ) (12 vs 4 ) ( 2 vs 3 )
Round  6: ( 1 vs 7 ) ( 8 vs 6 ) ( 9 vs 5 ) (10 vs 4 ) (11 vs 3 ) (12 vs 2 )
Round  7: ( 1 vs 6 ) ( 7 vs 5 ) ( 8 vs 4 ) ( 9 vs 3 ) (10 vs 2 ) (11 vs 12)
Round  8: ( 1 vs 5 ) ( 6 vs 4 ) ( 7 vs 3 ) ( 8 vs 2 ) ( 9 vs 12) (10 vs 11)
Round  9: ( 1 vs 4 ) ( 5 vs 3 ) ( 6 vs 2 ) ( 7 vs 12) ( 8 vs 11) ( 9 vs 10)
Round 10: ( 1 vs 3 ) ( 4 vs 2 ) ( 5 vs 12) ( 6 vs 11) ( 7 vs 10) ( 8 vs 9 )
Round 11: ( 1 vs 2 ) ( 3 vs 12) ( 4 vs 11) ( 5 vs 10) ( 6 vs 9 ) ( 7 vs 8 )

Ruby

<lang ruby>def round_robin( n )

 rotating_players = (2..n).map(&:to_s) #player 1 to be added later
 rotating_players << "bye" if n.odd? 
 Array.new(rotating_players.size) do |r|
   all = ["1"] + rotating_players.rotate(-r)
   [all[0, all.size/2], all[all.size/2..].reverse]
 end

end

round_robin(12).each.with_index(1) do |round, i|

 puts "Round #{i}"
 round.each do |players|
   puts players.map{|player| player.ljust(4)}.join
 end
 puts

end </lang>

Output:
Round 1
1   2   3   4   5   6   
12  11  10  9   8   7   

Round 2
1   12  2   3   4   5   
11  10  9   8   7   6   

Round 3
1   11  12  2   3   4   
10  9   8   7   6   5   

Round 4
1   10  11  12  2   3   
9   8   7   6   5   4   

Round 5
1   9   10  11  12  2   
8   7   6   5   4   3   

Round 6
1   8   9   10  11  12  
7   6   5   4   3   2   

Round 7
1   7   8   9   10  11  
6   5   4   3   2   12  

Round 8
1   6   7   8   9   10  
5   4   3   2   12  11  

Round 9
1   5   6   7   8   9   
4   3   2   12  11  10  

Round 10
1   4   5   6   7   8   
3   2   12  11  10  9   

Round 11
1   3   4   5   6   7   
2   12  11  10  9   8   

Wren

Library: Wren-fmt

<lang ecmascript>import "./fmt" for Fmt

var rotate = Fn.new { |lst|

   var last = lst[-1]
   for (i in lst.count-1..1) lst[i] = lst[i-1]
   lst[0] = last

}

var roundRobin = Fn.new { |n|

   var lst = (2..n).toList
   if (n % 2 == 1) {
       lst = lst + [0] // 0 denotes a bye
       n = n + 1
   }
   var n2 = n / 2
   for (r in 1...n) {
       Fmt.write("Round $2d", r)
       var lst2 = [1] + lst
       for (i in 0...n2) Fmt.write(" ($2d vs $-2d)", lst2[i], lst2[n - 1 - i])
       System.print()
       rotate.call(lst)
   }

}

System.print("Round robin for 12 players:\n") roundRobin.call(12) System.print("\n\nRound robin for 5 players (0 denotes a bye) :\n") roundRobin.call(5)</lang>

Output:
Round robin for 12 players:

Round  1 ( 1 vs 12) ( 2 vs 11) ( 3 vs 10) ( 4 vs 9 ) ( 5 vs 8 ) ( 6 vs 7 )
Round  2 ( 1 vs 11) (12 vs 10) ( 2 vs 9 ) ( 3 vs 8 ) ( 4 vs 7 ) ( 5 vs 6 )
Round  3 ( 1 vs 10) (11 vs 9 ) (12 vs 8 ) ( 2 vs 7 ) ( 3 vs 6 ) ( 4 vs 5 )
Round  4 ( 1 vs 9 ) (10 vs 8 ) (11 vs 7 ) (12 vs 6 ) ( 2 vs 5 ) ( 3 vs 4 )
Round  5 ( 1 vs 8 ) ( 9 vs 7 ) (10 vs 6 ) (11 vs 5 ) (12 vs 4 ) ( 2 vs 3 )
Round  6 ( 1 vs 7 ) ( 8 vs 6 ) ( 9 vs 5 ) (10 vs 4 ) (11 vs 3 ) (12 vs 2 )
Round  7 ( 1 vs 6 ) ( 7 vs 5 ) ( 8 vs 4 ) ( 9 vs 3 ) (10 vs 2 ) (11 vs 12)
Round  8 ( 1 vs 5 ) ( 6 vs 4 ) ( 7 vs 3 ) ( 8 vs 2 ) ( 9 vs 12) (10 vs 11)
Round  9 ( 1 vs 4 ) ( 5 vs 3 ) ( 6 vs 2 ) ( 7 vs 12) ( 8 vs 11) ( 9 vs 10)
Round 10 ( 1 vs 3 ) ( 4 vs 2 ) ( 5 vs 12) ( 6 vs 11) ( 7 vs 10) ( 8 vs 9 )
Round 11 ( 1 vs 2 ) ( 3 vs 12) ( 4 vs 11) ( 5 vs 10) ( 6 vs 9 ) ( 7 vs 8 )


Round robin for 5 players (0 denotes a bye) :

Round  1 ( 1 vs 0 ) ( 2 vs 5 ) ( 3 vs 4 )
Round  2 ( 1 vs 5 ) ( 0 vs 4 ) ( 2 vs 3 )
Round  3 ( 1 vs 4 ) ( 5 vs 3 ) ( 0 vs 2 )
Round  4 ( 1 vs 3 ) ( 4 vs 2 ) ( 5 vs 0 )
Round  5 ( 1 vs 2 ) ( 3 vs 0 ) ( 4 vs 5 )

XPL0

<lang XPL0>def N = 12; \number of players (must be even) int I, Player(N+1), Round, Temp; [for I:= 1 to N do Player(I):= I; for Round:= 1 to N-1 do

   [IntOut(0, Round);  ChOut(0, ^:);
   for I:= 1 to N/2 do
       [ChOut(0, 9\tab\);  IntOut(0, Player(I))];
   CrLf(0);
   for I:= N downto N/2+1 do
       [ChOut(0, 9\tab\);  IntOut(0, Player(I))];
   CrLf(0);  CrLf(0);
   Temp:= Player(N);   \rotate
   for I:= N-1 downto 2 do
       Player(I+1):= Player(I);
   Player(2):= Temp;
   ];

]</lang>

Output:
1:      1       2       3       4       5       6
        12      11      10      9       8       7

2:      1       12      2       3       4       5
        11      10      9       8       7       6

3:      1       11      12      2       3       4
        10      9       8       7       6       5

4:      1       10      11      12      2       3
        9       8       7       6       5       4

5:      1       9       10      11      12      2
        8       7       6       5       4       3

6:      1       8       9       10      11      12
        7       6       5       4       3       2

7:      1       7       8       9       10      11
        6       5       4       3       2       12

8:      1       6       7       8       9       10
        5       4       3       2       12      11

9:      1       5       6       7       8       9
        4       3       2       12      11      10

10:     1       4       5       6       7       8
        3       2       12      11      10      9

11:     1       3       4       5       6       7
        2       12      11      10      9       8