# Monty Hall Paradox in Java

I was wondering if this code looks neat, and if I should change anything. I was planning to implement Frames (or JFrame) tomorrow on it. Would it be a good idea to use functions?

import java.lang.Math.*;
import java.util.Random;
import java.util.Scanner;

public class Paradox {
public static void main(String[] args){
System.out.println("\n\nYou have got three doors, there is a price inside each of them. Pick a door: A, B, or C.");
Door A = new Door();
Door B = new Door();
Door C = new Door();
A.open=0;
B.open=0;
C.open=0;

Random rand = new Random();
int i = rand.nextInt(3);
/*System.out.println(i);*/

if(i==0) {
A.goatorcar="Car";
B.goatorcar="Goat";
C.goatorcar="Goat";
}
else if (i==1){
A.goatorcar="Goat";
B.goatorcar="Car";
C.goatorcar="Goat";
}
else if (i==2) {
A.goatorcar="Goat";
B.goatorcar="Goat";
C.goatorcar="Car";
} else { System.out.println("Unexpected error"); }

int pickedA=0;
int pickedB=0;
int pickedC=0;

Scanner sc = new Scanner(System.in);
String pickedDoor = sc.nextLine();
System.out.println("\n");

if (pickedDoor.equals("A") || pickedDoor.equals("1") || pickedDoor.equals("a")){
pickedA = 1;
}
if (pickedDoor.equals("B") || pickedDoor.equals("2") || pickedDoor.equals("b")){
pickedB = 1;
}
if (pickedDoor.equals("C") || pickedDoor.equals("3") || pickedDoor.equals("c")){
pickedC = 1;
}

if(pickedA==1) {
if (A.goatorcar.equals("Car")){
i = rand.nextInt(2);
if (i==0){ System.out.println("The door B contains a Goat"); B.open=1; }
else if (i==1){ System.out.println("The door C contains a Goat"); C.open=1; }
}
else {
if (B.goatorcar=="Goat") { System.out.println("The door B contains a Goat"); B.open=1; }
else if (C.goatorcar=="Goat") { System.out.println("The door C contains a Goat"); C.open=1; }
}
}
else if (pickedB==1) {
if (B.goatorcar.equals("Car")){
i = rand.nextInt(2);
if (i==0){ System.out.println("The door A contains a Goat"); A.open=1; }
else if (i==1){ System.out.println("The door C contains a Goat"); C.open=1; }
}
else {
if (A.goatorcar=="Goat") { System.out.println("The door A contains a Goat"); A.open=1; }
else if (C.goatorcar=="Goat") { System.out.println("The door C contains a Goat"); C.open=1; }
}
}
else if (pickedC==1) {
if (C.goatorcar.equals("Car")){
i = rand.nextInt(2);
if (i==0){ System.out.println("The door A contains a Goat"); A.open=1; }
else if (i==1){ System.out.println("The door B contains a Goat"); B.open=1; }
}
else {
if (A.goatorcar=="Goat") { System.out.println("The door A contains a Goat"); A.open=1; }
else if (B.goatorcar=="Goat") { System.out.println("The door B contains a Goat"); B.open=1; }
}
}
else { System.out.println("You haven't picked any door"); System.exit(0); }

System.out.println("\nKnowing where one of the Goats are, do you wish to stay on your current door, or do you want to change?");

String changeornot = sc.nextLine();
int change=2;
System.out.println();

if (changeornot.equals("change") || changeornot.equals("1") || changeornot.equals("yes")){
change=1;
}
else if (changeornot.equals("stay") || changeornot.equals("0") || changeornot.equals("no")){
change=0;
}

if(change==0){
System.out.print("Congratulations! You stayed, and won a ");
if(pickedA==1){
System.out.println(A.goatorcar);
}
if(pickedB==1){
System.out.println(B.goatorcar);
}
if (pickedC==1){
System.out.println(C.goatorcar);
}
}

else if (change==1){
System.out.print("Congratulations! You changed, and won a ");
if (pickedA==1 && B.open==1) {
System.out.println(C.goatorcar);
}
if (pickedA==1 && C.open==1) {
System.out.println(B.goatorcar);
}

if (pickedB==1 && A.open==1) {
System.out.println(C.goatorcar);
}
if (pickedB==1 && C.open==1) {
System.out.println(A.goatorcar);
}

if (pickedC==1 && A.open==1) {
System.out.println(B.goatorcar);
}
if (pickedC==1 && B.open==1) {
System.out.println(A.goatorcar);
}
}
else if (change==2){ System.out.println("Error at change"); }

/*System.out.println("Door A: " + A.goatorcar);
System.out.println("Door B: " + B.goatorcar);
System.out.println("Door C: " + C.goatorcar);*/

}
}
class Door {
String goatorcar;
int open;
}

