Monty hall simulation not functioning as expected - java

import java.util.Scanner;
import static java.lang.System.*;
import static java.lang.Math.*;
import java.util.Random;
public class Montyhall
{
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter number of attempts:");
int attempts = keyboard.nextInt();/*Decide how many times you want this to
run. The larger the number, the more realistic an answer you will get.*/
int curtains[] = new int[3]; //like the game show, one of these will be a winner
Random rand = new Random(); /*sets the methods up with the same random seed, which
otherwise changes by the milisecond and could influence the response*/
withoutswitch(curtains, attempts, rand);
withswitch(curtains, attempts, rand);
}
public static void withoutswitch(int curtains[], int attempts, Random rand)
{
int nsCorrect=0;
for(int x=0; x < attempts; x++)
{
int winner = rand.nextInt(3);//Sets the winner to 1, leaving the other two at 0.
curtains[winner] = 1; //It then checks to see if they are the same,
int guess = rand.nextInt(3); //a 1/3 chance, roughly.
if(curtains[guess]==1){
nsCorrect++;
}
curtains[0]=0;
curtains[1]=0;
curtains[2]=0;
//the player never changes their decision, so it does not matter if a door is opened.
}
System.out.println("Number of successes with no switch: " + nsCorrect);
}
public static void withswitch(int curtains[], int attempts, Random rand)
{
int ysCorrect=0;
int goat = 0;
for(int x=0; x < attempts; x++)
{
int winner = rand.nextInt(3);
curtains[winner] = 1;
int guess = rand.nextInt(3);
goat = rand.nextInt(3);//one of the doors is opened
while(goat == winner || goat == guess)//the opened door is randomized until
goat = rand.nextInt(3); //it isn't the guess or the winner.
int guess2 = rand.nextInt(3);
while(guess2 == guess || guess2 == goat)
guess2 = rand.nextInt(3);//the second guess goes through a similar process
if(curtains[guess2]==1){
ysCorrect++;
}
curtains[0]=0;
curtains[1]=0;
curtains[2]=0;
}
System.out.println("Number of successes with a switch: " + ysCorrect);
}
}
Sorry it's a bit messy, I'm trying to get back into coding after almost a year hiatus. The first part functions as intended, returning roughly a 1/3 chance of success. The second, however, should be giving me a 2/3 chance, but I'm still getting roughly the same amount right with the switch as with no switch. I looked through the site, and mostly found things outside of Java that I'm not familiar with. This one was very similar, but no one seemed to actually help with the main issue.
What can I do to make the odds more realistic? Advice on cleaning up the code would be appreciated as well.
Edit:Code now functions, I'm now just trying to slim it down.

In your method withoutswitch you need to change
if(guess==1)
nsCorrect++;
to
if (curtains[guess] == 1)
nsCorrect++;
same as in the withswitch method. After each run of the for-loop you need to reset the curtains to 0. Otherwise the previous 1 will be in there and after a few runs the curtains will only contain 1s.
private static void resetCurtains(int[] curtains) {
for (int i = 0; i < curtains.length; i++) {
curtains[i] = 0;
}
}
Call that method after every run within the for-loop.
In addition, i would recommend using {} even if the statements are 1-liner:
if (curtrains[guess] == 1) {
nsCorrect++;
}

Both of your methods do not function as intended.
Your "withoutswitch" method only picks a random number from 0, 1, or 2, and adds to a counter when its 1. In other words, I can simplify your "withoutswitch" method to this:
public static void withoutswitch(int attempts, Random rand) {
int counter = 0;
for (int i = 0; i < attempts; i++) {
if (rand.nextInt(3) == 1) counter++;
}
System.out.println(counter);
}
Your "withswitch" method, believe it or not, does the exact same thing. You start guessing using one variable, then you completely disregard it and do it to a second variable, and check if that is 1. So, it produces the exact same results.
Both of your methods use the "curtains" array, but not correctly. The point of this problem is to put the car behind a random door every time, but you never set your array back to all zeros, and so, after a few runs, it becomes an array of all ones, which definitely isn't what you want.
Here is some pseudocode to help you get started:
number of switch wins = 0
number of stay wins = 0
scan in the number of attempts
loop through each attempt:
make an array {0, 0, 0}
pick a random number (0, 1, or 2), and set that array index to 1 (winning index)
pick a random number (0, 1, or 2), and set it to choice
pick a random number (0, 1, or 2), and set it to the shown door
loop while the door number isn't the choice number or the winning index:
pick a random number (0, 1, or 2) and set it to the shown door
increment stay wins if the choice is equal to the winning index
increment switch wins if (3 - choice - showndoor) is equal to the winning index
print stay wins and switch wins
Note: that last bit of logic determines the index of the switched door, since your only possible indices are 0, 1, and 2, (0 + 1 + 2 = 3), then 3 - the door you chose - the door you were shown = the last door.
Hope this helps!

