Round-robin tournament schedule

From Rosetta Code
Task
Round-robin tournament schedule
You are encouraged to solve this task according to the task description, using any language you may know.

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


Ada

-- Create a round-robin schedule
-- J. Carter     2023 May
-- Circle method

with Ada.Text_IO;

procedure Round_Robin is
   type Player_ID is range 1 .. 12;
   
   type Player_List is array (Player_ID) of Player_ID;

   Circle : Player_List;
   J      : Player_ID;
begin -- Round_Robin
   Fill : for I in Circle'Range loop
      Circle (I) := I;
   end loop Fill;
   
   All_Rounds : for Round in 1 .. Player_ID'Last - 1 loop
      Ada.Text_IO.Put_Line (Item => "Round" & Round'Image);
      J := Player_ID'Last;

      Pairs : for I in 1 .. Player_ID'Last / 2 loop
         Order : declare
            Min : constant Player_ID := Player_ID'Min (Circle (I), Circle (J) );
            Max : constant Player_ID := Player_ID'Max (Circle (I), Circle (J) );
         begin -- Order
            Ada.Text_IO.Put_Line (Item => Min'Image & " v" & Max'Image);
            J := J - 1;
         end Order;
      end loop Pairs;
      
      Ada.Text_IO.New_Line;
      Circle := Circle (Circle'First) & Circle (Circle'Last) & Circle (Circle'First + 1 .. Circle'Last - 1);
   end loop All_Rounds;
end Round_Robin;
Output:
Round 1
 1 v 12
 2 v 11
 3 v 10
 4 v 9
 5 v 8
 6 v 7

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

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

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

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

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

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

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

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

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

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

ALGOL 68

Translation of: XPL0
BEGIN # round-robin tournament schedule - translation of XPL0 #
    INT n = 12;            # number of players (must be even) #
    [ 1 : n ]INT player;
    FOR i TO n DO player[ i ] := i OD;
    FOR round TO n - 1 DO
        print( ( whole( round, 0 ), ":" ) );
        FOR i TO n OVER 2 DO
            print( ( REPR 9, whole( player[ i ], 0 ) ) )
        OD;
        print( ( newline ) );
        FOR i FROM n BY -1 TO ( n OVER 2 ) + 1 DO
            print( ( REPR 9, whole( player[ i ], 0 ) ) )
        OD;
        print( ( newline, newline ) );
        INT nth player   = player[ n ];
        player[ 3 : n ] := player[ 2 : n - 1 ];
        player[ 2     ] := nth player
    OD
END
Output:

Same as the XPL0 sample.

APL

 SCHEDULER N;R;I
  R(N),(2|N)'-'
  I0  N(R)
 L:'ROUND',II+1
  ((N÷2)R),[0.5](N÷2)R
  R(1R),11R
  (I<N-1)/L

Output:
SCHEDULER 4
ROUND 1
1 2
4 3
ROUND 2
1 3
2 4
ROUND 3
1 4
3 2

AWK

# syntax: GAWK -f ROUND-ROBIN_TOURNAMENT_SCHEDULE.AWK
BEGIN {
    main(1)
    main(2)
    main(5,"The Bizzaros")
    main(12)
    exit(0)
}
function main(n,description,  arr,i,j,leng,tmp) {
    if (n < 2) {
      printf("\n%d is too few participants\n",n)
      return
    }
    printf("\n%d players  %s\n",n,description)
    for (i=1; i<=n; i++) {
      arr[i] = i
    }
    if (n % 2 == 1) {
      arr[++n] = 0 # a "bye"
    }
    leng = length(n-1)
    for (i=1; i<n; i++) {
      printf("\nround %*d:",leng,i)
      for (j=1; j<=n/2; j++) {
        printf("%4s",arr[j]==0?"bye":arr[j])
      }
      printf("\n%*s",leng+7,"")
      for (j=n; j>n/2; j--) {
        printf("%4s",arr[j]==0?"bye":arr[j])
      }
      printf("\n")
      tmp = arr[n]
      for (j=n; j>2; j--) {
        arr[j] = arr[j-1]
      }
      arr[2] = tmp
    }
}
Output:
1 is too few participants

2 players

round 1:   1
           2

5 players  The Bizzaros

round 1:   1   2   3
         bye   5   4

round 2:   1 bye   2
           5   4   3

round 3:   1   5 bye
           4   3   2

round 4:   1   4   5
           3   2 bye

round 5:   1   3   4
           2 bye   5

12 players

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

BASIC

BASIC256

Translation of: FreeBASIC
arraybase 1
print "Twelve teams"
call roundrob(12)
print "Nine teams with byes"
call roundrob(9)
end

function nob(n,i,byes)
  #helper function to allow byess to be printed intelligently

  if n > 9 then pad = " " else pad = ""
  if n = i and byes then
    return pad + "B"
  else
    if i < 10 then return pad + string(i) else return string(i)
  end if
end function

subroutine roundrob(n)
  byes = 0
  if n mod 2 = 1 then #if there is an odd number of competitors
    byes = 1          #make note of this fact
    n += 1            #and treat the tournament as having one more competitor
  end if
  dim schd(n)
  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 "Round "; rjust(string(r), 2); ":  ";
    for i = 1 to n/2  #print the pairings according to the scheme
                      #1 2 3 4
                      #5 6 7 8
      print "("; nob(n,schd[i],byes); " -"; nob(n,schd[i+n/2],byes); " )  ";
    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 #end ifll in the ones that "jumped" between rows
    schd[2] = temp2
  next r
end subroutine

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)
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)

uBasic/4tH

Translation of: FreeBASIC
Print "Twelve teams"
Proc _Roundrob(12)
Print
Print "Nine teams with byes"
Proc _Roundrob(9)

End

_Roundrob
  Param (1)
  Local (5)

  b@ = 0
                             ' if there is an odd number of competitors
  If a@ % 2 = 1 Then b@ = 1 : a@ = a@ + 1
                             ' make note of this fact and treat the tournament 
  For d@ = 1 To a@           ' as having one more competitor
    @(d@) = d@               ' initial population of the array with numbers 1-n
  Next

  For c@ = 1 To a@-1         ' print the pairings according to the scheme
    Print Using "Round __:  ";c@;
                             ' 1 2 3 4
    For d@ = 1 To a@/2       ' 5 6 7 8
      Print Show(Iif (a@ = @(d@) * b@, " ( B - ", Str(" (_# - ", @(d@))));
      Print Show(Iif (a@ = @(d@+a@/2) * b@, " B) ", Str("_#) ", @(d@+a@/2))));
    Next

    Print                    ' now move positions 2-n around clockwise
    e@ = @(a@/2)             ' need to track two temporary variables
    f@ = @(a@/2+1)
                             ' top row
    For d@ = a@/2 To 3 Step -1
      @(d@) = @(d@-1)
    Next
                             ' bottom row
    For d@ = a@/2+1 To a@-1
      @(d@) = @(d@+1)
    Next

    @(a@) = e@               ' fill in the ones that "jumped" between rows
    @(2) = f@
  Next
