Bulgarian Solitaire "Live" Case Study
    
    This case study describes the development of a solution to a Java
    programming problem.  This case study was not rehearsed in
    advance.  The documents here are the actual work products
    created during an onsight attempt at solving the problem.  The
    steps in italics describe the process to be followed.
    
    Program Development Process
    
    Step 1  Read the problem.  Note anything that is
      unclear, ambiguous, or omitted.
    
     The problem is called Bulgarian Solitaire, is given in
    Horstmann's Big Java as problem 7.12.
    "In this assignment, you will model the game of Bulgarian Solitaire.
    The game starts with 45 cards. ( They need not be playing cards.
    Unmarked index cards work just as well.) Randomly divide them into
    some number of piles of random size. For example, you might start
    with piles of size 20, 5, 1, 9, and 10. In each round, you take one
    card from each pile, forming a new pile with these cards. For
    example, the sample starting configuration would be transformed into
    piles of size 19, 4, 8, 10, and 5. The solitaire is over when the
    piles have size 1, 2, 3, 4, 5, 6, 7, 8, and 9, in some order. ( It
    can be shown that you always end up with such a configuration.) In
    your program, produce a random starting configuration and print it.
    Then keep applying the solitaire step and print the result. Stop
    when the solitaire final configuration is reached."
    
    Questions:  
    1. "Unmarked index cards" ... so, no ranks or suits at all? 
    What kind of solitaire is this?
    2. When I try the example,
    20  5  1  9 10
    I get 19  4  0  8  9, not 19, 4, 8, 10, 5. 
    Am I misunderstanding the rules?
    3. "you always end up with such a configuration"   Who is
    "you"?  Me the reader?  The player of the game?  Does
    "always end up with" mean every game ends this way?  
    Does that mean every game concludes with a winning configuration?
    Assumptions:
    After re-reading the problem several times, I conclude it's a very
    boring game where the user has no decisions to make at all, and
    every game is winnable.   Thus, in the simulation, there
    is no user input required.
    I assume that piles of size zero get eliminated.
    I think the problem has a typographical error, the 10 should be a 9.
    
      
    Step 2  Analyze the problem.  Write a description of
      what is required.  
    1. What functions must be performed? (Include any error
      handling.)
    2. What are the input and output data to the program?
    3. How does the user interface operate (if appropriate)?
    Note any assumptions made.
    
    Functions
    1. Generate a random board.
    2. Play a round, producing a new board.
    3. Determine if the game is over
       3a.  Does the board have the proper number of
    piles?
       3b.  Do the piles have the correct number of
    cards?
    4. Print the board.
    Then, to make it more interesting, I'm adding an additional
    requirement
    5. Count the number of rounds and display it at the end of the game.
    
    Inputs
    There is no external data input to the program.
    
    Outputs
    Display of the board after each round.  
    Display the number of rounds.  
    
    User Interface
    The board is displayed as a sequence of numbers where each number 
    shows the number of cards in that pile.  There's a blank
    between each number.  
    All numbers are on one line. 
    E.g., 
    20 5 1 9 10
    
    The game over message text is: "Game over after __ rounds." 
     
    
    Step 3  Create Test Data
    
    Since there is no input data, there's no obvious way to provide test
    data to the program.  In the worst case,  the output of
    the program would have to be manually verified by following each
    round and verifying the piles are calculated correctly.  This
    could be very time-consuming, as a game might easily last 50 or 60
    rounds.
    
    An alternative would be to modify the program so that it can accept
    an initial board configuration.   Then the tester can
    provide a starting configuration for which the expected output can
    be determined in advance.  So I'll add a new functional
    requirement
    6. Accept an initial configuration on the command line.
    E.g.,
      java Solitaire 20 5 1 9 10
    Assume that only integers are entered, separated by blanks.
    
    Now I can create test cases:
    Test Case 1 - shortest possible game
    Input              
     
    2 3 4 5 6 7 8 10
    Output
    1 2 3 4 5 6 7 9 8
    Game over after 1 rounds.
    
    Test Case 2  - shortest possible game reversed
    Input              
     
    10 8 7 6 5 4 3 2 
    Output
    9 7 6 5 4 3 2 1 8
    Game over after 1 rounds.
    
    Test Case 3 - shortest possible game scrambled
    Input         
    3 8 4 7 5 6 2 10
    Output
    2 7 3 6 4 5 1 9 8
    Game over after 1 rounds.
    
    Test Case 4 - rounds greater than 1
    Input         
    2 2 2 4 5 6 7 8 9
    Output
    1 1 1 3 4 5 6 7 8 9
    2 3 4 5 6 7 8 10
    1 2 3 4 5 6 7 9 8
    1 2 3 4 5 6 7 8 9
    Game over after 3 rounds.
    
    Test Case 5 - start with a single pile
    Input
    45
    Output
    44 1
    43 2
    42 1 2
    41 1 3
    40 2 3
    39 1 2 3
    38 1 2 4
    37 1 3 4
    36 2 3 4
    35 1 2 3 4
    ....
    10 2 3 4 5 6 7 8
    9 1 2 3 4 5 6 7 8
    Game over after 36 rounds
    
    Test Case 6: Run the game several times and verify it starts with a
    different random configuration each time. 
    
    Step 4  Create a design of the solution
    
    4a Identify the classes.
    Create a list of candidate classes from the nouns in the functional
    requirements:
    Game
    Board
    Pile
    Card
    Round
    
    I decide I can omit card, because it's just a placeholder.
      
    A pile is really just a positive integer representing the number of
    cards it contains.  We don't actually need any cards.
    
    A board is a collection of piles.  
    
    The game is the simulation itself.
    
    A round is just a counter.
    
    4b Identify the attributes for each class.
      class Board
         The primary data being encapsulated by
    Board is the collection of piles.  Since each pile is just an
    integer, we don't need a Pile class.
         private Collection<Integer>;
    
      class Game
         The game has a Board and a counter for
    rounds.
         private Board board;
         private int rounds;
    
    4c Identify the responsibilities of each class. 
    (Usually these are derived from the functional requirements).
    
      -  The board can generate a random initial configuration.
-  The board can setup a desired preset initial configuration.
-  The board can perform the "solitaire step" to determine the
        next configuration.  
-  The board knows if it's a winning configuration or not.
-  The board can return a printable representation of itself.
      -  The Game initializes the board.
-  The Game performs rounds until the game is over.
    4d Determine the relationships between each class: 
      Inheritance, Aggregation, or Dependency
       Game aggregates Board
    
    4e Draw the class diagram
       Game   <>-----   Board
    
    4f Design the public interface to each class.  This
      is the compilable class skeleton.
    
Completed class skeletons.
    Step 5 Write JUnit tests for each class.   Add
      minimal implementation for each class so the tests will run and
      fail.
BoardTest.java
GameTest.java
    
    Step 6 Write the algorithm for each method (in pseudocode)
    
Completed pseudocode.
    Step 7 Desk check the algorithms with a hand trace (using the
      test cases for input data)
    
Completed Desk Check.
    Step 8 Translate the algorithms into program statements. 
    8a. Start with lowest level classes.  
    8b. Run the unit tests on each class as it is completed.
    8c. Correct any defects until the unit tests all pass.
      
See finished implementation below.
    Step 9 Run the Test Cases. Correct any defects until the test
      cases all pass.
    
View Compile and Test Log. 
    
Completed source code: BulgarianSolitaire.zip
Download jar: Solitaire.jar