1 import java.applet.*;
2 import java.awt.*;
3 import java.awt.event.*;
4 import java.lang.Integer;
5 import java.util.Vector;
6
7 /**
8 * Applet to demonstrate Peter's Convenience Store Problem
9 * Creation date: (02/25/2002 10:07:02 AM)
10 * Modified date: (04/15/2002 04:35:00 PM)
11 * @author: Andrew Freed, arf132@psu.edu
12 */
13
14 /*
15 Development of this applet was sponsored by the Penn State Fund for
16 Excellence in Learning and Teaching (FELT), project "Java-based
17 Teaching of Mathematics in Information Sciences and Technology",
18 supervised by Frank Ritter and David Mudgett.
19 */
20
21 public class PetersProblemApplet extends Applet {
22 private Button btnGo = new Button("Go!");
23 private TextArea txtOutput = new TextArea("",11,80,TextArea.SCROLLBARS_VERTICAL_ONLY);
24
25 private Label lblPtrChoice = new Label("Peter:");
26 private Choice ptrChoice = new Choice();
27
28 private Label lblTrainerChoice = new Label("Trainers:");
29 private Choice trnTrainTrainerChoice = new Choice();
30 private Choice trnTrainInstallerChoice = new Choice();
31 private Choice trnInstallChoice = new Choice();
32 private Label lblTrainingTrainers = new Label("Training Trainers");
33 private Label lblTrainingInstallers = new Label("Training Installers");
34 private Label lblInstallers = new Label("Installing");
35
36 private Label lblInstallerChoice = new Label("Installers:");
37 private Choice insChoice = new Choice();
38
39 private Label lblTotalUnits = new Label("Total units:");
40 private TextField txtTotalUnits = new TextField("10");
41 private Label lblNumRemaining = new Label("Units remaining:");
42 private TextField txtNumRemaining = new TextField("?");
43
44 public int numUnitsRemaining; // Units left to be installed
45 public int TOTAL_UNITS_NEEDED; // Initial number of units to install
46 private int numWeek; // Maintain running date
47
48 private int numInstallers; // Peter's workforce
49 private int numTrainers; // Peter's workforce
50 private int numTrainersTrainingTrainers; // How many trainers started training a trainer last week
51
52 private boolean isPeterTrainingTrainer; // Peter can not stop training a trainer to do something else
53 private boolean weekInProgress; // boolean to determine current applet state
54 private boolean doReset; // boolean to determine current applet state
55
56 //Keeps track of whether or not the applet has run.
57 //Else, every pass through init() will create ANOTHER actionListener on btnGo
58 private boolean active = false;
59
60 private Vector myTrainers = new Vector();
61
62 // Training an installer involves updating the global count and inserting into choice box
63 private void addInstaller()
64 {
65 numInstallers++;
66 insChoice.removeAll();
67
68 for( int idx = numInstallers; idx >= 0; idx-- )
69 insChoice.add(new Integer(idx).toString());
70 }
71
72 // Peter training a trainer is a simplified case of a general trainer training a trainer
73 private void addTrainerByPeter()
74 {
75 //If he isn't in the middle of the training process, it must be started
76 if( !isPeterTrainingTrainer )
77 {
78 output("Peter began training a trainer");
79 isPeterTrainingTrainer = true;
80 ptrChoice.setEnabled(false);
81 }
82
83 //Otherwise finish the training process
84 else
85 {
86 output("Peter finished training a trainer");
87 myTrainers.addElement( new Trainer(++numTrainers) );
88 isPeterTrainingTrainer = false;
89 ptrChoice.setEnabled(true);
90 }
91 }
92
93 //Accessor function to retrieve value from choice box
94 private int getNumChosenInstallers()
95 {
96 return Integer.parseInt( insChoice.getSelectedItem() );
97 }
98
99 //Accessor function to retrieve value from choice box
100 private int getNumChosenTrainingTrainers()
101 {
102 return Integer.parseInt( trnTrainTrainerChoice.getSelectedItem() );
103 }
104
105 //Accessor function to retrieve value from choice box
106 private int getNumChosenTrainingInstallers()
107 {
108 return Integer.parseInt( trnTrainInstallerChoice.getSelectedItem() );
109 }
110
111 //Accessor function to retrieve value from choice box
112 private int getNumChosenTrainerInstallers()
113 {
114 return Integer.parseInt( trnInstallChoice.getSelectedItem() );
115 }
116
117 //Sets available choices for the trainer boxes. Note that trainers currently training
118 // other trainers are NOT available to do new tasks the following week.
119 private void setTrainerChoiceBoxes()
120 {
121 int numUnavailable = numTrainersTrainingTrainers; //getNumChosenTrainingTrainers();
122 trnTrainTrainerChoice.removeAll();
123 trnTrainInstallerChoice.removeAll();
124 trnInstallChoice.removeAll();
125
126 //This creates a list from the top down, the maximal number is the "default" choice
127 for( int idx = numTrainers - numUnavailable; idx >= 0; idx-- )
128 {
129
130 trnTrainTrainerChoice.add(new Integer(idx).toString());
131 trnTrainInstallerChoice.add(new Integer(idx).toString());
132 trnInstallChoice.add(new Integer(idx).toString());
133 }
134 //Default all available trainers to install.
135 trnTrainTrainerChoice.select("0");
136 trnTrainInstallerChoice.select("0");
137 }
138
139 //Fix the choice boxes based on user input. Input argument is which choice box to hold constant:
140 // 1 - trnTrainTrainerChoice
141 // 2 - trnTrainInstallerChoice
142 // 3 - trnInstallChoice
143 private void fixTrainerBoxes(int numOkChoice)
144 {
145 try
146 {
147 //Determine how many trainers are free
148 int numAvailTrainers = numTrainers - numTrainersTrainingTrainers;
149 int numTrainersUsed = 0;
150
151 if( numOkChoice == 1 )
152 numTrainersUsed += getNumChosenTrainingTrainers();
153 else if (numOkChoice == 2)
154 numTrainersUsed += getNumChosenTrainingInstallers();
155 else
156 numTrainersUsed += getNumChosenTrainerInstallers();
157
158 if( numOkChoice != 3)
159 {
160 if(numAvailTrainers - numTrainersUsed < getNumChosenTrainerInstallers())
161 trnInstallChoice.select( new Integer(numAvailTrainers - numTrainersUsed).toString());
162
163 numTrainersUsed += getNumChosenTrainerInstallers();
164 }
165 if( numOkChoice != 2)
166 {
167 if(numAvailTrainers - numTrainersUsed < getNumChosenTrainingInstallers())
168 trnTrainInstallerChoice.select( new Integer(numAvailTrainers - numTrainersUsed).toString());
169
170 numTrainersUsed += getNumChosenTrainingInstallers();
171 }
172 if( numOkChoice != 1)
173 {
174 if(numAvailTrainers - numTrainersUsed < getNumChosenTrainingTrainers());
175 trnTrainTrainerChoice.select( new Integer(numAvailTrainers - numTrainersUsed).toString());
176
177 numTrainersUsed += getNumChosenTrainingTrainers();
178 }
179 }
180 catch( Exception e)
181 {
182 output(e.toString());
183 output("Doh!!!");
184 }
185 }
186
187 //Handles Peter's work. Based on selection in list box, routes work to appropriate function
188 private void doPetersOptions()
189 {
190 boolean unitsRemaining = (numUnitsRemaining > 0);
191 if( ptrChoice.getSelectedItem().equals("Install") )
192 {
193 if( unitsRemaining )
194 {
195 numUnitsRemaining--;
196 output("Peter installed a unit");
197 }
198 else
199 {
200 output("Peter couldn't install -- All units installed");
201 }
202 }
203 else if ( ptrChoice.getSelectedItem().equals("Train Installer") )
204 {
205 addInstaller();
206 output("Peter trained an installer");
207 }
208 else // ptrChoice.getSelectedItem.equals("Train Trainer")
209 {
210 addTrainerByPeter();
211 }
212 }
213
214 //Handles installer actions. Essentially, the chosen number of installers either installs
215 // a unit, or reports that all units are installed.
216 private void doInstallersActions()
217 {
218 boolean unitsRemaining = (numUnitsRemaining > 0);
219 int numWorkingInstallers = getNumChosenInstallers();
220 int idx;
221
222 //Install available units
223 for( idx = 0; idx < numWorkingInstallers && unitsRemaining; idx++ )
224 {
225 numUnitsRemaining--;
226 output("Installer #" + (idx+1) + " installed a unit");
227 unitsRemaining = (numUnitsRemaining > 0);
228 }
229
230 //If job is completed, report failure to install
231 if( !unitsRemaining )
232 for( int i = idx; i < numWorkingInstallers; i++)
233 output("Installer #" + (i+1) + " couldn't install -- All units installed");
234
235 }
236
237 //Process actions for trainers. Based on selections from listbox.
238 //Currently, if too many trainers are requested to do actions, the following priority is used:
239 // 1) Train trainers
240 // 2) Remaining trainers will train installers
241 // 3) Remaining trainers will install units
242 //
243 // For instance, if there are 5 trainers and the boxes read "4", "3", "2" respectively, 4 will begin
244 // training trainers, one will train and installer, and none will install units.
245 //
246 // The Trainer member variable "hasWorkedThisWeek" regulates this. As a trainer is selected to perform
247 // an action, the "hasWorkedThisWeek" flag is set. Given the order of operations, it may be the case
248 // that all trainers have this flag set, before the requests to install units is processed.
249 private void doTrainerOptions()
250 {
251 //Retrieve listbox values
252 int trnTrainers = getNumChosenTrainingTrainers();
253 int trnInstallers = getNumChosenTrainingInstallers();
254 int trnInstalling = getNumChosenTrainerInstallers();
255
256 int idx;
257 int count;
258 int countFinishedTrainers = 0;
259 int countStartedTrainers = 0;
260
261 //Handle trainers training trainers. If a trainer is in the middle of training, allow them to finish.
262 //Otherwise, note their progress.
263 for( idx = 0; idx < numTrainers; idx++ )
264 {
265 Trainer temp = (Trainer) myTrainers.elementAt(idx);
266 if( !temp.isTrainingATrainer )
267 {
268 if(countStartedTrainers < trnTrainers)
269 {
270 output("Trainer #" + (idx+1) + " began training a trainer");
271 temp.isTrainingATrainer = true;
272 temp.hasWorkedThisWeek = true;
273 countStartedTrainers++;
274 }
275 }
276 else //temp.IsTrainingTrainer
277 {
278 if( countFinishedTrainers < numTrainersTrainingTrainers)
279 {
280 output("Trainer #" + (idx+1) + " finished training a trainer");
281 temp.isTrainingATrainer = false;
282 temp.hasWorkedThisWeek = true;
283 countFinishedTrainers++;
284 }
285 }
286 }
287
288 //Train installers
289 for( idx = 0, count = 0; idx < numTrainers && count < trnInstallers; idx++ )
290 {
291 Trainer temp = (Trainer) myTrainers.elementAt(idx);
292 if( !temp.hasWorkedThisWeek )
293 {
294 addInstaller();
295 output("Trainer #" + (idx+1) + " trained an installer");
296 temp.hasWorkedThisWeek = true;
297 count++;
298 }
299 }
300
301 //Trainers who are installing units
302 boolean unitsRemaining = ( numUnitsRemaining > 0 );
303 for( idx = 0, count = 0; idx < numTrainers && count < trnInstalling && unitsRemaining; idx++ )
304 {
305 Trainer temp = (Trainer) myTrainers.elementAt(idx);
306 if( !temp.hasWorkedThisWeek )
307 {
308 numUnitsRemaining--;
309 output("Trainer #" + (idx+1) + " installed a unit");
310 temp.hasWorkedThisWeek = true;
311 count++;
312 unitsRemaining = ( numUnitsRemaining > 0 );
313 }
314 }
315
316 //If no work left, report the failure to install
317 if( !unitsRemaining )
318 for( int i = idx; i < numTrainers; i++)
319 {
320 Trainer temp = (Trainer) myTrainers.elementAt(idx);
321 if( !temp.hasWorkedThisWeek )
322 {
323 output("Trainer #" + (i+1) + " couldn't install -- All units installed");
324 }
325 }
326
327 //Actually add the new trainers... so that they can work NEXT week
328 //If they are added before this point, they will be given work for THIS week
329 for( idx=0; idx < numTrainersTrainingTrainers ; idx++ )
330 {
331 myTrainers.addElement( new Trainer(++numTrainers) );
332 }
333
334 //Advance one week
335 numTrainersTrainingTrainers = trnTrainers;
336
337 //Reset 'hasWorkedThisWeek' flag
338 for( idx=0; idx < numTrainers; idx++ )
339 {
340 Trainer temp = (Trainer) myTrainers.elementAt(idx);
341 temp.hasWorkedThisWeek = false;
342 }
343 }
344
345 private void printWeekHeader()
346 {
347 output("********** BEGIN WEEK " + numWeek + " **********");
348 output("Peter has " + numUnitsRemaining + " units left to install");
349 output("Workforce: " + numInstallers + " installers, " + numTrainers + " trainers");
350 output("----------- WORK -----------");
351 }
352
353 private void printWeekFooter()
354 {
355 output("---------- RESULTS ----------");
356 output("Peter has " + numUnitsRemaining + " units left to install");
357 output("Workforce: " + numInstallers + " installers, " + numTrainers + " trainers");
358 output("********** END WEEK " + numWeek + " **********");
359 numWeek++;
360
361 if( numUnitsRemaining <= 0 )
362 {
363 output(">>> Done installing " + txtTotalUnits.getText() + " units!");
364 output(">>> Change \"Total units\" and press Go! to reset simulation");
365 weekInProgress = false;
366 txtTotalUnits.setEnabled(true);
367 doReset = true;
368 return;
369 }
370 }
371
372 private void runWeek()
373 {
374 //Apparently, there is a problem when this function dispatches it's work to the other functions
375
376 printWeekHeader();
377
378 //Installer actions
379 doInstallersActions();
380
381 //Trainer options
382 doTrainerOptions();
383
384 //Peter's options
385 doPetersOptions();
386
387 //Reset certain boxes
388 setTrainerChoiceBoxes();
389
390 //Update results
391 txtNumRemaining.setText( new Integer(numUnitsRemaining).toString() );
392
393 printWeekFooter();
394 }
395
396 /**
397 * Initializes the applet.
398 */
399 public void init() {
400 try {
401 super.init();
402 setName("PetersProblemApplet");
403 setLayout(null);
404 setSize(500, 400);
405
406 btnGo.setBounds(0, 320, 50, 30);
407
408 lblPtrChoice.setBounds(0,0,75,30);
409 ptrChoice.setBounds(75,0,100,30);
410
411 lblTrainerChoice.setBounds(0,50,75,30);
412 trnTrainTrainerChoice.setBounds(75,50,100,30);
413 trnTrainInstallerChoice.setBounds(200,50,100,30);
414 trnInstallChoice.setBounds(325,50,100,30);
415
416 lblTrainingTrainers.setBounds(75, 25, 125, 30);
417 lblTrainingInstallers.setBounds(200, 25, 125, 30);
418 lblInstallers.setBounds(325, 25, 100, 30);
419
420 lblInstallerChoice.setBounds(0,80,75,30);
421 insChoice.setBounds(75,80,100,30);
422
423 lblTotalUnits.setBounds(100,320,100,30);
424 txtTotalUnits.setBounds(200,320,30,30);
425 lblNumRemaining.setBounds(250,320,100,30);
426 txtNumRemaining.setBounds(350,320,30,30);
427
428 txtTotalUnits.setEnabled(true);
429 txtNumRemaining.setEditable(false);
430
431 txtOutput.setBounds(0,120,495,200);
432 txtOutput.setEditable(false);
433
434 add(txtOutput);
435 add(btnGo);
436 add(lblPtrChoice);
437 add(ptrChoice);
438 add(lblTrainerChoice);
439 add(trnTrainTrainerChoice);
440 add(trnTrainInstallerChoice);
441 add(trnInstallChoice);
442 add(lblTrainingTrainers);
443 add(lblTrainingInstallers);
444 add(lblInstallers);
445 add(lblInstallerChoice);
446 add(insChoice);
447 add(lblTotalUnits);
448 add(txtTotalUnits);
449 add(lblNumRemaining);
450 add(txtNumRemaining);
451
452 trnTrainTrainerChoice.removeAll();
453 trnTrainInstallerChoice.removeAll();
454 trnInstallChoice.removeAll();
455 insChoice.removeAll();
456
457 trnTrainTrainerChoice.add("0");
458 trnTrainInstallerChoice.add("0");
459 trnInstallChoice.add("0");
460 insChoice.add("0");
461
462 ptrChoice.removeAll();
463 ptrChoice.add("Install");
464 ptrChoice.add("Train Installer");
465 ptrChoice.add("Train Trainer");
466 ptrChoice.setEnabled(true);
467
468 numWeek = 1;
469 isPeterTrainingTrainer = false;
470 myTrainers = new Vector();
471 numInstallers = 0;
472 numTrainers = 0;
473 numTrainersTrainingTrainers = 0;
474 weekInProgress = false;
475
476 btnGo.setActionCommand("btnGo");
477
478 //Without this check, new ActionListeners are added on every Reset action
479 if( !active )
480 {
481 //Identical ActionListener added to both btnGo and txtTotalUnits
482
483 btnGo.addActionListener(new java.awt.event.ActionListener(){
484 public void actionPerformed(java.awt.event.ActionEvent e)
485 {
486 //If called at end of simulation, need to reset values
487 if( doReset )
488 {
489 doReset = false;
490 init();
491 }
492
493 //If simulation is just beginning, need to load unit info
494 if( !weekInProgress )
495 {
496 TOTAL_UNITS_NEEDED = Integer.parseInt( txtTotalUnits.getText() );
497 numUnitsRemaining = TOTAL_UNITS_NEEDED;
498 txtNumRemaining.setText( new Integer(numUnitsRemaining).toString() );
499 }
500
501 //Normal execution path
502 if( numUnitsRemaining > 0 )
503 {
504 weekInProgress = true;
505 txtTotalUnits.setEnabled(false);
506 runWeek();
507 }
508 }
509 });
510
511 txtTotalUnits.addActionListener(new java.awt.event.ActionListener(){
512 public void actionPerformed(java.awt.event.ActionEvent e)
513 {
514 //If called at end of simulation, need to reset values
515 if( doReset )
516 {
517 doReset = false;
518 init();
519 }
520
521 //If simulation is just beginning, need to load unit info
522 if( !weekInProgress )
523 {
524 TOTAL_UNITS_NEEDED = Integer.parseInt( txtTotalUnits.getText() );
525 numUnitsRemaining = TOTAL_UNITS_NEEDED;
526 txtNumRemaining.setText( new Integer(numUnitsRemaining).toString() );
527 }
528
529 //Normal execution path
530 if( numUnitsRemaining > 0 )
531 {
532 output("here");
533 weekInProgress = true;
534 txtTotalUnits.setEnabled(false);
535 runWeek();
536 }
537 }
538 });
539
540 trnTrainTrainerChoice.addItemListener( new java.awt.event.ItemListener(){
541 public void itemStateChanged(java.awt.event.ItemEvent e)
542 {
543 fixTrainerBoxes(1);
544 }
545 });
546 trnTrainInstallerChoice.addItemListener( new java.awt.event.ItemListener(){
547 public void itemStateChanged(java.awt.event.ItemEvent e)
548 {
549 fixTrainerBoxes(2);
550 }
551 });
552 trnInstallChoice.addItemListener( new java.awt.event.ItemListener(){
553 public void itemStateChanged(java.awt.event.ItemEvent e)
554 {
555 fixTrainerBoxes(3);
556 }
557 });
558 }
559
560 txtOutput.setText( "********** BEGIN SIMULATION **********\n"
561 + "Peter has to install " + numUnitsRemaining + " units into "
562 + " convenience stores. He may either install a unit himself,"
563 + " train another installer, or train a trainer. Please choose"
564 + " an action for Peter, and hit Go!\n\n");
565
566 active = true;
567
568 } catch (java.lang.Throwable Exc) {
569 handleException(Exc);
570 }
571 }
572
573 //Function to simplify output of messages
574 private void output(String msg)
575 {
576 txtOutput.append(msg + "\n");
577 }
578
579 /**
580 * Called whenever the part throws an exception.
581 * @param exception java.lang.Throwable
582 */
583 private void handleException(java.lang.Throwable exception) {
584 output(exception.toString());
585 }
586
587 //Main function allows you to run this applet as an application
588 /**
589 * main entrypoint - starts the part when it is run as an application
590 * @param args java.lang.String[]
591 */
592 public static void main(java.lang.String[] args) {
593 try {
594 Frame frame = new java.awt.Frame();
595 PetersProblemApplet aPetersProblemApplet;
596 Class iiCls = Class.forName("PetersProblemApplet");
597 ClassLoader iiClsLoader = iiCls.getClassLoader();
598 aPetersProblemApplet = (PetersProblemApplet)java.beans.Beans.instantiate(iiClsLoader,"PetersProblemApplet");
599 frame.add("Center", aPetersProblemApplet);
600 frame.setSize(aPetersProblemApplet.getSize());
601 frame.addWindowListener(new java.awt.event.WindowAdapter() {
602 public void windowClosing(java.awt.event.WindowEvent e) {
603 System.exit(0);
604 };
605 });
606 frame.show();
607 java.awt.Insets insets = frame.getInsets();
608 frame.setSize(frame.getWidth() + insets.left + insets.right, frame.getHeight() + insets.top + insets.bottom);
609 frame.setVisible(true);
610 } catch (Throwable exception) {
611 System.err.println("Exception occurred in main() of java.applet.Applet");
612 exception.printStackTrace(System.out);
613 }
614 }
615
616 public class Trainer
617 {
618 public Trainer(int _id)
619 {
620 trainerId = _id;
621 }
622
623 public boolean isTrainingATrainer = false;
624 public boolean hasWorkedThisWeek = false;
625 public int trainerId;
626 }
627
628 }
629