Return

Yabasic

Translation of: FreeBASIC
print "Twelve teams"
roundrob(12)
print "Nine teams with byes"
roundrob(9)
end

sub nob$(n,i,byes)
  //helper sub to allow byess to be printed intelligently
  //dim as string pad
  if n > 9 then pad$ = " " else pad$ = "" : fi
  if n = i and byes then
    return pad$+"B"
  else
    if i < 10 then return pad$+str$(i) else return str$(i) : fi
fi
end sub

sub roundrob(n)
byes = 0
if mod(n, 2) = 1 then //if there is an odd number of competitors
byes = 1 //make note of this fact
n = n+1  //and treat the tournament as having one more competitor
fi
dim schd(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 "Round ", r using "##", ":  ";
  for i = 1 to n/2 //print the pairings according to the scheme
    //1 2 3 4
    //5 6 7 8
    print "(", nob$(n,schd(i),byes), " -", nob$(n,schd(i+n/2),byes), " )  ";
  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

C++

#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <vector>

void round_robin(uint32_t team_count) {
	if ( team_count < 2 ) {
		throw std::invalid_argument("Number of teams must be greater than 2: " + team_count);
	}

	std::vector<uint32_t> rotating_list(team_count);
	std::iota(rotating_list.begin(), rotating_list.end(), 2);
	if ( team_count % 2 == 1 ) {
		rotating_list.emplace_back(0);
		team_count++;
	}

	for ( uint32_t round = 1; round < team_count; ++round ) {
		std::cout << "Round " << std::setw(2) << round << ":";
		std::vector<uint32_t> fixed_list(1, 1);
		fixed_list.insert(fixed_list.end(), rotating_list.begin(), rotating_list.end());
		for ( uint32_t i = 0; i < team_count / 2; ++i ) {
			std::cout << " ( " << std::setw(2) << fixed_list[i]
					  << " vs " << std::setw(2) << fixed_list[team_count - 1 - i] << " )";
		}
		std::cout << std::endl;
		std::rotate(rotating_list.rbegin(), rotating_list.rbegin() + 1, rotating_list.rend());
	}
}

int main() {
	std::cout << "Round robin for 12 players:" << std::endl;
	round_robin(12);
	std::cout << std::endl << std::endl;
	std::cout << "Round robin for 5 players, 0 denotes a bye:" << std::endl;
	round_robin(5);
}
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 ) ( 13 vs 10 ) (  2 vs  9 ) (  3 vs  8 ) (  4 vs  7 ) (  5 vs  6 )
Round  3: (  1 vs 10 ) ( 12 vs  9 ) ( 13 vs  8 ) (  2 vs  7 ) (  3 vs  6 ) (  4 vs  5 )
Round  4: (  1 vs  9 ) ( 11 vs  8 ) ( 12 vs  7 ) ( 13 vs  6 ) (  2 vs  5 ) (  3 vs  4 )
Round  5: (  1 vs  8 ) ( 10 vs  7 ) ( 11 vs  6 ) ( 12 vs  5 ) ( 13 vs  4 ) (  2 vs  3 )
Round  6: (  1 vs  7 ) (  9 vs  6 ) ( 10 vs  5 ) ( 11 vs  4 ) ( 12 vs  3 ) ( 13 vs  2 )
Round  7: (  1 vs  6 ) (  8 vs  5 ) (  9 vs  4 ) ( 10 vs  3 ) ( 11 vs  2 ) ( 12 vs 13 )
Round  8: (  1 vs  5 ) (  7 vs  4 ) (  8 vs  3 ) (  9 vs  2 ) ( 10 vs 13 ) ( 11 vs 12 )
Round  9: (  1 vs  4 ) (  6 vs  3 ) (  7 vs  2 ) (  8 vs 13 ) (  9 vs 12 ) ( 10 vs 11 )
Round 10: (  1 vs  3 ) (  5 vs  2 ) (  6 vs 13 ) (  7 vs 12 ) (  8 vs 11 ) (  9 vs 10 )
Round 11: (  1 vs  2 ) (  4 vs 13 ) (  5 vs 12 ) (  6 vs 11 ) (  7 vs 10 ) (  8 vs  9 )


Round robin for 5 players, 0 denotes a bye:
Round  1: (  1 vs  6 ) (  2 vs  5 ) (  3 vs  4 )
Round  2: (  1 vs  5 ) (  0 vs  4 ) (  2 vs  3 )
Round  3: (  1 vs  4 ) (  6 vs  3 ) (  0 vs  2 )
Round  4: (  1 vs  3 ) (  5 vs  2 ) (  6 vs  0 )
Round  5: (  1 vs  2 ) (  4 vs  0 ) (  5 vs  6 )

C#

Translation of: Java
using System;
using System.Collections.Generic;
using System.Linq;

public class RoundRobinTournamentSchedule
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Round robin for 12 players:");
        RoundRobin(12);
        Console.WriteLine("\n");
        Console.WriteLine("Round robin for 5 players, 0 denotes a bye:");
        RoundRobin(5);
    }

    private static void RoundRobin(int teamCount)
    {
        if (teamCount < 2)
        {
            throw new ArgumentException($"Number of teams must be greater than 2: {teamCount}");
        }

        List<int> rotatingList = Enumerable.Range(2, teamCount - 1).ToList();
        if (teamCount % 2 == 1)
        {
            rotatingList.Add(0);
            teamCount += 1;
        }

        for (int round = 1; round < teamCount; round++)
        {
            Console.Write($"Round {round,2}:");
            List<int> fixedList = new List<int> { 1 };
            fixedList.AddRange(rotatingList);
            for (int i = 0; i < teamCount / 2; i++)
            {
                Console.Write($" ( {fixedList[i],2} vs {fixedList[teamCount - 1 - i],2} )");
            }
            Console.WriteLine();
            Rotate(rotatingList, 1);
        }
    }

    private static void Rotate(List<int> list, int rotationCount)
    {
        int count = list.Count;
        if (count == 0) return;

        rotationCount %= count;
        if (rotationCount < 0)
        {
            rotationCount += count;
        }

        list.Reverse();
        list.Reverse(0, rotationCount);
        list.Reverse(rotationCount, count - rotationCount);
    }
}
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 )

