Program 2

Intermediate Program Suite I

Introduction to Computer Science I
ICS-21


Introduction Please print a copy of this assignment, read it carefully, and highlight material you think will be useful to you while you are working on the program or submitting it.

This programming assignment is designed to ensure that you know how to write programs that combine the standard control structures in Java: blocks, ifs, for loops, and break statements (to terminate for loops). You will also continue gaining experience with the more basic Java features: declarations and expression statements that use arithmetic, relational, logical, textual, and state-change operators -including lots of logical/boolean expressions. Finally, you will practice writing, testing, and debugging programs using iterative enhancement: a divide-and-conquer technique for building and testing programs a bit at a time.

You will write three programs in this assignment. This time, your programs must check whether some (not all) inputs are valid (and reprompt the user for them -or discard them- if they are not).

As always, you can check the behavior of your programs against mine by downloading my executable zip file Program #2 Executables and unzipping it. See Program #1) for details on how to run these executables on both PCs and in Eclipses (PCs and Macs). Remember, you can run these programs, but not examine their source (Java) code. Copy the input/output form of the executable programs in the programs that you write: use exactly the same prompts and messages. For the Darts and MontyHall programs, there are executable versions for the kernel and each enhancement.

For your information, I am listing below the number of lines in my solution programs. These programs are formated in the standard way. I am counting only lines with code (even if the only code on the line is a brace that closes a block); but I am not counting blank lines norlines filled with comments. My "darts" program is 24 lines; my "increasing" program is 30 lines; my "monty hall" program is 51 lines. Your programs might be smaller, and they might be larger; but if your program starts going over 2-3 times the size of mine, you might want to rethink it (or come get some help).

Please declare all variables to have their natural type: if some variable always stores integral values, declare it to be an int. If later in the program you need to use it as a double, cast it there.

Please follow the instructions below for each program: finish each enhancement before continuing to the next one (including printing whatever messages it displays in the console, copied exactly). Please use the infinite for loop and if/break statements to write all loops; when you are finished, you may simplify these loops.

As we improve our programming abilities, we should improve our programming style too (which will be part of the grading criteria for upcoming programming assignments). In each of these programs, please pay particularly close attention to the following style principles (discussed in the lecture on Coding Style).

  • Names: Choose good names for variables.
  • Alignment: Indent statements to clarify the meaning of their control structures.
  • Locality: Keep related information together; separate unrelated information.
  • Comments: Document your code appropriately with comments.
Please examine the Sample Programs that I have provided for examples of good programming style. Learn to copy this style, just as artists in the middle ages learned to copy their master's style before developing their own. In this program you will get feedback on your style (but it won't be graded). In the next program you will be graded on your style.