• It seems you haven't learnt about booleans, arrays, or collections yet and you should remedy that ASAP. – abuzittin gillifirca Mar 14 '15 at 19:40
• I know what they are in C, but I've always used them as lists of numbers, or such. Any tips on using them as Objects? I thought that was the purpose of classes. Correct me if I'm mistaken. – mazunki Mar 14 '15 at 20:00
• Enums are also good to learn for this sort of thing. – fluffy Mar 14 '15 at 22:08

## 7 Answers

A few thoughts:

• Some of your lines are very long. While it may seem convenient that they fit on your screen, code gets more difficult to understand as lines become longer. Many people have good reasons to desire an eighty char line limit. This is my personal preference; and many people will disagree; but i find

System.out.println(INTRODUCTION);


more amiable than

System.out.println("\n\nYou have got three doors, there is a price inside each of them. Pick a door: A, B, or C.");


... mainly because then I don't need to devote much of my screen real estate to a single file. If I am working on multiple files in multiple windows at once, or if I am using a Linux TTY, long lines become a pain if I need to scroll in four directions instead of two. As pointed out by astute readers, this practice is moreover archaic. These days, you can easily get away with lines longer than 80 characters.

• Writing modular code is an essential step towards ensuring your code isn't a hack. A hack is basically code that doesn't give freely to modification. When code is split up into methods, it becomes easier to understand, modify, and debug. For example, if you have instead a doorOption method that determines what door was chosen based on a String, you can simply call that method whenever you want the user to pick a door. The method can do the task of

if (pickedDoor.toLowerCase().equals("a") || pickedDoor.equals("1"))


in one place. You can also probably get away with enumerating the result of that method; that way you can refer to the results by name: DOOR_ONE DOOR_TWO, et cetera. Writing modular code can be a little daunting; but the rewards are quite desirable. Modular code is code that is divided into modules; each module does a specific task. According to Wikipedia,

Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.

• You have a lot of hard-coded strings. According to Google:

[Hard coding is to] fix (data or parameters) in a program in such a way that they cannot be altered without modifying the program.

You can probably get away with making those into static final fields. Something like

static final String INTRODUCTION = "\n\nYou have got three doors, there is a price inside each of them. Pick a door: A, B, or C.";


final means the variable can not be modified after assignment.

• I would look into making your code more maintainable before making a GUI. The process shouldn't be overly involved. I usually try to keep all the GUI methods in a separate class.

