Download The Dice Game

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Exact division wikipedia , lookup

Game mechanics wikipedia , lookup

Minimax wikipedia , lookup

Transcript
CS2092 - Object Oriented Programming in Java
Chapter 8: An Application - The Dice Game
C. C. Kirkham
I could just go on adding new AWT features one at a time, and letting you see them. What
I want to do instead is built up a larger example, and then turn it into an applet.
The Dice Game
I am going to incrementally develop an application which makes use of the AWT to create
a sort of dice-based fruit machine. You could imagine that it will be used in experiments on
gambling in some Psychology research. I want to have a number of dice, initially 3 but it is
nice to make this flexible, which the player can choose to roll individually or all together. The
player’s goal is to get six showing on every die, starting from some random initial position.
When he achieves that he will get a fixed reward. However he must pay for each move he
makes to get there and, naturally, we will charge much less for rolling all the dice at the same
time than we do for rolling them individually.
So let me first draw a simple die:
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
class Dice extends Canvas {
private Random ran ;
private int value ;
Dice() {
ran = new Random() ;
value = nextValue() ;
setSize(140,140) ;
}
private int nextValue() {
return Math.abs(ran.nextInt()) % 6 + 1 ;
}
public void roll() {
value = nextValue() ;
1
repaint() ;
}
public int getValue() {
return value ;
}
public void paint(Graphics g) {
g.drawLine(40,40,40,100) ;
g.drawLine(40,100,100,100) ;
g.drawLine(100,100,100,40) ;
g.drawLine(100,40,40,40) ;
if (value == 1 || value == 3 || value == 5) g.fillOval(68,68,4,4) ;
if (value != 1) { g.fillOval(53,83,4,4) ; g.fillOval(83,53,4,4) ;}
if (value == 4 || value == 5 || value == 6)
{ g.fillOval(53,53,4,4) ; g.fillOval(83,83,4,4) ;}
if (value == 6) { g.fillOval(68,53,4,4) ;g.fillOval(68,83,4,4) ;}
}
public static void main(String [] args) {
Frame f = new Frame("Dice") ;
Button b ;
Dice d = new Dice() ;
f.addWindowListener(new MyListener()) ;
f.add("Center",d);
f.add("South",b = new Button("Roll")) ;
b.addActionListener(new Doit(d)) ;
f.pack() ;
f.setVisible(true);
}
} // end Dice
class MyListener extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0) ;}
}
class Doit implements ActionListener {
private Dice d ;
Doit(Dice thisone) { d = thisone ; }
public void actionPerformed(ActionEvent e) {
d.roll() ; }
}
Having drawn one, and seen what it looks like, we can now draw a number of them - each
with its own roll button. The class which associates a button with each die extends Panel,
2
rather than Canvas. Another important difference is that a feature is added so that some other
object can be informed when the button has been pressed, so that the change in value does not
go unnoticed. The object to inform will be passed to the constructor, and informing it will
communicate the change in face value of the die - to save the object having to ask. This is
achieved using an interface:
interface DiceWatcher {
void inform(int change) ;
}
In this class I will make the class be its own ActionListener. This seems sensible if the class
which would be created as an ActionListener has no independent meaning, and is possible
because we are implementing an interface rather than extending a class:
import java.awt.*;
import java.awt.event.*;
class DiceWithButton extends Panel implements ActionListener {
private Dice d ;
private DiceWatcher whoToInform ;
DiceWithButton(DiceWatcher watcher) {
super(new BorderLayout()) ;
whoToInform = watcher ;
Button b = new Button("Roll") ;
d = new Dice() ;
add(d,"Center");
add(b,"South") ;
b.addActionListener(this) ;
}
public void roll() {
d.roll() ;
}
public int getValue() {
return d.getValue() ;
}
public void actionPerformed(ActionEvent ae) {
int oldValue = getValue() ;
roll() ;
int newValue = getValue() ;
if (whoToInform != null)
whoToInform.inform(newValue - oldValue) ;
}
3
public static void main(String [] args) {
final int howMany = 3 ;
Frame f = new Frame(howMany + " Dice") ;
f.setSize(howMany*200,200) ;
f.addWindowListener(new MyListener()) ;
f.setLayout(new BorderLayout()) ;
Panel centerPane = new Panel() ;
for (int i = 0 ; i < howMany ; i++)
centerPane.add(new DiceWithButton(null));
f.add(centerPane,"Center") ;
f.setVisible(true);
}
} // end DiceWithButton
We can now complete the exercise. We need the ability to roll all three at one button push, and
we need to notice when the game is over. This requires rather more common information to be
available. Below is some code which does all that.
import java.awt.*;
import java.awt.event.*;
public class DiceGame extends Frame
implements ActionListener, DiceWatcher {
final static int howMany = 3 ;
private int total ;
private int nudges, gambles ;
private DiceWithButton [] pane = new DiceWithButton[howMany];
public DiceGame(String title) {
super(title) ;
setLayout(new BorderLayout()) ;
nudges = 0 ;
gambles = 0 ;
addWindowListener(new MyListener()) ;
Panel centerPane = new Panel() ;
for (int i = 0 ; i < howMany ; i++)
centerPane.add(pane[i] = new DiceWithButton(this));
resetTotal() ;
add(centerPane,"Center") ;
Button b = new Button("Roll the lot") ;
b.addActionListener(this) ;
add(b, "North") ;
setSize(howMany*200,250) ;
}
private void resetTotal() {
4
total = 0 ;
for (int i = 0 ; i < howMany ; i++)
total += pane[i].getValue() ;
}
public void inform(int change) {
total += change ;
nudges++ ;
if (total == 6*howMany) finishoff("nudging") ;
}
private void finishoff(String mess) {
dispose() ;
System.out.println("Got to goal by "+ mess) ;
System.out.println("You used " + gambles + " gambles "
+ " and " + nudges + " nudges") ;
System.exit(0) ;
}
public void actionPerformed(ActionEvent e) {
gambles++ ;
for (int i = 0 ; i < pane.length ; i++)
pane[i].roll() ;
resetTotal() ;
if (total == 6*howMany) finishoff("gambling") ;
}
public static void main(String [] args) {
DiceGame game = new DiceGame("Dice Game") ;
game.setVisible(true) ;
}
}
Yes - this does extend Frame, and I am not really sure there is sufficient reason, but it is certainly
arguable that the game should be thought of as the Frame in which it gets played, and that this
balances the use of Canvas and Panel in the other classes.
Note that the final program uses the classes developed earlier, and their main methods can
be left in for testing. So the program is quite long, but it is not very helpful to draw the class
diagram to document it. Some of the complication is just about how what appears on the screen
is put together. We can represent that by a hierachical diagram which shows how things are
composed. Here is a very simple one for DiceWithButton:
5
DiceWithButton
d
b
Dice
Button
and here is a more complicated one for DiceGame.
DiceGame
pane[0]
centerPane
b
Panel
Button
pane[1]
pane[2]
DiceWithButton DiceWithButton DiceWithButton
6