To work on this assignment, create one Java project (call it Program2) and create three new Java classes in it (as you did for one class in Program #0). Each class will contain a program that you will write to solve one problem; name the classes Darts, Increasing, and MontyHall. Write, run, and debug each class/program as you did in Program #1. When you finish each part, submit its .java file.

Only one programmer of the pair should dropoff the programs: the same one for each part. It doesn't matter which of the pair submits, but that person should submit all the parts. Of course, each program should contain both student names (in the comment: the same one you cut, pasted, ane filled in at the top of each program in Program #1).


Calculating π with Darts Write a program that performs the following tasks.
  • Prompt the user for the number of darts to throw (accept only numbers greater than 0, reprompting the user whenever a non-positive value is entered -no matter how many times).
  • Simulate throwing that many darts at a 2x2 square whose center is the origin by using a random number generator, constrained by the square's boundary, to generate x and y coordinates for each dart.
  • Approximate the value of π (pi) by computing the ratio of those darts that land inside a circle inscribed in the square divided by the number of darts that landed inside the square (the total number of darts thrown, since all darts are constrained to land in the square).
That calculation approximates the ratio of the circle's area to the square's:

To simulate throwing darts, write an expression that returns a double in the range -1.0 to +1.0 that calls the Math.random method, which returns a result between 0.0 and 1.0, and use this expression when generating the x and y coordinates. Doing so ensures that both coordinates are within the square. Use multiplication and addition/subtraction to linearly "grow" and "shift" the range of the Math.random function to the desired range for each coordinate.

Use a boolean expression to determine whether or not the coordinates of the dart are inside or outside the circle that is inscribed in the square (remember some geometry).

Design, code, test, and debug this program using iterative-enhancement, as 6 mini-projects. Test each project to ensure that it is correct before proceeding to the next enhancement. This is the same methodology that we will use for larger programs; so, it is a good idea to practice this technique here, where the program is small, even if you can write the entire program all at once. Later, we will discuss this technique in greater depth. Before starting to write your program, run my executable a few times to familiarize youself with its input and output.

  1. Write a kernel program that prompts the user for the number of darts to throw, and then loops that many times, printing the literal "Dart Thrown" for each loop iteration. Here, assume the user always enters a positive number. Ensure the number of times Dart Thrown is printed is the same as the requested number of darts (it is easy to be off by 1). Enter a few different small values to test it.

  2. Enhance the program so that after it prints Dart Thrown, it simulates throwing a dart and prints the random x- and y-coordinates of each dart as it is thrown. Ensure that these values change, are all between -1. and +1. and seem random.

  3. Enhance the program so that after it prints the x- and y-coordinates of each dart, it prints either "Inside Circle" or "Outside Circle" for that dart's coordinates. Using a calculator, hand check that the inside/outside calculation is computing its result correctly for a few darts, printing each message correctly.

  4. Enhance the program to keep track of (count up) the number of darts that land inside the circle, and display this value during each iteration of the loop. Ensure that for each dart that lands inside the circle, this count increments by one. IMPORTANT REQUIREMENT: All counters in Java should be of type int; use explicit conversion (casting) if you need to treat these values like doubles, in some later computation.

  5. Enhance the program to approximate π (pi) by computing the ratio of darts that land in the circle to the total number of darts thrown, multiplying this value by 4 (the area of the circle) according to the formula above. Display this result before terminating.

  6. Enhance the program to allow the user to enter only positive values in the original prompt for the number of darts to throw; reprompting whenever the enters a non-positive value. Use a separate loop for this validation; do not use any fancy version of Prompt.forInt: just use the simplest one with a single String operand. Test your code by trying to enter 0 and/or negative numbers (multiple times).
Finally, remove all intermediate output statements: only the final answer should appear in the final output (it should produce exactly the same output as my executable).

Hand in ONLY THE FINAL ENHANCEMENT of the program: the one meeting the complete specifications, with intermediate output statements removed. Test it by throwing 10; 100; 1,000; 10,000; 100,000, 1 million, and 10 million darts (try a few billion, if you have a fast computer). Also, try the same number of darts more than once and observe that the computed value changes, because the darts are thrown randomly each time. Typically, the more darts thrown, the better the answer approximates the true value of π (pi).


Increasing Sequences Write a program that performs the following tasks.
  • Uses a sentinel loop to prompt user for a sequence of numbers until the user enters any negative number (so only non-negative valukes are processed by the program). As the values are input the program ...
  • Counts how many numbers are entered (excluding the sentinel).
  • Counts how often an entered values is larger than the value entered before it (e.g., values in the sequence are increasing).
  • Computes the longest sequence of entered values that are strictly increasing.

We will use two int variables to keep track of the previous value entered and the current value entered, to determine if the two values in the sequence is increasing. Before entring a new "current" value, the old "current" value must be stored in the previous variable (see step 3 below). This idiom is useful in many programs.

Design, code, test, and debug this program using iterative-enhancement, as 7 mini-projects. Test each project to ensure that it is correct before proceeding to the next enhancement. This is the same methodology that we will use for larger programs; so, it is a good idea to practice this technique here, where the program is small, even if you can write the entire program all at once. Later, we will discuss this technique in greater depth.

Before starting to write your program, run my executable a few times to familiarize youself with its input and output. Test your program (and mine) by entering the values specified below. You can use short input sequences to test the early enhancements to ensure that they work correctly; you must use longer input sequences to test the latter enhancements. Don't just use my test inputs; construct your own test inputs as well.

  1. Write a kernel program that declares a current variable, and prompts the user for its value; if its value is non-negative, the program loops until the user enters a negative value, at which point the loop terminates. At the end, the program should print Loop finished.

  2. Enhance the program so that it counts the number of non-negative values the user enters. Instead of printing Loop finished, print the number of non-negative values that the user entered, in the form
      Entered a total of 4 non-negative values
    Note, if the user enters a negative value to the first prompt, the loop is not executed and there are a total of 0 non-negative numbers.

  3. Enhance the program so that it declares a variable previous and updates it as appropriate: at the bottom of the loop, the program should print both the previous and current values. If we enter 2 then 3 then 1 then 4 then -1 the program should print
      Enter first value: 2
      Enter next value: 3
      previous = 2, current = 3
      Enter next value: 1
      previous = 3, current = 1
      Enter next value: 4
      previous = 1, current = 4
      Enter next value: -1
    
      Entered a total of 4 non-negative values
    (notice those outputs are interspersed with the prompts).

  4. Enhance the program so that it declares a variable increaseCount and uses it to count how many current values are bigger than their previous values. Update the output to show the number of increases as well. If we enter 2 then 3 then 1 then 4 then -1 the program should print
      Enter first value: 2
      Enter next value: 3
      previous = 2, current = 3, increaseCount = 1
      Enter next value: 1
      previous = 3, current = 1, increaseCount = 1
      Enter next value: 4
      previous = 1, current = 4, increaseCount = 2
      Enter next value: -1
    
      Entered a total of 4 non-negative values

  5. Enhance the program so that it declares a variable increaseInARow and uses it to count the length of each sequence of increasing values. Whenever the previous value is less than the current one, this variable increases by 1; otherwise this value should be reset to 0 (because the increasing sequence has ended). Update the output to show the number of increases in a row as well. If we enter a slightly longer, different input 2 then 4 then 1 then 3 then 5 then 7 then 4 then 6 then -1 the program should print
      Enter first value: 2
      Enter next value: 4
      previous = 2, current = 4, increaseCount = 1, increaseInARow = 1
      Enter next value: 1
      previous = 4, current = 1, increaseCount = 1, increaseInARow = 0
      Enter next value: 3
      previous = 1, current = 3, increaseCount = 2, increaseInARow = 1
      Enter next value: 5
      previous = 3, current = 5, increaseCount = 3, increaseInARow = 2
      Enter next value: 7
      previous = 5, current = 7, increaseCount = 4, increaseInARow = 3
      Enter next value: 4
      previous = 7, current = 4, increaseCount = 4, increaseInARow = 0
      Enter next value: 6
      previous = 4, current = 6, increaseCount = 5, increaseInARow = 1
      Enter next value: -1
    
      Entered a total of 8 non-negative values

  6. Enhance the program so that it declares a variable maxIncreaseInARow and uses it to count the length of the longest sequence of increasing values. If we again enter the input 2 then 4 then 1 then 3 then 5 then 7 then 4 then 6 then -1 the program should print
      Enter first value: 2
      Enter next value: 4
      previous = 2, current = 4, increaseCount = 1, increaseInARow = 1, maxIncreaseInARow = 1
      Enter next value: 1
      previous = 4, current = 1, increaseCount = 1, increaseInARow = 0, maxIncreaseInARow = 1
      Enter next value: 3
      previous = 1, current = 3, increaseCount = 2, increaseInARow = 1, maxIncreaseInARow = 1
      Enter next value: 5
      previous = 3, current = 5, increaseCount = 3, increaseInARow = 2, maxIncreaseInARow = 2
      Enter next value: 7
      previous = 5, current = 7, increaseCount = 4, increaseInARow = 3, maxIncreaseInARow = 3
      Enter next value: 4
      previous = 7, current = 4, increaseCount = 4, increaseInARow = 0, maxIncreaseInARow = 3
      Enter next value: 6
      previous = 4, current = 6, increaseCount = 5, increaseInARow = 1, maxIncreaseInARow = 3
      Enter next value: -1
    
      Entered a total of 8 non-negative values

  7. Enhance the program so that doesn't print any intermediate output. To do this, comment-out all the intermediate print statements, so they are still in the program (but do nothing, because they are in comments), and can be reactivated later, if the need arises. So, besides the prompting, the program prints just the total number of non-negative values entered, the total number of times the values increased, and the length of the longest sequence of increasing values.
Hand in ONLY THE FINAL ENHANCEMENT of the program: the one meeting the complete specifications, with intermediate output statements commented-out.

Test your program (and mine) on short and long sequences of numbers, with different patterns of increasing and decreasing values. Think of boundary cases, for example where the first two values entered aren't increasing (different from all the examples above) and verify that your program computes the right answers.


Monty Hall
Let's Make a Deal
In the 1970s, a popular TV game show was "Let's Make A Deal", whose host was Monty Hall. A typical contestant would be shown three doors: behind one door was a valuable prize; behind the other two doors were "goats" (worthless prizes). The contestant would first pick a door. Then, Monty would often show them a goat prize behind one of the other doors; no matter what door the contestant picked, there was always one other door with a goat prize behind it for Monty to show them. Next, Monty would often ask the contestant whether or not he/she wanted to keep the door they originally chose, or switch to the other door (the one not shown by Monty).

Is there an advantage to staying with your door? Is there an advantage to switching doors? Are both options equally good (in terms of how likely the contestant will win the valuable prize)? You could watch many shows and keep statistics on what strategy the contestant used and whether he/she won or lost with that strategy. Or, we can write a program that can simulate very many games, to determine if there is a best strategy, and what it is. Although such a computer simulation will tell you which strategy is best, it won't tell you why that strategy is best.

You may also want to use your reasoning powers to deduce the correct answer before running my/your program, but this problem is notoriously difficult to solve correctly. Marilyn vos Savant (she writes the column, "Ask Marilyn", in Parade Magazine; she supposedly has the highest IQ of anyone in the US) discussed this problem in her column in the early 1990s and it generated a huge volumne of mail, many from PhDs in mathematics who (incorrectly) disagreed with her analysis. If you do a web search, you'll find lots written about the Monty Hall problem. But before you do, try to come up with your own solution to this problem. In fact, it appears in the following clip from the movie 21; the student supplies the answer but does not justify the solution. You can also see various episodes of Let's Make a Deal on You Tube.

What is interesting here is that different people can each effectively argue that their solution is correct (because the problem is subtle, and many wrong solutions sound right). Once someone has formulated a solution, it is difficult to convince them that they are wrong. Yet, we can write a simple computer program to determine which, if any, strategy is best: even given such evidence, people have a hard time "giving up" on an incorrect solution.

So, you will write a program that prompts the user for the strategy to use (switch to the remaining door or stay with the door you chose originally), the number of games to play (accept only numbers greater than 0), and whether to output a detailed trace of the program; then it simulates playing that many games, keeping track of how often a player with the chosen strategy wins. The program prints the statistics it collects (the number of times the player won and lost) at the end: from these numbers, you can deduce which strategy is best (if there really is a significant difference).

To simulate choosing doors, a random door is chosen as the "good prize" door, and a random door is chosen as the "contestant's door", and then Monty chooses the door to expose: it can't be either the good prize or chosen door. Cut/paste the following code after the public class MontyHall but before public static void main(String[] args)

  //This method returns a random int value in the range [1,3]
  static int getRandomDoor()
  {return (int)(3*Math.random() + 1);}

When you need to choose a random door, call this method as getRandomDoor() and store the result of each call in a variable (e.g., prizeDoor, chosenDoor, exposedDoor) for use in subsequent statements in the program. Math.Random() returns a value in [0,1) the expression, before it is converted to an int has a value in [1,4)]. By converting to an int, either 1, 2, or 3 is the result (it truncates down, and 4) means all numbers up to but not including 4 can be generated), each with equal probability.