• Thank you for the great tips, but I didn't get what modular code means. Is it the same as "easy-to-read"? Yep, I have to put some methods in it. I'll do that as from tomorrow. <br /> On the other hand, what's the difference between "hardcoding" the strings, and putting them apart? I don't know what the final tag does either. >< – mazunki Mar 14 '15 at 19:57
• Ah, so modular is the same as using methods? – mazunki Mar 14 '15 at 20:08
• Upvoted, but can you explain your insistence on 80 character line width? I personally think this is really dated advice, since few of us are programming on punch cards anymore. I use a 120 character limit myself, but I think the more important point to stress is to avoid doing too much on one line, e.g. feature envy. With Java, especially, I think you have to be more tolerant of line lengths. – lealand Mar 14 '15 at 20:09
• sigh. ok guys, the original point of that comment had nothing to do with how much can fit on a screen. The original point was reading any form of text printed in extraordinarily long lines becomes increasingly difficult to follow. That is why, for example, textbooks and newspapers are printed up in columns. Kind of the same reason a 500 line function or method is not really that standard. – motoku Mar 16 '15 at 21:45
• @MotokoKusanagi I was hoping to make that same point in my original comment. To be clear, I believe there should be limits on line length, but it has to do more with organizational consistency that something arbitrary. I read something in the past few months about how one should write code to be read top to bottom, not left to right that is relevant, but I've yet to find it again! – lealand Mar 17 '15 at 2:34

### One-liners

This is not a huge point, but I noticed you have several one-liners which have multiple commands in them. Even though that's not technically "wrong" it could lead to some confusion for the next person who may have to maintain your code.

For example:

else if (pickedC==1) {
if (C.goatorcar.equals("Car")){
i = rand.nextInt(2);
if (i==0){ System.out.println("The door A contains a Goat"); A.open=1; }
else if (i==1){ System.out.println("The door B contains a Goat"); B.open=1; }
}
else {
if (A.goatorcar=="Goat") { System.out.println("The door A contains a Goat"); A.open=1; }
else if (B.goatorcar=="Goat") { System.out.println("The door B contains a Goat"); B.open=1; }
}
}
else { System.out.println("You haven't picked any door"); System.exit(0); }


Something like this formatting would more easily indicate there's more going on than printing to console.

else if (pickedC==1) {
if (C.goatorcar.equals("Car")){
i = rand.nextInt(2);
if (i==0){ System.out.println("The door A contains a Goat");
A.open=1; }
else if (i==1){ System.out.println("The door B contains a Goat");
B.open=1; }
}
else {
if (A.goatorcar=="Goat") { System.out.println("The door A contains a Goat");
A.open=1; }
else if (B.goatorcar=="Goat") { System.out.println("The door B contains a Goat");
B.open=1; }
}
}
else { System.out.println("You haven't picked any door");
System.exit(0); }


Ideally though, many could say you should just follow the standard Java indentation throughout, even though it takes more vertical room it makes things perfectly clear, like this:

else if (pickedC==1) {
if (C.goatorcar.equals("Car")) {
i = rand.nextInt(2);
if (i==0) {
System.out.println("The door A contains a Goat");
A.open=1;
}
else if (i==1) {
System.out.println("The door B contains a Goat");
B.open=1;
}
}
else {
if (A.goatorcar=="Goat") {
System.out.println("The door A contains a Goat");
A.open=1;
}
else if (B.goatorcar=="Goat") {
System.out.println("The door B contains a Goat");
B.open=1;
}
}
}
else {
System.out.println("You haven't picked any door");
System.exit(0);
}


### Naming and spacing

Something like this:

if(i==0) {
A.goatorcar="Car";
B.goatorcar="Goat";
C.goatorcar="Goat";
}


For one, the naming for variables like that would be easier to follow if you used camelCase, which is the convention for multi-word variables and methods. So goatorcar becomes more easily readable, goatOrCar.

Also a little bit of breathing room between operators would look better. Like this:

if(i == 0) {
A.goatOrCar = "Car";
B.goatOrCar = "Goat";
C.goatOrCar = "Goat";
}

• Great advice. I always did this, until a teacher of mine told me this was pointless. I tried to listen to him, but I see I should do as I used to. Thank you. – mazunki Mar 14 '15 at 20:25
• Great points! I just suggest spaces around the equal signs though. All the nested if statements still rub me the wrong way though... Also, why is open still an int? – lealand Mar 14 '15 at 20:38

If would definitly help if you had a function to get the user input : you'd have a better separation of concerns, behavior would be easier to change and the user interface would be slightly more intuitive and user-friendly.

