/** A class to analyze volleyball scores.
* @author Ian Barland
* @version 2006.Jan.30
*/
class VolleyballJudge {
/** Must reach at least this score to win. */
int GOAL = 21;
/** Must win by this much or more. */
int WINNING_MARGIN = 2;
/** Determine whether the current score indicates a game which
* is both (a) finished, and (b) the first team won.
* @param homeScore The score of the first team.
* @param visitorScore The score of the second team.
* @return true if the first team has finished defeating the second team.
* A return of false indicates that *either* (a) the game isn't over,
* or (b) the second team won.
* For example, if vj is an instance of VolleyballJudge,
* vj.hasFirstTeamWon( 17, 3 ) = false
* vj.hasFirstTeamWon( 21, 3 ) = true
* vj.hasFirstTeamWon( 21, 20 ) = false
* vj.hasFirstTeamWon( 23, 21 ) = true
* vj.hasFirstTeamWon( 23, 25 ) = false
*/
boolean hasFirstTeamWon( int homeScore, int visitorScore ) {
return ((homeScore >= GOAL) && (homeScore-visitorScore >= WINNING_MARGIN));
}
/** Determine whether the current score indicates a game which
* is both (a) finished, and (b) the first team won.
* @param homeScore The score of the first team.
* @param visitorScore The score of the second team.
* @return true if the first team has finished defeating the second team.
* A return of false indicates that *either* (a) the game isn't over,
* or (b) the second team won.
* For example, if vj is an instance of VolleyballJudge,
* vj.isGameOver( 17, 3 ) = false
* vj.isGameOver( 21, 3 ) = true
* vj.isGameOver( 21, 20 ) = false
* vj.isGameOver( 23, 21 ) = true
* vj.isGameOver( 23, 25 ) = true
*/
boolean isGameOver( int homeScore, int visitorScore ) {
return ( this.hasFirstTeamWon(homeScore, visitorScore)
|| this.hasFirstTeamWon(visitorScore, homeScore) );
}
/** Compute a PR message about the result of a volleyball game,
* suitable for printing, putting on a web page, text messaging, etc.
* @param homeName The name of the first team.
* @param homeScore The score of the first team.
* @param visitorName The name of the second team.
* @param visitorScore The score of the second team.
* @return a String stating who won (if anybody).
* For example, if vj is an instance of VolleyballJudge,
* vj.announceWinner( "beachfront boppers", 0, "valley volleyers", 0 )
* = "Game still in progress."
* vj.announceWinner( "beachfront boppers", 21, "valley volleyers", 15 )
* = "beachfront boppers won!"
* vj.announceWinner( "beachfront boppers", 15, "valley volleyers", 21 )
* = "valley volleyers won!"
* vj.announceWinner( "beachfront boppers", 21, "valley volleyers", 20 )
* = "Game still in progress."
* vj.announceWinner( "beachfront boppers", 25, "valley volleyers", 24 )
* = "Game still in progress."
*/
String announceWinner( String homeName, int homeScore,
String visitorName, int visitorScore ) {
String winningTeam;
if (this.hasFirstTeamWon( homeScore, visitorScore )) {
winningTeam = homeName;
}
else if (this.hasFirstTeamWon( visitorScore, homeScore )) {
winningTeam = visitorName;
}
else {
winningTeam = "announceWinner: dummy string -- this message should never be returned.";
}
if (this.isGameOver( homeScore, visitorScore )) {
return winningTeam + " won!";
}
else {
return "Game still in progress.";
}
/* There are a number of other good solutions:
* (a) Checking `isGameOver` first would let you make only one further `if`
* test, and would omit the need for the dummy value for winningTeam.
* (b) A 3-way if-else-if which returns a result in each branch, or
* (c) a 3-way if-else-if which assigns to a variable "theResult"
* in each branch (followed by a simple "return theResult").
*
* Approach (a) is probably best, even better than the solution.
* (The solution is given as it was to keep it very clear how
* one 'if' was initializing a variable, and the other 'if' was
* returning a value, rather than slightly muddling those two parts.)
*
* Approaches (b) and (c) have a (very minor) amount of repeated code:
* the concatentation of a team-name and "won!". (If you wanted
* two tweak the message, you'd have to tweak two places of code.)
* On the other hand, with those two approaches, you wouldn't have
* to rig the dummy value for winningTeam just to appease the compiler.
*/
}
// A field:
private java.util.Random randNumGenerator = new java.util.Random();
/** Play one game of volleyball, and say which team one.
* @return Whether or not the first team won.
*/
public boolean playOneGame() {
int score1 = 0;
int score2 = 0;
while (! isGameOver(score1,score2) ) {
// Play one point:
// Choose a random team to get a point, with 50/50 odds:
if (randNumGenerator.nextDouble() < 0.50) {
score1 = score1 + 1;
//System.err.println( "team1 score is now " + score1 );
}
else {
score2 = score2 + 1;
//System.err.println( "team2 score is now " + score2 );
}
}
// When we reach this line, we know the game is over -- *somebody* has won!
return this.hasFirstTeamWon(score1,score2);
}
}