Design, code, test, and debug this program using iterative-enhancement, as 7 mini-projects. Test each project to ensure that it is correct before proceeding to the next enhancement. This is the same methodology that we will use for larger programs; so, it is a good idea to practice this technique here, where the program is small. Soon, we will discuss this technique in greater depth.

Before starting to write your program, run my executable a few times to familiarize youself with its input and output. Run the executable using a detailed trace, so you can better understand this program as well.

  1. Write a kernel program that prompts the user for the number of games to play, and then loops that many times, printing the literal "Game Played" for each loop iteration. For this phase, always assume the user enters correct input (a positive number). Ensure the number of times Game Played is printed is the same as the requested number of games (enter a few different small values to test it).

  2. Enhance the program so that before each game is played, the program randomly chooses which door has the prize behind it and which door the contestant chooses; print these doors for each game (.e.g, Prize behind door 1; Contestant chooses door 2 -of course, these doors may have the same number). After printing these choices, the program should prompt the user (in this enhancement, the user plays Monty Hall) for which door number to expose to the contestant. Print this door number too.

  3. Enhance the program to first prompt for whether or not to use the switch strategy: whether or not for the simulated player to switch doors once Monty exposes his door. Store this boolean value in a variable. Then, after each game is played, print whether or not the player won or lost with that strategy (based on the strategy -the value of this variable- and all the chosen and prize doors).

  4. Enhance the program to keep track of the number of times that the player won. When printing whether the player won or lost, print the total number of times that they have won.

  5. Enhance the program to allow the user to enter only positive values in the original prompt for the number of games to play; if the user enters an incorrect number, reprompt. Use a separate loop for this validation; do not try to use some fancy version of Prompt.forInt: just use the simplest one with a single String parameter). Test your code by trying to enter 0 or negative numbers to ensure the user is continually prompted to enter a value until they enter a positive one.

  6. Enhance the program to randomly choose which door to expose (so Java can run this simulation at a high speed, without bothering the user to enter this value). Do this by repeatedly (in a loop) choosing any random door, but terminating the loop (allowing that choice) only when the choice is not the door chosen by the contestant, and not the door containing the prize (this is accomplished similarly to the enhancement above). Display each attempt (indented) and the final choice for which door to expose after terminating. Your program should be printing information identically to mine, when mine is run with a detailed trace.

  7. Enhance the program to prompt for whether or not to provde a detailed trace. Store this boolean value in a variable. Execute each of the your intermediate/tracing output statements only if this tracing variable is set to true. If this tracing variable is set to false, only the final answers should appear in the final output (after the prompt lines): a line printing the number of games played, and the number of times a player using the selected strategy won and the number of times the player lost.
Hand in ONLY THIS FINAL ENHANCEMENT of the program: the one meeting the complete specifications and printing just six lines of output, including the three prompts. Test it by playing 10; 100; 1,000; 10,000; 100,000, and 1 million games. Also, try the same number of games more than once and observe that the computed values change, because the doors are chosen randomly each time. Typically, the more games played, the more accurate the answer is.