D

import std.stdio;
import std.range;
import std.array;
import std.conv;
import std.algorithm;

void main() {
    12.generatePlayers.generateSchedule.displaySchedule;
}

string[] generatePlayers(int n) {
    ("\nRound-Robin for "~(n).text~" players:\n").writeln;
    //
    return (n%2 == 0) ? iota(1, n+1).map!(a => a.text).array : iota(1, n+1).map!(a => a.text).array~"bye";
}

string[] mutate(string[] arr) {
    return arr[0]~arr[$-1]~ arr[1..$-1].array;
}

string[][] generateSchedule(string[] players) {
    auto nbPlayer = players.length;

    string[][]schedule;

    schedule ~= players;

    for(int i = 1; i <= nbPlayer-2; i++)
    {
        schedule ~= schedule[$-1].mutate;
    }

    //
    return schedule;
}

void displaySchedule(string[][] schedule) {
    auto nbPlayer = schedule[0].length;

    foreach(i, row; schedule.array)
    {
        writef("Round %2s:  ", i+1);

        for(int k=0; k<nbPlayer/2; k++)
        {
            writef("(%2s vs %2s)", row[k], row[nbPlayer-(k+1)]);
            if (k==(nbPlayer/2)-1) writeln; else "  ".write;
        }       
    }
    
    //
    writeln;
}
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)

EasyLang

Translation of: AWK
proc roundrobin n . .
   numfmt 0 2
   print n & " players"
   for i to n
      arr[] &= i
   .
   if n mod 2 = 1
      n += 1
      arr[] &= 0
   .
   for i = 1 to n - 1
      print ""
      write "round " & i & ": "
      for j = 1 to n / 2
         write arr[j] & "  "
      .
      print ""
      write "          "
      for j = n downto n / 2 + 1
         write arr[j] & "  "
      .
      print ""
      h = arr[n]
      for j = n downto 3
         arr[j] = arr[j - 1]
      .
      arr[2] = h
   .
.
roundrobin 12

Go

Translation of: Wren
package main

import "fmt"

func rotate(lst []int) {
    len := len(lst)
    last := lst[len-1]
    for i := len - 1; i >= 1; i-- {
        lst[i] = lst[i-1]
    }
    lst[0] = last
}

func roundRobin(n int) {
    lst := make([]int, n-1)
    for i := 0; i < len(lst); i++ {
        lst[i] = i + 2
    }
    if n%2 == 1 {
        lst = append(lst, 0) // 0 denotes a bye
        n++
    }
    for r := 1; r < n; r++ {
        fmt.Printf("Round %2d", r)
        lst2 := append([]int{1}, lst...)
        for i := 0; i < n/2; i++ {
            fmt.Printf(" (%2d vs %-2d)", lst2[i], lst2[n-1-i])
        }
        fmt.Println()
        rotate(lst)
    }
}

func main() {
    fmt.Println("Round robin for 12 players:\n")
    roundRobin(12)
    fmt.Println("\n\nRound robin for 5 players (0 denotes a bye) :\n")
    roundRobin(5)
}
Output:
Same as Wren example.

J

Implementation (using the wikipedia circle method):

circ=: {{
  if. 1=2|y do.
    assert. 1<y
    <:(#~ [: */"1 *)"2 circ y+1
  else.
    ids=. i.y
    (-:y) ({.,.|.@}.)"_1] 0,.(}:ids)|."0 1}.ids
  end.
}}

Task example:

   rplc&'j:'"1":j./"1>:circ 12
1:12  2:11 3:10  4:9  5:8   6:7
 1:2  3:12 4:11 5:10  6:9   7:8
 1:3   4:2 5:12 6:11 7:10   8:9
 1:4   5:3  6:2 7:12 8:11  9:10
 1:5   6:4  7:3  8:2 9:12 10:11
 1:6   7:5  8:4  9:3 10:2 11:12
 1:7   8:6  9:5 10:4 11:3  12:2
 1:8   9:7 10:6 11:5 12:4   2:3
 1:9  10:8 11:7 12:6  2:5   3:4
1:10  11:9 12:8  2:7  3:6   4:5
1:11 12:10  2:9  3:8  4:7   5:6

(Here, circ uses index values which start at zero, so we need to add 1 to every index. Then we form the id pairs as complex numbers and replace the 'j' used to separate real from imaginary in their character representation with ':' for a hopefully compact and easy-to-read display.)

