Last Updated: 2015-04-09 Thu 07:50

Recursively Enumerating Party Pong Games

Table of Contents

1 Party Pong

A colorful game known as Party Pong involves two teams of players throwing small balls into plastic cups.

partypong.png

The house rules for a particular instance of the game are as follows:

  • There are two teams: Team 1 and Team 2 each with two players (A and B).
  • Each team starts with \(N\) cups.
  • On a team's turn, both players try to throw their balls in the opposing players' cups.
  • If Player A makes their shot, but Player B misses, one of the opponents' cups is eliminated.
  • If Player A misses, but Player B makes their shot, one of the opponents' cups is eliminated.
  • If Player A and B both make their shot, two cups are eliminated. They then have one bonus shot which can eliminate one more cup if made or no cups if missed.
  • If Player A and B both miss their shot, they eliminate one of their own cups.
  • It is then the other team's turn and play proceeds identically.
  • The game ends immediately when one team has all its cups eliminated.
  • Notice that since at least one cup is eliminated on each turn, the game always ends.

Solving this problem will result in a java program that enumerates all possible games of Party Pong according to the above rules. Utilizing recursion will simplify this task considerably. Output for your program should list the entire history of the game: who made each shot on each turn from start to finish.

2 Formatting Conventions: Game Strings

This problem will use a strict formatting convention on how to notate a whole game of party pong as a string. It has the following pattern

Team {1,2} Wins: 1:{A,B,AB,AB+} 2:{A,B,AB,AB+} ..
  • Each game string starts with the winning team written as either
    Team 1 Wins:
    Team 2 Wins:
    
  • All following strings are space separated. Each starts with the team who is throwing, then a colon, then which players made their shots. Possibilities are
    • 1:X Team 1 throwing, neither player made their shot, Team 1 loses a cup
    • 1:A Team 1 throwing, only player A makes their shot, Team 2 loses 1 cup
    • 1:B Team 1 throwing, only player B makes their shot, Team 2 loses 1 cup
    • 1:AB Team 1 throwing, both players A and B make their shot but miss their extra shot, Team 2 loses 2 cups
    • 1:AB+ Team 1 throwing, both players A and B make their shot AND make their extra shot, Team 2 loses 3 cups
    • All the above symmetric cases for Team 2 throwing:
      2:X 2:A 2:B 2:AB 2:AB+
      
  • Each turn is separated by a single space and every line ends with a space. In the following example game, the normal game is displayed and the caret character indicates where all spaces occur.
    Team 1 Wins: 1:A 2:A 1:A 2:X 1:A 2:AB+ 1:A 
        ^ ^     ^   ^   ^   ^   ^   ^     ^   ^
    
  • Teams alternate turns so that the action of a whole game can be followed by reading a string from left to right. Here is an example with 5 starting cups
    Team 1 Wins: 1:A 2:A 1:A 2:X 1:A 2:AB+ 1:A 
    

    Explanation:

    1. Team 1 only player A makes there shot (5 v 4 cups)
    2. Team 2 only player A makes there shot (4 v 4 cups)
    3. Team 1 only player A makes there shot (4 v 3 cups)
    4. Team 2 both players miss (4 v 2 cups)
    5. Team 1 only player A makes there shot (4 v 1 cups)
    6. Team 2 both players make their shot and make their bonus shot (1 v 1 cups)
    7. Team 1 only player A makes there shot (1 v 0 cups)
    8. Team 1 wins

Failure to adhere to the formatting convention on games will likely cause all tests to fail and result in a severe grading penalty.

3 Public Interface

import java.util.ArrayList;
public class PartyPong{
  // Return an ArrayList of strings representing all party pong games
  // where both teams start with the given number of cups
  public static ArrayList<String> getGames(int startCups);

  // Take a single integer argument on the command line and print all
  // party pong games where both teams start with the given number of
  // cups
  public static void main(String args[]);
}

These are the only two methods that will be used in testing but the problem almost certainly requires an internal private recursive method.

4 Implementation Hints

Consider using an internal recursive method with the following prototype

  public static void play(ArrayList<String> games,
                          int cups1, int cups2, 
                          int team, String history)

Consider using the following 3 base cases:

  • If either cup count is below 0, the game did not end properly so do nothing.
  • If cups2 is 0, Team 1 wins. Add the winner to the current history, add the completed game to the games seen and return.
  • If cups1 is 0, Team 2 wins. Add the winner to the current history, add the completed game to the games seen and return.

The general case occurs if neither cup count is zero or less. Inspect which team's turn it is and make recursive calls for all possible plays. Each call changes the cup counts and adds to the history string.

  • A: Only Player A makes their shot
  • B: Only Player B makes their shot
  • AB: Both A and B make their shot but miss the bonus shot
  • AB+: Both A and B make their shot and make the bonus shot
  • X: Both A and B miss their shots so their own team loses a cup