I would back up and restructure the whole thing. One object for the game, two descendents, one of which simply picks a door, one of which picks and then switches.
I'm not entirely following your switch logic but it's definitely wrong. Monty's logic is if the prize is behind the player's door you open one randomly, otherwise you open one with the goat. Only a single random number is desirable.
Likewise, the player switches. There is only one curtain at this point, no random numbers are needed.
A rough stab at the logic (not Java, not the whole program):
MontyHaulGame
{
int[] Curtains = new int[3];
int Car = Random(3);
int Guess;
Pick();
if (Guess == Car) Wins++;
}
MontyHaulNoSwitch : MontyHaulGame
{
Pick()
{
Guess = Random(3);
}
}
MontyHaulSwitch : MontyHaulGame
{
Pick()
{
Guess = Random(3);
OpenOne();
Switch();
}
OpenOne()
{
if Guess == Car then
Repeat
Monty = Random(3);
Until Monty != Guess;
else
Monty = 1;
While (Monty == Guess) || (Monty == Car)
Monty++;
}
Switch()
{
NewGuess = 1;
While (NewGuess == Guess) || (NewGuess == Monty)
NewGuess++;
Guess == NewGuess;
}
}

Related

What is this method doing? (Arrays and random numbers)

My textbook gave me this code to help count the amount of times a certain number shows up in an array of integers. I tried to apply the code my textbook gave me to my assignment but it doesn't seem to be working. Basically, I have to generate 30 random integers in an array, with the upper bound being 15 and lower bond being -5.
I want to find out how many times a number in the array is equal to 0, 1, 2... all the way until 10. The first code is the one my textbook gave me. They also used a random number generator but instead of finding how many elements is equal to 0, 1, etc, they want to find how many times each number appears. (The scores array is simply the random number generator, and their upper bound is 100). The second code is mine.
int[] counts = new int [100];
for (int i = 0; i < scores.length; i++) {
int index = scores[i];
counts[index]++;
}
//This is my code
public static void main(String[] args) {
int []a = arrayHist ();
printArray (a);
}
public static int randomInt (int low, int high) {
int range = (high - low) +1;
return (int) (Math.random() * range) + low;
}
public static int[] randomIntArray (int x) {
int[] random = new int[x];
for (int i = 0; i< x; i++) {
random [i] = randomInt (-5, 15);
}
return random;
}
public static int[] arrayHist () {
int[] counts = new int [30];
int[] hist = randomIntArray (30);
for (int i = 0; i < 10 && i >= 0; i++) {
int index = hist[i];
counts[index]++;
}
return hist;
}
public static void printArray (int[] a) {
for (int i = 0; i < a.length; i++) {
System.out.println (a[i]);
}
}
I'm supposed to be getting only 11 elements, but instead I get 30 random numbers again. Why is that?
I'll put some comments in your code, and see if you can spot where it goes wrong:
//take a histogram of the array. We're only going to count values between 0 and 10
//so 25th to 75 centiles, ignoring values that are lower than 0 or higher than 10
public static int[] arrayHist () {
//need to make an array of 11 numbers for the counts
int[] counts = new int [30];
//get an array of 30 random numbers
int[] hist = randomIntArray (30);
//loop over the whole array of 30 numbers
for (int i = 0; i < 10 && i >= 0; i++) {
//retrieve the random number into a variable temporarily
int index = hist[i];
//if the value is too low or too high, skip it
//else, store it in the counts array - the value from the random array
//serves as the index position in the counts array
counts[index]++;
}
//return the counts array
return hist;
}
What I've done with my comments is equivalent to designing the algorithm using the language you think in (English) and then you can translate it into the language you're learning (java). Very few developers think in the programming language they write. As a student I recommend you should ALWAYS write comments to explain your algorithm to yourself before you write code underneath the comments. You get points for writing comments (usually) so if you write them first then a) it helps you write the code and b) you don't have the tedious job of writing comments after you get the code working
Please please, for your own good/learning, try working out what is wrong from the above before looking at the spoilers(answers) below. Roll the mouse over the box to display the spoilers
//loop over the whole array of 30 numbers - YOU ONLY LOOP 10
for (int i = 0; i < 10 && i >= 0; i++) {
//if the value is too low or too high, skip it - YOU DIDN'T DO THIS CHECK
...
}
//return the counts array - YOU RETURNED THE WRONG ARRAY
return hist;
Edits in response to comments:
Checking a range
You'll have to check two limits, and hence it will need to be of one of the following forms:
if(x < 0 || x > 10) then don't do the count
if(!(x >= 0 && x <= 10)) then don't do the count
if(x >= 0 && x <= 10) then do the count
if(!(x < 0 || x > 10)) then do the count
Tests that use NOT - the exclamation mark ! - are typically a bit harder to read and understand, so try to avoid them is possible. Tests that are "positive minded" - i.e. they return a positive result rather than a negative that needs to be negated - are easier to read and understand.
A helpful tip for loops and methods, in terms of error checking, is to test for bad values that meet certain conditions, and if a bad value is encountered, then skip processing the rest of the loop (using the continue) keyword, or skip the rest of the method (by returning from it)
Doing this means that your if body (the bit between { and } ) doesnt get massive. Compare:
for(...){
if(test for bad values)
continue;
//50 lines long loop body
}
Is neater than doing:
for(...){
if(test for goodvalues){
//50 lines long loop body
}
}
If you use the bottom pattern, you can end up after several IFs in a real indented mess, with { and } all over the place and your code is way over to the right hand side of the screen:
for(...){
//code
if(...){
//code
if(...){
//code
if(...){
//code
if(...){
//code
if(...){
//code
if(...){
//code
}
//code
}
//code
}
//code
}
//code
}
//code
}
//code
}
Keeping indent levels to a minimum helps make your code more readable
Hence, I recommend in your case, that rather than test for the value being inside the range 0 to 10 and doing something with it, you adopt the form "if value is OUTSIDE" the range 0 to 10, skip doing the rest of the loop
Your arrayHist() method just returns the array with the random numbers. It should be more like this:
public static int[] arrayHist() {
// generate array with random numbers
int[] hist = randomIntArray(30);
// initialize the array for counting
int[] counts = new int[11];
// step through the random numbers array and increase corresponding counter if the number's values is between 0 and 10
for (int j = 0; j < hist.length; j++) {
int number = hist[j];
if (number > -1 && number < 11) {
counts[number]++;
}
}
return counts;
}