((Note that we could have instead centered each id pair on the ':' with only slightly more work. But it's not clear that that results in a more pleasing display.)):

   ,/"2(' ',_2&{.@[,':',2&{.@])&":/"1>:circ 12
  1:12  2:11  3:10  4:9   5:8   6:7 
  1:2   3:12  4:11  5:10  6:9   7:8 
  1:3   4:2   5:12  6:11  7:10  8:9 
  1:4   5:3   6:2   7:12  8:11  9:10
  1:5   6:4   7:3   8:2   9:12 10:11
  1:6   7:5   8:4   9:3  10:2  11:12
  1:7   8:6   9:5  10:4  11:3  12:2 
  1:8   9:7  10:6  11:5  12:4   2:3 
  1:9  10:8  11:7  12:6   2:5   3:4 
  1:10 11:9  12:8   2:7   3:6   4:5 
  1:11 12:10  2:9   3:8   4:7   5:6

Java

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public final class RoundRobinTournamentSchedule {

	public static void main(String[] args) {
		System.out.println("Round robin for 12 players:");
		roundRobin(12);
		System.out.println(System.lineSeparator());
		System.out.println("Round robin for 5 players, 0 denotes a bye:");
		roundRobin(5);
	}
	
	private static void roundRobin(int teamCount) {
		if ( teamCount < 2 ) {
			throw new IllegalArgumentException("Number of teams must be greater than 2: " + teamCount);
		}
		
		List<Integer> rotatingList = IntStream.rangeClosed(2, teamCount).boxed().collect(Collectors.toList()); 
		if ( teamCount % 2 == 1 ) {
		    rotatingList.add(0);
		    teamCount += 1;
		}
		
		for ( int round = 1; round < teamCount; round++ ) {
		    System.out.print(String.format("%s%2d%s", "Round ", round, ":"));
		    List<Integer> fixedList = IntStream.rangeClosed(1, 1).boxed().collect(Collectors.toList());
		    fixedList.addAll(rotatingList);
		    for ( int i = 0; i < teamCount / 2; i++ ) {
		    	System.out.print(String.format("%s%2d%s%2d%s",
		    		" ( ", fixedList.get(i), " vs ", fixedList.get(teamCount - 1 - i), " )"));
		    }
		    System.out.println();
		    Collections.rotate(rotatingList, +1);
		}
	}

}
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 )

jq

Works with: jq

Works with gojq, the Go implementation of jq

Adapted from Wren

def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;

def rotate: .[-1:] + .[:-1];

def roundRobin($n):
  {$n, lst: [range(2; $n+1)]}
  | if $n % 2 == 1
    then .lst += [0]   # 0 denotes a bye
    | .n += 1
    end
  | foreach range(1; .n) as $r (.;
        .emit = "Round \($r|lpad(3)): "
        | ([1] + .lst) as $lst2
        | reduce range(0; .n/2) as $i (.;
            .emit += " (\($lst2[$i]|lpad(2)) vs \($lst2[.n - 1 - $i]|lpad(2)))")
        | .lst |= rotate )
   | .emit ;

"Round robin for 12 players:",
roundRobin(12),
"\n\nRound robin for 5 players (0 denotes a bye):\n",
roundRobin(5)
Output:

Essentially the same as for Wren.

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)
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)

Nim

import std/[algorithm, sequtils, strformat]

proc roundRobin(n: Positive) =
  assert n >= 2
  var n = n
  var list1 = toSeq(2..n)
  if n mod 2 == 1:
    list1.add 0  # 0 denotes a "bye".
    inc n
  for r in 1..<n:
    stdout.write &"Round {r:2}:"
    let list2 = 1 & list1
    for i in 0..<(n div 2):
      stdout.write &" ({list2[i]:>2} vs {list2[n - i - 1]:<2})"
    echo()
    list1.rotateLeft(-1)

echo "Round robin for 12 players:\n"
roundRobin(12)
echo "\n\nRound robin for 5 players (0 denotes a bye) :\n"
roundRobin(5)
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 )

Pascal

A console program in Free Pascal. Uses the circle method, but not exactly as in Wikipedia: the fixed player is the dummy, if present, otherwise the last; and the rotation is anticlockwise.

program RoundRobin;
(*
Rosetta Code: write list of matches in a round robin tournament.
Command line:
    RoundRobin number_of_players
*)
{$mode objfpc}{$H+}

uses SysUtils;

var
  nrPlayers, round : integer;
  n, m, c, j, k : integer;
  a : array of integer;

    // Write the matches in a round, formatting nicely
    procedure WriteRound();
    var
      t, u : integer;
    begin
      Write( 'Round', round:3, ': ');
      u := 0;
      for t := 0 to m - 2 do begin
        Write( '(', a[u]:2);  inc(u);
        Write( ' v', a[u]:3, ') ');  inc(u);
      end;
      Write( '(', a[u]:2); // u = n - 2
      if c > 0 then
        WriteLn( ' v', c:3, ')')
      else
        WriteLn( ' bye)');
    end;

begin
  if ParamCount < 1 then begin
    WriteLn( 'Number of players is required');
    exit;
  end;
  nrPlayers := SysUtils.StrToIntDef( ParamStr(1), -1);
               // if string can't be converted, nrPlayers := -1
  if (nrPlayers < 2) then begin
    WriteLn( 'Invalid number of players');
    exit;
  end;
  WriteLn( 'Round robin with ', nrPlayers, ' players');
  m := (nrPlayers + 1) div 2;
  n := 2*m;
  if Odd( nrPlayers) then c := 0  // dummy player, opponent gets a bye
                     else c := n; // genuine player
  SetLength( a, n);
  k := 0;
  for j := 0 to m - 2 do begin
    a[k] := m - j;  inc(k);
    a[k] := m + 1 + j;  inc(k);
  end;
  a[k] := 1;
  a[n - 1] := c; // a[n - 1] stays = c throughout
  round := 1;
  WriteRound();
  for round := 2 to n - 1 do begin
    for j := 0 to n - 2 do begin // increment all entries except a[n - 1]
      inc(a[j]);
      if a[j] = n then a[j] := 1; // wrap round if necessary
    end;
    WriteRound();
  end;
end.
Output:
Round robin with 12 players
Round  1: ( 6 v  7) ( 5 v  8) ( 4 v  9) ( 3 v 10) ( 2 v 11) ( 1 v 12)
Round  2: ( 7 v  8) ( 6 v  9) ( 5 v 10) ( 4 v 11) ( 3 v  1) ( 2 v 12)
Round  3: ( 8 v  9) ( 7 v 10) ( 6 v 11) ( 5 v  1) ( 4 v  2) ( 3 v 12)
Round  4: ( 9 v 10) ( 8 v 11) ( 7 v  1) ( 6 v  2) ( 5 v  3) ( 4 v 12)
Round  5: (10 v 11) ( 9 v  1) ( 8 v  2) ( 7 v  3) ( 6 v  4) ( 5 v 12)
Round  6: (11 v  1) (10 v  2) ( 9 v  3) ( 8 v  4) ( 7 v  5) ( 6 v 12)
Round  7: ( 1 v  2) (11 v  3) (10 v  4) ( 9 v  5) ( 8 v  6) ( 7 v 12)
Round  8: ( 2 v  3) ( 1 v  4) (11 v  5) (10 v  6) ( 9 v  7) ( 8 v 12)
Round  9: ( 3 v  4) ( 2 v  5) ( 1 v  6) (11 v  7) (10 v  8) ( 9 v 12)
Round 10: ( 4 v  5) ( 3 v  6) ( 2 v  7) ( 1 v  8) (11 v  9) (10 v 12)
Round 11: ( 5 v  6) ( 4 v  7) ( 3 v  8) ( 2 v  9) ( 1 v 10) (11 v 12)

