#!/usr/bin/perl # This script takes the user data input and generates two plots. The first plot shows # the times for each match and the judging. The second plot shows which teams play # which and is used to make sure that no team plays too often or little. # The text output has the team pairings, schedule, and a list of which teams are # played by each team. The script also creates a tab delimited file with the competition # and judging schedule that can be read directly into the scoring spread sheet. The team # names are then pulled into the schedule and it is ready for formatting, printing, and then # handing out to the teams. The file name is MatchAndJudgeTimes.tab. # # We started with pairings developed by Tim Burks and then worked with them until # we had judging times that were not too close to competition matches and so that # they do not compete in subsequent matches. # # Use this script by simply running it on a unix machine or cygwin Windows machine # and ploting the resulting MatchTimes.gnu file with gnuplot. Gnuplot sends two # plots to the default x11 screen. It also generates MatchTimes.ps and MatchPairings.ps. # These can be converted with Acrobat to pdf's. This conversion can also be done # under cygwin with the "convert" command with # convert MatchTimes.ps MatchTimes.pdf # convert MatchPairings.ps MatchPairings.pdf # # The times for the Judging and team matches are not connected. They must work # in concert with eachother at the event. The only way I have figured out how # to do this is to make a set of plots and then figure out where things should go # and then update the lists below by hand. # # The script works for any number of matchs, teams, and rounds. # # # Michael and Wyn Schuh # Los Altos, CA # Michael@Boardsailor.com # # Version Date Who Comments # 1.5 05 Nov 05 Schuhs First working version. # 1.6 05 Nov 05 Schuhs Reworked the pairings to give teams more time and # added MatchAndJudgeTimes.tab file. # 1.7 06 Nov 05 Schuhs (Austin and Michael) Made number of teams dynamic, automaticly find # the number of matches per round, checks for errors in number of judgings # and repeated pairings. Fixed pairings so 6 is on table 1 in first match # of round d. # # Start of user data input. # $StartTime = 75; # Start time in minutes. 60 is 1:00 PM. # Round a b c d e @Cycle = ( 7, 7, 7, 6, 5 ); # Time between matches in each round @Break = ( 20, 0, 10, 0, 20 ); # Break time before each round $JudgingTimeSlotLength = 10; # This is the amount of time given to each judging session. $FirstBreak = $Break[0] + 5; # Used to have the judging start five minutes after the first competition match starts. # Break J1 J2 P @Judgings = ( [ $FirstBreak, 3, 2, 10 ], # First Set [ 0, 1, 3, 8 ], [ 0, 2, 1, 11 ], [ 0, 4, 5, 3 ], # Second Set [ 0, 6, 4, 7 ], [ 0, 5, 6, 9 ], [ 10, 7, 8, 12 ], # Third Set [ 0, 9, 7, 6 ], [ 0, 8, 9, 5 ], [ 0, 10, 11, 2 ], # Fourth Set [ 0, 12, 10, 4 ], [ 0, 11, 12, 1 ] ); @Matchings = ( [ # Round a [ 4, 8 ], [ 11, 7 ], [ 5, 9 ], [ 6, 10 ], ], [ # Round b [ 12, 7 ], [ 8, 9 ], [ 10, 11 ], [ 2, 12 ], [ 3, 1 ], ], [ # Round c [ 1, 5 ], [ 4, 11 ], [ 10, 2 ], [ 12, 3 ], ], [ # Round d [ 6, 4 ], [ 7, 1 ], [ 9, 3 ], [ 8, 5 ], [ 2, 6 ], ], [ # Round e [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9, 10 ], [ 11, 12 ], ] ); $NumberOfTeams = 0; # Number of the highest team. This is assumed to be the number of teams. foreach $i ( 0 .. $#Matchings ) { push @Matches, $#{$Matchings[$i]} + 1; # Number of matches in each round. foreach $match ( 0 .. $#{$Matchings[$i]} ) { $NumberOfTeams = $Matchings[$i][$match][0] if $Matchings[$i][$match][0] > $NumberOfTeams; $NumberOfTeams = $Matchings[$i][$match][1] if $Matchings[$i][$match][1] > $NumberOfTeams; } } if ( $NumberOfTeams != $#Judgings+1 ) { # Check to make sure we have the right number of Judgings. printf "\nERROR: The number of teams, $NumberOfTeams, does not equal the number of Judgings, %d\n\n",$#Judgings+1; exit(-5); } # # End of user data input. # # t1 t2 # t1 and t2 are filled with the number of times at each table. for ( 0 .. $NumberOfTeams ) { push @TableCountForEachTeam , [0, 0]; # Used to count the number of times a team plays at table 1 and table 2. } foreach $i ( 0 .. $NumberOfTeams ) { foreach $j ( 0 .. $NumberOfTeams ) { $PairingsTable[$i][$j] = 0; # 2D Used to keep track of the number of times a team plays each other team. } } $time = $StartTime; GP_CommandFile_HeaderFill(); # Write the first part of the plot command file. push @JudgeTimesAndTeamsTabs, "Competition Round Schedule\n"; # Build the contents for the MatchAndJudgeTimes.tab file. push @JudgeTimesAndTeamsTabs, "Round\tMatch\tTime\tTable 1\tTable 2\n"; @RoundNames = (qw(A B C D E)); # Used to label matches with letters. # Make the plot command lines and data files for showing when each team competes and for the pairings chart. foreach $RoundNumber ( 0 .. $#Matches ) { open(GP,">MatchTimes$RoundNumber.data"); open(GPP,">MatchPairings$RoundNumber.data"); $RoundMatches = $Matches[$RoundNumber]; $time += $Break[$RoundNumber]; foreach $Match ( 1 .. $RoundMatches ) { $timeEnd = $time + $Cycle[$RoundNumber]; $GPtimeStart = sprintf "%d:%2.2d",int($time/60), $time%60; # Set the match start and end times. $GPtimeEnd = int($timeEnd/60) . ":" . $timeEnd%60; $GPtimeCent = int(($time+$timeEnd)/120) . ":" . (($time+$timeEnd)/2)%60; $Table1team = $Matchings[$RoundNumber][$Match-1][0]; # Get the team names. $Table2team = $Matchings[$RoundNumber][$Match-1][1]; $TableCountForEachTeam[$Table1team][0] += 1; # Keep track of how many times the $TableCountForEachTeam[$Table2team][1] += 1; # teams play at each table. push @MatchTimesAndTeams, sprintf " $RoundNames[$RoundNumber] %6d $GPtimeStart %6d %6d\n",$Match,$Table1team,$Table2team; push @JudgeTimesAndTeamsTabs, sprintf "$RoundNames[$RoundNumber]\t%d\t$GPtimeStart\t=Team%d\t=Team%d\n",$Match,$Table1team,$Table2team; push @{ $TableCountForEachTeam[$Table1team] }, $Table2team; # Add the competing team to the list. push @{ $TableCountForEachTeam[$Table2team] }, $Table1team; # Add the competing team to the list. printf GP "$GPtimeStart %5.1f\n", $Table1team - .4; # Box for competition schedule. printf GP "$GPtimeEnd %5.1f\n", $Table1team - .4; printf GP "$GPtimeEnd %5.1f\n", $Table1team + .4; printf GP "$GPtimeStart %5.1f\n", $Table1team + .4; printf GP "$GPtimeStart %5.1f\n\n",$Table1team - .4; printf GP "$GPtimeStart %5.1f\n", $Table2team - .4; printf GP "$GPtimeEnd %5.1f\n", $Table2team - .4; printf GP "$GPtimeEnd %5.1f\n", $Table2team + .4; printf GP "$GPtimeStart %5.1f\n", $Table2team + .4; printf GP "$GPtimeStart %5.1f\n\n",$Table2team - .4; printf GPC "set label \"t1\" at \"$GPtimeCent\", $Table1team center tc lt %d\n",$RoundNumber+1; printf GPC "set label \"t2\" at \"$GPtimeCent\", $Table2team center tc lt %d\n",$RoundNumber+1; printf GPP "%5.1f %5.1f\n", $Table1team-.5, $Table2team-.5; # Box for pairings chart printf GPP "%5.1f %5.1f\n", $Table1team-.5, $Table2team+.5; printf GPP "%5.1f %5.1f\n", $Table1team+.5, $Table2team+.5; printf GPP "%5.1f %5.1f\n", $Table1team+.5, $Table2team-.5; printf GPP "%5.1f %5.1f\n\n", $Table1team-.5, $Table2team-.5; printf GPP "%5.1f %5.1f\n", $Table2team-.5, $Table1team-.5; # Box for pairings chart printf GPP "%5.1f %5.1f\n", $Table2team-.5, $Table1team+.5; printf GPP "%5.1f %5.1f\n", $Table2team+.5, $Table1team+.5; printf GPP "%5.1f %5.1f\n", $Table2team+.5, $Table1team-.5; printf GPP "%5.1f %5.1f\n\n", $Table2team-.5, $Table1team-.5; $PairingsTable[$Table1team][$Table2team] += 1; # Increment the number of times each team is paired with the other. $PairingsTable[$Table2team][$Table1team] += 1; $ErrorString = ($PairingsTable[$Table1team][$Table2team] > 1) ? " Error" : ""; # Check to see if they have more than 1 pairing. $TextColor = ($PairingsTable[$Table1team][$Table2team] > 1) ? 0 : $RoundNumber+1; # Use black text if they have more than 1 pairing. push @GPC, sprintf "set label \"$RoundNames[$RoundNumber]%d$ErrorString\" at $Table1team, $Table2team center tc lt %d\n",$Match,$TextColor; push @GPC, sprintf "set label \"$RoundNames[$RoundNumber]%d$ErrorString\" at $Table2team, $Table1team center tc lt %d\n",$Match,$TextColor; $time = $timeEnd } close(GP); close(GPP); } push @JudgeTimesAndTeamsTabs, " \n", " \n", "\tJudging Schedule\n"; push @JudgeTimesAndTeamsTabs, "\tSession\tTime\tRobot Design Go to Judging Room\tTeam Categories Go to Judging Room\tProgramming Go to your Pit Table\n"; $time = $StartTime; open(GP,">MatchJudgeTimes.data"); foreach $JudgingRoundNumber ( 0 .. $#Judgings ) { $time += $Judgings[$JudgingRoundNumber][0]; # Add in the time for the break $timeEnd = $time + $JudgingTimeSlotLength; $GPtimeStart = sprintf "%d:%2.2d",int($time/60), $time%60; # Set the Judging start and end times. $GPtimeEnd = int($timeEnd/60) . ":" . $timeEnd%60; $GPtimeCent = int(($time+$timeEnd)/120) . ":" . (($time+$timeEnd)/2)%60; $Judge1team = $Judgings[$JudgingRoundNumber][1]; $Judge2team = $Judgings[$JudgingRoundNumber][2]; $Judge3team = $Judgings[$JudgingRoundNumber][3]; push @JudgeTimesAndTeams, sprintf "%4d $GPtimeStart %8d %10d %10d\n",$JudgingRoundNumber+1,$Judge1team,$Judge2team,$Judge3team; push @JudgeTimesAndTeamsTabs, sprintf "\t%d\t$GPtimeStart\t=Team%d\t=Team%d\t=Team%d\n",$JudgingRoundNumber+1,$Judge1team,$Judge2team,$Judge3team; printf GP "$GPtimeStart %5.1f\n", $Judge1team - .4; printf GP "$GPtimeEnd %5.1f\n", $Judge1team - .4; printf GP "$GPtimeEnd %5.1f\n", $Judge1team + .4; printf GP "$GPtimeStart %5.1f\n", $Judge1team + .4; printf GP "$GPtimeStart %5.1f\n\n", $Judge1team - .4; printf GP "$GPtimeStart %5.1f\n", $Judge2team - .4; printf GP "$GPtimeEnd %5.1f\n", $Judge2team - .4; printf GP "$GPtimeEnd %5.1f\n", $Judge2team + .4; printf GP "$GPtimeStart %5.1f\n", $Judge2team + .4; printf GP "$GPtimeStart %5.1f\n\n", $Judge2team - .4; printf GP "$GPtimeStart %5.1f\n", $Judge3team - .4; printf GP "$GPtimeEnd %5.1f\n", $Judge3team - .4; printf GP "$GPtimeEnd %5.1f\n", $Judge3team + .4; printf GP "$GPtimeStart %5.1f\n", $Judge3team + .4; printf GP "$GPtimeStart %5.1f\n\n", $Judge3team - .4; printf GPC "set label \"j1\" at \"$GPtimeCent\", $Judge1team center tc lt 6\n"; printf GPC "set label \"j2\" at \"$GPtimeCent\", $Judge2team center tc lt 6\n"; printf GPC "set label \"P\" at \"$GPtimeCent\", $Judge3team center tc lt 6\n"; $time = $timeEnd } close (GP); GP_CommandFile_TrailerFill(); print "Check the list below to make sure that each team competes on each table half the time.\n"; print "The Table_1 and Table_2 columns contain the number of time they compete on the two tables.\n\n"; print " Team# Table_1 Table_2 | Teams Competing against this team.\n"; for $i ( 1 .. $NumberOfTeams ) { #printf "%5d %8d %7d %5d\n",$i,$TableCountForEachTeam[$i][0],$TableCountForEachTeam[$i][1],$#{$TableCountForEachTeam[$i]}; #printf "%5d %8d %7d %5d\n",$i,$TableCountForEachTeam[$i][0],$TableCountForEachTeam[$i][1],$TableCountForEachTeam[$i][2]; printf "%5d %8d %7d |",$i,$TableCountForEachTeam[$i][0],$TableCountForEachTeam[$i][1]; for $j ( 2 .. $#{$TableCountForEachTeam[$i]} ) { printf "%6d",$TableCountForEachTeam[$i][$j]; } print "\n"; } print "\n\nMatch Start times and team numbers\n"; print "Round Match StartTime Team_1 Team_2\n"; print @MatchTimesAndTeams; print "\n\nJudging Start times and team numbers\n"; print "Round StartTime Judging_1 Judging_2 Programming\n"; print @JudgeTimesAndTeams; # Create a tab delimited file for the match and judging schedule. # Read this file into Microsoft Excel by using the Data/ImportExternalData/ImportData tool. open(MSE,">MatchAndJudgeTimes.tab"); print MSE @JudgeTimesAndTeamsTabs; close(MSE); # Check to see if teams play each other more than once. foreach $i ( 0 .. $NumberOfTeams ) { foreach $j ( $i .. $NumberOfTeams ) { print "\nError: Teams $i and $j play each other more than once.\n" if $PairingsTable[$i][$j] > 1; } } # Print out the current date and time. print "\n"; system ("date"); # End # #================================================================================ #================================================================================ #================================================================================ # sub GP_CommandFile_HeaderFill { open(GPC,">MatchTimes.gnu"); print GPC ' # Tell gnuplot that the x data is in time format set xdata time # Set the time format which will be used for xrange and maybe other things. set timefmt "%H" set style data lines # %R = %H:%M (hours:minutes) set format x "%R" set xrange ["0:0":"3:00"] set autoscale x '; printf GPC " set yrange [0:%d] rever set yti 1,1,$NumberOfTeams ",$NumberOfTeams+1; print GPC ' set timefmt "%H:%M" unset label # Clear any labels that might have been set from a privious loading of this file. '; } # #================================================================================ #================================================================================ #================================================================================ # sub GP_CommandFile_TrailerFill { print GPC ' set time set tit "Match Times" set xlab "Time" set ylab "Team Number" plot "MatchTimes0.data" using 1:2 notit, \ "MatchTimes1.data" using 1:2 notit, \ "MatchTimes2.data" using 1:2 notit, \ "MatchTimes3.data" using 1:2 notit, \ "MatchTimes4.data" using 1:2 notit, \ "MatchJudgeTimes.data" using 1:2 notit pause -1 set term post color solid set output "MatchTimes.ps" replot set output unset label # Clear any labels that might have been set from a privious loading of this file. '; print GPC "@GPC"; print GPC ' set term x11 set xdata set format x '; printf GPC " set xrange [0:%d] set xti 1,1,$NumberOfTeams ",$NumberOfTeams+1; print GPC ' set tit "Team Pairings\nErrors are noted by \'Error\' in the pairings label." set xlab "Team Number" plot "MatchPairings0.data" using 1:2 notit, \ "MatchPairings1.data" using 1:2 notit, \ "MatchPairings2.data" using 1:2 notit, \ "MatchPairings3.data" using 1:2 notit, \ "MatchPairings4.data" using 1:2 notit pause -1 set term post color solid set output "MatchPairings.ps" replot; '; close(GPC); }