sub roundrobin { my ($n, $rounds, $bye) = @_; if ($n % 2) { $rounds = $n; $bye = 1; # There will be $rounds rounds with exactly one bye for each team. } else { $rounds = $n - 1; $bye = 0; # There will be $rounds rounds, and every team will quiz every round. } my $m = $n; ++$m if $n % 2; # $m is the lowest even number greater than or equal to $n my %s = (teams => $n, rounds => $rounds, bye => $bye); # The working schedule. # Fill in the working schedule with a nice diagonal pattern: for my $round (0 .. ($rounds - 1)) { for my $i (0 .. ($round-1)) { $s{table}->[$round]->[$i] = (($rounds + $round - $i + 1) + $m) % $m; } for my $i ($round .. ($n-1)) { $s{table}->[$round]->[$i] = (($rounds + $round - $i) + $m) % $m; } } use Data::Dumper; print Dumper(+{tentative => \%s}); # Now, do knight-like moves with the 0 (bye) in the first row. # Every time the 0 lands on a number, put that number in the first column: my $byeround = 0; for my $i (reverse (1 .. ($m - 2))) { $byeround = (($byeround - 2) + $rounds) % $rounds; $s{table}->[$byeround]->[0] = $s{table}->[$byeround]->[$i] || 'Oopsie'; $s{table}->[$byeround]->[$i] = 0; } # If m != n, then remove team n from all the games, and replace with -1 (which means a bye, i.e., the team sits out that round): if (not $m == $n) { for my $i (0 .. $rounds-1) { $s{table}->[$i]->[$i] = -1; } } return \%s; }