Round robin with 9 players
Round  1: ( 5 v  6) ( 4 v  7) ( 3 v  8) ( 2 v  9) ( 1 bye)
Round  2: ( 6 v  7) ( 5 v  8) ( 4 v  9) ( 3 v  1) ( 2 bye)
Round  3: ( 7 v  8) ( 6 v  9) ( 5 v  1) ( 4 v  2) ( 3 bye)
Round  4: ( 8 v  9) ( 7 v  1) ( 6 v  2) ( 5 v  3) ( 4 bye)
Round  5: ( 9 v  1) ( 8 v  2) ( 7 v  3) ( 6 v  4) ( 5 bye)
Round  6: ( 1 v  2) ( 9 v  3) ( 8 v  4) ( 7 v  5) ( 6 bye)
Round  7: ( 2 v  3) ( 1 v  4) ( 9 v  5) ( 8 v  6) ( 7 bye)
Round  8: ( 3 v  4) ( 2 v  5) ( 1 v  6) ( 9 v  7) ( 8 bye)
Round  9: ( 4 v  5) ( 3 v  6) ( 2 v  7) ( 1 v  8) ( 9 bye)

Perl

Even

#!/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 ];
  }
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 

Even and Odd

use strict;
use warnings;
use feature 'say';
use List::AllUtils <pairwise all>;

