Due: Wednesday, Oct 31 at 11:59pm via Turnin
Many tournaments are organized into elimination rounds, in which pairs of remaining contestants play a match and the winner advances onto the next round. In this assignment, we will model and implement programs over tournaments in Java.
This is a more challenging version of the standard assignment on tournaments. While it does not assume material beyond what we have done in class, it exercises that material at a deeper level. Enjoy!
The assignment unfolds in stages, to keep the presentation more manageable. Submit only the final classes/interfaces/etc you have after finishing all the problems (rather than the classes that you had after each stage). Be sure to include an Examples class with all of your examples of data and test cases.
As a starting point, the following Scheme/Racket data definitions capture the elimination rounds of the Soccer World Cup:
;; A tournament is either
;; - (make-init-match match-data)
;; - (make-advance-match match-data tournament tournament)
(define-struct init-match (data))
(define-struct advance-match (data feeder1 feeder2))
;; a match-data is (make-match-data string string soccer-score)
(define-struct match-data (team1 team2 score))
;; a soccer-score is (make-soccer-score number number boolean)
(define-struct soccer-score (goals1 goals2 extra-time?))
Develop class and interface definitions as needed to capture soccer tournaments.
The same core notion of tournaments could capture the baseball World Series and tennis Grand Slams, but scores in these sports have a different structure. Baseball scores look like:
;; a baseball-score is
;; (make-baseball-score number number number)
(define-struct baseball-score (runs1 runs2 total-innings))
Tennis scores are more complicated. A tennis match is divided into sets (up to 3 in women’s matches and up to 5 in men’s matches). For each set, the score reports how many games each player won. Whoever wins more games wins the set. Whoever wins more sets wins the match. For example, the following table shows a match in which Maria won the first and third sets and Annie won the second set. Maria won the match.
set1 set2 set3
Maria 6 3 6
Annie 4 6 2
Extend your class hierarchy to also support baseball and tennis scores.
Different tournaments have different notions of contestants: baseball and soccer are team sports, while tennis is an individual sport (we’ll ignore doubles). Soccer and tennis both track rankings (so top-ranked competitors won’t face each other in an early tournament round).
Generalize the type of contestants in your match-data class to players that could be teams and/or ranked (or neither). In particular:
A team contestant has a number of players and the name of the team captain.
A ranked contestant has a ranking, which must be an integer larger than 1.
All ranked contestants have a method hasBetterRanking that consumes another ranked contestant and determines whether the first is ranked as better than the second contestant. Lower numbers represent better ranks.
Baseball contestants are teams.
Soccer contestants are teams and ranked.
Tennis contestants are ranked.
The rules within a sport often imply that real scores satisfy certain constraints. For example, baseball games require at least 9 innings and may not end in a tie. The type of a baseball score (three numbers) isn’t rich enough to capture these constraints. We therefore want to write a function to check that scores are valid (by the rules of the corresponding sport).
Write a method isValid on scores that determines whether the score is valid for its corresponding sport. In particular:
Soccer scores: If the two teams have the same number of goals, extra time had to have been played.
Baseball scores: at least 9 innings must have been played and the two teams may not have the same number of runs.
Tennis scores: women’s matches have at most 3 sets, while men’s matches have at most 5 sets. Add a way to distinguish between men’s and women’s matches if you haven’t already. (There are many more constraints to tennis scores, but we’ll ignore them in this assignment).
Your code should require every score (even those for other sports that we might add later) to have an isValid method.
Write a method allScoresValid on tournaments that determines whether every match in the tournament has a valid score.
Just as games have rules that restrict valid scores, tournaments also have a notion of validity. For this assignment, we are interested in two conditions:
The players in each advance-match won a feeder match in the previous round (for example, you can’t make it into the final match without having won the semi-finals).
In tournaments for sports with player rankings, no initial match is between players in the same half of the ranking (in other words, all players in the top half of the ranking compete against a player in the lower half of the ranking in the first round).
Write a method tourValid on tournaments that produces a boolean indicating whether the tournament meets these two conditions. Your solution should include implementing the hasBetterRanking method required of ranked contestants (from section 3).
Write a method matchesPlayed on tournaments that consumes a contestant name and produces the number of matches in the tournament in which the named contestant played.
Answer these questions in a text file called questions.txt (no word or pdf files please!). Don’t edit your code to meet the criteria in the questions – simply answer them based on the code you submitted.
How does your code require every score to have an isValid method?
Does your data definition formally capture that soccer and tennis contestants are similar in having ranks? If yes, how? If no, what change to your code would achieve that?
Did your matchesPlayed method assume a valid tournament in which winners always advance? If yes, explain where you used that assumption and how you checked for it. If no, explain where you could have used that assumption and where you would have checked for it.
Does your implementation of hasBetterRanking require the two contestants to be in the same sport? How or why not?
How does your tourValid implementation handle the additional condition for ranked tournaments without duplicating common code about all valid tournaments?
Briefly critique the cleanliness of the collection of classes and interfaces you came up with for this assignment. Are there aspects of your design that you don’t like, or that you think should be cleaner to implement? Put differently, if you had a Java guru available as a consultant, are there questions you would ask about "how do I do X better"?
Submit .java files containing the final versions of all classes, interfaces, and examples developed for this assignment. Do not submit the .class files. Put your Examples class in its own file called Examples.java. Your may put all of your other classes and interfaces either into a single file or into separate ones (as you prefer).
This assignment will earn points towards the following learning outcomes:
Define classes and interfaces (skill)
Define correct methods (skill)
Create class hierarchy for a problem (ability)
Produce clean code (ability)
Write comprehensive test suites (ability)
Here are some details on what we will look for in grading this assignment:
Do your classes have appropriate variables and methods for the given problem?
Did you create an appropriate set of classes for the given problem?
Did you use interfaces where appropriate?
Do your methods have appropriate parameters for the given problems?
Do your methods produce the right answer?
Is your code well documented, with brief purpose statements on each method?
Is your code indented and presented in a clean, readable manner?
Are your test cases thorough, covering possible variations in the input data and exercising all of your code?
In previous years, typical submissions have lost the most points on inadequate test cases. This class takes test-case development seriously. A strong test suite indicates that you really understand both the data you are working with and the nuances of the problem. We grade your tests as closely as your code, so take time to think out your test cases and whether they really exercise both the data structure and the methods you are writing.