import java.applet.*;
import java.awt.*;
import java.util.Random;
import java.lang.Math;
/**
*
This is a simple applet that lets someone play the classic three door
* game from Let's Make a Deal. A prize is hidden behind one door. The
* player chooses one by clicking on it. Another door is then revealed
* to hold a booby prize. The player can then choose to keep either what's
* behind the door she selected or the other unopened door.
*
* This applet keeps track of the win & loss statistics for the two
* strategies of play (stay with selected door/switch to other door). It
* also has autoplay capability, so you can quickly see how the resulting
* statistics.
*
* There are three parameters that can be set in the APPLET tag:
*
*
* - doors - number of doors (at least 3)
*
- autoplayGames - number of games played when player
* clicks the autoplay button
*
- resetValue - maximum number of games played before
* statistics are reset
*
*
* @author Mark L. Irons
* @version 1.0
* @date 18-11-1998
*/
public class LetsMakeADealApplet extends Applet
implements ImageCanvasEventHandler
{
Random randomizer = new Random();
int gamesPlayed = 0;
int maxGamesPlayed = 100000;
int numAutoplayGames = 300;
int StayWinCount = 0;
int StayLoseCount = 0;
int SwitchWinCount = 0;
int SwitchLoseCount = 0;
int prizeDoor = -1; // door with prize
int selectedDoor = -1; // first door player selects
int fakeDoor = -1; // kept closed, no prize
int numDoors = 3; // default value
Label StayWinLabel = new Label();
Label StayLoseLabel = new Label();
Label SwitchWinLabel = new Label();
Label SwitchLoseLabel = new Label();
DoorCanvas Door[] = null;
Button ResetButton = new Button("Reset");
Button AutoplayButton = new Button("Autoplay");
Label prizeLabel = new Label("");
/**
* Reads parameters from APPLET tag, loads images, lays out components,
* initializes game.
*/
public void init()
{
// get applet parameters with some elementary sanity checks
String s = getParameter("doors");
if (s != null) {
int d = (new Integer(s)).intValue();
if ( d > 2 ) {
numDoors = d;
}
}
s = getParameter("autoplayGames");
if (s != null) {
int games = (new Integer(s)).intValue();
if (games > 0) {
numAutoplayGames = games;
}
}
s = getParameter("resetValue");
if (s != null) {
int play = (new Integer(s)).intValue();
if ( play > numAutoplayGames ) {
maxGamesPlayed = play;
}
}
// set background color
setBackground(Color.white);
// set layout
setLayout(new BorderLayout());
// load images
MediaTracker tracker = new MediaTracker(this);
Image UnknownDoorImg = getImage(getDocumentBase(),
"UnknownDoor.gif");
tracker.addImage(UnknownDoorImg,0);
Image SelectedDoorImg = getImage(getDocumentBase(),
"SelectedDoor.gif");
tracker.addImage(SelectedDoorImg,0);
Image BadDoorImg = getImage(getDocumentBase(),
"BadDoor.gif");
tracker.addImage(BadDoorImg,0);
try {
tracker.waitForID(0);
}
catch (InterruptedException iex) {
System.out.println("How to choose / with no choices?\nCan't load needed images; applet stopped.");
stop();
}
// create and lay out doors
Panel doorPanel = new Panel();
doorPanel.setLayout(new FlowLayout(FlowLayout.CENTER,15,15));
Door = new DoorCanvas[numDoors];
for (int i = 0; i < numDoors; i++) {
Door[i] = new DoorCanvas(this,UnknownDoorImg,SelectedDoorImg,BadDoorImg);
doorPanel.add(Door[i]);
}
this.add("Center",doorPanel);
// layout statistics
updateStats();
Panel statsPanel = new Panel();
statsPanel.setLayout(new FlowLayout(FlowLayout.CENTER,15,10));
statsPanel.add(StayWinLabel);
statsPanel.add(StayLoseLabel);
statsPanel.add(SwitchWinLabel);
statsPanel.add(SwitchLoseLabel);
// layout stats, reset & autoplay
Panel scoringPanel = new Panel();
scoringPanel.setLayout(new GridLayout(2,1,5,2));
scoringPanel.add(statsPanel);
Panel otherButtonPanel = new Panel();
otherButtonPanel.setLayout(new FlowLayout(FlowLayout.CENTER,20,2));
otherButtonPanel.add(ResetButton);
otherButtonPanel.add(AutoplayButton);
scoringPanel.add(otherButtonPanel);
this.add("South",scoringPanel);
// layout prize label
Panel prizeLabelPanel = new Panel();
prizeLabelPanel.setLayout(new FlowLayout(FlowLayout.RIGHT,5,5));
prizeLabelPanel.add(prizeLabel);
this.add("North",prizeLabelPanel);
// initialize
initGame();
paint(getGraphics());
}
public void paint(Graphics g) { }
/**
* Initializes game. Chooses a door to hide prize behind, resets
* everthing else.
*/
public void initGame()
{
// choose prize door
prizeDoor = Math.abs(randomizer.nextInt()) % numDoors;
// display it
prizeLabel.setText("prizeDoor: "+(new Integer(1+prizeDoor)).toString());
// reset everything else
selectedDoor = -1;
for (int i = 0; i < numDoors; i++) {
Door[i].setUnselected();
}
}
public void updateStayWin() {
StayWinLabel.setText("Stay/Win: "+(new Integer(StayWinCount)).toString());
}
public void updateStayLose() {
StayLoseLabel.setText("Stay/Lose: "+(new Integer(StayLoseCount)).toString());
}
public void updateSwitchWin() {
SwitchWinLabel.setText("Switch/Win: "+(new Integer(SwitchWinCount)).toString());
}
public void updateSwitchLose() {
SwitchLoseLabel.setText("Switch/Lose: "+(new Integer(SwitchLoseCount)).toString());
}
/**
* Updates all statistics
*/
public void updateStats()
{
updateStayWin();
updateStayLose();
updateSwitchWin();
updateSwitchLose();
}
/**
* Clears all counters and resets game
*/
public void clearEverything()
{
StayWinCount = 0;
StayLoseCount = 0;
SwitchWinCount = 0;
SwitchLoseCount = 0;
gamesPlayed = 0;
updateStats();
initGame();
paint(getGraphics());
}
/**
* Marks given door as selected. Reveals what's behind bad door(s).
*
* @param door player's intially selected door
*/
public void chooseFirstDoor(int door)
{
// mark selected door
selectedDoor = door;
Door[selectedDoor].setSelected();
// reveal bad doors
if (selectedDoor == prizeDoor) {
// pick fake door, open all doors but prize & fake
fakeDoor = Math.abs(randomizer.nextInt()) % (numDoors-1);
if (fakeDoor >= selectedDoor) fakeDoor++;
for (int i = 0; i < numDoors; i++) {
if ((i != selectedDoor) && (i != fakeDoor)) {
Door[i].setBad();
}
}
}
else {
// reveal all doors but prize door
for ( int i = 0; i < numDoors; i++ ) {
if ((i != selectedDoor) && (i != prizeDoor)) {
Door[i].setBad();
}
}
fakeDoor = selectedDoor;
}
paint(getGraphics());
}
/**
* Decides what to do when the player selects a door.
*
* @param door player's selected door
*/
public void gameLogic(int door)
{
if (selectedDoor == -1) {
chooseFirstDoor(door);
}
else {
if (Door[door].isBad()) {
// can't select already opened door, do nothing
}
else {
// compute win, and if it's a switch
if (selectedDoor == door) {
// stay
if (prizeDoor == door) {
StayWinCount++;
updateStayWin();
}
else {
StayLoseCount++;
updateStayLose();
}
}
else {
// switch
if (prizeDoor == door) {
SwitchWinCount++;
updateSwitchWin();
}
else {
SwitchLoseCount++;
updateSwitchLose();
}
}
gamesPlayed++;
if (gamesPlayed > maxGamesPlayed) {
clearEverything();
}
initGame();
paint(getGraphics());
}
}
}
/**
* Plays the game automatically
*/
public void autoPlay()
{
for ( int i = 0; i < numAutoplayGames; i++ ) {
// start new game
initGame();
// choose first door
int firstDoor = Math.abs(randomizer.nextInt()) % numDoors;
chooseFirstDoor(firstDoor);
// choose either selected door or other door
if ((Math.abs(randomizer.nextInt()) % 2) == 0) {
gameLogic(prizeDoor);
}
else {
gameLogic(fakeDoor);
}
}
}
/**
* This method is a callback that's called when the player
* clicks a door. It determines which door was clicked,
* then passes that information to gameLogic
.
*
* I know, it breaks encapsulation. So sue me.
*
* @param source door that was clicked
*/
public void imageCanvasEvent(ImageCanvas source)
{
for ( int i = 0; i < numDoors; i++ ) {
if (source == Door[i]) {
gameLogic(i);
}
}
}
/**
* Deal with all other interface interaction (except doors)
*/
public boolean action(Event event, Object arg)
{
if (event.target == ResetButton) {
clearEverything();
return true;
}
if (event.target == AutoplayButton) {
autoPlay();
return true;
}
else return super.action(event,arg);
}
} // class LetsMakeADealApplet