sub round_robin {
    my($n) = @_;
    my($round,@pairings);
    my @players = (1,0)[$n%2] .. $n;
    my $half    = +@players / 2;

    while () {
        my @a =         @players[    0 ..   $half-1];
        my @b = reverse @players[$half .. $#players];
        push @pairings, sprintf "Round %2d: %s\n", ++$round, join ' ', pairwise { sprintf "%3d vs %2d", $a, $b } @a, @b;
        push @players, splice @players, 1, @players-2;
        last if all { $players[$_-1] < $players[$_] } 1..$#players;
    }
    @pairings
}

say join '', round_robin 12;
say '';
say join '', map { s/0 vs /Bye: /r } round_robin 7;
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

Round  1:   Bye:  7   1 vs  6   2 vs  5   3 vs  4
Round  2:   Bye:  6   7 vs  5   1 vs  4   2 vs  3
Round  3:   Bye:  5   6 vs  4   7 vs  3   1 vs  2
Round  4:   Bye:  4   5 vs  3   6 vs  2   7 vs  1
Round  5:   Bye:  3   4 vs  2   5 vs  1   6 vs  7
Round  6:   Bye:  2   3 vs  1   4 vs  7   5 vs  6
Round  7:   Bye:  1   2 vs  7   3 vs  6   4 vs  5

Phix

Based on the circle with rotor diagrams on the wikipedia page, and implements home/away.

with javascript_semantics

function round_robin(integer n)
    --
    -- As per the wikipedia page, we do something like this:
    --
    -- even(n), say 6:  in round 1 we have 6 & 1,2,3,4,5 -> {{6,1},{2,5},{3,4}},
    --                           2             2,3,4,5,1 -> {{6,2},{3,1},{4,5}},
    --                           3             3,4,5,1,2 -> {{6,3},{4,2},{5,1}},
    --                           4             4,5,1,2,3 -> {{6,4},{5,3},{1,2}},
    --                           5             5,1,2,3,4 -> {{6,5},{1,4},{2,3}}
    --
    -- for an odd(n), say 5, simply replace all the 6 above with 0 (a bye).
    --
    -- As per the wikipedia diagram, we pick a rotor (6/0) and arrange the rest
    -- in a circle, and as it rotates around the circle we play it against that
    -- one then pick off second/last, third/last-but-one, and so forth from the
    -- perspective of the rotor. There must obviously be an odd number of teams
    -- in the circle itself, otherwise pairing-offs won't meet in the middle.
    --
    -- However, rather than physically rotate the {1,2,3,4,5}, we'll just say
    -- that anything past 5 starts from 1 again (the -= n below), and use the
    -- shorthand of l [===length(result)] as our starting position/offset.
    --
    -- Not shown above, but we'll also use even/odd rules for home/away matches.
    --
    integer rotor  = iff(even(n)?n:0),
            l = 0 -- length(result), shorthand
    n -= even(n) -- (circle must be odd)
    sequence result = {}
    for rownd=1 to n do -- (since "round" is a builtin)
        sequence games = {iff(even(rownd) or rotor=0?{rownd,rotor}:{rotor,rownd})}
        integer opponent = n -- pair rest off from last inwards,
        for m=2 to (n+1)/2 do -- such that m plays current opponent
            integer rom = m+l,          -- all shifted by
                    rop = opponent+l    -- l as an offset
            if rom>n then rom -= n end if 
            if rop>n then rop -= n end if 
            games &= iff(odd(m)?{{rom,rop}}:{{rop,rom}})
            opponent -= 1
        end for
        result = append(result,games)
        l += 1 -- (obviously "l = length(result)" works fine here too)
    end for
    return result
end function

function vs(sequence pair)  -- (display helper)
    return sprintf(iff(pair[2]=0?"%2d bye  ":"%2d vs %-2d"),pair)
end function

for test=12 to 3 by -9 do
    sequence res = round_robin(test)
    printf(1,"\nFor %d teams:\n",test)
    for r=1 to length(res) do
        printf(1,"Round %2d: %s\n",{r,join(apply(res[r],vs))})
    end for
end for
Output:
For 12 teams:
Round  1: 12 vs 1  11 vs 2   3 vs 10  9 vs 4   5 vs 8   7 vs 6
Round  2:  2 vs 12  1 vs 3   4 vs 11 10 vs 5   6 vs 9   8 vs 7
Round  3: 12 vs 3   2 vs 4   5 vs 1  11 vs 6   7 vs 10  9 vs 8
Round  4:  4 vs 12  3 vs 5   6 vs 2   1 vs 7   8 vs 11 10 vs 9
Round  5: 12 vs 5   4 vs 6   7 vs 3   2 vs 8   9 vs 1  11 vs 10
Round  6:  6 vs 12  5 vs 7   8 vs 4   3 vs 9  10 vs 2   1 vs 11
Round  7: 12 vs 7   6 vs 8   9 vs 5   4 vs 10 11 vs 3   2 vs 1
Round  8:  8 vs 12  7 vs 9  10 vs 6   5 vs 11  1 vs 4   3 vs 2
Round  9: 12 vs 9   8 vs 10 11 vs 7   6 vs 1   2 vs 5   4 vs 3
Round 10: 10 vs 12  9 vs 11  1 vs 8   7 vs 2   3 vs 6   5 vs 4
Round 11: 12 vs 11 10 vs 1   2 vs 9   8 vs 3   4 vs 7   6 vs 5

For 3 teams:
Round  1:  1 bye    3 vs 2
Round  2:  2 bye    1 vs 3
Round  3:  3 bye    2 vs 1

While I "optimised away" the need for a physical rotate, obviously not because I was concerned with performance but more in the hope of creating shorter and more elegant code, in the end it made little difference. Should it be more to your taste, you can remove "l" and replace the inner loop above with:

    sequence circle = tagset(n)
    for rownd=1 to n do -- (since "round" is a bultin)
        integer r = circle[1]
        sequence games = {iff(even(rownd) or rotor=0?{r,rotor}:{rotor,r})}
        integer ldx = 2, rdx = n
        while ldx<rdx do
            integer teama = circle[ldx],
                    teamb = circle[rdx]
            games &= {iff(odd(ldx)?{teama,teamb},{teamb,teama})}
            ldx += 1
            rdx -= 1
        end while
        result = append(result,games)
        circle = circle[2..$]&circle[1] -- (physically rotate it)
    end for

Picat

Constraint modelling

import sat.

main =>
  nolog,
  N = 12,
  tournament_cp(N, NumRounds,NumPairs,_,X,Bye),
  print_tournament(X,NumRounds,NumPairs,Bye),
  nl.

tournament_cp(N, NumRounds,NumPairs,Extras, X,Bye) =>
  % Adjust for odd number of players.
  % The bye (Dummy) player is N+1.
  if N mod 2 == 1 then
    N := N + 1,
    Bye = N
  end,

  NumRounds = N-1,
  NumPairs = N div 2,

  X = new_array(NumRounds,NumPairs,2),
  X :: 1..N,

  % ensure that all players play each other
  foreach(P1 in 1..N, P2 in P1+1..N)
    sum([X[Round,P,1] #= P1 #/\ X[Round,P,2] #= P2 : Round in 1..NumRounds, P in 1..NumPairs]) #= 1
  end,
  
  foreach(Round in 1..NumRounds)
    all_different([X[Round,I,J] : I in 1..NumPairs, J in 1..2]),
    
    % symmetry breaking
    % - all first players in increasing order
    increasing_strict([X[Round,I,1] : I in 1..NumPairs]),
    % - player 1 < player 2
    foreach(P in 1..NumPairs)
       X[Round,P,1] #< X[Round,P,2]
    end
  end,

  if Extras != [] then
    foreach([P1,P2,Round] in Extras)
      sum([X[Round,P,1] #= P1 #/\ X[Round,P,2] #= P2 : P in 1..NumPairs]) #= 1
    end
  end,
  solve($[ff,split],X).

print_tournament(X,NumRounds,NumPairs,Bye) =>
  N = X[1].len,
  foreach(Round in 1..NumRounds)
    printf("Round %2d: ", Round),
    if N > 10 then nl end,
    foreach(P in 1..NumPairs)
      P2Val = X[Round,P,2],
      if var(Bye) ; P2Val != Bye then
        printf("(%2w vs %2w) ",X[Round,P,1],P2Val),
        if N > 10 then nl end
      end
    end,
    nl
  end,
  nl.
Output:
Round  1: ( 1 vs 11) ( 2 vs  5) ( 3 vs  6) ( 4 vs 12) ( 7 vs  9) ( 8 vs 10) 
Round  2: ( 1 vs  5) ( 2 vs  4) ( 3 vs 10) ( 6 vs  7) ( 8 vs  9) (11 vs 12) 
Round  3: ( 1 vs  6) ( 2 vs  8) ( 3 vs  5) ( 4 vs 11) ( 7 vs 10) ( 9 vs 12) 
Round  4: ( 1 vs 12) ( 2 vs 11) ( 3 vs  7) ( 4 vs  6) ( 5 vs  8) ( 9 vs 10) 
Round  5: ( 1 vs  9) ( 2 vs  6) ( 3 vs 12) ( 4 vs  5) ( 7 vs  8) (10 vs 11) 
Round  6: ( 1 vs  4) ( 2 vs  3) ( 5 vs  7) ( 6 vs 10) ( 8 vs 12) ( 9 vs 11) 
Round  7: ( 1 vs  2) ( 3 vs  4) ( 5 vs 10) ( 6 vs  9) ( 7 vs 12) ( 8 vs 11) 
Round  8: ( 1 vs  3) ( 2 vs 12) ( 4 vs 10) ( 5 vs  9) ( 6 vs  8) ( 7 vs 11) 
Round  9: ( 1 vs 10) ( 2 vs  7) ( 3 vs  8) ( 4 vs  9) ( 5 vs 11) ( 6 vs 12) 
Round 10: ( 1 vs  8) ( 2 vs 10) ( 3 vs  9) ( 4 vs  7) ( 5 vs 12) ( 6 vs 11) 
Round 11: ( 1 vs  7) ( 2 vs  9) ( 3 vs 11) ( 4 vs  8) ( 5 vs  6) (10 vs 12) 

Constraint model with extra constraints

The constraint model is slower than the algorithmic approach for larger number of players. The advantage of a constraint model is that it is quite easy to add extra constraint, such that some players must play in a certain round (e.g. for availability reasons etc).

Here are some extra constraints:

  • 1 vs 2 must be played the third round
  • 5 vs 9 must be played in the 7th round
  • 2 vs 3 must be played in the last round
  • 7 vs 12 must be played in the last round
main =>
  nolog,
  N = 12,  
  Extras = [[1,2,3],
            [5,9,7],
            [2,3,N-1],
            [7,12,N-1]],
  tournament_cp(N, NumRounds,NumPairs,Extras,X,Bye),
  print_tournament(X,NumRounds,NumPairs,Bye).
Output:
Round  1: ( 1 vs 11) ( 2 vs  4) ( 3 vs 12) ( 5 vs  8) ( 6 vs  9) ( 7 vs 10) 
Round  2: ( 1 vs 12) ( 2 vs 11) ( 3 vs  9) ( 4 vs  7) ( 5 vs 10) ( 6 vs  8) 
Round  3: ( 1 vs  2) ( 3 vs 10) ( 4 vs 12) ( 5 vs 11) ( 6 vs  7) ( 8 vs  9) 
Round  4: ( 1 vs  4) ( 2 vs  6) ( 3 vs 11) ( 5 vs 12) ( 7 vs  8) ( 9 vs 10) 
Round  5: ( 1 vs 10) ( 2 vs  7) ( 3 vs  5) ( 4 vs  6) ( 8 vs 12) ( 9 vs 11) 
Round  6: ( 1 vs  6) ( 2 vs  5) ( 3 vs  4) ( 7 vs  9) ( 8 vs 11) (10 vs 12) 
Round  7: ( 1 vs  3) ( 2 vs 12) ( 4 vs  8) ( 5 vs  9) ( 6 vs 10) ( 7 vs 11) 
Round  8: ( 1 vs  7) ( 2 vs  8) ( 3 vs  6) ( 4 vs  5) ( 9 vs 12) (10 vs 11) 
Round  9: ( 1 vs  8) ( 2 vs  9) ( 3 vs  7) ( 4 vs 10) ( 5 vs  6) (11 vs 12) 
Round 10: ( 1 vs  9) ( 2 vs 10) ( 3 vs  8) ( 4 vs 11) ( 5 vs  7) ( 6 vs 12) 
Round 11: ( 1 vs  5) ( 2 vs  3) ( 4 vs  9) ( 6 vs 11) ( 7 vs 12) ( 8 vs 10) 

For this small tournament it took about the same time with and without these extra constraints (0.08s).

Number of solutions

Here are the number of different solutions for N = [2,4,6,8] with the symmetry constraints (but without the extra round constraints). The number of odd N players is the same as the number of N-1 players.

Here the cp solver is used since it's faster than the sat solver for generating all solutions.

import cp. 

main =>
  foreach(N in 2..2..8)
    Count = count_all(tournament_cp(N, _NumRounds,_NumPairs,_Extras,_X,_Bye)),
    println(N=Count)
  end.
Output:
2 = 1
4 = 6
6 = 720
8 = 31449600

This seems to be related to the OEIS sequence "A036981: (2n+1) X (2n+1) symmetric matrices each of whose rows is a permutation of 1..(2n+1)". The next term (for N=10) would be 444733651353600 which takes too long to check.

Python

Original method by R. Schurig

# round_robin.py by Xing216
from copy import deepcopy
def shift_up(myList):
    myLen = len(myList)
    return [myList[i % myLen] for i in range(1, 1 + myLen)]
def scheduler(competitors):
    """Uses the original method by Richard Schurig"""
    if competitors % 2 == 1:
        n = competitors + 1
        horizontal_rows = n - 1
    else:
        n = competitors
        horizontal_rows = n
    vertical_rows = n // 2
    table = [[[] for _ in range(vertical_rows)] for _ in range(horizontal_rows)]
    competitor = 1
    for i, row in enumerate(table):
        for col in table[i]:
            if competitor == competitors:
                col.append(competitor)
                competitor = 1
            else:
                col.append(competitor)
                competitor += 1
    table2 = deepcopy(table)
    table2 = shift_up(table2)
    for row in table2: row.reverse()
    for i, row in enumerate(table):
        for j, col in enumerate(table[i]):
            col.append(table2[i][j][0])
    return table
def print_table(table):
    for i, round in enumerate(table):
        print(f"Round {(i + 1):2}", end=": ")
        for match in round:
            print(f"{match[0]:2}-{match[1]:<2}", end=" ")
        print()
print_table(scheduler(12))
Output:
Round  1:  1-12  2-11  3-10  4-9   5-8   6-7  
Round  2:  7-6   8-5   9-4  10-3  11-2  12-1  
Round  3:  1-12  2-11  3-10  4-9   5-8   6-7
Round  4:  7-6   8-5   9-4  10-3  11-2  12-1
Round  5:  1-12  2-11  3-10  4-9   5-8   6-7
Round  6:  7-6   8-5   9-4  10-3  11-2  12-1
Round  7:  1-12  2-11  3-10  4-9   5-8   6-7
Round  8:  7-6   8-5   9-4  10-3  11-2  12-1
Round  9:  1-12  2-11  3-10  4-9   5-8   6-7
Round 10:  7-6   8-5   9-4  10-3  11-2  12-1
Round 11:  1-12  2-11  3-10  4-9   5-8   6-7
Round 12:  7-6   8-5   9-4  10-3  11-2  12-1

Berger Tables

# berger_table.py by Xing216
def scheduler(competitors):
    if competitors & 1:
        competitors += 1
    last = competitors
    half = competitors // 2
    rounds = last - 1
    tables = [list() for i in range(rounds)]
    for i in range(1, last):
        row = i - 1
        tables[row] = [list() * half]
        tables[row][0] = [0, 0]
        if i & 1:
            tables[row][0][1] = last
            opponent = (i + 1) // 2
            tables[row][0][0] = opponent
        else:
            tables[row][0][0] = last
            opponent = half + i // 2
            tables[row][0][1] = opponent
        for _ in range(1, half):
            next_opponent = opponent + 1 if opponent < last - 1 else 1
            tables[row].append([next_opponent, 0])
            opponent = next_opponent
    last_guest = 1
    for i in reversed(range(1, last)):
        row = i - 1
        for j in reversed(range(0, half)):
            opponent = last_guest
            if j > 0:
                tables[row][j][1] = opponent
                last_guest = opponent + 1 if opponent < last - 1 else 1
    return tables
def print_table(table):
    for i, round in enumerate(table):
        print(f"Round {(i + 1):2}", end=": ")
        for match in round:
            print(f"{match[0]:2}-{match[1]:<2}", end=" ")
        print()
print_table(scheduler(12))
Output:
Round  1:  1-12  2-11  3-10  4-9   5-8   6-7  
Round  2: 12-7   8-6   9-5  10-4  11-3   1-2  
Round  3:  2-12  3-1   4-11  5-10  6-9   7-8
Round  4: 12-8   9-7  10-6  11-5   1-4   2-3
Round  5:  3-12  4-2   5-1   6-11  7-10  8-9
Round  6: 12-9  10-8  11-7   1-6   2-5   3-4
Round  7:  4-12  5-3   6-2   7-1   8-11  9-10
Round  8: 12-10 11-9   1-8   2-7   3-6   4-5
Round  9:  5-12  6-4   7-3   8-2   9-1  10-11
Round 10: 12-11  1-10  2-9   3-8   4-7   5-6
Round 11:  6-12  7-5   8-4   9-3  10-2  11-1

Quackery

  [ stack ]                      is participants (   --> s )

  [ dup 10 < if sp echo ]        is recho        ( n -->   )

  [ dup participants share
    > iff
       [ drop say " bye " ]
         done
    say " vs "
    dup echo 10 < if sp ]        is lecho        ( n -->   )

  [ dup participants put
    dup 1 & +
    [] over 1 - times
      [ i 1+ join ]
    over 1 - times
      [ say "Round "
        i^ 1+ recho
        say ": "
        over dip
          [ 2dup join ]
        times
          [ i i^ < iff
              conclude done
            dup i peek recho
            dup i^ peek lecho
            say "  " ]
        drop cr
        over 2 / 1+
        split swap join ]
    2drop participants release ] is schedule     ( n -->   )

  say "12 participants:" cr
  12 schedule
  cr
  say "5 participants:" cr
  5 schedule
  cr
  say "1 participant:" cr
  1 schedule
  cr
  say "0 participants:" cr
  0 schedule
Output:
12 participants:
Round  1:  1 vs 12   2 vs 11   3 vs 10   4 vs 9    5 vs 8    6 vs 7   
Round  2:  5 vs 12   6 vs 4    7 vs 3    8 vs 2    9 vs 1   10 vs 11  
Round  3:  9 vs 12  10 vs 8   11 vs 7    1 vs 6    2 vs 5    3 vs 4   
Round  4:  2 vs 12   3 vs 1    4 vs 11   5 vs 10   6 vs 9    7 vs 8   
Round  5:  6 vs 12   7 vs 5    8 vs 4    9 vs 3   10 vs 2   11 vs 1   
Round  6: 10 vs 12  11 vs 9    1 vs 8    2 vs 7    3 vs 6    4 vs 5   
Round  7:  3 vs 12   4 vs 2    5 vs 1    6 vs 11   7 vs 10   8 vs 9   
Round  8:  7 vs 12   8 vs 6    9 vs 5   10 vs 4   11 vs 3    1 vs 2   
Round  9: 11 vs 12   1 vs 10   2 vs 9    3 vs 8    4 vs 7    5 vs 6   
Round 10:  4 vs 12   5 vs 3    6 vs 2    7 vs 1    8 vs 11   9 vs 10  
Round 11:  8 vs 12   9 vs 7   10 vs 6   11 vs 5    1 vs 4    2 vs 3   

5 participants:
Round  1:  1 bye    2 vs 5    3 vs 4   
Round  2:  2 bye    3 vs 1    4 vs 5   
Round  3:  3 bye    4 vs 2    5 vs 1   
Round  4:  4 bye    5 vs 3    1 vs 2   
Round  5:  5 bye    1 vs 4    2 vs 3   

1 participant:
Round  1:  1 bye   

0 participants:

Raku

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;
}
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

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
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   

Rust

Translation of: Nim
fn round_robin(n: usize) {
    assert!(n >= 2);
    let mut n = n;
    let mut list1: Vec<usize> = (2..=n).collect();
    
    if n % 2 == 1 {
        list1.push(0); // 0 denotes a "bye".
        n += 1;
    }
    
    for r in 1..n {
        print!("Round {:2}:", r);
        let list2 = vec![1].into_iter().chain(list1.iter().cloned()).collect::<Vec<_>>();
        
        for i in 0..(n / 2) {
            print!(" ({:>2} vs {:<2})", list2[i], list2[n - i - 1]);
        }
        
        println!();
        list1.rotate_right(1);
    }
}

fn main() {
    println!("Round robin for 12 players:\n");
    round_robin(12);

    println!("\n\nRound robin for 5 players (0 denotes a bye):\n");
    round_robin(5);
}
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 )


Scala

Translation of: Java
object RoundRobinTournamentSchedule extends App {
  
  def roundRobin(teamCount: Int): Unit = {
    require(teamCount >= 2, s"Number of teams must be greater than 2: $teamCount")

    var rotatingList = (2 to teamCount).toList
    var adjustedTeamCount = teamCount

    if (teamCount % 2 == 1) {
      rotatingList :+= 0
      adjustedTeamCount += 1
    }

    for (round <- 1 until adjustedTeamCount) {
      print(f"Round $round%2d:")
      val fixedList = 1 :: rotatingList
      for (i <- 0 until adjustedTeamCount / 2) {
        print(f" ( ${fixedList(i)}%2d vs ${fixedList(adjustedTeamCount - 1 - i)}%2d )")
      }
      println()
      rotatingList = rotatingList.last :: rotatingList.init
    }
  }

  println("Round robin for 12 players:")
  roundRobin(12)
  println()
  println("Round robin for 5 players, 0 denotes a bye:")
  roundRobin(5)
}
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 )


Swift

Translation of: Java
import Foundation

func roundRobin(teamCount: Int) {
    if teamCount < 2 {
        fatalError("Number of teams must be greater than 2: \(teamCount)")
    }

    var rotatingList = Array(2...teamCount)
    var effectiveTeamCount = teamCount

    if teamCount % 2 == 1 {
        rotatingList.append(0) // Adding a 'bye' in case of odd number of teams
        effectiveTeamCount += 1
    }

    for round in 1..<effectiveTeamCount {
        print("Round \(round):", terminator: "")
        let fixedList = [1] + rotatingList
        for i in 0..<(effectiveTeamCount / 2) {
            print(" (\(fixedList[i]) vs \(fixedList[effectiveTeamCount - 1 - i]))", terminator: "")
        }
        print()
        rotatingList.rotate(shift: 1)
    }
}

extension Array {
    mutating func rotate(shift: Int) {
        let index = shift >= 0 ?
            self.index(self.startIndex, offsetBy: self.count - shift, limitedBy: self.endIndex) :
            self.index(self.startIndex, offsetBy: -shift, limitedBy: self.endIndex)

        guard let validIndex = index else { return }
        self = Array(self[validIndex..<self.endIndex] + self[self.startIndex..<validIndex])
    }
}

// Example usage
print("Round robin for 12 players:")
roundRobin(teamCount: 12)
print("\nRound robin for 5 players, 0 denotes a bye:")
roundRobin(teamCount: 5)
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)

Wren

Library: Wren-fmt
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.add(0) // 0 denotes a bye
        n = n + 1
    }
    for (r in 1...n) {
        Fmt.write("Round $2d", r)
        var lst2 = [1] + lst
        for (i in 0...n/2) 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)
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

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;
    ];
]
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