Chris Pollett > Old Classes > PIC20B ( Print View ) Enrollment info Course Info:
|
HW3 Solutions Page// // Filenname: Slot.java // // Purpose: contains classes to implement a simple slot machine // application which uses Threads to stop the reels of the // machine after they are set in motion. // // import javax.swing.*; import java.awt.*; import java.awt.event.*; // // Interface Name: ReelParts // // Purpose: This interface contains all the constant used for drawing the // slot machine. It is also implemented by Reel and ReelPanel. // We do this so a Reel can synchronize against either a Reel or a // ReelPanel. // interface ReelParts { static String reelImageName = "reel.jpg"; // image used to draw reel static int BAR = 0, APPLE = 1; //enum of shapes on reel static int APPLEOFFSET = 120, BAROFFSET = 50; // where shapes are on image static int REELHT = 160, REELWTH = 290; //height and width of all reels //put together static int LEFTX = 0, TOPY = 0; //coordinates for three reels static int CENTERX = 90, RIGHTX = 180; static int INDICATORX=0, INDICATORY=60, INDICATORWTH=5; //coordinates //of indicator static int BTNMSGHT = 40; //combined height of buttons and message label } // // Class Name: Slot // // Purpose: main class for this application // public class Slot extends JFrame { ReelPanel rp; JPanel bp; JLabel msgLabel; // // Method Name: Slot // // Purpose: constructor. Sets up the message label the slot machine // reels and the buttons for spin/inserting a coin. public Slot() { super("Slot Machine"); Container c = getContentPane(); c.setLayout(new BorderLayout()); setBackground(Color.white); msgLabel = new JLabel(" "); // a message beginning with space means // we still have to insert a coin. c.add(msgLabel, BorderLayout.NORTH); Image img = (new ImageIcon(ReelParts.reelImageName)).getImage(); rp = new ReelPanel(img, msgLabel); //panel with slot machine reels. c.add(rp, BorderLayout.CENTER); bp = ButtonPanel(); //set up buttons c.add(bp, BorderLayout.SOUTH); setSize(ReelParts.REELWTH,ReelParts.REELHT+ ReelParts.BTNMSGHT); show(); } // // Method Name: ButtonPanel // // Purpose: sets up spin and insert coins buttons and their listeners // public JPanel ButtonPanel() { bp = new JPanel(); bp.setLayout(new GridLayout(1,2)); JButton spin = new JButton("Spin"); spin.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { if(msgLabel.getText().startsWith(" ")) { msgLabel.setText( " Please insert coin"); } else { msgLabel.setText(" "); rp.spin(); } } } ); bp.add(spin,0); JButton insertCoin = new JButton("Insert Coin"); insertCoin.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { if(msgLabel.getText().startsWith(" ")) { msgLabel.setText("Spin Away"); } else { msgLabel.setText( "Return.Max 1 Coin.Please Spin."); } } } ); bp.add(insertCoin,1); return bp; } // // Method Name: main // // Purpose: instantiates a Slot object and sets up a window listener for our // frame public static void main (String args[]) { Slot app = new Slot(); app.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } } // // Class Name: ReelPanel // // Purpose: panel on which the reels of the slot machine are drawn. // This class manages these reels and their animation. class ReelPanel extends JPanel implements ReelParts { private Reel r1, r2, r3; // three reels on slot machine private JLabel msgLabel; // so can say if user won on a given spin private int amountPaid; // how much user has been paid so far private Timer animationTimer; //timer used to animate reels. private Thread payThread; //used to stop animationTimer and (if need be) //pay user private boolean payout; //flag used to determine if we pay the user this spin. // // Method Name: ReelPanel // // Purpose: constructor. Stes up three Reel, animationTimer, and payoutThread // ReelPanel(Image img, JLabel mLabel) { msgLabel=mLabel; amountPaid=0; //at start haven't paid user anything. r1 = new Reel(img,this, RIGHTX, TOPY, REELWTH, REELHT); r2 = new Reel(img,r1, CENTERX, TOPY, RIGHTX, REELHT); r3 = new Reel(img,r2, LEFTX, TOPY, CENTERX, REELHT); initPayoutThread(); setBackground(Color.white); setSize(getPreferredSize()); } // // Method Name: initPayoutThread // // Purpose: sets up the Timer to control reel animation and // sets up a Thread to stop this animation after // the reels have stopped spinning and (if need be) // pay the user. // public void initPayoutThread() { animationTimer = new Timer(50, new ActionListener(){ public void actionPerformed(ActionEvent e) { move(); repaint(); } }); payThread = new Thread(new Runnable(){ public void run() { while(true) { synchronized(r3) { try { r3.wait(); } catch(InterruptedException e) { e.printStackTrace(); } } animationTimer.stop(); if(payout) { try{ pay(); } catch (TiltException e) { System.err.println("Machine out of money"); System.exit(-1); } } } } }); payThread.start(); } // // Method Name: move // // Purpose: updates the animation for each of the reels. // public void move() { r1.move(); r2.move(); r3.move(); } // // Method Name: paintComponent // // Purpose: draws the slot machine reels and the indicator // bar // public void paintComponent( Graphics g) { super.paintComponent(g); r1.draw(g, this); r2.draw(g, this); r3.draw(g, this); g.setColor(Color.yellow); g.fillRect(INDICATORX, INDICATORY, REELWTH, INDICATORWTH); } // // Method Name: pay // // Purpose: Tell user they won and handle total payout so far. // If this is more than 2 dollars throw a TiltException. public void pay() throws TiltException { msgLabel.setText(" You won $1.00."); amountPaid +=1; if( amountPaid >2) throw new TiltException(); } // // Method Name: spin // // Purpose: selects the final value for each reel then spins // the three reels as in the description of the homework // for a while until they stop on these values. public synchronized void spin() { payout=false; int tmp=0; int r=0; if(Math.random()<=.2) // win at least 20 percent of the time { r3.start(BAR); r2.start(BAR); r1.start(BAR); payout =true; } else //otherwise randomly choose a symbol { tmp=r=(int)(Math.random()+.5); r3.start(r); tmp+=(r=(int)(Math.random()+.5)); r2.start(r); tmp+=(r=(int)(Math.random()+.5)); r1.start(r); if(tmp % 3 == 0) payout = true; } animationTimer.start(); notify(); } // // Method Name: getPreferredSize // // Purpose: returns the best size for drawing the slot machine reel // public Dimension getPreferredSize() { return new Dimension(REELWTH,REELHT); } } // // Class Name: Reel // // Purpose: this class is used to manage one reel on a slot machine // class Reel implements ReelParts { private int dx1, dy1, dx2, dy2;//location to draw reel to private Image img; // image used to draw reel private ReelParts rr; // object this Reel's stop Thread waits on private int offset, animSpeed; // offset controls what part of //of img to draw and animSpeed is the number of //pixels through the animation we go / ActionEvent private Thread reelStopper; //thread used to stop Reel spinning private boolean stopReel = false; //used to tell move() whether to stop //moving the Reel. private int fruitOffset; // where in img the fruit we are supposed to // stop on lives. // // Method Name: Reel // // Purpose: constructor of the class. image is the // the image used to draw the reel. rightReel // is the object this Reel's reelStopper Thread waits on. // The destxi and destyi specify where to draw reel. Reel(Image image, ReelParts rightReel, int destx1, int desty1, int destx2, int desty2 ) { img = image; rr = rightReel; dx1=destx1; dy1=desty1; dx2=destx2; dy2=desty2; offset=(int)(Math.random()*30); animSpeed= 15 + (int)(Math.random()*5); reelStopper = new Thread(new Runnable(){ public void run() { while(true) { synchronized(rr) { try { rr.wait(); } catch(InterruptedException e) { e.printStackTrace(); } } try{ Thread.sleep(1000+(int)(Math.random()*1000)); } catch(InterruptedException e) { e.printStackTrace(); } stopReel = true; } } }); reelStopper.start(); } // // Method Name: move() // // Purpose: If Reel should still be spun advance it by animSpeed. // Otherwise, notify object waiting on this Reel. public void move() { if(stopReel && offset <= fruitOffset && fruitOffset <=offset+animSpeed) { synchronized(Reel.this) { Reel.this.notify(); } } else { offset +=animSpeed; if(offset>160) offset=0; } } // // Method Name: draw // // Purpose: draws the reel with the Graphics g and ImageObsever ob // passed to it. // public void draw(Graphics g, Component ob) { g.drawImage(img, dx1, dy1, dx2, dy2, 0, 0+offset, 70, REELHT+offset, ob); } // // Method Name: start // // Purpose: starts the reel spinning, sets up the reels // final resting position. // public void start(int reelFruit) { if(reelFruit == APPLE) fruitOffset = APPLEOFFSET; if(reelFruit == BAR) fruitOffset = BAROFFSET; stopReel = false; } } // // Class Name: TiltException // // Purpose: the kind of Exception thrown when the slot machine runs out of money // class TiltException extends Exception { TiltException() { super("TiltException"); } } |