import java.awt.*; import java.applet.*; import java.awt.event.*; import java.net.*; import java.io.*; import java.util.Vector; /* * This class lays out the components and handles thread functions and events */ public class DataStructure extends Applet implements ActionListener, ItemListener, Runnable{ private GridBagLayout gbLayout; private GridBagConstraints gbc; private AnimationCanvas animateCv; private MemoryCanvas memCv; private MessageCanvas stackMsgCv, queueMsgCv, linkListMsgCv; private Button pushBtn, popBtn, retrieveBtn, resetBtn, quizBtn, demoBtn, optionBtn, helpBtn, okayBtn, runBtn, stepBtn, pauseBtn, enqueueBtn, dequeueBtn, okayBtn2, insertBtn, deleteBtn, okayBtn3; public TextField pushTF, enqueueTF, insertTF; private TextArea commentTA; private Choice dataStructCB; private CodeText codeTA; private MemorySprite[] memBlock; private StackSprite[] node; private TopStackSprite topnode; private Xsprite xsprite; private StackVarDisplay stackVariables; private StackManager stackmanager; private MemoryManager memorymanager; private ListVarDisplay queueVariables; private ListManager queuemanager; private CodeManager codemanager; private IOManager IOmanager; private StructureFunctions currFunction; private StackFunctions stackFunction; private ListFunctions queueFunction; private QuizManager quizmanager; private volatile Thread animation = null; private CardLayout cardManager; private Panel stateDeck, structureDeck, stackInputDeck, queueInputDeck, linkListInputDeck; private Panel demoPnl, quizPnl; private OptionsDialog optionsDlg; private int state, runMode, currStruct; private boolean animateFlag = true; private boolean soundFlag = true; private Constants c; public AudioClip pushSnd, popSnd, errorSnd, goodSnd; private String helpPage; // QUIZ COMPONENTS private TextArea infoTA, questionTA, answerTA[]; private Button backBtn, nextBtn, scoreBtn, quizResetBtn; private CheckboxGroup answerGrp; private Checkbox answerBx[]; private int animationRate = 30; private int scrollRate = 1000; public void init() { state = c.DEMO; runMode = c.RUN; currStruct = c.STACK; Color lightColor = new Color( 110, 170, 255 ); Color medColor = new Color( 50, 110, 190 ); Color darkColor = new Color( 0, 20, 110 ); // Get the name of the HTML help file */ String param = null; param = getParameter("HelpFile"); if(param == null) helpPage = null; else helpPage = param; // Get the name of the stack quiz file to read. String param1 = null; String stackfile = null; param1 = getParameter("stackquiz"); if(param1 != null) stackfile = param1; // Get the name of the queue quiz file to read. String param2 = null; String queuefile = null; param2 = getParameter("queuequiz"); if(param2 != null) queuefile = param2; // Get the name of the list quiz file to read. String param3 = null; String listfile = null; param3 = getParameter("listquiz"); if(param3 != null) listfile = param3; memBlock = new MemorySprite[16]; for( int i = 0; i < memBlock.length; i++ ) { String addr = new String( "$12" + toHex(4*i + 4) ); memBlock[i] = new MemorySprite( addr, "" ); } node = new StackSprite[10]; for( int i = 0; i < node.length; i++ ) { node[i] = new StackSprite( "" ); } topnode = new TopStackSprite(); xsprite = new Xsprite(); stackVariables = new StackVarDisplay( 10 ); queueVariables = new ListVarDisplay( 6 ); // Sounds pushSnd = getAudioClip( getDocumentBase(), "push.au" ); popSnd = getAudioClip( getDocumentBase(), "pop.au" ); errorSnd = getAudioClip( getDocumentBase(), "error.au" ); goodSnd = getAudioClip( getDocumentBase(), "clap.au" ); pushSnd.play(); pushSnd.stop(); popSnd.play(); popSnd.stop(); errorSnd.play(); errorSnd.stop(); goodSnd.play(); goodSnd.stop(); // Fonts Font font11p = new Font( "SansSerif", Font.PLAIN, 11 ); Font font12b = new Font( "SanSerif", Font.BOLD, 12 ); /********** Applet Layout *************************************************/ // Layouts gbLayout = new GridBagLayout(); gbc = new GridBagConstraints(); cardManager = new CardLayout(); // Top panel and components Panel topPnl = new Panel(); topPnl.setBackground( lightColor ); topPnl.setLayout( gbLayout ); // animation Canvas and components Image animateImg = createImage( 450, 225 ); animateCv = new AnimationCanvas( 450, 225, animateImg ); animateCv.setStackVariables(node, topnode, xsprite, stackVariables ); // memory Canvas and components Image memImg = createImage( 180, 225 ); memCv = new MemoryCanvas( 180, 225, memImg, memBlock ); memCv.setBackground( new Color( 0, 20, 110 )); // control Panel and components Panel ctrlPnl = new Panel(); ctrlPnl.setBackground( lightColor ); ctrlPnl.setLayout( gbLayout ); Label dataStructLbl = new Label( "Data Structure", Label.CENTER ); dataStructLbl.setFont( font12b ); dataStructCB = new Choice(); dataStructCB.add( "Stack" ); dataStructCB.add( "Queue" ); dataStructCB.add( "Linked list" ); dataStructCB.addItemListener( this ); // General Buttons Panel and components Panel generalButtonPnl = new Panel(); generalButtonPnl.setBackground( lightColor ); generalButtonPnl.setLayout( new GridLayout( 4, 1, 0, 10 )); demoBtn = new Button( "Demo" ); demoBtn.addActionListener( this ); demoBtn.setEnabled( false ); quizBtn = new Button( "Quiz" ); quizBtn.addActionListener( this ); optionBtn = new Button( "Options" ); optionBtn.addActionListener( this ); helpBtn = new Button( "Help" ); helpBtn.addActionListener( this ); generalButtonPnl.add( demoBtn ); generalButtonPnl.add( quizBtn ); generalButtonPnl.add( optionBtn ); generalButtonPnl.add( helpBtn ); gbc.weightx = 100; gbc.weighty = 100; gbc.anchor = GridBagConstraints.NORTH; addComponent( ctrlPnl, dataStructLbl, gbc, 0, 0, 1, 1 ); addComponent( ctrlPnl, dataStructCB, gbc, 1, 0, 1, 1 ); gbc.insets = new Insets( 15, 0, 0, 0 ); addComponent( ctrlPnl, generalButtonPnl, gbc, 2, 0, 1, 1 ); gbc.insets = new Insets( 0, 0, 0, 0 ); gbc.weightx = 0; gbc.anchor = GridBagConstraints.WEST; addComponent( topPnl, animateCv, gbc, 0, 0, 1, 1 ); addComponent( topPnl, memCv, gbc, 0, 1, 1, 1 ); gbc.weightx = 100; gbc.anchor = GridBagConstraints.NORTH; addComponent( topPnl, ctrlPnl, gbc, 0, 2, 1, 1 ); // Bottom panel and components Panel bottomPnl = new Panel(); bottomPnl.setBackground( darkColor ); bottomPnl.setLayout( gbLayout ); // State deck and subpanels stateDeck = new Panel(); stateDeck.setLayout( cardManager ); demoPnl = new Panel(); demoPnl.setLayout( gbLayout ); // Source code panel and components Panel codePnl = new Panel(); codePnl.setLayout( gbLayout ); codePnl.setBackground( lightColor ); Label codeLbl = new Label( "Source Code", Label.CENTER ); codeLbl.setFont( font12b ); codeLbl.setBackground( medColor ); codeTA = new CodeText( 12, false ); codeTA.setFont( font11p ); // x = 100, y = 100 gbc.anchor = GridBagConstraints.NORTHWEST; gbc.fill = GridBagConstraints.HORIZONTAL; addComponent( codePnl, codeLbl, gbc, 0, 0, 1, 1 ); addComponent( codePnl, codeTA, gbc, 1, 0, 1, 1 ); // Info and step/run panel and components Panel midPnl = new Panel(); midPnl.setBackground( lightColor ); midPnl.setLayout( gbLayout ); Label commentLbl = new Label( "Comments", Label.CENTER ); commentLbl.setFont( font12b ); commentLbl.setBackground( medColor ); commentTA = new TextArea( "", 8, 30, TextArea.SCROLLBARS_NONE ); commentTA.setFont( font11p ); commentTA.setEditable( false ); commentTA.setBackground( Color.white ); Panel runPnl = new Panel(); runPnl.setBackground( lightColor ); runPnl.setLayout( new FlowLayout( FlowLayout.CENTER, 7, 7 )); runBtn = new Button( "Run" ); runBtn.addActionListener( this ); stepBtn = new Button( "Step" ); stepBtn.addActionListener( this ); pauseBtn = new Button( "Pause" ); pauseBtn.addActionListener( this ); resetBtn = new Button( "Reset" ); resetBtn.addActionListener( this ); runPnl.add( runBtn ); runPnl.add( stepBtn ); runPnl.add( pauseBtn ); runPnl.add( resetBtn ); gbc.anchor = GridBagConstraints.NORTH; addComponent( midPnl, commentLbl, gbc, 0, 0, 1, 1 ); addComponent( midPnl, commentTA, gbc, 1, 0, 1, 1 ); gbc.fill = GridBagConstraints.BOTH; addComponent( midPnl, runPnl, gbc, 2, 0, 1, 1 ); gbc.fill = GridBagConstraints.NONE; // Function specific panel and components structureDeck = new Panel(); structureDeck.setLayout( cardManager ); // Stack panel and components Panel stackCard = new Panel(); stackCard.setLayout( gbLayout ); stackCard.setBackground( lightColor ); Label stackLbl = new Label( "Stack Functions", Label.CENTER ); stackLbl.setBackground( medColor ); stackLbl.setFont( font12b ); // Stack buttons panel and components Panel stackButtonsPnl = new Panel(); stackButtonsPnl.setLayout( new GridLayout( 5, 1, 0, 10 )); Label spacer1 = new Label( "" ); pushBtn = new Button( "Push" ); pushBtn.addActionListener( this ); popBtn = new Button( "Pop" ); popBtn.addActionListener( this ); retrieveBtn = new Button( "Retrieve" ); retrieveBtn.addActionListener( this ); stackButtonsPnl.add( spacer1 ); stackButtonsPnl.add( pushBtn ); stackButtonsPnl.add( popBtn ); stackButtonsPnl.add( retrieveBtn ); // Stack input panel and components stackInputDeck = new Panel(); stackInputDeck.setLayout( cardManager ); Panel blankCrd = new Panel(); Panel pushCrd = new Panel(); pushCrd.setBackground( lightColor ); pushCrd.setLayout( gbLayout ); Label pushLbl = new Label( "Enter an integer", Label.CENTER ); Label rangeLbl = new Label( "(-99 to 99)", Label.CENTER ); pushLbl.setFont( font12b ); pushTF = new TextField( 2 ); okayBtn = new Button( " OK " ); okayBtn.addActionListener( this ); gbc.insets = new Insets( 0, 0, 0, 0 ); gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.NONE; addComponent( pushCrd, pushLbl, gbc, 0, 0, 1, 1 ); addComponent( pushCrd, rangeLbl, gbc, 1, 0, 1, 1 ); gbc.insets = new Insets( 6, 0, 0, 0 ); addComponent( pushCrd, pushTF, gbc, 2, 0, 1, 1 ); addComponent( pushCrd, okayBtn, gbc, 3, 0, 1, 1 ); Panel popCrd = new Panel(); popCrd.setLayout( new BorderLayout() ); stackMsgCv = new MessageCanvas(); stackMsgCv.setSize( 180, 100 ); popCrd.add( stackMsgCv, BorderLayout.CENTER ); stackInputDeck.add( blankCrd, "blank" ); stackInputDeck.add( pushCrd, c.push ); stackInputDeck.add( popCrd, c.pop ); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets( 0, 0, 0, 0 ); addComponent( stackCard, stackLbl, gbc, 0, 0, 2, 1 ); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0; gbc.anchor = gbc.NORTH; gbc.insets = new Insets( 0, 6, 0, 0 ); addComponent( stackCard, stackButtonsPnl, gbc, 1, 0, 1, 1 ); gbc.insets = new Insets( 0, 0, 0, 0 ); gbc.weightx = 20; gbc.fill = GridBagConstraints.HORIZONTAL; addComponent( stackCard, stackInputDeck, gbc, 1, 1, 1, 1 ); // Queue panel and components Panel queueCard = new Panel(); queueCard.setLayout( gbLayout ); queueCard.setBackground( lightColor ); Label queueLbl = new Label( "Queue Functions", Label.CENTER ); queueLbl.setBackground(medColor ); queueLbl.setFont( font12b ); // Queue buttons panel and components Panel queueButtonsPnl = new Panel(); queueButtonsPnl.setLayout( new GridLayout( 5, 1, 0, 10 )); Label spacer2 = new Label( "" ); enqueueBtn = new Button( "Enqueue" ); enqueueBtn.addActionListener( this ); dequeueBtn = new Button( "Dequeue" ); dequeueBtn.addActionListener( this ); queueButtonsPnl.add( spacer2 ); queueButtonsPnl.add( enqueueBtn ); queueButtonsPnl.add( dequeueBtn ); // Queue input panel and components queueInputDeck = new Panel(); queueInputDeck.setLayout( cardManager ); Panel blankCrd2 = new Panel(); // this is a dummy panel used to set the minimum size of the IO panel Panel strutCrd = new Panel(); Label strutLbl = new Label( "XXXXXXXXXXXXXXXXXXXXXX", Label.CENTER ); strutCrd.add( strutLbl ); Panel enqueueCrd = new Panel(); enqueueCrd.setBackground( lightColor ); enqueueCrd.setLayout( gbLayout ); Label enqueueLbl = new Label( "Enter an integer", Label.CENTER ); Label rangeLbl2 = new Label( "(-99 to 99)", Label.CENTER ); enqueueLbl.setFont( font12b ); enqueueTF = new TextField( 2 ); okayBtn2 = new Button( " OK " ); okayBtn2.addActionListener( this ); gbc.insets = new Insets( 0, 0, 0, 0 ); gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.NONE; addComponent( enqueueCrd, enqueueLbl, gbc, 0, 0, 1, 1 ); addComponent( enqueueCrd, rangeLbl2, gbc, 1, 0, 1, 1 ); gbc.insets = new Insets( 6, 0, 0, 0 ); addComponent( enqueueCrd, enqueueTF, gbc, 2, 0, 1, 1 ); addComponent( enqueueCrd, okayBtn2, gbc, 3, 0, 1, 1 ); Panel dequeueCrd = new Panel(); dequeueCrd.setLayout( new BorderLayout() ); queueMsgCv = new MessageCanvas(); dequeueCrd.add( queueMsgCv, BorderLayout.CENTER ); queueInputDeck.add( blankCrd2, "blank2" ); queueInputDeck.add( enqueueCrd, c.enqueue ); queueInputDeck.add( dequeueCrd, c.dequeue ); queueInputDeck.add( strutCrd, "strut" ); // never be seen gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets( 0, 0, 0, 0 ); addComponent( queueCard, queueLbl, gbc, 0, 0, 2, 1 ); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0; gbc.anchor = gbc.NORTH; gbc.insets = new Insets( 0, 6, 0, 0 ); addComponent( queueCard, queueButtonsPnl, gbc, 1, 0, 1, 1 ); gbc.insets = new Insets( 0, 0, 0, 0 ); gbc.weightx = 20; gbc.fill = GridBagConstraints.HORIZONTAL; addComponent( queueCard, queueInputDeck, gbc, 1, 1, 1, 1 ); // LinkList panel and components Panel linkListCard = new Panel(); linkListCard.setLayout( gbLayout ); linkListCard.setBackground( lightColor ); Label linkListLbl = new Label( "Link List Functions", Label.CENTER ); linkListLbl.setBackground( medColor ); linkListLbl.setFont( font12b ); // Queue buttons panel and components Panel linkListButtonsPnl = new Panel(); linkListButtonsPnl.setLayout( new GridLayout( 5, 1, 0, 10 )); Label spacer3 = new Label( "" ); insertBtn = new Button( "Insert" ); insertBtn.addActionListener( this ); deleteBtn = new Button( "Delete" ); deleteBtn.addActionListener( this ); linkListButtonsPnl.add( spacer3 ); linkListButtonsPnl.add( insertBtn ); linkListButtonsPnl.add( deleteBtn ); // Linked List input panel and components linkListInputDeck = new Panel(); linkListInputDeck.setLayout( cardManager ); Panel blankCrd3 = new Panel(); Panel insertCrd = new Panel(); insertCrd.setBackground( lightColor ); insertCrd.setLayout( gbLayout ); Label insertLbl = new Label( "Enter an integer", Label.CENTER ); Label rangeLbl3 = new Label( "(-99 to 99)", Label.CENTER ); insertLbl.setFont( font12b ); insertTF = new TextField( 2 ); okayBtn3 = new Button( " OK " ); okayBtn3.addActionListener( this ); gbc.insets = new Insets( 0, 0, 0, 0 ); gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.NONE; addComponent( insertCrd, insertLbl, gbc, 0, 0, 1, 1 ); addComponent( insertCrd, rangeLbl3, gbc, 1, 0, 1, 1 ); gbc.insets = new Insets( 6, 0, 0, 0 ); addComponent( insertCrd, insertTF, gbc, 2, 0, 1, 1 ); addComponent( insertCrd, okayBtn3, gbc, 3, 0, 1, 1 ); Panel deleteCrd = new Panel(); //// deleteCrd.setLayout( new BorderLayout() ); linkListMsgCv = new MessageCanvas(); deleteCrd.add( linkListMsgCv, BorderLayout.CENTER ); linkListInputDeck.add( blankCrd3, "blank3" ); linkListInputDeck.add( insertCrd, c.insert ); linkListInputDeck.add( deleteCrd, c.delete ); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets( 0, 0, 0, 0 ); addComponent( linkListCard, linkListLbl, gbc, 0, 0, 2, 1 ); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0; gbc.anchor = gbc.NORTH; gbc.insets = new Insets( 0, 6, 0, 0 ); addComponent( linkListCard, linkListButtonsPnl, gbc, 1, 0, 1, 1 ); gbc.insets = new Insets( 0, 0, 0, 0 ); gbc.weightx = 20; gbc.fill = GridBagConstraints.HORIZONTAL; addComponent( linkListCard, linkListInputDeck, gbc, 1, 1, 1, 1 ); structureDeck.add( stackCard, c.stack ); structureDeck.add( linkListCard, c.linklist ); structureDeck.add( queueCard, c.queue ); gbc.weightx = 5; gbc.fill = GridBagConstraints.BOTH; gbc.anchor = GridBagConstraints.NORTHWEST; gbc.insets = new Insets( 2, 0, 0, 5 ); addComponent( demoPnl, codePnl, gbc, 0, 0, 1, 1 ); gbc.weightx = 0; addComponent( demoPnl, midPnl, gbc, 0, 1, 1, 1 ); gbc.weightx = 0; gbc.fill = GridBagConstraints.BOTH; gbc.insets = new Insets( 2, 0, 0, 0); addComponent( demoPnl, structureDeck, gbc, 0, 2, 1, 1 ); gbc.insets = new Insets( 0, 0, 0, 0); // QUIZ PANEL AND COMPONENTS quizPnl = new Panel(); quizPnl.setBackground( darkColor ); quizPnl.setLayout( gbLayout ); Panel infoPnl = new Panel(); infoPnl.setLayout( gbLayout ); infoPnl.setBackground( lightColor ); Label infoLbl = new Label( "Additional Information", Label.CENTER ); infoLbl.setFont( font12b ); infoLbl.setBackground( medColor ); infoTA = new TextArea( "", 8, 20, TextArea.SCROLLBARS_NONE ); infoTA.setFont( font11p ); infoTA.setEditable( false ); infoTA.setBackground( Color.white ); gbc.weightx = 100; gbc.weighty = 0; gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.HORIZONTAL; addComponent( infoPnl, infoLbl, gbc, 0, 0, 1, 1 ); gbc.weighty = 100; addComponent( infoPnl, infoTA, gbc, 1, 0, 1, 1 ); Panel questionPnl = new Panel(); questionPnl.setLayout( gbLayout ); questionPnl.setBackground( lightColor ); Label questionLbl = new Label( "Question", Label.CENTER ); questionLbl.setFont( font12b ); questionLbl.setBackground( medColor ); questionTA = new TextArea( "", 8, 30, TextArea.SCROLLBARS_NONE ); questionTA.setFont( font11p ); questionTA.setEditable( false ); questionTA.setBackground( Color.white ); Panel quizBtnPnl = new Panel(); quizBtnPnl.setLayout( new FlowLayout( FlowLayout.CENTER, 7, 7 )); backBtn = new Button( "Back" ); nextBtn = new Button( "Next" ); scoreBtn = new Button( "Score" ); quizResetBtn = new Button( "Reset" ); quizBtnPnl.add( backBtn ); quizBtnPnl.add( nextBtn ); quizBtnPnl.add( scoreBtn ); quizBtnPnl.add( quizResetBtn ); gbc.weighty = 0; addComponent( questionPnl, questionLbl, gbc, 0, 0, 1, 1 ); gbc.weighty = 100; addComponent( questionPnl, questionTA, gbc, 1, 0, 1, 1 ); addComponent( questionPnl, quizBtnPnl, gbc, 2, 0, 1, 1 ); Panel answerPnl = new Panel(); answerPnl.setLayout( gbLayout ); answerPnl.setBackground( lightColor ); Label answerLbl = new Label( "Answers", Label.CENTER ); answerLbl.setFont( font12b ); answerLbl.setBackground( medColor ); answerTA = new TextArea[ 4 ]; for( int i = 0; i < 4; i++ ){ answerTA[i] = new TextArea( "", 2, 25, TextArea.SCROLLBARS_NONE ); answerTA[i].setFont( font11p ); answerTA[i].setEditable( false ); answerTA[i].setBackground( Color.white ); } answerGrp = new CheckboxGroup(); answerBx = new Checkbox[4]; for( int i = 0; i < 4; i++ ){ answerBx[i] = new Checkbox( "", answerGrp, false ); } addComponent( answerPnl, answerLbl, gbc, 0, 0, 2, 1 ); gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0; gbc.insets = new Insets( 0, 3, 0, 0); for( int i = 0; i < 4; i++ ) addComponent( answerPnl, answerBx[i], gbc, i+1, 0, 1, 1 ); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 100; gbc.insets = new Insets( 0, 0, 3, 3); for( int i = 0; i < 3; i++ ) addComponent( answerPnl, answerTA[i], gbc, i+1, 1, 1, 1 ); gbc.insets = new Insets( 0, 0, 7, 3); addComponent( answerPnl, answerTA[3], gbc, 4, 1, 1, 1 ); gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.BOTH; gbc.insets = new Insets( 2, 0, 0, 5 ); addComponent( quizPnl, infoPnl, gbc, 0, 0, 1, 1 ); addComponent( quizPnl, questionPnl, gbc, 0, 1, 1, 1); addComponent( quizPnl, answerPnl, gbc, 0, 2, 1, 1 ); gbc.insets = new Insets( 0, 0, 0, 0); stateDeck.add( demoPnl, c.demo ); stateDeck.add( quizPnl, c.quiz ); gbc.weightx = 100; gbc.anchor = gbc.WEST; gbc.fill = GridBagConstraints.BOTH; addComponent( bottomPnl, stateDeck, gbc, 0, 0, 1, 1 ); setLayout( new BorderLayout() ); add( topPnl, BorderLayout.NORTH ); add( bottomPnl, BorderLayout.CENTER ); // create stackmanager and initialize nodes stackmanager = new StackManager( this, node, memBlock, topnode, xsprite, stackVariables ); stackmanager.initializeNodes( animateCv ); // create queuemanager and intialize nodes queuemanager = new ListManager( memBlock, queueVariables, this ); queuemanager.initialize( animateCv ); queueVariables.setCanvasSize( animateCv ); // create memorymanager and initialize memory blocks memorymanager = new MemoryManager( memBlock ); memorymanager.positionBlocks( memCv ); memorymanager.allocate( node.length ); // create codemanager codemanager = new CodeManager( codeTA, commentTA ); codemanager.setStructure( c.STACK ); animateCv.setState( state, currStruct ); // create IOmanager IOmanager = new IOManager( this, cardManager, stateDeck, structureDeck ); IOmanager.setState( state ); IOmanager.setStruc( currStruct ); IOmanager.setStackPanel( stackInputDeck, stackMsgCv ); IOmanager.setQueuePanel( queueInputDeck, queueMsgCv ); IOmanager.setListPanel( linkListInputDeck, linkListMsgCv ); IOmanager.setStackButtons( pushBtn, popBtn, retrieveBtn, okayBtn ); IOmanager.setQueueButtons( enqueueBtn, dequeueBtn, okayBtn2 ); IOmanager.setListButtons( insertBtn, deleteBtn, okayBtn3 ); // create and initialize Options dialog box optionsDlg = new OptionsDialog( this, stackmanager, animationRate, scrollRate, "Options" ); optionsDlg.setSize( 280, 280 ); optionsDlg.setVisible( false ); optionsDlg.setResizable( false ); optionsDlg.setBackground( lightColor ); stackFunction = new StackFunctions( this, stackmanager, memorymanager, codemanager, IOmanager ); queueFunction = new ListFunctions( this, queuemanager, memorymanager, codemanager, IOmanager ); currFunction = stackFunction; quizmanager = new QuizManager( this, infoTA, questionTA, answerTA, answerBx, answerGrp ); quizmanager.setButtons( backBtn, nextBtn, scoreBtn, quizResetBtn ); for( int i = 0; i < 4; i++ ) answerBx[i].addItemListener( quizmanager ); backBtn.addActionListener( quizmanager ); nextBtn.addActionListener( quizmanager ); scoreBtn.addActionListener( quizmanager ); quizResetBtn.addActionListener( quizmanager ); // read quiz files into vectors and use vectors to initialize quizmanager Vector temp1 = new Vector( 50 ); readFile( stackfile, temp1 ); quizmanager.initQuiz( c.STACK, temp1 ); Vector temp2 = new Vector( 50 ); readFile( listfile, temp2 ); quizmanager.initQuiz( c.LINKLIST, temp2 ); Vector temp3 = new Vector( 50 ); readFile( queuefile, temp3 ); quizmanager.initQuiz( c.QUEUE, temp3 ); quizmanager.setCurrentStruct( currStruct ); cardManager.show( structureDeck, "stack" ); setRunButtons(); } /* Method name: showPage * Purpose: Open new browser window displaying a new page * Receives: page - the name of the page to display * pageTitle - a name required by the showDocument method * (method will not open a new page if it is * already open) * Returns: no return value * Calls: no programmer defined methods * Called by: actionPerformed */ public void showPage(String page, String pageTitle ) { /* if no page parameter was passed to applet */ if (page == null) { showError( "Page parameter not specified" ); return; } URL pageAddr = null; try { pageAddr = new URL (getCodeBase(), page); } catch (MalformedURLException mue) { showError( "Caught MalformedURLException accessing requested page." ); return; } /* open page in new browser window (unless already open) */ getAppletContext().showDocument( pageAddr, pageTitle ); } // display red message in either demo or quiz text area public void showError( String error ) { if( state == c.DEMO ) { commentTA.setForeground( Color.red ); commentTA.setText( error ); } else if( state == c.QUIZ ) { infoTA.setForeground( Color.red ); infoTA.setText( error ); } } // display black message in either demo or quiz text area public void showMessage( String error ) { if( state == c.DEMO ) { commentTA.setForeground( Color.black); commentTA.setText( error ); } else if( state == c.QUIZ ) { infoTA.setForeground( Color.black ); infoTA.setText( error ); } } public void addComponent( Panel p, Component c, GridBagConstraints gbc, int row, int col, int width, int height ) // Method name: addComponent // Purpose: adds GUI components to a GridBagLayout // Receives: p - the container panel // c - a GUI component // gbc - the GridBagConstraints being used // row - the row in which the component is placed // col - the column in which the component is placed // width - The number of columns the component occupies // height - The number of rows the component occupies // Calls: none // Called by: init() { gbc.gridx = col; gbc.gridy = row; gbc.gridwidth = width; gbc.gridheight = height; p.add( c, gbc ); } /* Method name: readFile * Purpose: makes network connection to text file and reads lines * into a vector * Receives: fileName - the name of the text file * v - the Vector to hold the strings * Returns: none * Modifies: boolean errorFlag * Calls: no programmer defined methods * Called by: init() */ private void readFile( String fileName, Vector v ) { if(fileName == null){ showError( "No \"data\" parameter specified." ); return; } URL dataFile = null; URLConnection dataConnection = null; DataInputStream dis = null; BufferedReader reader = null; try{ dataFile = new URL (getCodeBase(), fileName); } catch (MalformedURLException mue) { showError( "Caught MalformedURLException accessing data file."); return; } try{ dataConnection = dataFile.openConnection (); } catch (IOException ioe){ showError("Caught IOException opening a connection to the " + "data file."); return; } try{ dis = new DataInputStream (dataConnection.getInputStream ()); } catch (IOException ioe){ showError("Caught IOException opening stream on data file."); return; } reader = new BufferedReader (new InputStreamReader (dis)); showMessage( "Retrieving quiz data ..." ); String line = null; while(true){ try{ line = reader.readLine(); } catch( IOException ioe ){ showError("IOException reading from data file."); return; } if (line == null) break; v.addElement (line); } // end while try{ dis.close (); } catch(IOException ioe){ showError("IOException closing DataInputStream on text data."); } showMessage(""); } // plays sound based on argument public void playSound( int func ) { if( soundFlag ) { switch( func ) { case c.PUSH: pushSnd.play(); break; case c.POP: popSnd.play(); break; case c.ERROR: errorSnd.play(); break; case c.GOOD: goodSnd.play(); break; } } } // enables or disables Run, Step and Pause buttons public void setRunButtons() { switch( runMode ) { case c.RUN: runBtn.setEnabled( false ); stepBtn.setEnabled( false ); pauseBtn.setEnabled( true ); break; case c.STEP: runBtn.setEnabled( true ); stepBtn.setEnabled( true ); pauseBtn.setEnabled( false ); break; case c.PAUSE: runBtn.setEnabled( true ); stepBtn.setEnabled( true ); pauseBtn.setEnabled( false ); break; } } public void disableRunButtons() { runBtn.setEnabled( false ); stepBtn.setEnabled( false ); pauseBtn.setEnabled( false ); } public void setSound( boolean b ) { soundFlag = b; } public void setAnimation( boolean b ) { animateFlag = b; stackmanager.setAnimation( b ); queuemanager.setAnimation( b ); } public boolean getAnimation( ) { return animateFlag; } public boolean getStep( ) { if( runMode == c.STEP ) return true; else return false; } public void setAnimationRate( int rate ) { animationRate = rate; } public void setScrollRate( int rate ) { scrollRate = rate; } public int getAnimationRate() { return animationRate; } public int getScrollRate() { return scrollRate; } // resets animation and datastructures used with demo public void resetDemo( ) { if( animation != null ){ animation.stop(); animation = null; } IOmanager.enableFunctionButtons( true ); disableRunButtons(); codemanager.reset(); memorymanager.reset(); if( currStruct == c.STACK ){ stackmanager.reset(); memorymanager.allocate( node.length ); cardManager.show( stackInputDeck, "blank" ); stackVariables.reset(); } else if( currStruct == c.QUEUE ){ queuemanager.reset(); cardManager.show( queueInputDeck, "blank2" ); queueVariables.reset(); } else if( currStruct == c.LINKLIST ){ queuemanager.reset(); cardManager.show( linkListInputDeck, "blank3" ); queueVariables.reset(); } animateCv.repaint(); } // handle button events public void actionPerformed( ActionEvent e ) { boolean errorFlag = false; if( e.getSource() == demoBtn ) { state = c.DEMO; cardManager.show( stateDeck, "demo" ); demoPnl.validate(); quizBtn.setEnabled( true ); demoBtn.setEnabled( false ); animateCv.setState( state, currStruct ); } else if( e.getSource() == quizBtn ) { state = c.QUIZ; cardManager.show( stateDeck, "quiz" ); quizPnl.validate(); quizBtn.setEnabled( false ); demoBtn.setEnabled( true ); animateCv.setState( state, currStruct ); } else if( e.getSource() == optionBtn ) { optionsDlg.setVisible( true ); } else if( e.getSource() == helpBtn ) { showPage(helpPage, "Help" ); } else if( e.getSource() == runBtn ) { if( runMode != c.RUN ) { runMode = c.RUN; setRunButtons(); } animation.resume(); } else if( e.getSource() == stepBtn ) { if( runMode != c.STEP ) { runMode = c.STEP; setRunButtons(); } animation.resume(); } else if( e.getSource() == resetBtn ) { resetDemo(); } else if( e.getSource() == pauseBtn ) { animation.suspend(); runMode = c.PAUSE; setRunButtons(); } else if( e.getSource() == pushBtn ) { cardManager.show( stackInputDeck, "push" ); stackmanager.functionReset(); codemanager.pushCode( ); } else if( e.getSource() == okayBtn ) { String pushVal = pushTF.getText(); if( testInput( pushVal ) != 999 ) { codemanager.pushCode(); ((StackFunctions)currFunction).setPush( pushVal ); pushTF.setText(""); startThread(); } else { codemanager.inputError(); playSound( c.ERROR ); errorFlag = true; } } else if( e.getSource() == popBtn ) { cardManager.show( stackInputDeck, "pop" ); codemanager.popCode( ); ((StackFunctions)currFunction).setPop(); startThread(); } else if( e.getSource() == retrieveBtn ) { codemanager.retrieveCode( ); ((StackFunctions)currFunction).setRetrieve(); startThread(); } else if( e.getSource() == enqueueBtn ) { cardManager.show( queueInputDeck, c.enqueue ); queuemanager.functionReset(); } else if( e.getSource() == okayBtn2 ) { String enqueueVal = enqueueTF.getText(); if( testInput( enqueueVal ) != 999 ) { codemanager.enqueueCode( ); ((ListFunctions)currFunction).setEnqueue( testInput( enqueueVal ) ); enqueueTF.setText(""); startThread(); } else { codemanager.inputError(); playSound( c.ERROR ); errorFlag = true; } } else if( e.getSource() == dequeueBtn ) { cardManager.show( queueInputDeck, c.dequeue ); codemanager.dequeueCode( ); ((ListFunctions)currFunction).setDequeue(); startThread(); } else if( e.getSource() == insertBtn ) { cardManager.show( linkListInputDeck, c.insert ); queuemanager.functionReset(); } else if( e.getSource() == okayBtn3 ) { String insertVal = insertTF.getText(); if( testInput( insertVal ) != 999 ) { codemanager.insertCode( ); ((ListFunctions)currFunction).setInsert( testInput( insertVal ) ); insertTF.setText(""); startThread(); } else { codemanager.inputError(); playSound( c.ERROR ); errorFlag = true; } } else if( e.getSource() == deleteBtn ) { cardManager.show( linkListInputDeck, c.delete ); codemanager.deleteCode( ); ((ListFunctions)currFunction).setDelete(); startThread(); } if( !errorFlag ) codemanager.resetColor(); } // handle menu events public void itemStateChanged( ItemEvent e ) { if( e.getSource() == dataStructCB ) { int index = dataStructCB.getSelectedIndex(); switch( index ) { case 0: currStruct = c.STACK; currFunction = stackFunction; resetDemo(); quizmanager.setCurrentStruct( currStruct ); break; case 1: currStruct = c.QUEUE; memorymanager.reset(); currFunction = queueFunction; resetDemo(); queuemanager.setStructure( currStruct ); quizmanager.setCurrentStruct( currStruct ); break; case 2: currStruct = c.LINKLIST; memorymanager.reset(); currFunction = queueFunction; resetDemo(); queuemanager.setStructure( currStruct ); quizmanager.setCurrentStruct( currStruct ); break; } animateCv.setState( state, currStruct ); IOmanager.setStruc( currStruct ); demoPnl.validate(); quizPnl.validate(); codemanager.setStructure( currStruct ); } } // test if input is an integer -99 to 99 // returns 999 for an error public int testInput( String input ) { int pushNum; boolean goodFlag = true; try{ pushNum = Integer.parseInt( input ); } catch( NumberFormatException nfe ){ pushNum = 999; goodFlag = false; } if( goodFlag ){ if( pushNum < -99 || pushNum > 99 ) pushNum = 999; } return pushNum; } public void start() { } public void startThread() { if(animation == null ){ animation = new Thread(this); animation.start(); } } // the thread's run method - makes one pass through a function public void run() { StructureFunctions runnableFunction; runnableFunction = currFunction; setRunButtons(); IOmanager.enableFunctionButtons( false ); runnableFunction.run(); IOmanager.enableFunctionButtons( true ); disableRunButtons(); animation = null; } // pause the thread, time is in milliseconds public void pause( int time ) { try { animation.sleep( time ); } catch( InterruptedException ie ) { // System.err.println( "pause problem" ); } } // pause or suspend the thread public void stepOrPause() { if( getStep() ) suspend(); else pause( scrollRate ); } // pause or suspend the thread (if animating, don't pause) public void conditionalPause() { if( !animateFlag ) stepOrPause(); else{ if( getStep() ) suspend(); } } public void suspend() { animation.suspend(); } public void stop() { animation = null; optionsDlg = null; } public String toHex(int num) { String answer = ""; if( num <= 15 ) answer =( "0" + Character.toUpperCase(Character.forDigit( num, 16 ))); else answer =("" + Character.toUpperCase(Character.forDigit(num/16, 16 )) + Character.toUpperCase(Character.forDigit(num%16, 16))); return answer; } } // end DataStructure class // abstract parent class abstract class StructureFunctions { abstract void run(); } // handles display and I/O for linked list and queue class ListFunctions extends StructureFunctions { private int currentFunc; private DataStructure dataStruct; private ListManager queuemanager; private MemoryManager memorymanager; private CodeManager codemanager; private IOManager iomanager; private int enqueueVal, insertVal; private Constants c; public ListFunctions( DataStructure ds, ListManager lm, MemoryManager mm, CodeManager cm, IOManager io ) { dataStruct = ds; queuemanager = lm; memorymanager = mm; codemanager = cm; iomanager = io; } public void run() { switch( currentFunc ) { case c.ENQUEUE: enqueue(); break; case c.DEQUEUE: dequeue(); break; case c.INSERT: insert(); break; case c.DELETE: delete(); break; } } public void setEnqueue( int num ) { currentFunc = c.ENQUEUE; enqueueVal = num; } public void setDequeue() { currentFunc = c.DEQUEUE; } public void setInsert( int num ) { currentFunc = c.INSERT; insertVal = num; } public void setDelete() { currentFunc = c.DELETE; } public void enqueue() { queuemanager.showXvariable( "" + enqueueVal ); iomanager.setMessage( currentFunc ); codemanager.selectLine( 1 ); // if(Size >=MaxQueue) dataStruct.stepOrPause(); if( queuemanager.isFull() ) { codemanager.selectLine( 2 ); // queue is full iomanager.setMessage( currentFunc, false ); dataStruct.stepOrPause(); } else { codemanager.selectLine( 4 ); // if( size == 0 ) dataStruct.stepOrPause(); if( queuemanager.getSize() == 0 ) { codemanager.selectLine( 5 ); queuemanager.enqueue(); int index = memorymanager.newSpace(); dataStruct.stepOrPause(); codemanager.selectLine( 6 ); queuemanager.setData( index, enqueueVal ); memorymanager.setValue( index, enqueueVal ); dataStruct.stepOrPause(); codemanager.selectLine( 7 ); queuemanager.setLastNull(); dataStruct.stepOrPause(); codemanager.selectLine( 8 ); queuemanager.setTail(); queuemanager.updateSprites(); dataStruct.conditionalPause(); } else { codemanager.selectLine( 11 ); queuemanager.enqueue(); int index = memorymanager.newSpace(); dataStruct.stepOrPause(); codemanager.selectLine( 12 ); queuemanager.setTail(); queuemanager.updateSprites(); dataStruct.conditionalPause(); codemanager.selectLine( 13 ); queuemanager.setData( index, enqueueVal ); memorymanager.setValue( index, enqueueVal ); dataStruct.stepOrPause(); codemanager.selectLine( 14 ); queuemanager.setLastNull(); dataStruct.stepOrPause(); } codemanager.selectLine( 16 ); queuemanager.setSizeVariable(); dataStruct.stepOrPause(); codemanager.selectLine( 17 ); queuemanager.showSuccess(); iomanager.setMessage( currentFunc, true ); } } public void dequeue() { queuemanager.functionReset(); iomanager.setMessage( currentFunc ); codemanager.selectLine( 1 ); // if(Size == 0) dataStruct.stepOrPause(); if( queuemanager.isEmpty() ) { codemanager.selectLine( 2 ); // queue is empty iomanager.setMessage( currentFunc, false ); dataStruct.stepOrPause(); } else { codemanager.selectLine( 4 ); // QueueElement *Remove = Head queuemanager.setDeletePtr(); dataStruct.stepOrPause(); codemanager.selectLine( 5 ); // if( Head == Rear ) dataStruct.stepOrPause(); if( queuemanager.getSize() == 1 ) { codemanager.selectLine( 6 ); // Head = Rear = Null queuemanager.setEmpty(); dataStruct.stepOrPause(); } else { codemanager.selectLine( 8 ); // Head = Head->Successor; queuemanager.advanceHead(); queuemanager.updateSprites(); dataStruct.conditionalPause(); } codemanager.selectLine( 9 ); // X = Remove->Data; queuemanager.showXvariable(); dataStruct.stepOrPause(); codemanager.selectLine( 10 ); // delete Remove; memorymanager.clearSpace( queuemanager.dequeue()); if( queuemanager.getSize() !=0 ){ queuemanager.moveForward(); queuemanager.travelPointers(); queuemanager.updateSprites(); dataStruct.conditionalPause(); } else dataStruct.stepOrPause(); codemanager.selectLine( 11 ); // size-- queuemanager.setSizeVariable(); dataStruct.stepOrPause(); codemanager.selectLine( 17 ); queuemanager.showSuccess(); iomanager.setMessage( currentFunc, true ); } } public void delete() { queuemanager.functionReset(); iomanager.setMessage( currentFunc ); codemanager.selectLine( 1 ); // if(Size == 0) dataStruct.stepOrPause(); if( queuemanager.isEmpty() ) { codemanager.selectLine( 2 ); // queue is empty iomanager.setMessage( currentFunc, false ); dataStruct.stepOrPause(); } else { codemanager.selectLine( 4 ); // ListElement *Remove = Rear queuemanager.setDeletePtr(); dataStruct.stepOrPause(); codemanager.selectLine( 5 ); // if( Head == Rear ) dataStruct.stepOrPause(); if( queuemanager.getSize() == 1 ) { codemanager.selectLine( 6 ); // Head = Rear = Null queuemanager.setEmpty(); } else { codemanager.selectLine( 8 ); // ListElement *Cursor = Head; queuemanager.setCursorPtr(); dataStruct.stepOrPause(); codemanager.selectLine( 9 ); // while( Cursor->Successor != Rear) dataStruct.stepOrPause(); while( !queuemanager.delIterate() ){ codemanager.selectLine( 10 ); // Cursor = Cursor->Successor queuemanager.updateSprites(); dataStruct.conditionalPause(); codemanager.selectLine( 9 ); // while( Cursor->Successor != Rear) dataStruct.stepOrPause(); } codemanager.selectLine( 11 ); // Rear = Cursor queuemanager.retreatTail(); queuemanager.updateSprites(); dataStruct.conditionalPause(); codemanager.selectLine( 12 ); // Cursor->Successor = NULL queuemanager.setNewLastNull(); } dataStruct.stepOrPause(); codemanager.selectLine( 14 ); // X = Remove->Data; queuemanager.showXvariable(); dataStruct.stepOrPause(); codemanager.selectLine( 15 ); // delete Remove; memorymanager.clearSpace( queuemanager.delete()); queuemanager.updateSprites(); dataStruct.stepOrPause(); codemanager.selectLine( 16 ); // size-- queuemanager.setSizeVariable(); dataStruct.stepOrPause(); codemanager.selectLine( 17 ); queuemanager.showSuccess(); iomanager.setMessage( currentFunc, true ); } } public void insert() { queuemanager.showXvariable( "" + insertVal ); iomanager.setMessage( currentFunc ); codemanager.selectLine( 1 ); // if(Size >=MaxList) dataStruct.stepOrPause(); if( queuemanager.isFull() ) { codemanager.selectLine( 2 ); // Success = false iomanager.setMessage( currentFunc, false ); dataStruct.stepOrPause(); } else { codemanager.selectLine( 4 ); // ListElement *Start = new ListElement queuemanager.createStart(); int index = memorymanager.newSpace(); dataStruct.stepOrPause(); codemanager.selectLine( 5 ); // Start->Data = X; queuemanager.setData( index, insertVal ); memorymanager.setValue( index, insertVal ); dataStruct.stepOrPause(); codemanager.selectLine( 6 ); //Start->Successor = NULL; queuemanager.setStartNull(); dataStruct.stepOrPause(); codemanager.selectLine( 7 ); // if( Head == NULL || Head->Data > Start->Data ) dataStruct.stepOrPause(); if( queuemanager.getSize() == 1 || queuemanager.compare() ){ codemanager.selectLine( 8 ); // Start->Successor = Head; if( queuemanager.getSize() > 1 ){ queuemanager.moveBack(); queuemanager.travelPointers(); } queuemanager.moveStartUp(); queuemanager.updateSprites(); if( queuemanager.getSize() > 1 ) queuemanager.pointToHead(); dataStruct.conditionalPause(); codemanager.selectLine( 9 ); // Head = Start queuemanager.headEqualStart(); queuemanager.updateSprites(); dataStruct.conditionalPause(); } else{ codemanager.selectLine( 12 ); // ListElement *Cursor = Head; queuemanager.setCursorPtr(); dataStruct.stepOrPause(); codemanager.selectLine( 13 ); // while( Cursor->Successor != NULL && X > data) dataStruct.stepOrPause(); while( !queuemanager.insIterate() ){ codemanager.selectLine( 15 ); // Cursor = Cursor->Successor queuemanager.updateSprites(); dataStruct.conditionalPause(); codemanager.selectLine( 13 ); // while( Cursor->Successor != NULL && X > data) dataStruct.stepOrPause(); } codemanager.selectLine( 17 ); // Start->Successor = Cursor->Successor queuemanager.insMoveBack(); queuemanager.positionStart(); queuemanager.updateSprites(); queuemanager.setStartPointer(); dataStruct.conditionalPause(); codemanager.selectLine( 18 ); // Cursor->Successor = Start; queuemanager.pointToStart(); queuemanager.updateSprites(); dataStruct.conditionalPause(); queuemanager.threadInNode(); } codemanager.selectLine( 20 ); queuemanager.setSizeVariable(); dataStruct.stepOrPause(); codemanager.selectLine( 21 ); dataStruct.stepOrPause(); if( queuemanager.startIsLast() ){ codemanager.selectLine( 22 ); queuemanager.setTail(); queuemanager.updateSprites(); dataStruct.conditionalPause(); } codemanager.selectLine( 23 ); queuemanager.showSuccess(); iomanager.setMessage( currentFunc, true ); } } } // handles display and I/O for stack class StackFunctions extends StructureFunctions { private int currentFunc; private DataStructure dataStruct; private StackManager stackmanager; private MemoryManager memorymanager; private CodeManager codemanager; private IOManager iomanager; private String pushVal; private Constants c; public StackFunctions( DataStructure ds, StackManager sm, MemoryManager mm, CodeManager cm, IOManager io ) { dataStruct = ds; stackmanager = sm; memorymanager = mm; codemanager = cm; iomanager = io; } public void run() { switch( currentFunc ) { case c.PUSH: push(); break; case c.POP: pop(); break; case c.RETRIEVE: retrieve(); break; } } public void setPush( String num ) { currentFunc = c.PUSH; pushVal = num; } public void setPop() { currentFunc = c.POP; } public void setRetrieve() { currentFunc = c.RETRIEVE; } public void push() { stackmanager.showXvariable( pushVal ); iomanager.setMessage( currentFunc ); codemanager.selectLine( 1 ); // if(Top>=(MaxStack -1)) dataStruct.stepOrPause(); if( stackmanager.isFull() ) { codemanager.selectLine( 2 ); // stack is full iomanager.setMessage( currentFunc, false ); dataStruct.stepOrPause(); } else { codemanager.selectLine( 4 ); // Top++ stackmanager.incrementTop(); stackmanager.updateTop(); stackmanager.pushTopVariable(); dataStruct.stepOrPause(); codemanager.selectLine( 5); // X=Items[Top] stackmanager.push( pushVal ); stackmanager.updateSprites(); dataStruct.playSound( currentFunc ); memorymanager.push( pushVal ); stackmanager.showItemsTop(); dataStruct.conditionalPause(); codemanager.selectLine( 6 ); // Success = True stackmanager.showSuccess(); iomanager.setMessage( currentFunc, true ); } } public void pop() { stackmanager.functionReset(); stackmanager.showItemsTop(); iomanager.setMessage( currentFunc ); codemanager.selectLine( 1 ); // if(Top < 0) dataStruct.stepOrPause(); if( stackmanager.isEmpty() ) { codemanager.selectLine( 2 ); // stack is empty iomanager.setMessage( currentFunc, false ); dataStruct.stepOrPause(); } else { codemanager.selectLine( 4 ); // X = Items[Top] stackmanager.showXvariable( stackmanager.pop()); dataStruct.playSound( currentFunc ); stackmanager.updateSprites(); memorymanager.pop(); dataStruct.conditionalPause(); codemanager.selectLine( 5 ); // Top-- stackmanager.decrementTop(); stackmanager.updateTop(); stackmanager.popTopVariable(); stackmanager.showItemsTop(); dataStruct.stepOrPause(); codemanager.selectLine( 6 ); // Success = True stackmanager.showSuccess(); iomanager.setMessage( currentFunc, true ); } } public void retrieve() { stackmanager.functionReset(); stackmanager.showItemsTop(); iomanager.setMessage( currentFunc ); codemanager.selectLine( 1 ); // if(Top < 0) dataStruct.stepOrPause(); if( stackmanager.isEmpty() ) { codemanager.selectLine( 2 ); // stack is empty iomanager.setMessage( currentFunc, false ); dataStruct.stepOrPause(); } else { codemanager.selectLine( 4 ); // X = Items[Top] stackmanager.showXvariable (stackmanager.retrieve() ); stackmanager.updateSprites(); dataStruct.conditionalPause(); codemanager.selectLine( 5 ); // Success = True stackmanager.showSuccess(); iomanager.setMessage( currentFunc, true ); } } } // class handles displaying panels and messages class IOManager { private int state, structure, function; private DataStructure ds; private CardLayout cm; private Panel statePnl, strucPnl, stackIOPnl, queueIOPnl, listIOPnl; private MessageCanvas stackMC, queueMC, listMC; private Constants c; private Button pushBtn, popBtn, retrieveBtn, okayBtn, enqueueBtn, dequeueBtn, okayBtn2, insertBtn, deleteBtn, okayBtn3; public IOManager( DataStructure ds, CardLayout cm, Panel state, Panel struc ) { this.ds =ds; this.cm = cm; statePnl = state; strucPnl = struc; } public void setStackPanel( Panel stackIO, MessageCanvas messCV ) { stackIOPnl = stackIO; stackMC = messCV; } public void setQueuePanel( Panel queueIO, MessageCanvas messCV ) { queueIOPnl = queueIO; queueMC = messCV; } public void setListPanel( Panel listIO, MessageCanvas messCV ) { listIOPnl = listIO; listMC = messCV; } public void setState( int state ) { if( state == c.DEMO ) cm.show( statePnl, c.demo ); else if( state == c.QUIZ ) cm.show( statePnl, c.quiz ); this.state = state; } public void setStruc( int struct ) { structure = struct; switch( structure ) { case c.STACK: cm.show( strucPnl, c.stack ); break; case c.QUEUE: cm.show( strucPnl, c.queue ); break; case c.LINKLIST: cm.show( strucPnl, c.linklist ); } } public void setStackButtons( Button push, Button pop, Button retrieve, Button ok ) { pushBtn = push; popBtn = pop; retrieveBtn = retrieve; okayBtn = ok; } public void setQueueButtons( Button enqueue, Button dequeue, Button ok ) { enqueueBtn = enqueue; dequeueBtn = dequeue; okayBtn2 = ok; } public void setListButtons( Button insert, Button delete, Button ok ) { insertBtn = insert; deleteBtn = delete; okayBtn3 = ok; } public void enableFunctionButtons( boolean b ) { pushBtn.setEnabled( b ); popBtn.setEnabled( b ); retrieveBtn.setEnabled( b ); okayBtn.setEnabled( b ); enqueueBtn.setEnabled( b ); dequeueBtn.setEnabled( b ); okayBtn2.setEnabled( b ); insertBtn.setEnabled( b ); deleteBtn.setEnabled( b ); okayBtn3.setEnabled( b ); } public void setMessage( int func ) { switch( structure ) { case c.STACK: cm.show( stackIOPnl, c.pop ); stackMC.showFunction( func ); break; case c.QUEUE: cm.show( queueIOPnl, c.dequeue ); queueMC.showFunction( func ); break; case c.LINKLIST: cm.show( listIOPnl, c.delete ); listMC.showFunction( func ); break; } } public void setMessage( int func, boolean b ) { if( structure == c.STACK ){ cm.show( stackIOPnl, c.pop ); stackMC.showResult( func, b ); } else if( structure == c.QUEUE ){ cm.show( queueIOPnl, c.dequeue ); queueMC.showResult( func, b ); } else if( structure == c.LINKLIST ){ cm.show( listIOPnl, c.delete ); listMC.showResult( func, b ); } } } // class handles displaying correct code and syncronized comments class CodeManager { private CodeText codeTxt; private TextArea commentTxt; final int SPACES = 3; private int pushIndex, popIndex, retrieveIndex, currentIndex, enqueueIndex, dequeueIndex, insertIndex, deleteIndex, structure; private Constants c; private String[] stackComments = { "Pushes X onto stack\n" + "Pre: X is defined and Stack is initialized.\n" + "Post: Sets Success to True to indicate a " + "push and False to indicate failure.", "test for full stack", "stack is full", " ", "increment stack top pointer", "copy X to stack", "", "", "", "","", "", "Pops top of a stack into X\n" + "Pre: X is defined and Stack is initialized.\n" + "Post: X contains top stack element which has " + "been removed from the stack. Success is set to " + "True if pop is successful and False if not", "test for empty stack", "stack is empty", " ", "pop top of stack into X", "decrement top of stack pointer", "", "", "", "", "", "", "Copies value at top of stack to X\n" + "Pre: Stack is defined.\n" + "Post: X contains top stack element and the stack " + "is unchanged. Success set to True for successful" + "retrieve and False otherwise", "test for empty stack", "stack is empty", " ", "copy top stack element", "", "" , "", "", "", "", "", "", ""}; private String[] pushCode = { "void Stack::Push( StackElement X, bool &Success ) ", "{ if( Top >= ( MaxStack - 1 )) ", " Success = false; ", " else{ ", " Top++; ", " Items[Top] = X; ", " Success = true; ", " } ", "} "}; private String[] popCode = { "void Stack::Pop( StackElement &X, bool &Success ) ", "{ if( Top < 0 ) ", " Success = false; ", " else{ ", " X = Items[Top]; ", " Top--; ", " Success = true; ", " } ", "}"}; private String[] retrieveCode = { "void Stack::Retrieve( StackElement &X, bool &Success ) ", "{ if( Top < 0 ) ", " Success = false; ", " else{ ", " X = Items[Top]; ", " Success = true; ", " } ", "}", "", "", ""}; private String[] queueComments = { "Inserts X in the rear of the queue\n" + "Pre: X is defined and Queue is initialized.\n" + "Post: Sets Success to True to indicate an " + "enqueue and False to indicate failure.", "test for full queue", "queue is full", " ", "test for empty queue", "create a QueueElement", "copy X to new element", "mark element as end of queue", "set Rear to point to last element", "","", "create an element at the end of the queue", "set Rear to point to last element", "copy X to new element", "mark element as end of queue", "", "increment Size variable", "","","","","","", "Deletes element from front of queue\n" + "Pre: Queue is initialized.\n" + "Post: X contains data from deleted element. " + "Head points to next element in queue. Memory space is " + "returned to heap. Success is set to " + "True if dequeue is successful and False if not", "test for empty queue", "queue is empty", " ", "Instantiate Remove as a copy of Head", "test for only one element", "set Head and Rear to NULL, leaving queue empty", "", "advance Head pointer to next element", "copy element data to X", "delete memory space pointed to by Remove", "decrement size variable","", "" , "", "", "", "", "", "", ""}; private String[] enqueueCode = { "void Queue::Enqueue( QueueElement X, bool &Success ) ", "{ if( Size >= MaxQueue ) ", " Success = false; ", " else{ ", " if( Size == 0 ){ ", " Head = new QueueElement; ", " Head->Data = X; ", " Head->Successor = NULL; ", " Rear = Head; ", " } ", " else{ ", " Rear->Successor = new QueueElement; ", " Rear = Rear->Successor; ", " Rear->Data = X; ", " Rear->Successor = NULL; ", " } ", " Size++; ", " Success = true; ", " } ", "}"}; private String[] dequeueCode = { "void Queue::Dequeue( QueueElement X, bool &Success ) ", "{ if( Size == 0 ) ", " Success = false; ", " else{ ", " QueueElement *Remove = Head; ", " if( Head == Rear ) ", " Head = Rear = NULL; ", " else ", " Head = Head->Successor; ", " X = Remove->Data; ", " delete Remove; ", " Size--; ", " Success = true; ", " } ", "}"}; private String[] linkListComments = { "Inserts X in the linked list in numerical order\n" + "Pre: X is defined and LinkList is initialized.\n" + "Post: Sets Success to True to indicate an " + "insert and False to indicate failure.", "test for full list", "list is full", " ", "create a new ListElement", "copy X to new element", "new elements pointer to NULL", "test if new element is first element", "set new element's pointer to the list", "set Head to point to first element", " ", "find where element fits", "create a new ListElement", "iterate through the list", "","","", "insert element into list", "","", "increment Size variable", "reset Rear pointer if new element is the last node", "","","","","","","", "Deletes element from rear of list\n" + "Pre: LinkList is initialized.\n" + "Post: X contains data from deleted element. " + "Rear points to the preceding element in the list. Memory space is " + "returned to heap. Success is set to " + "true if delete is successful and false if not", "test for empty list", "list is empty", " ", "Instantiate Remove as a copy of Rear", "test for only one element", "set Head and Rear to NULL, leaving list empty", "", "Instantiate Cursor as a copy of Head", "iterate through the list to the second to last element", "set Rear to point to new last element", "mark element as end of list", "copy element data to X", "delete memory space pointed to by Remove", "decrement size variable","", "" , "", "", "", "", "", "", ""}; private String[] insertCode = { "void LinkList::InsertInOrder( int X, bool &Success ) ", "{ if( Size >= MaxList ) ", " Success = false; ", " else{ ", " ListElement *Start = new ListElement ", " Start->Data = X; ", " Start->Successor = NULL; ", " if( Head == NULL || Head->Data > Start->Data ){ ", " Start->Successor = Head; ", " Head = Start; ", " } ", " else{ ", " ListElement *Cursor = new ListElement ", " while( Cursor->Successor != NULL && ", " Cursor->Successor->Data < Start->Data ){", " Cursor = Cursor->Successor; ", " } ", " Start->Successor = Cursor->Successor; ", " Cursor->Successor = Start; ", " } ", " Size++; ", " if( Start->Successor == NULL ) ", " Rear = Start; ", " Success = true; ", " } ", "}"}; private String[] deleteCode = { "void LinkList::DeleteRear( int X, bool &Success ) ", "{ if( Size == 0 ) ", " Success = false; ", " else{ ", " ListElement *Remove = Rear; ", " if( Head == Rear ) ", " Head = Rear = NULL; ", " else{ ", " ListElement *Cursor = Head; ", " while( Cursor->Successor != Rear ) ", " Cursor = Cursor->Successor; ", " Rear = Cursor; ", " Cursor->Successor = NULL; ", " } ", " X = Remove->Data; ", " delete Remove; ", " Size--; ", " Success = true; ", " } ", "}"}; private String invalidStr = "\n\tINVALID ENTRY!\n\t Try again"; public CodeManager( CodeText ct, TextArea ta ) { codeTxt = ct; commentTxt = ta; } public void setStructure( int struct ) { structure = struct; switch( structure ) { case c.STACK: setStackText(); break; case c.QUEUE: setQueueText(); break; case c.LINKLIST: setLinkListText(); break; } currentIndex = 0; selectLine( 0 ); } public void reset() { resetColor(); currentIndex = 0; selectLine( 0 ); } public void setStackText() { codeTxt.removeAll(); commentTxt.setText( "" ); for( int i = 0; i < pushCode.length; i++ ) codeTxt.add( pushCode[i] ); for( int i = 0; i < SPACES; i++ ) codeTxt.add( "" ); for( int i = 0; i < popCode.length; i++ ) codeTxt.add( popCode[i] ); for( int i = 0; i < SPACES; i++ ) codeTxt.add( "" ); for( int i = 0; i < retrieveCode.length; i++ ) codeTxt.add( retrieveCode[i] ); pushIndex = 0; popIndex = pushCode.length + SPACES; retrieveIndex = popIndex + popCode.length + SPACES; } public void setQueueText() { codeTxt.removeAll(); commentTxt.setText( "" ); for( int i = 0; i < enqueueCode.length; i++ ) codeTxt.add( enqueueCode[i] ); for( int i = 0; i < SPACES; i++ ) codeTxt.add( "" ); for( int i = 0; i < dequeueCode.length; i++ ) codeTxt.add( dequeueCode[i] ); for( int i = 0; i < SPACES; i++ ) codeTxt.add( "" ); enqueueIndex = 0; dequeueIndex = enqueueCode.length + SPACES; } public void setLinkListText() { codeTxt.removeAll(); commentTxt.setText( "" ); for( int i = 0; i < insertCode.length; i++ ) codeTxt.add( insertCode[i] ); for( int i = 0; i < SPACES; i++ ) codeTxt.add( "" ); for( int i = 0; i < deleteCode.length; i++ ) codeTxt.add( deleteCode[i] ); for( int i = 0; i < SPACES; i++ ) codeTxt.add( "" ); insertIndex = 0; deleteIndex = insertCode.length + SPACES; } public void popCode( ) { codeTxt.makeVisible( popIndex ); currentIndex = popIndex; codeTxt.select( currentIndex ); commentTxt.setText( stackComments[ popIndex ] ); } public void pushCode() { codeTxt.makeVisible( pushIndex ); currentIndex = pushIndex; codeTxt.select( currentIndex ); commentTxt.setText( stackComments[ pushIndex ] ); } public void retrieveCode() { codeTxt.makeVisible( retrieveIndex ); currentIndex = retrieveIndex; codeTxt.select( currentIndex ); commentTxt.setText( stackComments[ retrieveIndex ] ); } public void enqueueCode() { codeTxt.makeVisible( enqueueIndex ); currentIndex = enqueueIndex; codeTxt.select( currentIndex ); commentTxt.setText( queueComments[ currentIndex ] ); } public void dequeueCode() { codeTxt.makeVisible( dequeueIndex ); currentIndex = dequeueIndex; codeTxt.select( currentIndex ); commentTxt.setText( queueComments[ currentIndex ] ); } public void insertCode() { codeTxt.makeVisible( insertIndex ); currentIndex = insertIndex; codeTxt.select( currentIndex ); commentTxt.setText( linkListComments[ currentIndex ] ); } public void deleteCode() { codeTxt.makeVisible( deleteIndex ); currentIndex = deleteIndex; codeTxt.select( currentIndex ); commentTxt.setText( linkListComments[ currentIndex ] ); } public void selectLine( int offset ) { codeTxt.select( currentIndex + offset ); if( structure == c.STACK ) commentTxt.setText( stackComments[ currentIndex + offset ] ); else if( structure == c.QUEUE ) commentTxt.setText( queueComments[ currentIndex + offset ] ); else if( structure == c.LINKLIST ) commentTxt.setText( linkListComments[ currentIndex + offset ] ); } public void inputError() { commentTxt.setForeground( Color.red ); commentTxt.setText( invalidStr ); } public void resetColor() { commentTxt.setForeground( Color.black ); } } // the list box that contains the source code class CodeText extends List { final int SPACES = 3; private int pushIndex, popIndex, retrieveIndex, currentIndex; CodeText( int lines, boolean b ) { super( lines, b ); } } // canvas used to to display current function and outcome class MessageCanvas extends Canvas { String functionStr = " ", returnStr = " "; Constants c; Font font12b = new Font( "SanSerif", Font.BOLD, 12 ); boolean done = false; public void paint( Graphics g ) { Dimension d = getSize(); g.setFont( font12b ); FontMetrics fm = g.getFontMetrics(); int funcWidth = fm.stringWidth( functionStr ); int xpos = (d.width - funcWidth)/2; g.drawString( functionStr, xpos, 40 ); if( done ) { int returnWidth = fm.stringWidth( returnStr ); xpos = (d.width - returnWidth)/2; g.drawString( returnStr, xpos, 60 ); } } public void showFunction( int func ) { done = false; switch( func ) { case c.PUSH: functionStr = "Pushing..."; break; case c.POP: functionStr = "Popping..."; break; case c.RETRIEVE: functionStr = "Retrieving..."; break; case c.ENQUEUE: functionStr = "Enqueuing..."; break; case c.DEQUEUE: functionStr = "Dequeuing..."; break; case c.INSERT: functionStr = "Inserting in order..."; break; case c.DELETE: functionStr = "Deleting from rear..."; break; } repaint(); } public void showResult( int func, boolean result ) { done = true; switch( func ) { case c.PUSH: functionStr = "Push"; break; case c.POP: functionStr = "Pop"; break; case c.RETRIEVE: functionStr = "Retrieve"; break; case c.ENQUEUE: functionStr = "Enqueue"; break; case c.DEQUEUE: functionStr = "Dequeue"; break; case c.INSERT: functionStr = "Insert"; break; case c.DELETE: functionStr = "Delete"; break; } if( result ) returnStr = "Successful"; else returnStr = "Unsuccessful"; repaint(); } } // canvas used to display the animation class AnimationCanvas extends Canvas { StackSprite[] nSprites; TopStackSprite topnode; Xsprite xsprite; StackVarDisplay stackVariables; ListVarDisplay queueVariables; ListManager queuemanager; PointerSprite headPtr, tailPtr, deletePtr, cursorPtr; Graphics offscreen; Image image; int width, height; Constants c; int state, currStruct; Color bgColor; AnimationCanvas( int w, int h, Image img ) { width = w; height = h; setSize( width, height ); image = img; offscreen = image.getGraphics(); bgColor = new Color( 215, 240, 255 ); } public void setStackVariables( StackSprite[] ns, TopStackSprite tns, Xsprite xs, StackVarDisplay svd ) { nSprites = ns; topnode = tns; xsprite = xs; stackVariables = svd; } public void setQueueVariables( ListVarDisplay qvd, ListManager qm ) { queueVariables = qvd; queuemanager = qm; } public void setState( int state, int struct ) { this.state = state; currStruct = struct; repaint(); } public void paint( Graphics g ) { offscreen.setColor( bgColor ); offscreen.fillRect(0, 0, width, height ); offscreen.setColor( new Color( 145, 180, 225 )); offscreen.drawLine( 0, 0, 0, height ); offscreen.drawLine( 1, 1, 1, height ); offscreen.drawLine( 0, 0, width, 0 ); offscreen.drawLine( 1, 1, width, 1 ); if( state == c.DEMO ) { if( currStruct == c.STACK ) { topnode.paint( offscreen ); xsprite.paint( offscreen ); offscreen.setColor( Color.white ); offscreen.fillRect( width - 110, 2, width - 90, 90 ); stackVariables.paint( offscreen ); for( int i = 0; i < nSprites.length; i++ ) nSprites[i].paint( offscreen ); } else if( currStruct == c.QUEUE || currStruct == c.LINKLIST ) { offscreen.setColor( Color.white ); offscreen.fillRect( width - 120, 2, width - 120, 75 ); queueVariables.paint( offscreen ); queuemanager.paintQueue( offscreen ); } } else if( state == c.QUIZ ) { String selftest = "Self Test"; String structStr = "new"; offscreen.setColor( Color.black ); offscreen.setFont( new Font( "SansSerif", Font.BOLD, 16 )); if( currStruct == c.STACK ) structStr = "Stack"; else if( currStruct == c.QUEUE ) structStr = "Queue"; else if( currStruct == c.LINKLIST ) structStr = "Linked List"; int xpos = centerString( offscreen, structStr ); offscreen.drawString( structStr, xpos, 90 ); xpos = centerString( offscreen, selftest ); offscreen.drawString( selftest, xpos, 120 ); } g.drawImage( image, 0, 0, this ); } public int centerString( Graphics g, String str ) { Dimension d = this.getSize(); FontMetrics fm = g.getFontMetrics(); int width = fm.stringWidth( str ); int pos = (d.width - width)/2; return pos; } public void update(Graphics g ){ paint(g); } } // canvas which displays memory allocation class MemoryCanvas extends Canvas { MemorySprite blocks[]; boolean posBlocks = false; boolean posTitle = false; Font font12; int titlePos; int width, height; String title; Image image; Graphics offscreen; // constructor MemoryCanvas( int w, int h, Image img, MemorySprite[] ms ) { width = w; height = h; setSize( width, height ); image = img; blocks = ms; offscreen = image.getGraphics(); font12 = new Font( "SansSerif", Font.BOLD, 12 ); title = new String( "Memory Allocation" ); } public int positionTitle( Graphics g, String str ) { Dimension d = this.getSize(); g.setFont( font12 ); FontMetrics fm = g.getFontMetrics(); int width = fm.stringWidth( str ); int pos = (d.width - width)/2; posTitle = true; return pos; } public void paint(Graphics g) { if( !posTitle ) titlePos = positionTitle( g, title ); offscreen.setColor( new Color( 0, 20, 110 ) ); offscreen.fillRect( 0, 0, width, height ); offscreen.setFont( font12 ); offscreen.setColor( Color.white ); offscreen.drawString( title, titlePos, 13 ); for( int i = 0; i < blocks.length; i++ ) blocks[i].paint( offscreen ); g.drawImage( image, 0, 0, this ); } public void update(Graphics g ){ paint(g); } } class MemoryManager { private MemorySprite[] mSprite; private MemoryCanvas memCanvas; private int maxMemory, maxStack, memIndex, top; private boolean[] availMemory; public MemoryManager( MemorySprite[] ms ) { mSprite = ms; maxMemory = mSprite.length; availMemory = new boolean[maxMemory]; for( int i = 0; i < maxMemory; i++ ) availMemory[i] = true; } public void positionBlocks( MemoryCanvas mc ) { memCanvas = mc; Dimension d = memCanvas.getSize(); int msHeight = mSprite[0].getHeight(); int msWidth = mSprite[0].getWidth(); int xSpace = (d.width - 2*msWidth)/3; int ySpace = 9; int topLoc = 20; for(int i = 0; i < mSprite.length/2; i++ ) { mSprite[i].setPosition( xSpace, topLoc + i*(ySpace + msHeight)); mSprite[i].setVisible( true ); } for(int i = mSprite.length/2, j = 0; i < mSprite.length; i++, j++ ) { mSprite[i].setPosition( 2*xSpace + msWidth, topLoc + j*(ySpace + msHeight)); mSprite[i].setVisible( true ); } } public void push( String val ) { if( !isFull() ) { memIndex++; top++; mSprite[memIndex].pushed( val ); memCanvas.repaint(); } } public void pop() { if( !isEmpty() ) { mSprite[memIndex].popped(); memIndex--; top--; memCanvas.repaint(); } } public boolean isFull() { if( top == maxStack - 1 ) return true; else return false; } public boolean isEmpty() { if( top == -1 ) return true; else return false; } public void reset() { for( int i = 0; i < mSprite.length; i++ ){ mSprite[i].reset(); availMemory[i] = true; } memCanvas.repaint(); } public void allocate( int numBlocks ) { maxStack = numBlocks; memIndex = (int)( Math.random()*(mSprite.length - maxStack +1)); top = -1; for( int i = memIndex; i < (memIndex + maxStack); i++ ) mSprite[i].setFill( Color.yellow ); memCanvas.repaint(); memIndex -= 1; } public int newSpace() { int index = (int)(Math.random()*( mSprite.length )); while( !availMemory[index] ) index = (int)(Math.random()*( mSprite.length )); availMemory[index] = false; mSprite[index].popped(); memCanvas.repaint(); return index; } public void clearSpace( int index ) { availMemory[index] = true; mSprite[index].reset(); memCanvas.repaint(); } public void setValue( int index, int value ) { mSprite[index].pushed( "" + value ); memCanvas.repaint(); } } // class tracks state of queue or linked list and controls animated sprites class ListManager { private int size, maxQueue, maxMemory; private QueueSprite firstNode, lastNode, newNode; private MemorySprite[] mSprite; private ListVarDisplay queueVariables; private DataStructure parent; private AnimationCanvas animateCv; private int topLimit, bottomLimit, leftLimit, rightLimit, space, arrowLength, qsWidth; private PointerSprite headPtr, tailPtr, deletePtr, cursorPtr, startPtr; private boolean animateFlag = true; private Constants c; private int struct; public ListManager( MemorySprite[] ms, ListVarDisplay qvd, DataStructure ds ) { size = 0; maxQueue = 6; mSprite = ms; queueVariables = qvd; parent = ds; maxMemory = mSprite.length; space = 18; arrowLength = 20; firstNode = lastNode = null; headPtr = new PointerSprite( "Head", true, true, arrowLength ); headPtr.setAnimation( animateFlag ); headPtr.setVisible( true ); tailPtr = new PointerSprite( "Rear", false, true, arrowLength ); tailPtr.setAnimation( animateFlag ); tailPtr.setVisible( true ); deletePtr = new PointerSprite( "Remove", false, false, arrowLength ); deletePtr.setAnimation( animateFlag ); cursorPtr = new PointerSprite( "Cursor", true, false, arrowLength ); cursorPtr.setAnimation( animateFlag ); startPtr = new PointerSprite( "Start", true, false, arrowLength ); startPtr.setAnimation( animateFlag ); newNode = new QueueSprite(); newNode.setAnimation( animateFlag ); newNode.setVisible( false ); } public void initialize( AnimationCanvas ac ) { animateCv = ac; animateCv.setQueueVariables( queueVariables, this ); Dimension d = ac.getSize(); QueueSprite tempQS = new QueueSprite(); int qsHeight = tempQS.getHeight(); qsWidth = tempQS.getWidth(); leftLimit = (d.width - (6*qsWidth + 5*space ))/2; // rightLimit = d.width - leftLimit; int margin = 105; topLimit = margin; bottomLimit = topLimit + 4*qsHeight ; headPtr.setPosition( leftLimit, topLimit - arrowLength ); headPtr.setTip( leftLimit, topLimit ); tailPtr.setPosition( leftLimit + qsWidth, topLimit - arrowLength ); tailPtr.setTip( leftLimit + qsWidth, topLimit ); deletePtr.setPosition( leftLimit + qsWidth, topLimit + qsHeight + arrowLength ); deletePtr.setTip( leftLimit, topLimit + qsHeight ); } public void setStructure( int struct ) { this.struct = struct; queueVariables.setStructure( struct ); } public void updateSprites() { boolean busyFlag; do { busyFlag = false; if( size > 0 ) { QueueSprite currentNode = firstNode; while( currentNode != null ) { currentNode.update(); if( currentNode.isAnimating() ) busyFlag = true; currentNode = currentNode.getPointer(); } } headPtr.update(); tailPtr.update(); deletePtr.update(); cursorPtr.update(); newNode.update(); startPtr.update(); if( tailPtr.isAnimating() || headPtr.isAnimating() || deletePtr.isAnimating() || cursorPtr.isAnimating()) busyFlag = true; if( startPtr.isAnimating() || newNode.isAnimating() ) busyFlag = true; parent.pause( parent.getAnimationRate() ); animateCv.repaint(); }while( busyFlag ); } public void travelPointers() { headPtr.travel(); tailPtr.travel(); } public void setAnimation( boolean b ) { animateFlag = b; QueueSprite currentNode = firstNode; while( currentNode != null ) { currentNode.setAnimation( b ); currentNode = currentNode.getPointer(); } headPtr.setAnimation( b ); tailPtr.setAnimation( b ); deletePtr.setAnimation( b ); cursorPtr.setAnimation( b ); startPtr.setAnimation( b ); newNode.setAnimation( b ); } public void moveBack() { QueueSprite currentNode = firstNode; while( currentNode != null ) { currentNode.moveBack(); currentNode = currentNode.getPointer(); } } public void insMoveBack() { if( cursorPtr.getPointer() != lastNode ) { QueueSprite currentNode = cursorPtr.getPointer().getPointer(); currentNode.setArrowBase( cursorPtr.getPointer() ); currentNode.setDynaArrow1( true ); tailPtr.travel(); while( currentNode != null ) { currentNode.moveBack(); currentNode = currentNode.getPointer(); } } } public void threadInNode() { QueueSprite tempNode = new QueueSprite(); tempNode.setAnimation( animateFlag ); tempNode.setLimits( topLimit, bottomLimit, leftLimit, rightLimit, space ); tempNode.setValue( newNode.getValue() ); tempNode.setMemIndex( newNode.getMemIndex() ); Point2D p = newNode.getPosition(); tempNode.setPosition( p.x, p.y ); newNode.setVisible( false ); tempNode.setIsPointedTo( true ); if( cursorPtr.getPointer() == lastNode ){ lastNode = tempNode; tempNode.showPointerNull( true ); } else{ cursorPtr.getPointer().getPointer().setIsPointedTo( true ); tempNode.setPointer( cursorPtr.getPointer().getPointer() ); } cursorPtr.getPointer().setPointer( tempNode ); animateCv.repaint(); } public void pointToStart() { newNode.setArrowBase( cursorPtr.getPointer() ); newNode.setIsPointedTo( true ); newNode.setPointer( cursorPtr.getPointer() ); newNode.setDynaArrow1( true ); cursorPtr.getPointer().showPointerNull( false ); if( cursorPtr.getPointer() != lastNode ){ cursorPtr.getPointer().getPointer().setDynaArrow1( false ); cursorPtr.getPointer().getPointer().setIsPointedTo( false ); } moveStartUp(); } public void setStartPointer() { if( cursorPtr.getPointer() != lastNode ) { newNode.setPointer( cursorPtr.getPointer().getPointer() ); newNode.showPointerNull( false ); newNode.setArrowBase2( cursorPtr.getPointer().getPointer() ); newNode.setDynaArrow2( true ); animateCv.repaint(); } } public void moveForward() { QueueSprite currentNode = firstNode; while( currentNode != null ) { currentNode.moveForward(); currentNode = currentNode.getPointer(); } } public boolean delIterate() { if( (cursorPtr.getPointer()).getPointer() == lastNode ) return true; else cursorPtr.advance(); animateCv.repaint(); return false; } public boolean insIterate() { if( (cursorPtr.getPointer()).getPointer() == null || newNode.getValue() <= ((cursorPtr.getPointer()).getPointer()).getValue()) return true; else cursorPtr.advance(); animateCv.repaint(); return false; } public void setEmpty() { headPtr.setNull( true ); tailPtr.setNull( true ); animateCv.repaint(); } public void setDeletePtr(){ deletePtr.setVisible( true ); if( struct == c.QUEUE ) deletePtr.initPointer( firstNode ); else if( struct == c.LINKLIST ) deletePtr.initPointer( lastNode ); deletePtr.setNull( false ); animateCv.repaint(); } public void setCursorPtr(){ cursorPtr.setVisible( true ); cursorPtr.initPointer( firstNode ); cursorPtr.setNull( false ); animateCv.repaint(); } public void reset() { size = 0; firstNode = lastNode = null; headPtr.setPosition( leftLimit, topLimit - arrowLength ); headPtr.setTip( leftLimit, topLimit ); headPtr.setNull( true ); tailPtr.setPosition( leftLimit + qsWidth, topLimit - arrowLength ); tailPtr.setTip( leftLimit + qsWidth, topLimit ); tailPtr.setNull( true ); deletePtr.setVisible( false ); cursorPtr.setVisible( false ); startPtr.setVisible( false ); newNode.reset(); } public void enqueue() { if( size == 0 ){ firstNode = new QueueSprite(); firstNode.setPosition( leftLimit, topLimit ); firstNode.setLimits( topLimit, bottomLimit, leftLimit, rightLimit, space ); headPtr.setPointer( firstNode ); headPtr.setNull( false ); firstNode.setPointer( null ); firstNode.setAnimation( animateFlag ); lastNode = firstNode; } else { lastNode.setPointer( new QueueSprite() ); lastNode.showPointerNull( false ); lastNode = lastNode.getPointer(); lastNode.setAnimation( animateFlag ); int xpos = leftLimit + size*(qsWidth + space ); lastNode.setPosition( xpos, topLimit ); lastNode.setLimits( topLimit, bottomLimit, leftLimit, rightLimit, space ); lastNode.setPointer( null ); lastNode.setIsPointedTo( true ); } size++; animateCv.repaint(); } public int dequeue() { QueueSprite tempNode = firstNode; int index = (deletePtr.getPointer()).getMemIndex(); firstNode = firstNode.getPointer(); if( size > 1 ) firstNode.setIsPointedTo( false ); tempNode = null; deletePtr.setNull( true ); size--; animateCv.repaint(); return index; } public int delete() { QueueSprite tempNode = lastNode; int index = (deletePtr.getPointer()).getMemIndex(); if( size > 1 ){ QueueSprite currentNode = firstNode; while( currentNode.getPointer() != lastNode ) currentNode = currentNode.getPointer(); lastNode = currentNode; } lastNode.setPointer( null ); if( tempNode == newNode ) newNode.setVisible( false ); tempNode = null; deletePtr.setNull( true ); size--; animateCv.repaint(); return index; } public boolean startIsLast() { if( size == 1 || tailPtr.getPointer() != lastNode ) //( newNode == lastNode ) return true; else return false; } public boolean compare() { boolean result = true; if( size > 0 ) if( newNode.getValue() >= headPtr.getPointer().getValue() ) result = false; return result; } public void moveStartUp() { newNode.moveUp(); startPtr.travel(); animateCv.repaint(); } public void positionStart() { Point2D p = cursorPtr.getPointer().getPosition(); newNode.preInsert( p ); startPtr.travel(); animateCv.repaint(); } public void pointToHead() { firstNode.setIsPointedTo( true ); newNode.showPointerNull( false ); } public void headEqualStart() { if( size == 1 ) setHead(); else{ newNode.setPointer( firstNode ); firstNode = newNode; headPtr.setPointer( firstNode ); headPtr.retreat(); } } public void createStart() { newNode = new QueueSprite(); newNode.setPosition( leftLimit, bottomLimit ); newNode.setLimits( topLimit, bottomLimit, leftLimit, rightLimit, space ); newNode.setVisible( true ); newNode.setAnimation( animateFlag ); size++; if( size == 1 ){ firstNode = newNode; lastNode = firstNode; headPtr.setPointer( firstNode ); tailPtr.setPointer( lastNode ); } startPtr.initPointer( newNode ); startPtr.setNull( false ); startPtr.setVisible( true ); animateCv.repaint(); } public void showXvariable( String x ) { queueVariables.setX( x ); animateCv.repaint(); } public void showXvariable() { queueVariables.setX( "" + (deletePtr.getPointer()).getValue() ); animateCv.repaint(); } public void showSuccess() { queueVariables.setSuccess( true ); animateCv.repaint(); } public void setData( int index, int num ) { if( struct == c.QUEUE ){ lastNode.setMemIndex( index ); lastNode.setValue( num ); } else if( struct == c.LINKLIST ){ newNode.setMemIndex( index ); newNode.setValue( num ); } animateCv.repaint(); } public void setHead() { headPtr.setPointer( firstNode ); headPtr.setNull( false ); } public void advanceHead() { headPtr.advance(); animateCv.repaint(); } public void setTail() { if( size == 1 ) tailPtr.setPointer( lastNode ); else tailPtr.advance(); tailPtr.setNull( false ); animateCv.repaint(); } public void retreatTail() { if( size == 1 ) tailPtr.setPointer( firstNode ); else{ tailPtr.setPointer( cursorPtr.getPointer() ); tailPtr.retreat(); } tailPtr.setNull( false ); animateCv.repaint(); } public void setLastNull() { lastNode.showPointerNull( true ); animateCv.repaint(); } public void setStartNull() { newNode.showPointerNull( true ); animateCv.repaint(); } public void setNewLastNull() { (cursorPtr.getPointer()).showPointerNull( true ); lastNode.setIsPointedTo( false ); animateCv.repaint(); } public void setSizeVariable( ) { queueVariables.setSize( size ); animateCv.repaint(); } public void functionReset() { queueVariables.beginSettings(); deletePtr.setVisible( false ); cursorPtr.setVisible( false ); startPtr.setVisible( false ); animateCv.repaint(); } public void paintQueue( Graphics g ) { if( size > 0 ) { QueueSprite currentNode = firstNode; while( currentNode != null ) { currentNode.paint( g ); currentNode = currentNode.getPointer(); } } headPtr.paint( g ); tailPtr.paint( g ); deletePtr.paint( g ); cursorPtr.paint( g ); startPtr.paint( g ); newNode.paint( g ); } public boolean isFull() { if( size == maxQueue ) { queueVariables.setSuccess( false ); animateCv.repaint(); return true; } else return false; } public int getSize() { return size; } public boolean isEmpty() { if( size == 0 ) { queueVariables.setSuccess( false ); animateCv.repaint(); return true; } else return false; } } // class tracks state of queue or linked list and controls animated sprites class StackManager { private int top, maxNodes, maxMemory, memIndex; private DataStructure parent; private StackSprite[] nSprite; private MemorySprite[] mSprite; private TopStackSprite topSprite; private Xsprite xsprite; private StackVarDisplay stackVariables; private AnimationCanvas animateCv; public StackManager( DataStructure ds, StackSprite[] ns, MemorySprite[] ms, TopStackSprite tns, Xsprite xs, StackVarDisplay vd ) { top = -1; parent = ds; nSprite = ns; mSprite = ms; topSprite = tns; xsprite = xs; stackVariables = vd; maxNodes = nSprite.length; maxMemory = mSprite.length; } public void initializeNodes( AnimationCanvas ac ) { animateCv = ac; Dimension d = ac.getSize(); int nsHeight = nSprite[0].getHeight(); int nsWidth = nSprite[0].getWidth(); int startY = (d.height - nsHeight)/2; int stackX = (d.width - 2*nsWidth)/6; int startX = 4*stackX - nsWidth/2; int bottomY = d.height -10; topSprite.setPosition( stackX, bottomY ); xsprite.setPositions( startX, startY, stackX, bottomY ); stackVariables.setCanvasSize( ac ); Color bkgrd = ac.getBackground(); for( int i = 0; i < nSprite.length; i++ ) { nSprite[i].setPositions( startX, startY, stackX, bottomY ); nSprite[i].setBackground( bkgrd ); } } public void updateSprites() { boolean busyFlag; do { busyFlag = false; for(int i = 0; i < nSprite.length; i++ ) { nSprite[i].update(); if( nSprite[i].isAnimating() ) busyFlag = true; } xsprite.update(); if( xsprite.isAnimating() ) busyFlag = true; parent.pause( parent.getAnimationRate() ); animateCv.repaint(); }while( busyFlag ); } public void updateTop() { boolean busyFlag; do { busyFlag = false; topSprite.update(); if( topSprite.isAnimating() ) busyFlag = true; parent.pause( parent.getAnimationRate() ); animateCv.repaint(); }while( busyFlag ); } public void reset() { for( int i = 0; i < nSprite.length; i++ ) nSprite[i].reset(); topSprite.reset(); top = -1; } public void functionReset() { stackVariables.beginSettings(); animateCv.repaint(); } public void showXvariable( String x ) { stackVariables.setX( x ); animateCv.repaint(); } public void showItemsTop() { if( top != -1 ) stackVariables.setItemsTop( nSprite[top].getValue() ); else stackVariables.setShowItems( false ); animateCv.repaint(); } public void showSuccess() { stackVariables.setSuccess( true ); animateCv.repaint(); } public void incrementTop() { topSprite.topPlusPlus(); } public void pushTopVariable() { stackVariables.setTop( top + 1 ); animateCv.repaint(); } public void popTopVariable() { stackVariables.setTop( top ); animateCv.repaint(); } public void decrementTop() { topSprite.topMinusMinus(); } public String retrieve() { String result = ""; if( !isEmpty() ) { result = nSprite[top].getValue(); xsprite.retrieve( top, result ); } return result; } public void push( String val ) { if( !isFull() ) { top++; nSprite[top].pushed( val, top ); } } public String pop( ) { String result = ""; if( !isEmpty() ) { result = nSprite[top].getValue(); nSprite[top].popped( ); top--; } return result; } public void setAnimation( boolean b ) { topSprite.setAnimation( b ); xsprite.setAnimation( b ); for( int i = 0; i < nSprite.length; i++ ) nSprite[i].setAnimation( b ); } public boolean isFull() { if( top == nSprite.length - 1 ) { stackVariables.setSuccess( false ); animateCv.repaint(); return true; } else return false; } public boolean isEmpty() { if( top == -1 ) { stackVariables.setSuccess( false ); animateCv.repaint(); return true; } else return false; } } // class that displays dialog box with animation and sound controls class OptionsDialog extends Frame implements ItemListener, AdjustmentListener { private Scrollbar animationSb, scrollRateSb; private DataStructure parent; private StackManager stackmanager; private Checkbox soundCb, animationCb; private GridBagLayout gbLayout; private GridBagConstraints gbc; private Label animationSlowLbl, animationFastLbl; public OptionsDialog( DataStructure a, StackManager sm, int anRate, int scRate, String title ) { super( title ); addWindowListener( new WL() ); parent = a; stackmanager = sm; soundCb = new Checkbox( "Sound" ); soundCb.addItemListener( this ); soundCb.setState( true ); animationCb = new Checkbox( "Animation" ); animationCb.addItemListener( this ); animationCb.setState( true ); Label animationRateLbl = new Label( "Animation speed" ); animationSlowLbl = new Label( "Slow" ); animationFastLbl = new Label( "Fast", Label.RIGHT ); Label scrollRateLbl = new Label( "Scroll speed" ); Label scrollSlowLbl = new Label( "Slow" ); Label scrollFastLbl = new Label( "Fast", Label.RIGHT ); animationSb = new Scrollbar( Scrollbar.HORIZONTAL, 80-anRate, 10, 0, 80 ); animationSb.addAdjustmentListener( this ); scrollRateSb = new Scrollbar( Scrollbar.HORIZONTAL, 3000-scRate, 355, 0, 3000 ); scrollRateSb.addAdjustmentListener( this ); gbLayout = new GridBagLayout(); gbc = new GridBagConstraints(); Panel p = new Panel(); p.setLayout( gbLayout ); gbc.anchor = gbc.WEST; parent.addComponent( p, soundCb, gbc, 0, 0, 1, 1 ); parent.addComponent( p, animationCb, gbc, 1, 0, 1, 1 ); parent.addComponent( p, animationRateLbl, gbc, 2, 0, 1, 1 ); parent.addComponent( p, animationSlowLbl, gbc, 3, 0, 1, 1 ); parent.addComponent( p, animationFastLbl, gbc, 3, 1, 1, 1 ); gbc.fill = GridBagConstraints.HORIZONTAL; parent.addComponent( p, animationSb, gbc, 4, 0, 2, 1 ); gbc.insets = new Insets( 15, 0, 0, 0 ); parent.addComponent( p, scrollRateLbl, gbc, 5, 0, 1, 1 ); gbc.insets = new Insets( 0, 0, 0, 0 ); parent.addComponent( p, scrollSlowLbl, gbc, 6, 0, 1, 1 ); parent.addComponent( p, scrollFastLbl, gbc, 6, 1, 1, 1 ); parent.addComponent( p, scrollRateSb, gbc, 7, 0, 2, 1 ); add( p, BorderLayout.CENTER ); } public class WL extends WindowAdapter // user can close help frame { public void windowClosing( WindowEvent e ) { setVisible( false ); } } public void itemStateChanged( ItemEvent e ) { if( animationCb.getState() ) { animationSb.setEnabled( true ); animationSlowLbl.setEnabled( true ); animationFastLbl.setEnabled( true ); parent.setAnimation( true ); } else { animationSb.setEnabled( false ); animationSlowLbl.setEnabled( false ); animationFastLbl.setEnabled( false ); parent.setAnimation( false ); } if( soundCb.getState() ) { parent.setSound( true ); } else { parent.setSound( false ); } } public void adjustmentValueChanged( AdjustmentEvent ae ) { if( ae.getSource() == animationSb ) { parent.setAnimationRate( 80 - ae.getValue() ); } if( ae.getSource() == scrollRateSb ) { parent.setScrollRate( 2825 - ae.getValue() ); parent.showStatus( "" + ae.getValue()); } } } // class that controls stack variable list on animated canvas class StackVarDisplay { Constants c; int state; String maxEqual = "MaxStack = "; String topEqual = "Top = "; String itemsTopStr = "Items[Top]"; String equal = " = "; String xStr = "X"; String successStr = "Success"; String successVal; int maxStack; int top = -1; String topStr = "-1"; String itemsTop; String x; int leftMargin, topMargin, lineSpace, currentY; int canvasWidth; private Font font12b; private boolean firstPaint, showItems, showX, showSuccess; public StackVarDisplay( int maxStack ) { this.maxStack = maxStack; font12b = new Font( "SanSerif", Font.BOLD, 12 ); firstPaint = true; showItems = false; showX = false; showSuccess = false; } public void setCanvasSize( AnimationCanvas ac ) { Dimension d = ac.getSize(); canvasWidth = d.width; } public void reset() { showItems = false; showX = false; showSuccess = false; top = -1; } public void setSpacing( Graphics g ) { g.setFont( font12b ); FontMetrics fm = g.getFontMetrics(); leftMargin = canvasWidth - fm.stringWidth( itemsTopStr + equal + "XXX" ); lineSpace = fm.getMaxAscent() + 3; topMargin = lineSpace + 4; firstPaint = false; } public void beginSettings() { showItems = false; showX = false; showSuccess = false; } public void setX( String num ) { x = num; showX = true; } public void setTop( int num ) { top = num; } public void setItemsTop( String num ) { itemsTop = num; showItems =true; } public void setShowItems( boolean b ) { showItems = b; } public void setSuccess( boolean b ) { if( b ) successVal = "True"; else successVal = "False"; showSuccess = true; } public void paint( Graphics g ) { Color fadeColor = new Color( 200, 200, 200 ); g.setColor( Color.black ); if( firstPaint ) setSpacing( g ); else g.setFont( font12b ); currentY = topMargin; g.drawString( maxEqual + maxStack, leftMargin, topMargin ); g.drawString( topEqual + top, leftMargin, currentY += lineSpace ); if( !showItems ){ g.setColor( fadeColor); g.drawString( itemsTopStr, leftMargin, currentY += lineSpace ); } else{ g.setColor( Color.black ); g.drawString( itemsTopStr + equal + itemsTop, leftMargin, currentY += lineSpace ); } if( !showX ){ g.setColor( fadeColor ); g.drawString( xStr, leftMargin, currentY += lineSpace ); } else{ g.setColor( Color.black ); g.drawString( xStr + equal + x, leftMargin, currentY += lineSpace ); } if( !showSuccess ){ g.setColor( fadeColor ); g.drawString( successStr, leftMargin, currentY += lineSpace ); } else{ g.setColor( Color.black ); g.drawString( successStr + equal + successVal, leftMargin, currentY += lineSpace ); } } } // class that controls linked list or queue variable list on animated canvas class ListVarDisplay { Constants c; int state; String maxQEqual = "MaxQueue = "; String maxListEqual = "MaxList = "; String sizeEqual = "Size = "; String equal = " = "; String xStr = "X"; String successStr = "Success"; String successVal; int maxQueue; int size = 0; String sizeStr = "0"; String x; int leftMargin, topMargin, lineSpace, currentY; int canvasWidth; private Font font12b; private boolean firstPaint, showX, showSuccess; private int struct; public ListVarDisplay( int maxQ ) { maxQueue = maxQ; font12b = new Font( "SanSerif", Font.BOLD, 12 ); firstPaint = true; showX = false; showSuccess = false; } public void setCanvasSize( AnimationCanvas ac ) { Dimension d = ac.getSize(); canvasWidth = d.width; } public void setSpacing( Graphics g ) { g.setFont( font12b ); FontMetrics fm = g.getFontMetrics(); leftMargin = canvasWidth - fm.stringWidth( successStr + equal + "false" + "XX" ); lineSpace = fm.getMaxAscent() + 3; topMargin = lineSpace + 4; firstPaint = false; } public void setStructure( int struct ) { this.struct = struct; } public void reset() { showX = false; showSuccess = false; size = 0; } public void beginSettings() { showX = false; showSuccess = false; } public void setX( String num ) { x = num; showX = true; } public void setSize( int num ) { size = num; } public void setSuccess( boolean b ) { if( b ) successVal = "True"; else successVal = "False"; showSuccess = true; } public void paint( Graphics g ) { Color fadeColor = new Color( 200, 200, 200 ); g.setColor( Color.black ); if( firstPaint ) setSpacing( g ); else g.setFont( font12b ); currentY = topMargin; if( struct == c.QUEUE ) g.drawString( maxQEqual + maxQueue, leftMargin, topMargin ); else if( struct == c.LINKLIST ) g.drawString( maxListEqual + maxQueue, leftMargin, topMargin ); g.drawString( sizeEqual + size, leftMargin, currentY += lineSpace ); if( !showX ){ g.setColor( fadeColor ); g.drawString( xStr, leftMargin, currentY += lineSpace ); } else{ g.setColor( Color.black ); g.drawString( xStr + equal + x, leftMargin, currentY += lineSpace ); } if( !showSuccess ){ g.setColor( fadeColor ); g.drawString( successStr, leftMargin, currentY += lineSpace ); } else{ g.setColor( Color.black ); g.drawString( successStr + equal + successVal, leftMargin, currentY += lineSpace ); } } } // base class for animated elements abstract class Sprite { protected boolean visible; protected int xpos, ypos; abstract void paint( Graphics g ); abstract void update(); public void setPosition( int x, int y ) { xpos = x; ypos = y; } public int getXposition() { return xpos; } public int getYposition() { return ypos; } public void setVisible( boolean b ) { visible = b; } public boolean getVisible() { return visible; } } // class for animated top stack element class TopStackSprite extends Sprite { static final int IN_PLACE = 0; static final int MOVE_UP = 1; static final int MOVE_DOWN = 2; static final int ON_BOTTOM = 3; private int state; private int width = 60, height = 18; private int stackX, bottomStackY, topStackY; private int top, vy; private boolean animateFlag, inMotionFlag = false; private Font font13b; public TopStackSprite() { vy = 1; animateFlag = true; top = -1; state = ON_BOTTOM; font13b = new Font( "SanSerif", Font.BOLD, 13 ); } public void setPosition( int stackX, int botY ) { this.stackX = xpos = stackX; bottomStackY = topStackY = ypos = botY - height; } public void reset() { xpos = stackX; ypos = bottomStackY; top = -1; state = ON_BOTTOM; } public void update() { switch( state ) { case ON_BOTTOM: inMotionFlag = false; break; case MOVE_UP: if( ypos == topStackY ) state = IN_PLACE; else ypos-= vy; break; case MOVE_DOWN: if( ypos == topStackY ) state = IN_PLACE; else ypos += vy; if( ypos == bottomStackY ) state = ON_BOTTOM; break; case IN_PLACE: inMotionFlag = false; break; } } public void topPlusPlus() { inMotionFlag = true; top++; topStackY = bottomStackY - top*height; if( animateFlag ) { state = MOVE_UP; } else { ypos = topStackY; state = IN_PLACE; } } public void topMinusMinus() { inMotionFlag = true; if( --top != -1 ) topStackY = bottomStackY - top*height; if( animateFlag ) { state = MOVE_DOWN; } else { state = IN_PLACE; ypos = topStackY; } } public void setAnimation( boolean b ) { animateFlag = b; } public boolean isAnimating() { return inMotionFlag; } public void paint( Graphics g ) { if( top != -1 ) { g.setColor( Color.yellow ); g.setFont( font13b ); g.fillRect( xpos, ypos, width + 1, height + 1 ); g.setColor( Color.black ); g.drawString( "Top:", xpos - 35, ypos + 13 ); g.drawRect( xpos, ypos, width, height); } } } // class for animated "X" used with stack class Xsprite extends Sprite { final int MOVE_UP = 1; final int MOVE_RIGHT = 2; final int MOVE_DOWN = 3; final int ON_STACK = 4; final int END = 0; private Font font10b; private int width = 60, height = 18, vx, vy; private int state, index, endX, endY, stackX, bottomStackY; private boolean inMotionFlag = false, animateFlag = true; private String xEquals = "X = ", value, showStr; public Xsprite() { state = ON_STACK; vx = 2; vy = 2; font10b = new Font( "SansSerif", Font.BOLD, 10 ); } public void setPositions( int endX, int endY, int stackX, int botY ) { this.endX = endX; this.endY = endY; this.stackX = stackX; bottomStackY = botY; } public void retrieve( int index, String value ) { if( animateFlag ) { inMotionFlag = true; xpos = stackX; ypos = bottomStackY - (index + 1)*height; state = MOVE_RIGHT; this.value = value; } } public void update() { switch( state ) { case END: inMotionFlag = false; break; case MOVE_UP: if( ypos <= endY ) state = END; else ypos-=vy; break; case MOVE_RIGHT: if( xpos == endX ) { if( ypos < endY ) state = MOVE_DOWN; else if( ypos > endY ) state = MOVE_UP; else state = END; } else if( xpos + vx >= endX ) xpos = endX; else xpos+=vx; break; case MOVE_DOWN: if( ypos == endY ) state = END; else if( ypos + vy >= endY ) ypos = endY; else ypos+=vy; break; case ON_STACK: inMotionFlag = false; break; } } public void setAnimation( boolean b ) { animateFlag = b; } public boolean isAnimating() { return inMotionFlag; } public void paint( Graphics g ) { if(( state != END )&&( state != ON_STACK )) { g.setColor( Color.black ); g.drawRect( xpos, ypos, width, height); Font oldFont = g.getFont(); g.setFont( font10b ); showStr = xEquals + value; FontMetrics fm = g.getFontMetrics(); int valWidth = fm.stringWidth( showStr ); int pos = ( width - valWidth)/2; g.drawString( showStr, xpos + pos, ypos + height - 5 ); g.setFont( oldFont ); } } } class Point2D { public int x, y; public Point2D( int x, int y ) { this.x = x; this.y = y; } } // class used to draw arrow class Arrow { int originX, originY; double xtip, ytip, length = 3, width = 3; public void draw( Graphics g, int x, int y, int xt, int yt ) { g.setColor( Color.black ); g.drawLine( x, y, xt, yt ); double hypot, theta, ax, ay, bx, by, cx, cy, piOver2; originX = x; originY = y; xtip = (double)xt; ytip = (double)yt; piOver2 = Math.PI/2; hypot = Math.sqrt( ( xtip - originX )*( xtip - originX ) + ( ytip - originY )*( ytip - originY ) ) - length; theta = Math.atan( ( originY - ytip )/( xtip - originX ) ); if( xtip >= originX ) { ax = hypot*Math.cos( theta ) + originX; ay = originY - hypot*Math.sin( theta ); } else { ax = originX - hypot*Math.cos( theta ); ay = originY + hypot*Math.sin( theta ); } bx = ax + width*Math.cos( piOver2 - theta ); cx = ax - width*Math.cos( piOver2 - theta ); by = ay + width*Math.sin( piOver2 - theta ); cy = ay - width*Math.sin( piOver2 - theta ); int headx1, heady1, headx2, heady2; headx1 = Math.round( (float)bx ); heady1 = Math.round( (float)by ); headx2 = Math.round( (float)cx ); heady2 = Math.round( (float)cy ); Polygon head = new Polygon(); head.addPoint( xt, yt ); head.addPoint( headx1, heady1 ); head.addPoint( headx2, heady2 ); g.fillPolygon( head ); } } // class used for animated nodes of linked list or queue class QueueSprite extends Sprite { static final int MOVE_FORWARD = 0; static final int ZIG_UP = 1; static final int MOVE_BACK = 2; static final int ZIG_DOWN = 3; static final int STOPPED = 4; static final int MOVE_UP = 5; static final int PRE_INSERT = 6; private int state; private int value; private Font font10b; private int width = 40, height = 16, divider, memIndex; private int leftLimit, rightLimit, topLimit, bottomLimit; private int vx, vy, gap, newX, newY, arrowBaseX, arrowBaseY, arrowBase2X, arrowBase2Y; private boolean animateFlag, inMotionFlag = false, ptrIsNull = false, isData = false, isPointedTo = false, dynaArrow1 = false, dynaArrow2 = false; private QueueSprite next; private Arrow arrow1, arrow2; public QueueSprite() { divider = width - height; font10b = new Font( "SansSerif", Font.BOLD, 10 ); next = null; vx = vy = 2; visible = true; animateFlag = true; state = STOPPED; arrow1 = new Arrow(); arrow2 = new Arrow(); } public void reset() { isData = false; isPointedTo = false; ptrIsNull = false; visible = false; } public void setAnimation( boolean b ) { animateFlag = b; } public void setDynaArrow1( boolean b) { dynaArrow1 = b; } public void setDynaArrow2( boolean b) { dynaArrow2 = b; } public void setArrowBase( QueueSprite qs ) { Point2D p = qs.getPosition(); arrowBaseX = p.x + qs.getWidth(); arrowBaseY = p.y + qs.getHeight()/2; } public void setArrowBase2( QueueSprite qs ) { Point2D p = qs.getPosition(); arrowBase2X = p.x; arrowBase2Y = p.y + qs.getHeight()/2; } public boolean isAnimating() { return inMotionFlag; } public void setIsPointedTo( boolean b ) { isPointedTo = b; } public Point2D getPosition() { Point2D p = new Point2D( xpos, ypos ); return p; } public void moveForward() { if( xpos > leftLimit ){ newX = xpos - width - gap; newY = ypos; } else{ newY = topLimit; newX = rightLimit - width; } if( animateFlag ){ inMotionFlag = true; state = MOVE_FORWARD; } else{ xpos = newX; ypos = newY; } } public void moveBack() { if( xpos < rightLimit ){ newX = xpos + width + gap; newY = ypos; } else{ newY = bottomLimit; newX = leftLimit; } if( animateFlag ){ inMotionFlag = true; state = MOVE_BACK; } else{ xpos = newX; ypos = newY; } } public void preInsert( Point2D p ) { newX = p.x + width + gap; newY = p.y + 2*height; if( animateFlag ){ inMotionFlag = true; state = PRE_INSERT; } else xpos = newX; } public void moveUp() { if( animateFlag ){ inMotionFlag = true; state = MOVE_UP; } else ypos = topLimit; } public void update() { int midLine = (topLimit + bottomLimit)/2; switch( state ) { case STOPPED: inMotionFlag = false; break; case MOVE_BACK: if( xpos == newX ) state = STOPPED; else if( xpos + vx >= newX ) xpos = newX; else xpos+=vx; break; case PRE_INSERT: if( ypos == newY && xpos == newX ) state = STOPPED; if(( ypos - vy <= newY )&&(xpos == newX )) ypos = newY; if( ypos > newY && xpos == newX ) ypos -= vy; if( xpos == newX && ypos - vy < newY ) ypos = newY; else if( xpos + vx >= newX ) xpos = newX; else xpos+=vx; break; case MOVE_FORWARD: if( xpos == newX ) state = STOPPED; else if( xpos - vx <= newX ) xpos = newX; else xpos-=vx; break; case MOVE_UP: if( ypos == topLimit ) state = STOPPED; else if( ypos - vy < topLimit ) ypos = topLimit; else ypos-=vy; break; } } public void setMemIndex( int i ) { memIndex = i; } public int getMemIndex() { return memIndex; } public void setPointer( QueueSprite qs ) { next = qs; } public QueueSprite getPointer() { return next; } public void showPointerNull( boolean b ) { ptrIsNull = b; } public void setLimits( int top, int bot, int left, int right, int gap ) { topLimit = top; bottomLimit = bot; leftLimit = left; rightLimit = right; this.gap = gap; } public void setValue( int val ) { value = val; isData = true; } public int getValue() { return value; } public int getWidth() { return width; } public int getHeight() { return height; } public void paint( Graphics g ) { if( visible ) { g.setColor( Color.yellow ); g.fillRect( xpos, ypos, width + 1, height + 1 ); g.setColor( Color.black ); g.drawRect( xpos, ypos, width, height); g.drawLine( xpos + divider, ypos, xpos + divider, ypos + height ); if( ptrIsNull ) g.drawLine( xpos + divider, ypos, xpos + width, ypos + height ); if( isData ) { g.setFont( font10b ); FontMetrics fm = g.getFontMetrics(); int valWidth = fm.stringWidth( "" + value ); int pos = ( divider - valWidth)/2 + xpos; g.drawString( "" + value, pos, ypos + height - 5 ); } if( isPointedTo ){ if( dynaArrow1 ) arrow1.draw( g, arrowBaseX, arrowBaseY, xpos, ypos + height/2 ); if( !dynaArrow1 && !dynaArrow2 ) arrow1.draw( g, xpos - gap, ypos + height/2, xpos, ypos + height/2 ); } if( dynaArrow2 ) arrow2.draw( g, xpos + width, ypos + height/2, arrowBase2X, arrowBase2Y ); } } } // class used to create an animated stack element class StackSprite extends Sprite { // node states static final int INIT = 0; static final int FADE_IN = 1; static final int PUSH_UP = 2; static final int PUSH_OVER = 3; static final int PUSH_DOWN = 4; static final int ON_STACK = 5; static final int POP_UP = 6; static final int POP_OVER = 7; static final int POP_DOWN = 8; static final int FADE_OUT = 9; private int state; private String value, shownStr, Xequals = "X = "; private Font font10b; private int width = 60, height = 18; private int startX, startY, stackX, bottomStackY, topStackY, clearanceY, index; private int vx, vy; private int redBkgd, greenBkgd, blueBkgd; private boolean animateFlag, inMotionFlag = false; public StackSprite( String val ) { value = val; xpos = -50; ypos = -50; vx = 2; vy = 2; font10b = new Font( "SansSerif", Font.BOLD, 10 ); state = INIT; clearanceY = (int)( 1.5*height ); animateFlag = true; } public void setAnimation( boolean b ) { animateFlag = b; } public String getValue() { return value; } public int getWidth() { return width; } public int getHeight() { return height; } public void pushed( String val, int index ) { value = val; this.index = index; topStackY = bottomStackY - (index+1 )*height; if( animateFlag ) { inMotionFlag = true; shownStr = Xequals + value; state = PUSH_UP; } else { xpos = stackX; ypos = topStackY; state = ON_STACK; } } public void popped( ) { if( animateFlag ){ shownStr = Xequals + value; inMotionFlag = true; state = POP_UP; } else { state = INIT; xpos = startX; ypos = startY; } } public boolean isAnimating() { return inMotionFlag; } public void setPositions( int x, int y, int stackX, int botY ) { startX = xpos = x; startY = ypos = y; this.stackX = stackX; bottomStackY = botY; } public void setBackground( Color bkgrd ) { Color bkgrdColor = bkgrd; } public void reset() { value = ""; state = INIT; xpos = startX; ypos = startY; inMotionFlag = false; } public void update() { switch( state ) { case INIT: inMotionFlag = false; break; case PUSH_UP: if( ypos <= topStackY - clearanceY ) state = PUSH_OVER; else ypos-=vy; break; case PUSH_OVER: if( xpos == stackX ) state = PUSH_DOWN; else if( xpos - vx <= stackX ) xpos = stackX; else xpos-=vx; break; case PUSH_DOWN: if( ypos == topStackY ) { state = ON_STACK; shownStr = value; } else if( ypos + vy >= topStackY ) ypos = topStackY; else ypos+=vy; break; case POP_UP: if( (ypos <= startY) && (ypos <= topStackY - clearanceY) ) state = POP_OVER; else ypos-=vy; break; case POP_OVER: if( xpos == startX ) state = POP_DOWN; else if( xpos + vx >= startX ) xpos = startX; else xpos+=vx; break; case POP_DOWN: if( ypos == startY ) state = INIT; else if( ypos + vy >= startY ) ypos = startY; else ypos+=vy; break; case ON_STACK: shownStr = value; inMotionFlag = false; break; } } public void paint( Graphics g ) { if( state != INIT ) { if( state == ON_STACK ) { g.setColor( Color.yellow ); g.fillRect( xpos, ypos, width + 1, height + 1 ); } g.setColor( Color.black ); g.drawRect( xpos, ypos, width, height); g.setFont( font10b ); FontMetrics fm = g.getFontMetrics(); int valWidth = fm.stringWidth( shownStr ); int pos = ( width - valWidth)/2; g.drawString( shownStr, xpos + pos, ypos + height - 5 ); } } } // class used to create animated pointers for linked list and queue class PointerSprite extends Sprite { static final int IN_PLACE = 3; static final int ADVANCE = 1; static final int TRAVEL = 2; static final int RETREAT = 4; private int state, vx, vy; private String label; private boolean isNull, isLeft, isAbove, animateFlag, inMotionFlag = false; private int width, height, atipx, atipy, newX, newY, arrowLength; private Font font11b; private Arrow arrow; private QueueSprite pointTo; // private boolean msgFlag = false; int line = 1, updateCount = 1; public PointerSprite( String label, boolean left, boolean above, int len ) { this.label = label; isNull = true; isLeft = left; isAbove = above; font11b = new Font( "SansSerif", Font.BOLD, 11 ); width = height = 7; arrow = new Arrow(); pointTo = null; state = IN_PLACE; arrowLength = len; animateFlag = true; vx = vy = 2; } public void setTip( Point2D point ) { atipx = point.x; atipy = point.y; } public boolean isAnimating() { return inMotionFlag; } public void setAnimation( boolean b ) { animateFlag = b; } public void setTip( int x, int y ) { atipx = x; atipy = y; } public void setNull( boolean b ) { isNull = b; if( b ){ pointTo = null; state = IN_PLACE; } } public void travel() { state = TRAVEL; } public void setPointer( QueueSprite qs ) { pointTo = qs; positionTip(); } public void initPointer( QueueSprite qs ) { setPointer( qs ); xpos = atipx; if( isAbove ) ypos = atipy - arrowLength; else ypos = atipy + arrowLength; } public QueueSprite getPointer() { return pointTo; } public void positionTip() { Point2D pos = pointTo.getPosition(); if( isLeft ) atipx = pos.x; else atipx = pos.x + pointTo.getWidth(); if( isAbove ) atipy = pos.y; else atipy = pos.y + pointTo.getHeight(); } public void advance() { setPointer( pointTo.getPointer() ); if( atipx < xpos ){ xpos = atipx; if( isAbove ) ypos = atipy - arrowLength; else ypos = atipy + pointTo.getHeight(); } newX = atipx; if( animateFlag ){ inMotionFlag = true; state = ADVANCE; } else xpos = newX; } public void retreat() { if( atipx > xpos ){ xpos = atipx; if( isAbove ) ypos = atipy - arrowLength; else ypos = atipy + pointTo.getHeight(); } newX = atipx; if( animateFlag ){ inMotionFlag = true; state = RETREAT; } else xpos = newX; } public void update() { updateCount++; switch( state ) { case IN_PLACE: inMotionFlag = false; break; case ADVANCE: if( xpos == newX ) state = IN_PLACE; else if( xpos + vx >= newX ) xpos = newX; else xpos+=vx; break; case RETREAT: if( xpos == newX ) state = IN_PLACE; else if( xpos - vx <= newX ) xpos = newX; else xpos-=vx; break; case TRAVEL: positionTip(); xpos = atipx; if( isAbove ) ypos = atipy - arrowLength; else ypos = atipy + arrowLength; break; } } public void paint( Graphics g ) { if( visible ) { g.setColor( Color.black ); g.drawRect( xpos - width/2, ypos - height/2, width, height ); if( isNull ) g.drawLine( xpos - width/2, ypos - height/2, xpos + width/2, ypos + height/2 ); else arrow.draw( g, xpos, ypos, atipx, atipy ); g.setFont( font11b ); FontMetrics fm = g.getFontMetrics(); int labelWidth = fm.stringWidth( label ); int pos; if( isLeft ) pos = xpos - width/2 - labelWidth - 4; else pos = xpos + width/2 + 6; g.drawString( label, pos, ypos + height/2 + 2 ); } } } // class used to paint individual memory locations class MemorySprite extends Sprite { // memory states static final int NOT_AVAIL = 0; static final int ALLOCATED = 1; static final int TAKEN = 2; private int state; private String address, value; private Font font9; private int width = 60, height = 16, divider = 40; private int fillRed, fillGreen, fillBlue; private double fadeRed, fadeGreen, fadeBlue, fadeIncRed, fadeIncGreen, fadeIncBlue; private double fadeRate = 20; private Color red, green, yellow, fillColor; public MemorySprite( String addr, String val ) { xpos = -2*width; ypos = -2*height; address = addr; value = val; font9 = new Font( "SansSerif", Font.PLAIN, 9 ); fillRed = 255; fillGreen = 0; fillBlue = 0; fillColor = new Color( fillRed, fillGreen, fillBlue ); red = Color.red; green = Color.green; yellow = Color.yellow; } public void reset() { value = ""; fillColor = red; } public void pushed( String val ) { value = val; fillColor = green; } public void popped() { value = ""; fillColor = yellow; } public void setValue( String val ) { value = val; } public void setPosition( int x, int y ) { xpos = x; ypos = y; } public void setFill( Color fill ) { fillColor = new Color( fill.getRed(),fill.getGreen(), fill.getBlue()); } public int getWidth() { return width; } public int getHeight() { return height; } public void update() { } public void paint( Graphics g ) { if( visible ) { g.setColor( fillColor ); g.fillRect( xpos, ypos, width + 1, height + 1 ); g.setColor( Color.black ); g.drawRect( xpos, ypos, width, height); g.drawLine( xpos + divider, ypos, xpos + divider, ypos + height ); g.setFont( font9 ); FontMetrics fm = g.getFontMetrics(); int valWidth = fm.stringWidth( value ); int pos = ( width - divider - valWidth)/2 + divider + xpos; g.drawString( address, xpos + 5, ypos + height - 5 ); g.drawString( value, pos, ypos + height - 5 ); } } } // class used to organize questions, answers and info for quiz class QuizQuestion { private Vector preDisplay, postDisplay; private String infoStr, questionStr, answerStr[]; private int answer; public QuizQuestion() { answerStr = new String[4]; } public void setInfo( String i ) { infoStr = i.substring( 3, i.length() ); } public void setQuestion( String q ) { questionStr = q.substring( 3, q.length() ); } public void setAnswer( int i, String a ) { answerStr[i] = a.substring( 3, a.length() ); } public void setCorrectAns( int i ) { answer = i - 1; // adjust to zero based index } public String getInfo() { return infoStr; } public String getQuestion() { return questionStr; } public String getAnswer( int i ) { return answerStr[i]; } public int getCorrectAns() { return answer; } } // class controls displaying and scoring quiz for each datastructure class QuizManager implements ActionListener, ItemListener { final int INIT = 0; final int ACTIVE = 1; private int state; private QuizQuestion[] stackQuestions, queueQuestions, listQuestions, currentQuestions; private int numQuest, numStack, numQueue, numList, score, currStruct, currQuest, stackGuesses[], queueGuesses[], listGuesses[], currGuesses[]; private DataStructure parent; private TextArea infoTA, questionTA, answerTA[]; private Checkbox answerBx[]; private CheckboxGroup answerGrp; private Button backBtn, nextBtn, scoreBtn, resetBtn; private Constants c; private String startStr = "Self Test\n\nAnswer each question. When you are " + "finished, click the Score button.\n\nClick the " + "Next button to begin"; private boolean scoreFlag = false; public QuizManager( DataStructure ds, TextArea info, TextArea quest, TextArea[] ansTA, Checkbox[] ansBx, CheckboxGroup cbg ) { parent = ds; infoTA = info; questionTA = quest; answerTA = ansTA; answerBx = ansBx; answerGrp = cbg; score = 0; currQuest = 0; state = INIT; infoTA.setText( startStr ); } public void reset() { state = INIT; score = 0; scoreFlag = false; currQuest = 0; backBtn.setEnabled( false ); nextBtn.setEnabled( true ); clearText(); infoTA.setText( startStr ); answerGrp.setSelectedCheckbox( null ); for( int i = 0; i < numQuest; i++ ) currGuesses[i] = -1; } public void setButtons( Button b, Button n, Button f, Button r ) { backBtn = b; nextBtn = n; scoreBtn = f; resetBtn = r; backBtn.setEnabled( false ); } public void setCurrentStruct( int struct ) { switch( struct ) { case c.STACK: currentQuestions = stackQuestions; numQuest = numStack; currGuesses = stackGuesses; break; case c.QUEUE: currentQuestions = queueQuestions; numQuest = numQueue; currGuesses = queueGuesses; break; case c.LINKLIST: currentQuestions = listQuestions; numQuest = numList; currGuesses = listGuesses; break; } reset(); } public int countQuestions( Vector v ) { int count = 0; int size = v.size(); String line; for( int i = 0; i < size; i++ ) { line = (String)v.elementAt(i); if( line.startsWith("^Q^") ) count++; } return count; } public void initQuiz( int struct, Vector v ) { final int INFO = 0; final int QUEST = 1; final int ANS = 2; final int CORR = 3; int lineType =-1, correct; String question, answer, currentStr = "", infoStr = ""; QuizQuestion[] quizQuestions; int quizGuesses[]; numQuest = countQuestions( v ); quizQuestions = new QuizQuestion[numQuest]; for( int i=0; i < numQuest; i++ ) quizQuestions[i] = new QuizQuestion(); quizGuesses = new int[numQuest]; for( int i = 0; i < quizGuesses.length; i++ ) quizGuesses[i] = -1; int index = -1, answerNum =-1; int size = v.size(); for( int i = 0; i < size; i++ ) { String line = (String)v.elementAt(i); if( line.startsWith("^Q^") ) { answerNum = -1; lineType = QUEST; index++; currentStr = line; } else if( line.startsWith("^I^")) { lineType = INFO; infoStr = line; } else if( line.startsWith("^A^") ) { answerNum++; if(( lineType == QUEST ) || ( lineType == INFO )) quizQuestions[index].setQuestion( currentStr ); else quizQuestions[index].setAnswer(answerNum-1, currentStr ); lineType = ANS; currentStr = line; } else if( !line.startsWith("^") ) { if( lineType == INFO ) infoStr = infoStr + "\n" + line; else currentStr = currentStr + "\n" + line; } else if( line.startsWith("^C^")) { lineType = CORR; quizQuestions[index].setInfo( infoStr ); quizQuestions[index].setAnswer(answerNum, currentStr ); try{ line = line.substring( 3, line.length() ); correct = Integer.parseInt( line ); quizQuestions[index].setCorrectAns( correct ); } catch( NumberFormatException nfe ){ } } } switch( struct ) { case c.STACK: stackQuestions = quizQuestions; stackGuesses = quizGuesses; numStack = numQuest; break; case c.QUEUE: queueQuestions = quizQuestions; queueGuesses = quizGuesses; numQueue = numQuest; break; case c.LINKLIST: listQuestions = quizQuestions; listGuesses = quizGuesses; numList = numQuest; break; } } public void showQuestion( int index ) { questionTA.setText( "Question " + ( currQuest + 1 ) + " of " + numQuest + ":\n" ); questionTA.append( currentQuestions[index].getQuestion() ); infoTA.setText( currentQuestions[index].getInfo() ); for( int i = 0; i < answerBx.length; i++ ) answerTA[i].setText( currentQuestions[index].getAnswer( i ) ); } public void setRadioButtons( int questNum ) { answerGrp.setSelectedCheckbox( null ); if( currGuesses[questNum] != -1 ) answerBx[currGuesses[questNum]].setState( true ); } public void adjustScore( int index ) { int answer = currentQuestions[currQuest].getCorrectAns(); if( currGuesses[currQuest] != index && index == answer ) { score++; } else if( index != answer && currGuesses[currQuest] == answer ) score--; currGuesses[currQuest] = index; } public void actionPerformed( ActionEvent e ) { if( e.getSource() == backBtn ) { if( scoreFlag ) { scoreFlag = false; if( currQuest < numQuest - 1 ) nextBtn.setEnabled( true ); } else{ nextBtn.setEnabled( true ); currQuest--; } setRadioButtons( currQuest ); showQuestion( currQuest ); if( currQuest == 0 ) backBtn.setEnabled( false ); } else if( e.getSource() == nextBtn ) { if( state == INIT ){ showQuestion( 0 ); state = ACTIVE; } else{ backBtn.setEnabled( true ); if( currQuest != numQuest-1 ){ currQuest++; setRadioButtons( currQuest ); showQuestion( currQuest ); } } if( currQuest == numQuest - 1 ) nextBtn.setEnabled( false ); } else if( e.getSource() == scoreBtn ) { clearText(); infoTA.setText( "Score = " + score + " out of " + numQuest + "\n\nClick the Back button to review your answers " + "or click the Reset button to start over."); scoreFlag = true; answerGrp.setSelectedCheckbox( null ); nextBtn.setEnabled( false ); backBtn.setEnabled( true ); if( score == numQuest ) parent.playSound( c.GOOD ); } else if( e.getSource() == resetBtn ) { reset(); } } public void clearText() { infoTA.setText(""); questionTA.setText(""); for( int i = 0; i < 4; i++ ) answerTA[i].setText(""); } public void itemStateChanged( ItemEvent e ) { if( !scoreFlag ) for( int i = 0; i < answerBx.length; i++ ) if( e.getSource() == answerBx[i] ) adjustScore(i); } } // constant values used frequently by differnt classes class Constants { public static final int ERROR = -99; public static final int GOOD = 99; public static final int DEMO = 100; public static final int QUIZ = 200; public static final int RUN = 0; public static final int STEP = 1; public static final int PAUSE =2; public static final int STACK = 10; public static final int QUEUE = 20; public static final int LINKLIST =30; public static final int PUSH = 11; public static final int POP = 12; public static final int RETRIEVE =13; public static final int ENQUEUE = 21; public static final int DEQUEUE = 22; public static final int INSERT = 31; public static final int DELETE = 32; public static final String demo = "demo"; public static final String quiz = "quiz"; public static final String stack = "stack"; public static final String queue = "queue"; public static final String linklist = "linklist"; public static final String push = "push"; public static final String pop = "pop"; public static final String retrieve = "retrieve"; public static final String enqueue = "enqueue"; public static final String dequeue = "dequeue"; public static final String insert = "insert"; public static final String delete = "delete"; }