> ### Solution for
> Programming Exercise 6.1

> THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.

> Exercise 6.1: Write an applet that shows a pair of dice. When the user clicks on the applet, the dice should be rolled (that is, the dice should be assigned newly computed random values). Each die should be drawn as a square showing from 1 to 6 dots. Since you have to draw two dice, its a good idea to write a subroutine, "`void drawDie(Graphics g, int val, int x, int y)`", to draw a die at the specified `(x,y)` coordinates. The second parameter, `val`, specifes the value that is showing on the die. Assume that the size of the applet is 100 by 100 pixels. Here is a working version of the applet. (My applet plays a clicking sound when the dice are rolled. See the solution to see how this is done.)

> Discussion

> The applet must be declared to "`implement MouseListener`", and it must define the `mousePressed()` method to roll the dice. (The other methods of the `MouseListener` interface will be empty.) The applet's `init()` method must call `addMouseListener(this)` to register the applet to listen for mouse events on itself. I defined the `mousePressed()` routine simply as

>             public void mousePressed(MouseEvent evt) {
>                roll();
>             }

> and I defined the `roll()` subroutine to roll the dice. It would be reasonable to put the code for rolling the dice in the `mousePressed()` routine, but writing a subroutine to do it makes the program a little easier to modify for the next two exercises. Anyway, when you can identify a self-contained, meaningful task to be performed, it's never a bad a idea to write a subroutine to do it. It will make the program more readable, if nothing else. My roll subroutine assigns random values to the dice and calls `repaint()` so that the new values will be shown. It also plays the clicking sound with the command

>                         play(getCodeBase(), "click.au");

> The `play()` method is a predefined instance method in the `Applet` class. The sound comes from a file. The second parameter, `"click.au"`, is the name of the file that contains the sound. The first parameter, `getCodeBase()`, specifies the directory that contains the sound file. This parameter is actually a URL, but all you need to know is that `getCodeBase()` specifies that the sound file is in the same directory that contains the compiled class file of the applet. Unfortunately, not all sound files can be played by Java, and some sound files might work on one platform but not on another. A sound file with a name ending in ".au" is most likely to work. An interesting thing about the `play()` method is that it only starts the sound playing. It doesn't wait for the playback to finish. So, the applet continues to run while the sound plays. Here is a link that you can use to download the click sound, click.au.

> The hardest part of this exercise is drawing the dice. I made each die 35 pixels wide, leaving a 10 pixel border on each side and 10 pixels between the dice. The top left corner of the left die is at `(10,10)`, the top left corner of the right die is at `(55,55)`. The 55 includes the 10 pixel border on the left, the 35 pixel width of the other die, and the 10 pixels between the dice. The paint method calls a `drawDie()` routine to draw each die, using the commands:

>                     drawDie(g, die1, 10, 10);
>                     drawDie(g, die2, 55, 55);

> where `die1` is the numerical value shown on the first die and `die2` is the numerical value of the second die.

> As for the `drawDie` routine, there are two quite different algorithms that could have been used for drawing the dots. Either:

>                   if the value shown is 1
>                       draw 1 dot (in the center)
>                   else if the value shown is 2
>                       draw 2 dots (in the top-left and bottom-right corners)
>                     .
>                     .
>                     .
>                   else if the value shown is 6
>                       draw 6 dots (along the left and right edges)

> Or:

>                   if the value has a dot in the top-left corner
>                        draw the top-left dot
>                   else if the value has a dot in the top-right corner
>                        draw the top-right dot
>                      .
>                      .
>                      .
>                   else if the value has a dot in the bottom-right corner
>                        draw the bottom-right dot

> Although the first algorithm is more obvious, the second requires much less typing. (The first algorithm ends up using 21 `drawOval()` commands, while the second uses only 7.) Furthermore, after drawing the dice on paper, I found that the conditions for testing when a given dot needs to be drawn are simpler than I expected. For example, the values that need a dot in the top-left position are all the values greater than 1. The algorithm leads to my `drawDice()` routine:

>           void drawDie(Graphics g, int val, int x, int y) {
>                  // Draw a die with upper left corner at (x,y).  The die is
>                  // 35 by 35 pixels in size.  The val parameter gives the
>                  // value showing on the die (that is, the number of dots).
>               g.setColor(Color.white);
>               g.fillRect(x, y, 35, 35);
>               g.setColor(Color.black);
>               g.drawRect(x, y, 34, 34);
>               if (val > 1)  // upper left dot
>                  g.fillOval(x+3, y+3, 9, 9);
>               if (val > 3)  // upper right dot
>                  g.fillOval(x+23, y+3, 9, 9);
>               if (val == 6) // middle left dot
>                  g.fillOval(x+3, y+13, 9, 9);
>               if (val % 2 == 1) // middle dot (for odd-numbered val's)
>                  g.fillOval(x+13, y+13, 9, 9);
>               if (val == 6) // middle right dot
>                  g.fillOval(x+23, y+13, 9, 9);
>               if (val > 3)  // bottom left dot
>                  g.fillOval(x+3, y+23, 9, 9);
>               if (val > 1)  // bottom right dot
>                  g.fillOval(x+23, y+23, 9,9);
>            }

> It took some care to figure out the numbers to use in the `fillOval` commands. The individual dots have a radius of 9 pixels. There are three rows of dots, which have a combined height of 27 pixels. That leaves 35-27, or 8 pixels for spacing. I use 3 pixels between the dots and the edge of the die, and 1 pixel between rows. This puts the tops of the rows at 3, 3+9+1, and 3+9+1+9+1, that is, at 3, 13, and 23. The columns use the same numbers. (If you believe that I got all this right the first time, I won't disillusion you!)

> The Solution

>         /*
>            Shows a pair of dice that are rolled when the user clicks on the
>            applet.  It is assumed that the applet is 100-by-100 pixels.  A clicking
>            sound is played when the dice are rolled.
>         */

>         import java.awt.*;
>         import java.awt.event.*;
>         import java.applet.*;

>         public class ClickableDice extends Applet implements MouseListener {

>            int die1 = 4;  // The values shown on the dice.
>            int die2 = 3;

>            public void init() {
>                   // To initialize the applet, register the applet to listen
>                   // for mouse events on itself.  Also set a light blue
>                   // background color.
>               addMouseListener(this);
>               setBackground( new Color(200,200,255) );
>            }

>            public void paint(Graphics g) {
>                   // The paint method draws a blue border and then
>                   // draws the two dice.
>               g.setColor( Color.blue );
>               g.drawRect(0,0,99,99);
>               g.drawRect(1,1,97,97);
>               drawDie(g, die1, 10, 10);
>               drawDie(g, die2, 55, 55);
>            }

>            void drawDie(Graphics g, int val, int x, int y) {
>                  // Draw a die with upper left corner at (x,y).  The die is
>                  // 35 by 35 pixels in size.  The val parameter gives the
>                  // value showing on the die (that is, the number of dots).
>               g.setColor(Color.white);
>               g.fillRect(x, y, 35, 35);
>               g.setColor(Color.black);
>               g.drawRect(x, y, 34, 34);
>               if (val > 1)  // upper left dot
>                  g.fillOval(x+3, y+3, 9, 9);
>               if (val > 3)  // upper right dot
>                  g.fillOval(x+23, y+3, 9, 9);
>               if (val == 6) // middle left dot
>                  g.fillOval(x+3, y+13, 9, 9);
>               if (val % 2 == 1) // middle dot (for odd-numbered val's)
>                  g.fillOval(x+13, y+13, 9, 9);
>               if (val == 6) // middle right dot
>                  g.fillOval(x+23, y+13, 9, 9);
>               if (val > 3)  // bottom left dot
>                  g.fillOval(x+3, y+23, 9, 9);
>               if (val > 1)  // bottom right dot
>                  g.fillOval(x+23, y+23, 9,9);
>            }

>            void roll() {
>                  // Roll the dice by randomizing their values.  Tell the
>                  // system to repaint the applet, to show the new values.
>                  // Also, play a clicking sound to give the user more feedback.
>               die1 = (int)(Math.random()*6) + 1;
>               die2 = (int)(Math.random()*6) + 1;
>               play(getCodeBase(), "click.au");
>               repaint();
>            }

>            public void mousePressed(MouseEvent evt) {
>                  // When the user clicks the applet, roll the dice.
>               roll();
>            }

>            public void mouseReleased(MouseEvent evt) { }
>            public void mouseClicked(MouseEvent evt) { }
>            public void mouseEntered(MouseEvent evt) { }
>            public void mouseExited(MouseEvent evt) { }

>         } // end class ClickableDice

> [ Exercises | Chapter Index | Main Index ]