import java.util.*; import java.awt.*; import javax.swing.*; public class Vic { private static Stack theStack = new Stack(); // where spare CDs are kept private ArrayList itsSequence; // its slots private int itsPos; // 0,1,2,...; 0 is at front private int itsID; // 1 for first Vic, 2 for... /* QUERY METHODS */ /** Return the current position as a String value. */ public String getPosition() { return itsID + ", " + itsPos; } //====================== /** Tell whether there is a slot at its position. */ public boolean seesSlot() { return itsPos < itsSequence.size(); } //====================== /** Tell whether there is a CD in its current slot. */ public boolean seesCD() { if (! seesSlot()) fail ("Can't see a CD where there is no slot!"); return itsSequence.get (itsPos) != null; } //====================== /** Return the CD that is in its current slot. */ public String getCD() { if (! seesSlot()) fail ("There is no slot to get a CD from!"); if (! seesCD()) fail ("There is no CD in this slot!"); return (String) itsSequence.get (itsPos); } //====================== /** Tell whether the stack has any CDs available. */ public static boolean stackHasCD() { return ! theStack.isEmpty(); } //====================== /* ACTION METHODS */ /** Move forward to the next slot in the sequence. */ public void moveOn() { if (! seesSlot()) fail ("Already at the end of the sequence!"); itsPos++; trace ("moveOn to slot " + (itsPos + 1)); } //====================== /** Back up to the previous slot in the sequence. */ public void backUp() { if (itsPos == 0) fail ("Already at the front of the sequence!"); itsPos--; trace ("backUp to slot " + (itsPos + 1)); } //====================== /** Move a CD from the stack to the current slot. */ public void putCD() { if( seesCD() ) fail("Already has a CD in this slot!"); if ( !stackHasCD()) fail("No CD on stack to put in this slot!"); if (! seesCD() && stackHasCD()) itsSequence.set (itsPos, theStack.pop()); trace ("putCD at slot " + (itsPos + 1)); } //====================== /** Move a CD from the current slot to the stack. */ public void takeCD() { if(!seesCD()) fail("No CD to take!"); if (seesCD()) { theStack.push (itsSequence.get (itsPos)); itsSequence.set (itsPos, null); } trace ("takeCD at slot " + (itsPos + 1)); } //====================== public static void emptyStack() { while(!theStack.isEmpty()) { theStack.pop(); } } /** Terminate the program with an appropriate message. */ private void fail (String cause) { JOptionPane.showMessageDialog (null, "STOPPING: " + cause + " (Vic #)" + itsID + ", position =" + itsPos); System.exit (0); } //====================== /** Two convenience methods */ public void shiftFromSlotToStack() { takeCD(); } //====================== public void shiftFromStackToSlot() { putCD(); } //====================== /* METHODS THAT USE THE FRAME */ private static String vicSay = "Programmable CD Organizer " + " mfd by Jones & Co."; private static final VicFrame theFrame = new VicFrame(); ////////////////////////////////// public static void say (String message) { vicSay = message; theFrame.repaint(); } //====================== /** Print a trace of the Vic's action. */ private void trace (String message) { System.out.println (message + " for Vic #" + itsID); theFrame.repaint(); pause (500); // half-a-second between actions } //====================== /** Pause for the specified number of milliseconds. */ private static void pause (int milliseconds) { try { Thread.sleep (milliseconds); } catch (InterruptedException e) { // never happens } } //====================== /* THE INITIALIZER AND CONSTRUCTOR METHODS */ private static final int MAXSLOTS = 8; private static final int MINSLOTS = 3; private static final int MAXVICS = 4; private static final Random random = new Random(); private static int theMaxVics = random.nextInt (MAXVICS) + 1; private static ArrayList[] theSeq = new ArrayList[theMaxVics]; private static int theNumVics = 0; private static final Vic[] theVics = {null, null, null, null}; ////////////////////////////////// /** Initialize individual sequences and stacks. An initializer method is used because these have to exist before any Vics are created. */ static { for (int k = 0; k < theMaxVics; k++) { theSeq[k] = new ArrayList(); int numSlots = random.nextInt (MAXSLOTS - MINSLOTS + 1) + MINSLOTS; for (int i = 0; i < numSlots; i++) { String it = random.nextInt (2) == 0 ? null : "" + (char) (i + 'a') + (k + 1); theSeq[k].add (it); } } // start with up to 2 CDs on the stack if (random.nextInt (3) > 0) // 2 times out of 3 { theStack.push ("GarthB"); if (random.nextInt (2) == 0) // 1 time out of 3 theStack.push ("LyleL"); } } //====================== /** Construct a new Vic. */ public Vic() { super(); itsSequence = theNumVics < theMaxVics ? theSeq[theNumVics] : new ArrayList(); itsPos = 0; itsID = theNumVics + 1; theVics[theNumVics] = this; theNumVics++; trace ("construction"); pause(2000); } //====================== /** Replace random arrangement by user-specified arrangement. */ public static void reset (String[] args) { if (args.length > 0 && theNumVics == 0) { theMaxVics = Math.min (args.length, MAXVICS); theSeq = new ArrayList[theMaxVics]; for (int k = 0; k < theMaxVics; k++) { theSeq[k] = new ArrayList(); int longest = Math.min (args[k].length(), MAXSLOTS); for (int i = 0; i < longest; i++) { String it = args[k].charAt (i) == '0' ? null : "" + (char)(i + 'a') + (k + 1); theSeq[k].add (it); } } } } //====================== // THE NESTED FRAME CLASS static class VicFrame extends JFrame { private final int SLOT = 75; // between CD slots private final int EDGE = 10; // leave free at left side private final int WIDTH = (MAXSLOTS + 2) * SLOT + 2 * EDGE; private final int DIST = 60; // between CD sequences private final int SAY = 45; // depth of say's output private final int TOPSEQ = SAY + DIST; // depth of first seq public VicFrame() { addWindowListener (new Closer()); setSize (WIDTH, TOPSEQ + MAXVICS * DIST + 2 * EDGE); setBackground (new Color (255, 252, 224)); // a nice cream setVisible (true); // make it visible to user } //====================== /** Same as for an applet; called by repaint. */ public void paint (Graphics page) { // PRINT THE vicSay MESSAGE AT THE TOP page.setColor (getBackground()); page.fillRect (EDGE, EDGE, WIDTH - 2 * EDGE, TOPSEQ + MAXVICS * DIST); page.setColor (Color.white); page.fillRect (20, SAY - 20, WIDTH - 40, 20); page.setColor (new Color (0, 96, 0)); // a light green page.drawString (vicSay, 25, SAY - 5); // message // DRAW UP TO FOUR Vic SEQUENCES AND THE STACK for (int k = 0; k < theMaxVics; k++) drawSequence (page, k, TOPSEQ + k * DIST); page.setColor (Color.red); int y = TOPSEQ + MAXVICS * DIST; page.drawString ("stack", EDGE, y); page.fillRect (EDGE, y - 25, 40, 5); // dividing line for (int k = 0; k < theStack.size(); k++) page.drawString ((String) theStack.get (k), EDGE, y - 30 - k * 20); } //====================== /** Called by VicFrame's paint method. */ private void drawSequence (Graphics page, int index, int y) { page.setColor (Color.red); if (theVics[index] != null) drawMacMan (page, theVics[index].itsPos, y - 15); page.setColor (Color.blue); drawAllCDs (page, y, theSeq[index]); } //====================== private void drawAllCDs (Graphics page, int y, ArrayList slots) { int atEnd = slots.size(); for (int n = 0; n < atEnd; n++) { String it = (String) slots.get (n); page.drawString (it == null ? "---" : it, (n + 1) * SLOT + EDGE, y); } page.drawString ("END", (atEnd + 1) * SLOT + EDGE, y); } //====================== private void drawMacMan (Graphics page, int pos, int y) { // is the lower-left corner of the stick figure int x = pos * SLOT + EDGE + 78; page.setColor (Color.black); page.drawLine (x, y, x + 6, y - 6); // leg page.drawLine (x + 6, y - 6, x + 12, y); // leg page.drawLine (x + 6, y - 6, x + 6, y - 18); // body page.drawLine (x, y - 14, x + 12, y - 14); // arms page.drawOval (x + 1, y - 28, 10, 10); // head page.drawLine (x + 4, y - 25, x + 5, y - 25); // eye page.drawLine (x + 7, y - 25, x + 8, y - 25); // eye page.drawLine (x + 3, y - 22, x + 9, y - 22); // mouth } //====================== } // end of VicFrame class private static class Closer extends java.awt.event.WindowAdapter { public void windowClosing (java.awt.event.WindowEvent e) { System.exit (0); } //====================== } } //