Tournament Brackets
PROJECT
By Alyce Brady
PROBLEM DESCRIPTION
In this project you will implement a program to read tournament
participants (for example, tennis players or basketball teams) in from a
file along with their rankings, print that information sorted by ranking,
and determine initial match-ups. In general, match-ups pair the
highest-ranked participant with the lowest-ranked participant, the second
highest-ranked participant with the second lowest-ranked participant, and
so on.
If the number of participants is not an even power of two, then there will
be an initial round involving only some participants in order to get the
number of match-ups to an even power of 2; the highest-ranked participants
will have a bye for the first round. The second round would then have a
full complement of participants. For example, if there are 68 teams in a
tournament, the first round (the bye round would consist of only
the 8 lowest-ranked teams, with the other 60 teams having a bye for the
first round. The four winners of the bye round would then join the other
60 teams for a full round of 64 teams participating in 32 matches. In a
less-realistic but shorter example of a tournament with 3 participating
teams, the top-ranked team would have a bye for the first round and would
then play the winner of the other two teams. The table below compares this
scenario agains a single match-up between 2 teams with no bye.
| Example with Byes | Example with no Byes |
Initial Rankings:
1. S Carolina
2. UConn
3. UCLA
Number of Rounds: 2
Number of Byes: 1
First-Round Byes:
1. S Carolina
----------------
Round 1 Match-Ups:
2. UConn vs. 3. UCLA
Round 1 Scores:
2. UConn (78) vs. 3. UCLA (64)
----------------
Round 2 Match-Ups:
1. S Carolina vs. 2. UConn
Round 2 Scores:
2. UConn (82) vs. 1. S Carolina (59)
|
Initial Rankings:
1. S Carolina
2. UConn
Number of Rounds: 1
Number of Byes: 0
----------------
Round 1 Match-Ups:
1. S Carolina vs. 2. UConn
Round 1 Scores:
2. UConn (82) vs. 1. S Carolina (59)
|
Getting Started
Most of the functionality for the Tournament program is in the
Tournament class, although there are several other classes
that represent participant information as (name, value) pairs, match-up
assignments between participants, and classes that know how to read those
values from files.
Download the files for the Tournament Brackets Project:
- Tournament.java
— Contains most of the functionality of the program,
including the
main method.
(Needs to be completed.)
- ParticipantInfo.java
— Represents (name, value) information about
participants, such as their name and ranking. (Fully implemented)
- ParticipantReader.java
— An object that knows how to read participant information
from a file, one participant per line. (Fully implemented)
- Matchup.java
— Represents a pairing of two participants and their scores.
(Fully implemented)
- MatchupReader.java
— An object that knows how to read participant information
from a file, two participants per line.
(Needs to be completed.)
- ValidatedInputReader.java
— Class with static methods
that can prompt users for numeric or string input.
(Fully implemented)
- There are two files containing sample rankings data:
18rankings.txt (18 participants, so
byes are needed)
and
16rankings.txt (16 participants, so no
byes necessary).
- There are two files containing sample score results:
byeRoundScores.txt and
fullRoundScores.txt.
The Tournament class follows the Template
Method pattern, with high-level methods breaking their tasks down
and calling lower-level methods to complete those tasks. For example:
The runTournament method calls
reportRankings,
setRoundsAndByes, and
runByeRound,
and will call others when completed.
The runByeRound method calls
determineMatchups,
printMatchups, and
reportScores.
The incomplete Tournament class provided to you contains the
general structure of the class and some of the detailed code (especially
the code related to reading in information from files), but also has code
missing and other code commented out.
First Look: Reading and Running Code for Understanding
Start by reading the code, but don't try to read every detail at once.
The Tournament class contains the main method
at the bottom of the class -- what does it do? Where is the
runTournament
method? In general, (leaving main aside), are the methods laid out in a
top-down or a bottom-up fashion?
Does the Tournament class have many instance variables that are shared
among all of the methods? One of the first methods that the
runTournament
method calls is reportRankings. Are the rankings only used within
reportRankings, or are they communicated back to
runTournament, and if so,
how?
Before diving deeply into all the details of the Tournament class,
glance at the 18rankings.txt file and
round2Scores.txt to see what the format is of the data being
used by the program. Run the program to see what it does with the data.
Look back at Tournament and notice which blocks of code are commented-out
and which are not -- does the initial behavior of the code make sense based
on your initial look at the runTournament method?
Making Modifications
Following the precepts and practices of Agile Development, you should start
by making the smallest modifications you can, and test them before going on
to other modifications. As you work on the program, your output should
slowly look more and more like that in the
Sample Output below.
You may complete the implementation of the Tournament and
MatchupReader classes based only on the comments in the
existing code and the
Sample Output as a guide, or, if
you prefer more detailed guidance, you may follow the
guided directions provided here.
Guided Directions
(Display)
⇓
It makes sense to go through the methods called by
runTournament in the
order they are called, ignoring other code that isn't immediately relevant.
That means starting with reportRankings, which is partly implemented.
Reading in Participant Rankings
reportRankings:
reportRankings first reads in the rankings from a file, then
reports them. You do not need to study the internals of the
ParticipantReader at this time, since it is fully implemented,
but you may want to read its class documentation just to be sure you
understand what it is supposed to do. Returning to
reportRankings: What seems to be missing here, given the
method documentation and internal comments describing what the method
should do, and what you saw when you ran the program? Make the
modifications you determine are needed and then re-run the program with
both 16rankings.txt and 18rankings.txt to test
your changes. Does your output contain all of the teams ordered by
ranking?
setRoundsAndByes:
The setRoundsAndByes method is fully implemented, but you may
want to look it over to make sure you understand what it is supposed to be
doing. You may also wish to understand how it is doing it,
or you could use it withough studying it at that level of detail. Using
functioning code based on an understanding of whatT it
does, rather than how it does it, is common practice.
Handling a Bye Round
runByeRound:
If setRoundsAndByes determined that byes are necessary, the
next thing runTournament does is call
runByeRound. This method is partially implemented, partially
missing, and partially commented out to simplify it as you fill in the
missing parts. As you complete sections of this method, test it using the
18rankings.txt input file, since the number of participants
in that file requires a bye round.
- The implemented code prints a subset of the players or teams, those
with byes, who do not need to participate in the bye round. The
missing code should make a list of the rest of the participants,
those who do need to participate in the by round.
How would you fill in that list? You might want to temporarily
print the new "active" list to test your code. It should contain
all of the participants who were not listed as byes.
Once you have that working, move the begin-comment line to
uncomment the next block in runByeRound, which calls
determineMatchups and printMatchups.
Are the match-ups what you expected, given the list of participants
who should be participating in the bye round?
determineMatchups:
This method should determine which participants to match and add them to
the matchups list. The method should match the first and last
participants in the list, then the second and second-to-last participants,
and so on. If, for example, a bye round consists of 8 participants, the
matchups would be:
The active participant at index 0 with the participant at index 7,
The active participant at index 1 with the participant at index 6,
The active participant at index 2 with the participant at index 5, and
The active participant at index 3 with the participant at index 4.
printMatchups:
This method should print the information from the matchups
list.
- Go back to
runByeRound and modify it to call
determineMatchups and printMatchups.
Test your program again. Now are the match-ups what you expected,
given the list of participants who should be participating in the
bye round? How do they compare to the results in the
Sample Output section?
Test your program with both 18rankings.txt (has 4
participants in a Round 1 bye round), then
16rankings.txt (has no byes, so no bye round).
(Given the parts of the code you have been working on so far,
what do you expect the program to do when there is no bye
round?)
- Once you have
determineMatchups and
printMatchups working, you can delete the temporary
code in runByeRound that was printing the new "active"
list before the call to determineMatchups.
reportScores:
The reportScores method itself is fully implemented, but it
creates a MatchupReader and asks it to read in scores from a file
before calling printScores. Both of those methods are incomplete.
-
MatchupReader: The structure of this class should be similar
to that of ParticipantReader, except that
MatchupReader
creates and fills a list of Matchup objects instead of a list of
ParticipantInfo objects.
MatchupReader
is also missing some key functionality.
readScores: The readScores method is very
similar to the readParticipantInfo method, except that
it fills and returns a different type of list, and its
parseLine method takes 4 parameters rather than 3.
-
parseLine: The differences between the two
parseLine methods are bigger. Instead of each line in
the file containing the (name, ranking) information for a single
new ParticipantInfo object and adding it to the list,
each line read by the MatchupReader contains (name,
score) information for two participants. The
parseLine method should read in the name and score for
one participant, find that participant in the list of participants
and set its score value, then do the same for the second
participant. Having set the scores for both participants, it
should create a Matchup object for those two
participants and add it to the list of results.
For add robustness, you could add a check to
MatchupReader to either throw a meaningful exception
if it reads a name that cannot be found in the participant list or
report that as an error and skip the line with the unknown name(s).
-
printScores: Complete that method, then modify
runByeRound to return allResults instead of
null. Test your program with both 18rankings.txt
(has 4 participants in a Round 1 bye round), and
16rankings.txt (has no byes, so no bye round).
Going back to runTournament: Add code immediately after
calling runByeRound to remove the bye round losers from the
list of currently active participants.
When the program is done with the if ( this.numByes > 0 )
code block in runTournament,
the number of participants in the "active" list should be a full
power of 2. Either it was a full power of 2 to start with, in which case
there would be no byes and the code would never enter the "runByeRound"
block, or there were extra participants but the right number have been
removed as a result of the "runByeRound" block.
For example, if there were originally
18 participants, there should be 4 participants in the bye round, taking
part in 2 matches. Removing the 2 losers from the "active" list leaves 16
participants for the first full round of competition.
Handling the First Full Round
Now you are ready to handle that first full round of competition.
Add code after the "runByeRound" block to create matchups and then get scores
for the players currently in the "active" list. Note that this is a
repetition of a subset of the runByeRound behavior. How do
you expect your program's behavior to change if you are using the
18rankings.txt input file? How about if you use the
16rankings.txt file? Test your code with both files.
How does your output compare to the results in the
Sample Output section?
Sample Output
(Display)
⇓
Output using 18rankings.txt |
Output using 16rankings.txt |
Initial Rankings:
1. UConn
2. Maryland
3. UCLA
4. Texas
5. USC
6. TCU
7. Duke
8. LSU
9. NC State
10. UNC
11. Notre Dame
12. Kansas State
13. Tennessee
14. Ole Miss
15. Baylor
16. Kentucky
17. S Carolina
18. Oklahoma
Number of Rounds: 5
Number of Byes: 14
First-Round Byes:
1. UConn
2. Maryland
3. UCLA
4. Texas
5. USC
6. TCU
7. Duke
8. LSU
9. NC State
10. UNC
11. Notre Dame
12. Kansas State
13. Tennessee
14. Ole Miss
----------------
Round 1 Match-Ups:
15. Baylor vs. 18. Oklahoma
16. Kentucky vs. 17. S Carolina
Round 1 Scores:
18. Oklahoma (68) vs. 15. Baylor (58)
17. S Carolina (75) vs. 16. Kentucky (62)
----------------
Round 2 Match-Ups:
1. UConn vs. 18. Oklahoma
2. Maryland vs. 17. S Carolina
3. UCLA vs. 14. Ole Miss
4. Texas vs. 13. Tennessee
5. USC vs. 12. Kansas State
6. TCU vs. 11. Notre Dame
7. Duke vs. 10. UNC
8. LSU vs. 9. NC State
Round 2 Scores:
1. UConn (82) vs. 18. Oklahoma (59)
2. Maryland (67) vs. 17. S Carolina (71)
3. UCLA (76) vs. 14. Ole Miss (62)
4. Texas (67) vs. 13. Tennessee (59)
5. USC (67) vs. 12. Kansas State (61)
6. TCU (71) vs. 11. Notre Dame (62)
7. Duke (47) vs. 10. UNC (38)
8. LSU (80) vs. 9. NC State (73)
|
Initial Rankings:
1. UConn
2. S Carolina
3. UCLA
4. Texas
5. USC
6. TCU
7. Duke
8. LSU
9. NC State
10. UNC
11. Notre Dame
12. Kansas State
13. Tennessee
14. Ole Miss
15. Maryland
16. Oklahoma
Number of Rounds: 4
Number of Byes: 0
----------------
Round 1 Match-Ups:
1. UConn vs. 16. Oklahoma
2. S Carolina vs. 15. Maryland
3. UCLA vs. 14. Ole Miss
4. Texas vs. 13. Tennessee
5. USC vs. 12. Kansas State
6. TCU vs. 11. Notre Dame
7. Duke vs. 10. UNC
8. LSU vs. 9. NC State
Round 1 Scores:
1. UConn (82) vs. 16. Oklahoma (59)
15. Maryland (67) vs. 2. S Carolina (71)
3. UCLA (76) vs. 14. Ole Miss (62)
4. Texas (67) vs. 13. Tennessee (59)
5. USC (67) vs. 12. Kansas State (61)
6. TCU (71) vs. 11. Notre Dame (62)
7. Duke (47) vs. 10. UNC (38)
8. LSU (80) vs. 9. NC State (73)
|
*Note: These results are somewhat doctored versions of the results of
the 2025 NCAA Women's Basketball championships. The changes (especially
the artifically low ranking for South Carolina) was to test correct behavior
when the lower-ranked team won.
Clean and Refactor
Follow this link to
clean and refactor your
comments and code.
Submission
Submit your completed program through Kit,
under Tournament Brackets Project.
Have fun! And if you have any questions remember I am
available during office hours and the Collaboration Center
folks are here for you as well!