/** 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); } }