My Java is a bit rusty but something like (following code is not correct, what matters is the idea more than the code itself):

public static boolean getBooleanFromUser(String prompt, String retry, List<String> yesOptions, List<String> noOptions)
{
System.out.println(prompt);
while (true)
{
String userInput = sc.nextLine();
System.out.println();
if (yesOptions.contains(userInput))
return true;
if (noOptions.contains(userInput))
return false;
System.out.println(retry);
}

public static boolean userStaysOrNot()
{
return getBooleanFromUser("\nKnowing where one of the Goats are, do you wish to stay on your current door, or do you want to change?", "Invalid input, please retry", ["change", "1", "yes"], ["stay", "0", "false"]);
}


I would use a boolean value to represent if the door has a car behind it or not. I would modify:

class Door {
String goatorcar;
int open;
}


to

class Door {
boolean hasCar;
int open;
}


Then, you can change all of

if(i==0) {
A.goatorcar="Car";
B.goatorcar="Goat";
C.goatorcar="Goat";
}
else if (i==1){
A.goatorcar="Goat";
B.goatorcar="Car";
C.goatorcar="Goat";
}
else if (i==2) {
A.goatorcar="Goat";
B.goatorcar="Goat";
C.goatorcar="Car";
} else { System.out.println("Unexpected error"); }


to simply

A.hasCar = i == 0;
B.hasCar = i == 1;
C.hasCar = i == 2;


Much simpler!

Now, whenever you do A.goatcar.equals("Car"), you can change that to A.hasCar. Similarly, A.goatcar.equals("Goat") can become !A.hasCar. There are many more changes you could maker but this is an important one.

• I never got the catch of booleans, not even in C. What is its purpose? I see it makes it simplier, but I don't see what you did at the last intended code. – mazunki Mar 14 '15 at 20:53
• Booleans only have two possible values, and they are always appropriate for variables which may be either true or false. /u/soktinkpk is using a somewhat confusing way to assign this truth value to the different doors. For example, for door B, hasCar is true if and only if i is 1. – lealand Mar 14 '15 at 20:57
• Ah, it's a binary int value, kind of. (?) Great to know! – mazunki Mar 14 '15 at 21:22
• @mazunki In "the last intended code", i == 0 will return a boolean. That's how if-statements work: the expressions within evaluate to true or false, and the code inside is executed if true. However, using the boolean that the operator returns isn't confined to use in if-statements. The result of == just like the result of a function call, and in this case we're assigning that result into another variable. I hope this helps; feel free to ask about anything that still isn't clear. – EMBLEM Mar 14 '15 at 21:38
• Yeah, I think I got it. Is there any notes on how to use booleans? – mazunki Mar 14 '15 at 22:23

There are a lot of good suggestions in the other answers for improving the coding style of this program. If the goal is to simulate the set of a game show with a one-to-one correspondence between objects on the set and Objects in your source code, you should follow that advice as well as you can.

If the goal is simply to simulate the events that occur while playing the game, however (which appears to be the goal, since those are the only things that are output by the program), then there is a much simpler model of the game that will work just as well. This model is built around two variables describing the set of the game show:

• doorWithCar This variable has value 1, 2, or 3, indicating whether the car is behind the first, second, or third door.
• doorOpened This variable initially has value 0, when all the doors are closed; when Monty opens a door, this variable is assigned the number of the door Monty opened.

In addition, you can use two variables to represent the player's decisions:

• initialChoiceDoor The number of the door first chosen by the player.
• finalChoiceDoor The number of the door chosen by the player after Monty has opened one of the other doors.

Everything you need to know about the state of things at each stage of the game (up to the moment when Monty reveals what the player has won) can be represented by these four variables.

You'll still need code to handle input and output, for example a mapping from the values of the four variables above to the names of the doors (if you want to print names different from the values used for the internal state of the program), and an input function that takes a response from the user and determines what it means (door 1, 2, or 3; switch or stay). You might also want functions for things such as which door Monty opens (this function's input would be doorWithCar and initialChoiceDoor) or which door the player finally chooses (this function's input could be initialChoiceDoor, doorOpened, and a boolean value indicating whether the player chose to "switch").

You might end up with code where the main class looks something like this:

public class Paradox {
public static void main(String[] args) {
playGame();
}

void playGame() {
Random randomVar   = new Random();
int    doorWithCar = randomVar.nextInt(3);

System.out.println("\n\nPick a door: A, B, or C.");
Scanner sc = new Scanner(System.in);
int initialChoiceDoor = doorSelectedByString(sc.nextLine());

int doorOpened = chooseDoorToOpen(initialChoiceDoor, doorWithCar);

System.out.println("The door " + nameOfDoor(doorOpened) + " contains a Goat");
System.out.println("\nDo you want to change?");

bool isChange = isChangeString(sc.nextLine());
int  finalChoiceDoor = isChange ? neitherOfTheseDoors(initialChoiceDoor, doorOpened) :
initialChoiceDoor ;

String tactic = isChange ? "changed" : "stayed":
String prize  = (finalChoiceDoor == doorWithCar) ? "Car" : "Goat";
System.out.print("Congratulations! You " + tactic + ", and won a " + prize);
}

/* other functions here ... */
}


To handle bad input, you could have the functions doorSelectedByString and isChangeString print an error message and exit if the input does not make a valid choice; if you want to be able to re-use this class in a larger program, you could have these functions throw exceptions instead of exiting,and handle the exceptions in the main() function.

Admittedly, there is precious little in the way of object-oriented programming in this example. But the point is that this is such a simple exercise, it does not need a lot of objects. If you must create a bunch of objects just to handle such a simple problem, what do you do when you have to solve a problem that is fundamentally much more complicated? Keeping things as simple as possible means the code for large, complicated problems is easier to understand.

Here's a (partial) alternate version.

1. Instead of a Door class, a Door enum is used. It'd be trivial to use the int type instead, maybe save a little memory. But, it's convenient to have all the legal door values enumerated. State is stored directly in the game object, which is convenient (and works) because the game is so simple.
2. Implementations specify how the input happens, eg InteractiveGame, RandomGame, AlwaysSwitchGame, etc
3. Now you can test the game logic without simulating standard input.
4. The game algorithm is encapsulated in a short easy to read method.
5. Implementations specify the random source.
6. Consecutive games (whether real or test) can re-use a Random object instead of re-seeding every game.
7. Tests can make the random seed a fixture. Now tests are deterministic.
8. Each game has its own state. Your main method might run a few games, then display statistics. You can have a separate method that takes a Game and displays the result, eg

Door A has the car. You picked door B. Door C was opened. You stuck with your pick and lost!

9. Each Game object is immutable. The game is run on construction. It leaves you with the outcome. You can safely process games in a multi-threaded environment.

.

public enum Door {
A, B, C;
}

public abstract class Game {

protected final Random rnd;
public final Door hasCar;
public final Door choice1;
public final Door opened;
public final Door choice2;

protected abstract Door userPicks();
protected abstract boolean userSwitches();

public Game(Random rnd) {
this.rnd = rnd;
hasCar = Door.values()[rnd.nextInt(Door.values().length)];
choice1 = userPicks();
opened = hostOpens();
choice2 = userSwitches() ? userPicks() : choice1;
}

private Door hostOpens() {
List<Door> could = new ArrayList<>();
for (Door d : Door.values()) {
if (d != hasCar && d != choice1) {
could.add(d);
}
}
return could.get(rnd.nextInt(could.size()));
}
}


Use some kind of data container like an array or a set to put the doors in. And yes, some methods might help as well.

Look at this version

import java.lang.Math.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.Scanner;

public class Paradox {
private static Random rand = new Random();
private static int cars = 0;

private static String pickRandom(Set<String> set) {
return (String)set.toArray()[rand.nextInt(set.size())];
}

public static void run(boolean automatic, String changeornot) {
Set<String> closedDoors = new HashSet<>(Arrays.asList("A", "B", "C"));
String doorWithCar = pickRandom(closedDoors);
Set<String> doorsWithGoat = new HashSet<>(closedDoors);
doorsWithGoat.remove(doorWithCar);

Scanner sc = new Scanner(System.in);

System.out.println("\n\nYou have got three doors, there is a price inside each of them. Pick a door: A, B, or C.");
String pickedDoor = "";
if(automatic) {
pickedDoor = pickRandom(closedDoors);
} else {
while(true) {
pickedDoor = sc.nextLine().toUpperCase();
System.out.println("\n");
try {
pickedDoor = "" + (char)(Integer.parseInt(pickedDoor) - 1 + 'A');
} catch(NumberFormatException e) {
}
if(closedDoors.contains(pickedDoor)) break;
System.out.println("The door you chose is not available. Try again.");
}
}
System.out.println("you picked door " + pickedDoor);
Set<String> possibleChoices = new HashSet<>(doorsWithGoat);
possibleChoices.remove(pickedDoor);

String openDoor = pickRandom(possibleChoices);
closedDoors.remove(openDoor);

System.out.println("The door " + openDoor + " contains a Goat");

System.out.println("\nKnowing where one of the Goats are, do you wish to stay on your current door, or do you want to change?");
if(!automatic) {
while(true) {
changeornot = sc.nextLine().toLowerCase();
System.out.println();

if (changeornot.equals("1") || changeornot.equals("yes")) {
changeornot = "change";
}
else if (changeornot.equals("0") || changeornot.equals("no")) {
changeornot = "stay";
}
if(changeornot.equals("change") || changeornot.equals("stay")) break;
System.out.println("choose either change or stay");
}
}
if(changeornot.equals("change")) {
closedDoors.remove(pickedDoor);
pickedDoor = (String)closedDoors.toArray()[0];
}
String price = "goat";
if(pickedDoor.equals(doorWithCar)) price = "car";
System.out.print("Congratulations! You chose to " + changeornot + ", and won a " + price + ".");
System.out.println();
if(price.equals("car")) cars++;

System.out.println("---------------------------------------");
}

public static void main(String[] args) {
String choice = "stay";
for(int i = 0; i < 1000; i++) run(true, choice);
System.out.println("You chose to " + choice + " and won a total of " + cars + " cars.");
}
}


edit: There was a lot of repetition in your code. That can be fixed by using variables so you can write e.g. System.out.println("The door " + openDoor + " contains a Goat"); instead of having several println statements that do the same job. Also using collection classes like Set or List can simplify things because you can then again use a variable to state which element in that collection you want to access instead of having to decide that when you write the code and you can also easily add or remove items from a collection allowing you to manage arbitrary amounts of data.

• Thanks for the great edit, I'll have to learn using arrays as objects, not just as lists. I didn't quite figure out what if(automatic) is. Is it the same as if(true)? If so, what purpose would it have? – mazunki Mar 14 '15 at 19:53
• if automatic is set to true the program will "play" the game automatically instead of waiting for the user to type something in. – SpiderPig Mar 14 '15 at 19:57
• @SpiderPig I would recommend to edit your answer to provide more explanation of what you changed, and more importantly, why. – Phrancis Mar 14 '15 at 20:25
• As others have commented, there are some readability and code-convention issues in your answer. You might want to consider posting your own code as a question? (That is quite common practice to do around here, there is even a tag for it) – Simon Forsberg Mar 14 '15 at 22:12
• @Snowbody the order of elements in a set is not guaranteed, neither to be sorted nor random (nor predictable). in practice, the order of a particular group of elements placed into a HashSet is consistent, at least with oracle's last few major jre versions. – djeikyb Mar 17 '15 at 15:07