Java (dice roll deciding who goes first in a snakes and ladders game )

I am developing a snakes and ladders game. I'm having trouble to include a dice roll that determines which player goes first before the game starts.
Any help would be much appreciated.
This is what I have attempted:
Random rand = new Random();
int result = rand.nextInt(3); // a random number, either 0 or 1, see http://docs.oracle.com/javase/6/docs/api/java/util/Random.html#nextInt(int)
if (result == 0) {
Player 1 goes first
}
else {
Player 2 goes first
}
You are off by 1 when you generate a random number.
result = rand.nextInt(2) //will return 0 or 1
You can create an ArrayList to hold all the rolls, then create a temporary arraylist to hold the rolls. Sort the temp list to get the max value, and then find the index of the max value in the original list.
If you also store your players in an array or list you can use the index you just found to determine which player had the max value
for (int i = 0; i < n; i++)
roll.add(rand.nextInt(n+1));// this will add n random integers to the arraylist
ArrayList<Integer> tmp = roll;
tmp.sort(null);
int index = roll.indexOf(tmp.get(n));
if you are going with max of 4 players then n value would be 2<=n<=4.
List<Integer> decideDiceRollingOrder(int n)
{
ArrayList<Integer> playingOrder=null;
if(n<=1 || n>4)
{
System.out.println("Please check the players count");
playingOrder=Collection.emptyList(); // for not throwing the null pointer Exception
}
else
{
Random rand = new Random();
playingOrder=new ArrayList<Integer>();
for(i=1;i<=n;i++)
{
playingOrder(i,rand.nextInt(n);// n number of players
}
//Sort the ArrayList for deciding the order
}
return playingOrder//sorted list;
}//method
I hope this gives you the major idea on the solution.
I would do it this way:
import java.lang.Math;
int diceRoll = (int) ((6*Math.random())+1);
if(diceRoll <= 3){
player1 goes first;
}
else{
player2 goes first;
}
Something along those lines. The line: 6*Math.random() will give you a number 0-5 and the +1 makes it a dice roll of 1-6 if that is what you're looking for.
Edit to add: forgot to cast it to an int for you. Also, if you want the number to be from 0 to n, just change the number in front of Math.random() to n+1 (example: you want 0 to 100... 101*Math.random). Casting to an int isn't necessary if you give the if/else a range instead of an equality...

Printing something 3 times in a row, and recording it?

This randomly prints heads or tails, and if heads is printed 3 times in a row, then I report that. Right now I have it so if 3 heads are printed total it reports it.Thanks.
public static void flip(Random r){
int heads = 0;
int totalFlips = 0;
Random number = new Random();
int randomNumber;
do {
randomNumber = number.nextInt(2)+1;
if(randomNumber == 1){
System.out.println("heads");
heads++;
totalFlips++;
}
else {
System.out.println("tails");
totalFlips++;
}
} while(heads < 3);
if(heads == 3){
System.out.print("3 heads in a row after " +totalFlips + " flips");
}
}
You are setting the random number outside the loop so it will pick a 1 or a 2 and it won't change. I suggest you move the random number generation inside your loop to generate a new number each time.
The reason it appears to only pick heads is that if it picks tails it will go into an infinite loop.
BTW Using a debugger would have found this bug faster.

Java- Assigning random number to a do while loop

What I'm attempting to do is have 2 or three do while loops that each have 10 or so if statements within that contain questions. Each if statement (question) is assigned a number (generated by random num gen) and triggers a different question. I want them to trigger randomly when the program is run- So if you run it once the 3rd question in the list might trigger first and the next time the 7th question might trigger first. A sample do while loop is below:
do {
i++;
//set what variable you want to represent random vars
randomint = randomGenerator.nextInt(10);
System.out.println(randomint);
/*
* need to generate 1 number per do loop (as opposed to 10 each loop which this is doing)
* and make sure that the numbers 1-10 are all hit within the 10 cycles of the do loop
* then will do again for a harder set of questions in the second loop
*/
if(randomint==1) {
System.out.println("What is the capital of PA?");
guess= in.nextLine();
if(answer1a.equals(guess) || answer1b.equals(guess)) {
System.out.println("Correct! Good job!");
score=score+5;
}
/*
* add another for loop that gives 4,3,2,1,0 points based on # of guesses used
*/
else {
do {
System.out.println("Nope, try again!");
guess= in.nextLine();
if (answer1a.equals(guess) || answer1b.equals(guess))
System.out.println("Correct! Good Job!");
}while (!answer1a.equals(guess) && !answer1b.equals(guess));
}
}
} while (i !=10);
So that same "if" statement will be repeated for ==2,==3, etc.. for different questions
Obviously the problem here is that every time the do loop repeats I generate a completely new set of 10 random numbers. Is there a way to generate 10 random numbers but it stops after each one and scans through my if statements so it picks one, then continues onto the second value in the random number generator? I want this to ask each individual question (10) and then exit the original do loop as determined by my i++ count.
I did try to search for this but was having trouble finding anything- It might possible be a term tat I havent come across yet. Thanks all
Use an Array to save all generated value, for the next iteration..
int[] anArray; //use this array to save all showed question
anArray = new int[10];
int i = 0;
//set what variable you want to represent random vars
randomint = randomGenerator.nextInt(10);
do{
if(i > 0){
//if there is min. 1 value in the array check if the next
//random value was already in the array
while(Arrays.asList(anArray).contains(randomint) == true){
randomint = randomGenerator.nextInt(10);
}
}
anArray[i] = randomint; //save the new value for the next checking
i++;
System.out.println(randomint);
//the Question if statements goes here...
}while (i !=10);
OR, you can use Shuffle to shuffle the array ordering, see code below:
public static void main(String args[])
{
int[] solutionArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
shuffleArray(solutionArray);
for (int i = 0; i < solutionArray.length; i++)
{
System.out.print(solutionArray[i] + " ");
}
System.out.println();
}
// Implementing Fisher–Yates shuffle
static void shuffleArray(int[] ar)
{
Random rnd = new Random();
for (int i = ar.length - 1; i > 0; i--)
{
int index = rnd.nextInt(i + 1);
// Simple swap
int a = ar[index];
ar[index] = ar[i];
ar[i] = a;
}
}
Prior to your do-while loop, create an ArrayList with the ten numbers. Shuffle the ArrayList. Then change your do-while to an iterator loop over the shuffled values.
I'd also recommend using a switch statement rather than a series of ifs.

Assignment and random

I am trying to write a method that repeatedly flips a coin until three heads in a row are seen. Each time the coin is flipped, what is seen is displayed (H for heads, T for tails). When 3 heads in a row are flipped a congratulatory message is printed.
eg.T T T H T H H H
Three heads in a row!
public static void threeHeads(){
Random rnd=new Random();
char c = (char) (rnd.nextInt(26) + 'a');
for(int i=1;i<=c.
}
I am stuck inside for loops.How should I specify the number of times it will loop.Even if I declare 3 different char c,how can I convert it to the number of times to loop.I was thinking if I should find the ascii table to find which number is H and T to print these 2 out specially?Or a loop is redundant?
public static void threeHeads(){
Random rnd=new Random();
char c = (char) (rnd.nextInt(26) + 'a');
if(c=='H' && c=='H' && c=='H'){
System.out.println("Three heads in a row!");
}
}
Another problem is assignment which is == and equals.
For a boolean value,i use ==
I understand that for strings,I should use equal.Then for a char character,what should I use?
eg.char=='y'
Am I right?
I assume this is a homework.
Instead of using Random.nextInt, use Random.nextBoolean.
Say TAIL is false and HEAD is true
You then need a counter of HEADS in a row, that is incremented when new HEAD is turned, and reset to 0 when TAIL is flipped.
Once that counter has a value of 3 you have an exit condition for your loop.
The outcome of coin flip is binary. Match H to 1 and T to 0. You only generate these two numbers randomly.
Put a counter cnt in your loop which will set to 0 when it is T (0) and cnt++ if it is H (1). Then you'll have to break out of the loop if cnt > 2 (something like if(cnt>2) break;)
Don't forget that you need to regenerate random number each time you go through the loop. In your current code it is done only once.
I think these ideas should be enough to write your code.
In general, whenever you find yourself asking "How do i keep track of XXX", the answer is to declare a new variable. In your case, however, you can use the loop counter i:
Here is how i would approach this problem:
public static void threeHeads()
{
Random rnd=new Random();
char c; //no need to initialize the char
//ostensibly, we will loop 3 times
for(int i=0; i < 3; i ++)
{
c = rnd.nextBoolean() ? 'h' : 't'; /*get random char*/;
if (c != 'h')
{
//but if we encounter a tails, reset the loop counter to -1
//that way it will be 0 next time the loop executes
i = -1;
}
System.out.println(c);
}
}
This way it will keep trying to loop three times until c is 'h' every time.
To answer your question about == versus equals():
You can always use == on primitive types (int, char, double, anything that is not an object). For objects (Strings, Double-with-a-capital D's, Lists), you are better off using equals. This is because == will test whether or not the objects are exactly the same object -- which is only true if they occupy the same location in memory. Nine times out of ten you are actually interested in checking whether or not the objects are equivalent and you don't care whether or not they are literally the same object. It is still a good idea to understand the details of this however, in case you encounter a situation where you do want to use ==.
int head =0;
int tail =1;
public static void threeHeads(){
Random rnd=new Random();
int headsSeen = 0;
while(headsSeen < 3){
int res = rnd.nextInt(1); //returns 1 or 0
if (res == head){
headsSeen ++;
}else{
headsSeen = 0; //there was a tail so reset counter
}
}
///At this point three heads seen in a row
}

Categories

Resources