10 REM CPM-PERT PROGRAM FROM INTERFACE AGE, FEB. 1981
12 REM WRITTEN BY RICHARD PARRY
14 REM ADAPTED TO MICROSOFT BASIC BY CHARLES H STROM
16 REM
17 REM NOTE: PRINTER OPERATION REQUIRES LOADING SETUP.ASM BEFORE MBASIC
18 REM *INITIALIZE NORMAL DISTRIBUTION CONSTANTS
20 RN=15: RS=SQR(3/RN)
25 CL$=CHR$(27)+CHR$(28): REM CHARACTER STRING TO HOME CURSOR & CLEAR SCREEN
30 REM **************
40 REM * INPUT DATA *
50 REM **************
55 PRINT CL$
60 INPUT "CPM or PERT Simulation (C/P) "; Q$
65 INPUT "Do you want a HARD-COPY record (Y/N)"; HC$: HC$=LEFT$(HC$,1)
66 IF HC$="Y" THEN PRINT "NOTE - SETUP.ASM MUST BE LOADED BEFORE MBASIC OR PRINTER WILL NOT FUNCTION!"
68 PRINT
70 INPUT "Number of Activities"; N
80 DIM ML(N), MO(N), MP(N), CP(N), ME(N), SD(N), IC(20)
90 DIM S(N), F(N), D(N), E(N), L(N), F1(N)
100 FOR I=1 TO N
110 PRINT CL$: PRINT "ACTIVITY"; I: PRINT
120  REM * GO TO INPUT DATA ROUTINE
130  GOSUB 1920
140 NEXT I
150 PRINT CL$: INPUT "Would you like to examine or edit the input data (Y/N)";Q1$
160 IF LEFT$(Q1$,1) = "N" THEN 430
170 REM *SORT INPUT DATA
180 GOSUB 2080
190 REM **********************
200 REM * DISPLAY INPUT DATA *
210 REM **********************
215 IF HC$="Y" THEN POKE 37,195
220 PRINT CL$: IF LEFT$(Q$,1)<>"C" THEN 280
230 PRINT "ACTIVITY #    FROM       TO     DURATION"
240 FOR I = 1 TO N
250  PRINT TAB(5); I; TAB(15); S(I); TAB(25); F(I); TAB(35); D(I)
260 NEXT I
270 GOTO 340
280 PRINT "ACTIVITY #    FROM       TO        ML       MO        MP"
290 FOR I = 1 TO N
300  PRINT TAB(5); I; TAB(15); S(I); TAB(25); F(I);
310  PRINT TAB(35); ML(I); TAB(45); MO(I); TAB(55); MP(I)
320 NEXT I
330 PRINT
340 POKE 37,201:PRINT: INPUT "Would you like to edit an activity (Y/N)"; Q1$
350 IF LEFT$(Q1$,1) = "N" THEN 430
360 REM * EDIT MODE
370 PRINT: INPUT "What activity needs alteration (0 to end)"; I
380 IF I=0 THEN 150
390 REM * GO TO INPUT DATA ROUTINE
400 GOSUB 1920
410 GOTO 370
420 REM * GO TO SORT ROUTINE
430 GOSUB 2080
440 IF LEFT$(Q$,1) <>"C" THEN 760
450 REM ***********************************************************
460 REM * CRITICAL PATH ANALYSIS REQUESTED. PERFORM CRITICAL PATH *
470 REM * ANALYSIS ONCE AND DISPLAY RESULTS.                      *
480 REM ***********************************************************
490 GOSUB 2340
500 C2=0
505 IF HC$="Y" THEN POKE 37,195
510 PRINT CL$: PRINT "CP ANALYSIS IS:"
520 PRINT: PRINT: PRINT "FROM","TO","EST","LFT","FLOAT": PRINT
530 FOR I = 1 TO N
540  PRINT S(I),F(I),E(S(I)),L(F(I)),F1(I)
550 NEXT I
560 PRINT "THE CRITICAL PATH LENGTH IS ";PL
570 PRINT: PRINT "THE CRITICAL PATH IS:": PRINT"FROM","TO": PRINT
580 FOR I = 1 TO N
590  IF F1(I) = 0 THEN 610
600 NEXT I
610 PRINT S(I),F(I): C2=C2+1: IF I>N THEN 650
620 FOR M= 1 TO N
630  IF S(M)=F(I) AND F1(M) = 0 THEN I=M: GOTO 610
640 NEXT M
650 IF C1<>C2 THEN PRINT: PRINT "THERE IS MORE THAN ONE CRITICAL PATH"
660 PRINT: POKE 37,201
670 INPUT "Would you like to edit an activity or stop program (E/S)"; Q1$
680 IF LEFT$(Q1$,1) = "E" THEN PRINT: GOTO 220:
690 END
700 REM *****************************************************************
710 REM * PERT SIMULATION REQUESTED. PERFORM CRITICAL PATH ANALYSIS THE *
720 REM * NUMBER OF TIMES SPECIFIED. STORE PATH LENGTHS AND INCREMENT   *
730 REM * ACTIVITIES WHICH APPEAR ON CRITICAL PATH. CONSTRUCT HISTOGRAM *
740 REM * AND DISPLAY RESULTS.                                          *
750 REM *****************************************************************
760 FOR I = 1 TO N
770  REM * COMPUTE MEAN OF EACH ACTIVITY
780  ME(I) = (MO(I)+4*ML(I)+MP(I))/6
790  REM * COMPUTE STANDARD DEVIATION OF EACH ACTIVITY
800  SD(I) = (MP(I)-MO(I))/6
810 NEXT I
820 REM * COMPUTE MOST OPTIMISTIC PATH LENGTH
830 DU=0: FOR I=1 TO N: CP(I)=0: E(I)=0: L(I)=0: NEXT I
840 FOR I = 1 TO N
850  D(I)=MO(I)
860 NEXT I
870 GOSUB 2340
880 BC=PL
890 REM * COMPUTE MOST PESSIMISTIC PATH LENGTH
900 DU=0: FOR I=1 TO N: CP(I)=0: E(I)=0: L(I)=0: NEXT I
910 FOR I = 1 TO N
920  D(I)=MP(I)
930 NEXT I
940 GOSUB 2340
950 WC=PL
960 REM * INITIALIZ KEY VARIABLES
970 DU=0: FOR I = 1 TO N: CP(I)=0: E(I)=0: L(I)=0: NEXT I
980 LS=0: HS=0: FOR I=1 TO 20: IC(I)=0: NEXT I
990 REM * INITIALIZE RANDOM NUMBER GENERATOR
1000 RANDOMIZE
1010 REM * PROPOSE # OF TRANSACTIONS AS 20 TIMES # OF ACTIVITIES
1020 PRINT "Number of transactions should be >= "; 20*N
1030 INPUT "Number of transactions"; NS
1040 PRINT: PRINT "++SIMULATION IN PROGRESS++"
1050 REM ***********************
1060 REM * CONSTRUCT HISTOGRAM *
1070 REM ***********************
1080 REM * SET APPROPRIATE INTERVAL (I.E. INTEGER >=1)
1090 LL=INT(BC)
1100 IF WC-BC<=20 THEN IN=1
1110 IN=INT((WC-BC)/20)+1
1120 REM **********************
1130 REM * PERFORM SIMULATION *
1140 REM **********************
1150 TC=100
1160 FOR K=1 TO NS
1170  IF K=TC THEN PRINT "++SIMULATION IN PROGRESS++", TC: TC=TC+100
1180  FOR J=1 TO N
1190   S=0: E(J)=0: L(J)=0
1200   IF ML(J)=0 THEN D(J)=0: GOTO 1250
1210   FOR I=1 TO RN
1220    S=S+2*RND-1
1230   NEXT I
1240   D(J)=ME(J)+SD(J)*S*RS
1250  NEXT J
1260  GOSUB 2340
1270  REM * FIND INTERVAL FOR THIS PATH LENGTH
1280  I3=(PL-LL)/IN+2
1290  IF I3<1 THEN LS=LS+1: GOTO 1330
1300  IF I3>20 THEN HS=HS+1: GOTO 1330
1310  I3=INT(I3)
1320  IC(I3)=IC(I3)+1
1330 NEXT K
1340 REM **************************************
1350 REM * PRINT FREQUENCY DISTRIBUTION TABLE *
1360 REM **************************************
1365 IF HC$="Y" THEN POKE 37,195
1370 PRINT CL$: PRINT "++FREQUENCY DISTRIBUTION TABLE++": PRINT
1380 PRINT "Most OPTIMISTIC  path length"; BC
1390 PRINT "Most PESSIMISTIC path length"; WC
1400 PRINT "Number of transactions LOWER  than histogram range ";LS
1410 PRINT "Number of transactions HIGHER than histogram range ";HS: PRINT
1420 PRINT "     INTERVAL      FREQ.      PCT."
1430 I1=LL-IN: I2=LL
1440 FOR M=1 TO 20
1450  PRINT"=>";I1;"<";I2;TAB(20);IC(M);TAB(30);INT(.5+100*IC(M)/NS)
1460  I1=I1+IN: I2=I2+IN
1470 NEXT M
1480 REM *******************
1490 REM * PRINT HISTOGRAM *
1500 REM *******************
1510 REM * COMPUTE HISTOGRAM SCALE FACTOR
1520 SC=0: LO=18: J=0: LL=INT(BC)
1530 FOR M=1 TO 20
1540  IF IC(M)>SC THEN SC=IC(M)
1550 NEXT M
1560 SC=50/SC
1570 X$="PATH LENGTH"
1580 PRINT: PRINT: PRINT TAB(24); "++ HISTOGRAM ++": PRINT
1590 PRINT TAB(18);"RELATIVE FREQUENCY OF PATH LENGTHS"
1600 PRINT TAB(LO); "+------------------------------------------------+"
1610 FOR M=1 TO 20
1620  HM=IC(M)*SC
1630  FOR K=1 TO 3
1640   J=J+1: PRINT MID$(X$,J,1);TAB(2);
1650   IF K=2 THEN PRINT ">=";LL-IN;"<";LL;: LL=LL+IN
1660   PRINT TAB(LO);
1670   IF IC(M)=0 THEN PRINT: GOTO 1720
1680   FOR I=1 TO HM
1690    PRINT "*";
1700   NEXT I
1710   PRINT
1720  NEXT K
1730 NEXT M
1740 REM ***************************
1750 REM * PRINT ACTIVITY ANALYSIS *
1760 REM ***************************
1770 PRINT: PRINT
1780 PRINT TAB(10); "+++ CP ACTIVITY ANALYSIS TABLE +++": PRINT
1790 PRINT "ACTIVITY #    FROM      TO     CP FREQ.    PCT."
1800 FOR I=1 TO N
1810  PRINT TAB(5);I;TAB(15);S(I);TAB(25);F(I);
1820  PRINT TAB(35);CP(I);TAB(45);INT(.5+100*CP(I)/NS)
1830 NEXT I
1840 PRINT: PRINT "DUPLICATE critical paths occurred";DU;"times."
1850 PRINT: POKE 37,201
1860 INPUT "Would you like to edit an activity or stop program (E/S)"; Q1$
1870 IF LEFT$(Q1$,1)="E" THEN PRINT: GOTO 220
1880 END
1890 REM **********************
1900 REM * INPUT DATA ROUTINE *
1910 REM **********************
1920 INPUT "FROM";S(I)
1930 INPUT "TO";F(I)
1940 IF F(I)>N THEN PRINT "++END NODE # NOT <= # OF ACTIVITIES++":GOTO 1930
1950 IF S(I)>F(I) THEN PRINT "++START NODE MUST BE < END NODE++":GOTO 1920
1960 IF LEFT$(Q$,1)="C" THEN INPUT "DURATION";D(I): GOTO 2040
1970 INPUT "MOST LIKELY";ML(I)
1980 REM * CHECK FOR DUMMY ACTIVITY
1990 IF ML(I)=0 THEN MO(I)=0: MP(I)=0: GOTO 2040
2000 INPUT "MOST OPTIMISTIC"; MO(I)
2010 IF MO(I)>ML(I) THEN PRINT "++MO MUST BE <= ML++": GOTO 2000
2020 INPUT "MOST PESSIMISTIC"; MP(I)
2030 IF MP(I)<ML(I) THEN PRINT "++MP MUST BE >= ML++": GOTO 2020
2040 RETURN
2050 REM *************************************
2060 REM * SORT DATA USING START NODE AS KEY *
2070 REM *************************************
2080 PRINT: PRINT "SORTING IN PROGRESS": PRINT
2090 SW=0
2100 FOR I=1 TO N-1
2110  J=I+1
2120 IF S(I)<=S(J) THEN 2200
2130  EX=S(I): S(I)=S(J): S(J)=EX
2140  EX=F(I): F(I)=F(J): F(J)=EX
2150  EX=D(I): D(I)=D(J): D(J)=EX
2160  EX=ML(I): ML(I)=ML(J): ML(J)=EX
2170  EX=MO(I): MO(I)=MO(J): MO(J)=EX
2180  EX=MP(I): MP(I)=MP(J): MP(J)=EX
2190  SW=1
2200 NEXT I
2210 IF SW=1 THEN 2090
2220 RETURN
2230 REM *************************************************************
2240 REM * THE FOLLOWING SUBROUTINE IS USED BY BOTH THE CPM ANALYSIS *
2250 REM * AS WELL AS THE PERT SIMULATION ANALYSIS.  WHILE THE CPM   *
2260 REM * ANALYSIS CALLS THE ROUTINE ONLY ONCE,  THE SIMULATION     *
2270 REM * CALLS THE ROUTINE THE NUMBER OF TIMES REQUESTED BY THE    *
2280 REM * USER.  THE EARLIEST, LATEST, AND FLOAT TIMES ARE COMPUTED *
2290 REM * AND FROM THIS DATA THE CRITICAL PATH LENGTH AND CRITICAL  *
2300 REM * PATH ARE CALCULATED.  DUPLICATE CRITICAL PATHS ARE ONLY   *
2310 REM * COUNTED ONCE.                                             *
2320 REM *************************************************************
2330 REM * COMPUTE EARLIEST STARTING TIME
2340 C1=0: C2=0: PL=0
2350 FOR I=1 TO N
2360  M1=E(S(I))+D(I)
2370  IF E(F(I))<=M1 THEN E(F(I))=M1
2380 NEXT I
2390 REM * COMPUTE LATEST FINISHING TIME
2400 L(F(N))=E(F(N))
2410 FOR I=N TO 1 STEP -1
2420  L1=S(I): M2=L(F(I))-D(I)
2430  IF L(L1)>=M2 OR L(L1)=0 THEN L(L1)=M2
2440 NEXT I
2450 REM * COMPUTE FLOAT TIME
2460 FOR I=1 TO N
2470  F1(I)=L(F(I))-E(S(I))-D(I)
2480  IF F1(I)<.0001 THEN F1(I)=0: C1=C1+1
2490 NEXT I
2500 REM * COMPUTE CRITICAL PATH LENGTH
2510 FOR I=1 TO N
2520  IF L(F(I))>PL THEN PL=L(F(I))
2530 NEXT I
2540 REM * COMPUTE CRITICAL PATH
2550 FOR I=1 TO N
2560  IF F1(I)=0 THEN 2580
2570 NEXT I
2580 C2=C2+1: CP(I)=CP(I)+1
2590 IF I>N THEN 2630
2600 FOR M=1 TO N
2610  IF S(M)=F(I) AND F1(M)=0 THEN I=M: GOTO 2580
2620 NEXT M
2630 IF C1<>C2 THEN DU=DU+1
2640 RETURN
3000 REM
3010 SUB POKE(X,Y)
3020 END SUB