5 Sample Runs

For the command line main method of PartyPong, the first 3 party pong games should look as follows

aphaedrus [2H1_Chris_Kauffman_p6]% java PartyPong 0
Team 1 Wins: 
aphaedrus [2H1_Chris_Kauffman_p6]% java PartyPong 1
Team 1 Wins: 1:A 
Team 1 Wins: 1:B 
Team 2 Wins: 1:X 
aphaedrus [2H1_Chris_Kauffman_p6]% java PartyPong 2
Team 1 Wins: 1:A 2:A 1:A 
Team 1 Wins: 1:A 2:A 1:B 
Team 2 Wins: 1:A 2:A 1:X 
Team 1 Wins: 1:A 2:B 1:A 
Team 1 Wins: 1:A 2:B 1:B 
Team 2 Wins: 1:A 2:B 1:X 
Team 2 Wins: 1:A 2:AB 
Team 1 Wins: 1:A 2:X 
Team 1 Wins: 1:B 2:A 1:A 
Team 1 Wins: 1:B 2:A 1:B 
Team 2 Wins: 1:B 2:A 1:X 
Team 1 Wins: 1:B 2:B 1:A 
Team 1 Wins: 1:B 2:B 1:B 
Team 2 Wins: 1:B 2:B 1:X 
Team 2 Wins: 1:B 2:AB 
Team 1 Wins: 1:B 2:X 
Team 1 Wins: 1:AB 
Team 2 Wins: 1:X 2:A 
Team 2 Wins: 1:X 2:B 
Team 1 Wins: 1:X 2:X 1:A 
Team 1 Wins: 1:X 2:X 1:B 
Team 2 Wins: 1:X 2:X 1:X

Note that the order in which you print the games does not have to match the above exactly, but every game should be printed somewhere in the exact form shown.

The public method getGames(..) can be used similarly in the DrJava interative loop.

Welcome to DrJava.  Working directory is 2H1_Chris_Kauffman_p6
> import java.util.*;
> ArrayList<String> games;
> games = PartyPong.getGames(2);
> games
[Team 1 Wins: 1:A 2:A 1:A , Team 1 Wins: 1:A 2:A 1:B , Team 2 Wins:
1:A 2:A 1:X , Team 1 Wins: 1:A 2:B 1:A , Team 1 Wins: 1:A 2:B 1:B ,
Team 2 Wins: 1:A 2:B 1:X , Team 2 Wins: 1:A 2:AB , Team 1 Wins: 1:A
2:X , Team 1 Wins: 1:B 2:A 1:A , Team 1 Wins: 1:B 2:A 1:B , Team 2
Wins: 1:B 2:A 1:X , Team 1 Wins: 1:B 2:B 1:A , Team 1 Wins: 1:B 2:B
1:B , Team 2 Wins: 1:B 2:B 1:X , Team 2 Wins: 1:B 2:AB , Team 1 Wins:
1:B 2:X , Team 1 Wins: 1:AB , Team 2 Wins: 1:X 2:A , Team 2 Wins: 1:X
2:B , Team 1 Wins: 1:X 2:X 1:A , Team 1 Wins: 1:X 2:X 1:B , Team 2
Wins: 1:X 2:X 1:X ]
> System.out.println(games)
[Team 1 Wins: 1:A 2:A 1:A , Team 1 Wins: 1:A 2:A 1:B , Team 2 Wins:
1:A 2:A 1:X , Team 1 Wins: 1:A 2:B 1:A , Team 1 Wins: 1:A 2:B 1:B ,
Team 2 Wins: 1:A 2:B 1:X , Team 2 Wins: 1:A 2:AB , Team 1 Wins: 1:A
2:X , Team 1 Wins: 1:B 2:A 1:A , Team 1 Wins: 1:B 2:A 1:B , Team 2
Wins: 1:B 2:A 1:X , Team 1 Wins: 1:B 2:B 1:A , Team 1 Wins: 1:B 2:B
1:B , Team 2 Wins: 1:B 2:B 1:X , Team 2 Wins: 1:B 2:AB , Team 1 Wins:
1:B 2:X , Team 1 Wins: 1:AB , Team 2 Wins: 1:X 2:A , Team 2 Wins: 1:X
2:B , Team 1 Wins: 1:X 2:X 1:A , Team 1 Wins: 1:X 2:X 1:B , Team 2
Wins: 1:X 2:X 1:X ]

Games with 4 cups or more are too large to print. Your lab this week will develop a framework to read in files containing party pong games, sort them, and use them to verify your results against the reference solution results.