home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / sampler / 02 / mandel / mandel4.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1988-03-14  |  16.5 KB  |  615 lines

  1. PROGRAM Mandel4;
  2.  
  3. {This program generates a section of the Mandelbrot Set, can save it
  4. on disk, and use existing Mandelbrot pictures to zoom further into
  5. the Set.}
  6.  
  7. USES
  8.    Crt, Graph, Cmplx; { CMPLX.TPU is created from CMPLX.PAS }
  9.  
  10. CONST
  11.    Scan_Width = 359; { 719 (max Hercules) DIV 2 }
  12.    Max_Scan_Lines = 349; { PC3270 maximum }
  13.    Aspect = 0.75; { Typical screen aspect ratio }
  14.    Real_Length = 30;
  15.    Yes_N_No:  SET OF char = ['Y', 'N', 'y', 'n'];
  16.    Yes:  SET OF char = ['Y', 'y'];
  17.    No:  SET OF char = ['N', 'n'];
  18.    TP_Path = 'T:';
  19.  
  20. TYPE
  21.    Scan_Line = ARRAY [0..Scan_Width] OF byte;
  22.    Scan_Line_Ptr = ^Scan_Line;
  23.    Real_String = STRING[Real_Length];
  24.    Color_Array = ARRAY [0..55] OF integer;
  25.  
  26. CONST
  27.    Colors_2:  Color_Array = (0, 0, 0, 0, 1, 1, 1, 1,
  28.                              0, 0, 0, 0, 1, 1, 1, 1,
  29.    { Color arrangement for } 0, 0, 0, 0, 1, 1, 1, 1,
  30.    { 2-color screens       } 0, 0, 0, 0, 1, 1, 1, 1,
  31.                              0, 0, 0, 0, 1, 1, 1, 1,
  32.                              0, 0, 0, 0, 1, 1, 1, 1,
  33.                              0, 0, 0, 0, 1, 1, 1, 1);
  34.  
  35.    Colors_4:  Color_Array = (1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
  36.                              3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1,
  37.    { Color arrangement for } 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
  38.    { 4-color screens       } 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
  39.                              3, 3, 3, 3, 3, 3, 0, 0);
  40.  
  41.    Colors_16:  Color_Array = (1,  9, 1,  9, 1,  9, 1,  9,
  42.                               2, 10, 2, 10, 2, 10, 2, 10,
  43.    { Color arrangement for }  3, 11, 3, 11, 3, 11, 3, 11,
  44.    { 16-color screens      }  4, 12, 4, 12, 4, 12, 4, 12,
  45.                               5, 13, 5, 13, 5, 13, 5, 13,
  46.                               6, 14, 6, 14, 6, 14, 6, 14,
  47.                               7, 15, 7, 15, 7, 15, 7, 15);
  48.  
  49. VAR
  50.    Ch:  Char;
  51.    Low, High, Delta:  Complex;
  52.    Dots_Horizontal, Dots_Vertical, Start_Y, Max_Count, Color_Count,
  53.       Device, Graph_Mode, Max_Colors, Max_X:  integer;
  54.    Use_Color:  Color_Array;
  55.    Picture_Loaded:  boolean;
  56.    File_Name:  STRING[80];
  57.  
  58.    Data_Line:  Scan_Line;
  59.    Screen_File:  FILE OF Scan_Line;
  60.    Screen:  ARRAY [0..Max_Scan_Lines] OF Scan_Line_Ptr;
  61.    Screen_Data:  RECORD
  62.                     Dots_H, Dots_V, Count, Start:  integer;
  63.                     Low_Real, Low_Imag,
  64.                     High_Real, High_Imag:  Real_String;
  65.                     Note:  String[200]
  66.                  END ABSOLUTE Data_Line;
  67.  
  68. {*******************************************************************}
  69.  
  70. PROCEDURE Initialize;
  71.  
  72. {  This procedure checks for the graphics screen and selects a mode
  73. based on a compromise between resolution and the number of colors.  }
  74.  
  75. VAR
  76.    X:  integer;
  77.  
  78. BEGIN
  79. TextMode (LastMode);
  80. TextColor (LightBlue);
  81. TextBackground (Black);
  82. DirectVideo := False;
  83. File_Name := '';
  84. Picture_Loaded := False;
  85. DetectGraph (Device, Graph_Mode);
  86. X := GraphResult;
  87.  
  88. IF X<>grOk THEN
  89.    BEGIN
  90.    Writeln ('Sorry, I can''t cope with this:  ', GraphErrorMsg (X));
  91.    Halt
  92.    END {* THEN *};
  93.  
  94. CASE Device OF
  95.    EGA:  Graph_Mode := EGAHi;
  96.    VGA:  Graph_Mode := VGAMed;
  97.    MCGA:  Graph_Mode := MCGAC0;
  98.    EGA64:  Graph_Mode := EGA64Lo;
  99.    ATT400:  Graph_Mode := ATT400C0;
  100.    PC3270:  Graph_Mode := PC3270Hi;
  101.    HercMono:  Graph_Mode := HercMonoHi;
  102.    CGA, RESERVED:  Graph_Mode := CGAC0
  103. END {* CASE *};
  104.  
  105. InitGraph (Device, Graph_Mode, TP_Path);
  106.  
  107. CASE Device OF
  108.    CGA, MCGA, RESERVED,
  109.    ATT400:  BEGIN
  110.             Color_Count := 54;
  111.             Use_Color := Colors_4;
  112.             Max_Colors := 3;
  113.             Max_X := GetMaxX
  114.             END {* CASE CGAC0, MCGAC0, ATT400C0 *};
  115.  
  116.    EGA, VGA,
  117.    EGA64:  BEGIN
  118.            Color_Count := 56;
  119.            Use_Color := Colors_16;
  120.            Max_Colors := 15;
  121.            Max_X := GetMaxX DIV 2
  122.            END {* CASE EGAHi, VGAHi, EGA64Lo *};
  123.  
  124.    ELSE BEGIN
  125.         Color_Count := 56;
  126.         Use_Color := Colors_2;
  127.         Max_Colors := 1;
  128.         Max_X := GetMaxX DIV 2
  129.         END {* CASE ELSE *}
  130. END {* CASE *};
  131.  
  132. FOR X := 0 TO Max_Scan_Lines DO
  133.    New (Screen[X]);
  134.  
  135. RestoreCrtMode
  136. END {* Initialize *};
  137.  
  138. {*******************************************************************}
  139.  
  140. PROCEDURE Plot (X, Y:  integer;
  141.                 Color:  word);
  142.  
  143. {  This procedure plots points on the screen.  For high-resolution-
  144. width screens, two adjacent pixels are set.  }
  145.  
  146. BEGIN
  147. CASE Device OF
  148.    CGA, MCGA, RESERVED,
  149.    ATT400:  PutPixel (X, Y, Color);
  150.  
  151.    ELSE BEGIN
  152.         PutPixel (X*2, Y, Color);
  153.         PutPixel (X*2+1, Y, Color)
  154.         END {* CASE ELSE *}
  155. END {* CASE *}
  156. END {* Plot *};
  157.  
  158. {*******************************************************************}
  159.  
  160. PROCEDURE Define_Screen;
  161.  
  162. {This procedure defines the area of the Mandelbrot Set to be viewed.
  163. It can either be typed in at the keyboard, loaded as a partially
  164. completed screen, or as a smaller sector of a completed picture.  }
  165.  
  166. VAR
  167.    X, Y:  integer;
  168.    Temp, Ratio:  double;
  169.  
  170.    {****************************************************************}
  171.  
  172.    PROCEDURE No_Blank (VAR RS:  Real_String);
  173.  
  174.    {  This procedure removes leading blanks from the string RS.  }
  175.  
  176.    BEGIN
  177.    WHILE RS[1]=' ' DO
  178.       RS := Copy (RS, 2, Length (RS)-1)
  179.    END {* No_Blank *};
  180.  
  181.    {****************************************************************}
  182.  
  183.    PROCEDURE Sub_Picture;
  184.  
  185.    {  This procedure allows the user to select a sub-section of a
  186.    completed screen to be blown up, effectively zooming in on a
  187.    smaller area.
  188.  
  189.       Pressing keys 2 thru 5 changes the grid on the screen.  A sub-
  190.    section may be chosen by pressing a letter, starting with A in the
  191.    upper left corner and moving across:
  192.                                             ┌─────┬─────┬─────┐
  193.              ┌─────┬─────┐                  │  A  │  B  │  C  │
  194.              │  A  │  B  │                  ├─────┼─────┼─────┤
  195.          2:  ├─────┼─────┤              3:  │  D  │  E  │  F  │
  196.              │  C  │  D  │                  ├─────┼─────┼─────┤
  197.              └─────┴─────┘                  │  G  │  H  │  I  │
  198.                                             └─────┴─────┴─────┘
  199.                                       ┌─────┬─────┬─────┬─────┬─────┐
  200.        ┌─────┬─────┬─────┬─────┐      │  A  │  B  │  C  │  D  │  E  │
  201.        │  A  │  B  │  C  │  D  │      ├─────┼─────┼─────┼─────┼─────┤
  202.        ├─────┼─────┼─────┼─────┤      │  F  │  G  │  H  │  I  │  J  │
  203.        │  E  │  F  │  G  │  H  │      ├─────┼─────┼─────┼─────┼─────┤
  204.    4:  ├─────┼─────┼─────┼─────┤  5:  │  K  │  L  │  M  │  N  │  O  │
  205.        │  I  │  J  │  K  │  L  │      ├─────┼─────┼─────┼─────┼─────┤
  206.        ├─────┼─────┼─────┼─────┤      │  P  │  Q  │  R  │  S  │  T  │
  207.        │  M  │  N  │  O  │  P  │      ├─────┼─────┼─────┼─────┼─────┤
  208.        └─────┴─────┴─────┴─────┘      │  U  │  V  │  W  │  X  │  Y  │
  209.                                       └─────┴─────┴─────┴─────┴─────┘
  210.  
  211.    Once a section has been chosen, the program proceeds to calculate
  212.    and display the smaller section, as large as the screen may allow.}
  213.  
  214.    CONST
  215.       Max_Letter:  ARRAY [2..5] OF char = ('D', 'I', 'P', 'Y');
  216.  
  217.    VAR
  218.       Ch:  char;
  219.       New_Size, Size, X, Y, Z, Sector, Sector_X, Sector_Y:  integer;
  220.  
  221.    BEGIN
  222.    Size := 1;
  223.    File_Name := '';
  224.    Ch := '2';
  225.  
  226.    REPEAT
  227.       IF Ch IN ['2'..'5'] THEN
  228.          BEGIN {* Change grid *}
  229.          New_Size := Ord (Ch) - Ord ('0');
  230.  
  231.          IF Size<>New_Size THEN
  232.             BEGIN
  233.             { Undo existing grid }
  234.             FOR X := 0 TO Dots_Horizontal DO
  235.                FOR Z := 1 TO Size-1 DO
  236.                   BEGIN
  237.                   Y := Z * Dots_Vertical DIV Size;
  238.                   Plot (X, Y, Screen[Y]^[X])
  239.                   END {* FOR, FOR *};
  240.  
  241.             FOR Y := 0 TO Dots_Vertical DO
  242.                FOR Z := 1 TO Size-1 DO
  243.                   BEGIN
  244.                   X := Z * Dots_Horizontal DIV Size;
  245.                   Plot (X, Y, Screen[Y]^[X])
  246.                   END {* FOR, FOR *};
  247.  
  248.             Size := New_Size;
  249.  
  250.             { Make new grid }
  251.             FOR X := 0 TO Dots_Horizontal DO
  252.                FOR Z := 1 TO Size-1 DO
  253.                   BEGIN
  254.                   Y := Z * Dots_Vertical DIV Size;
  255.                   Plot (X, Y, Max_Colors-Screen[Y]^[X])
  256.                   END {* FOR, FOR *};
  257.  
  258.             FOR Y := 0 TO Dots_Vertical DO
  259.                FOR Z := 1 TO Size-1 DO
  260.                   BEGIN
  261.                   X := Z * Dots_Horizontal DIV Size;
  262.                   Plot (X, Y, Max_Colors-Screen[Y]^[X])
  263.                   END {* FOR, FOR *}
  264.             END {* THEN *}
  265.          END {* THEN *};
  266.  
  267.       Ch := UpCase (ReadKey)
  268.    UNTIL (Size IN [2..5]) AND (Ch IN ['A'..Max_Letter[Size]]);
  269.  
  270.    { Calculate new limits }
  271.    Sector := Ord (Ch) - Ord ('A');
  272.    Sector_X := Sector MOD Size;
  273.    Sector_Y := Size - 1 - Sector DIV Size;
  274.    Sub_Comp (High, Low, Delta);
  275.    Div_C_By_R (Delta, Size, Delta);
  276.    Low.R := Low.R + Delta.R * Sector_X;
  277.    High.R := Low.R + Delta.R;
  278.    Low.I := Low.I + Delta.I * Sector_Y;
  279.    High.I := Low.I + Delta.I;
  280.  
  281.    WITH Screen_Data DO
  282.       BEGIN
  283.       Start_Y := 0;
  284.       Dots_H := Dots_Horizontal;
  285.       Dots_V := Dots_Vertical;
  286.       Count := Max_Count;
  287.       Str (Low.R, Low_Real);
  288.       Str (Low.I, Low_Imag);
  289.       Str (High.R, High_Real);
  290.       Str (High.I, High_Imag);
  291.       No_Blank (Low_Imag);
  292.       No_Blank (Low_Real);
  293.       No_Blank (High_Imag);
  294.       No_Blank (High_Real)
  295.       END {* WITH *};
  296.  
  297.    RestoreCrtMode;
  298.    Write
  299.    ('Maximum iteration count = ', Max_Count, '.  Change it? (Y/N) ');
  300.  
  301.    REPEAT
  302.       Ch := ReadKey
  303.    UNTIL Ch IN Yes_N_No;
  304.  
  305.    Writeln (Ch);
  306.  
  307.    IF Ch IN Yes THEN
  308.       BEGIN
  309.       REPEAT
  310.          Write ('Enter maximum iteration count:  ');
  311.          {$I-} Readln (Max_Count) {$I+}
  312.       UNTIL IOResult=0;
  313.  
  314.       IF Max_Count<10 THEN
  315.          Max_Count := 10;
  316.  
  317.       Screen_Data.Count := Max_Count
  318.       END {* THEN *};
  319.  
  320.    Write ('Enter note:  ');
  321.    Readln (Screen_Data.Note);
  322.    SetGraphMode (Graph_Mode)
  323.    END {* Sub_Picture *};
  324.  
  325.    {****************************************************************}
  326.  
  327. BEGIN {* Define_Screen *}
  328. Ch := 'N';
  329.  
  330. IF Picture_Loaded THEN
  331.    BEGIN
  332.    Write ('Use picture in memory? (Y/N) ');
  333.  
  334.    REPEAT
  335.       Ch := ReadKey
  336.    UNTIL Ch IN Yes_N_No;
  337.  
  338.    Writeln (Ch)
  339.    END {* THEN *};
  340.  
  341. IF Ch IN No THEN
  342.    BEGIN
  343.    Write ('Load a picture file? (Y/N) ');
  344.  
  345.    REPEAT
  346.       Ch := ReadKey
  347.    UNTIL Ch IN Yes_N_No;
  348.  
  349.    Writeln (Ch);
  350.  
  351.    IF Ch IN Yes THEN
  352.       BEGIN { Load picture file }
  353.       REPEAT
  354.          Write ('Enter name of file:  ');
  355.          Readln (File_Name);
  356.          Assign (Screen_File, File_Name);
  357.          {$I-} Reset (Screen_File) {$I+};
  358.       UNTIL IOResult=0;
  359.  
  360.       Read (Screen_File, Data_Line);
  361.  
  362.       FOR X := 0 TO Screen_Data.Start-1 DO
  363.          Read (Screen_File, Screen[X]^);
  364.  
  365.       Close (Screen_File);
  366.       Picture_Loaded := True
  367.       END {* THEN *}
  368.  
  369.    ELSE
  370.       BEGIN { Get info from keyboard }
  371.       REPEAT
  372.          Write ('Enter range for the real (horiz.) axis:  ');
  373.          {$I-} Readln (Low.R, High.R) {$I+}
  374.       UNTIL (IOResult=0) AND (Low.R<>High.R);
  375.  
  376.       IF Low.R>High.R THEN
  377.          BEGIN
  378.          Temp := Low.R;
  379.          Low.R := High.R;
  380.          High.R := Temp
  381.          END {* THEN *};
  382.  
  383.       REPEAT
  384.          Write ('Enter range for the imaginary (vert.) axis:  ');
  385.          {$I-} Readln (Low.I, High.I) {$I+}
  386.       UNTIL (IOResult=0) AND (Low.I<>High.I);
  387.  
  388.       IF Low.I>High.I THEN
  389.          BEGIN
  390.          Temp := Low.I;
  391.          Low.I := High.I;
  392.          High.I := Temp
  393.          END {* THEN *};
  394.  
  395.       REPEAT
  396.          Write ('Enter maximum iteration count:  ');
  397.          {$I-} Readln (Max_Count) {$I+}
  398.       UNTIL IOResult=0;
  399.  
  400.       IF Max_Count<10 THEN
  401.          Max_Count := 10;
  402.  
  403.       Write ('Enter note:  ');
  404.       Readln (Screen_Data.Note);
  405.       Start_Y := 0;
  406.       Sub_Comp (High, Low, Delta);
  407.       Ratio := Delta.I / Delta.R;
  408.       SetGraphMode (Graph_Mode);
  409.  
  410.       IF Ratio>=Aspect THEN
  411.          BEGIN
  412.          Dots_Horizontal := Round ((Max_X + 1) * Aspect / Ratio) - 1;
  413.          Dots_Vertical := GetMaxY
  414.          END (* THEN *)
  415.  
  416.       ELSE
  417.          BEGIN
  418.          Dots_Vertical := Round ((GetMaxY + 1) * Ratio / Aspect) - 1;
  419.          Dots_Horizontal := Max_X
  420.          END (* ELSE *);
  421.  
  422.       WITH Screen_Data DO
  423.          BEGIN
  424.          Dots_H := Dots_Horizontal;
  425.          Dots_V := Dots_Vertical;
  426.          Count := Max_Count;
  427.          Str (Low.I, Low_Imag);
  428.          Str (Low.R, Low_Real);
  429.          Str (High.I, High_Imag);
  430.          Str (High.R, High_Real);
  431.          No_Blank (Low_Imag);
  432.          No_Blank (Low_Real);
  433.          No_Blank (High_Imag);
  434.          No_Blank (High_Real)
  435.          END {* WITH *};
  436.  
  437.       Picture_Loaded := False;
  438.       File_Name := ''
  439.       END {* ELSE *}
  440.    END {* THEN *};
  441.  
  442. IF Picture_Loaded THEN
  443.    BEGIN { Dump picture onto the screen }
  444.    SetGraphMode (Graph_Mode);
  445.  
  446.    WITH Screen_Data DO
  447.       BEGIN
  448.       Start_Y := Start;
  449.       Max_Count := Count;
  450.       Dots_Horizontal := Dots_H;
  451.       Dots_Vertical := Dots_V;
  452.       Val (Low_Real, Low.R, X);
  453.       Val (Low_Imag, Low.I, X);
  454.       Val (High_Real, High.R, X);
  455.       Val (High_Imag, High.I, X)
  456.       END {* WITH *};
  457.  
  458.    FOR Y := 0 TO Start_Y-1 DO
  459.       FOR X := 0 TO Dots_Horizontal DO
  460.          Plot (X, Y, Screen[Y]^[X]);
  461.  
  462.    IF Start_Y>GetMaxY THEN
  463.       Sub_Picture { Get a subregion of the completed picture }
  464.    ELSE
  465.       Sub_Comp (High, Low, Delta) { Continue drawing the picture }
  466.    END {* THEN *};
  467.  
  468. Delta.R := Delta.R / (Dots_Horizontal + 1);
  469. Delta.I := Delta.I / (Dots_Vertical + 1)
  470. END {* Define_Screen *};
  471.  
  472. {*******************************************************************}
  473.  
  474. PROCEDURE Generate;
  475.  
  476. {  This is where most of the program's time is spent, generating the
  477. screen.  The section marked 1* is where code has been optimized by
  478. putting the complex-number math instructions in this procedure rather
  479. than calling the actual procedures.  }
  480.  
  481. VAR
  482.    X, Y, Count:  integer;
  483.    Z_Point, C_Point:  Complex;
  484.    Temp:  double;
  485.  
  486. BEGIN {* Generate *}
  487. Plot (Dots_Horizontal, Dots_Vertical, Max_Colors);
  488. C_Point.I := High.I - Start_Y * Delta.I;
  489. Y := Start_Y;
  490.  
  491. WHILE (Y<=Dots_Vertical) AND NOT KeyPressed DO
  492.    BEGIN
  493.    FillChar (Screen[Y]^, Scan_Width+1, 0);
  494.    C_Point.R := Low.R - Delta.R;
  495.  
  496.    FOR X := 0 TO Dots_Horizontal DO
  497.       BEGIN
  498.       Plot (X, Y, Max_Colors);
  499.       C_Point.R := C_Point.R + Delta.R;
  500.       Z_Point := C_Point;
  501.       Count := 0;
  502.  
  503.       WHILE (Count<=Max_Count) AND (Square_Size_Of_C (Z_Point)<4.0) DO
  504.          BEGIN
  505. { 1*     Mult_Comp (Z_Point, Z_Point, Z_Point);  }
  506. { 2*     Add_Comp (Z_Point, C_Point, Z_Point);  }
  507.  
  508.          Temp := Sqr (Z_Point.R) - Sqr (Z_Point.I) + C_Point.R;
  509.          Z_Point.I := 2.0 * Z_Point.I * Z_Point.R + C_Point.I;
  510.          Z_Point.R := Temp;
  511.          Count := Succ (Count)
  512.          END {* WHILE *};
  513.  
  514.       IF Count<Max_Count THEN
  515.          Screen[Y]^[X] := Use_Color[Count MOD Color_Count];
  516.  
  517.       Plot (X, Y, Screen[Y]^[X])
  518.       END {* FOR *};
  519.  
  520.    C_Point.I := C_Point.I - Delta.I;
  521.    Y := Y + 1
  522.    END {* WHILE *};
  523.  
  524. Screen_Data.Start := Y
  525. END {* Generate *};
  526.  
  527. {*******************************************************************}
  528.  
  529. PROCEDURE Wrap_Up;
  530.  
  531. {  This procedure deals with the shutting down of a picture.  }
  532.  
  533. VAR
  534.    X:  integer;
  535.  
  536. BEGIN
  537. Picture_Loaded := True;
  538.  
  539. IF KeyPressed THEN
  540.    Sound (440)
  541.  
  542. ELSE
  543.    BEGIN
  544.    Sound (660);
  545.    Delay (20);
  546.    Sound (1000)
  547.    END {* ELSE *};
  548.  
  549. Delay (50);
  550. NoSound;
  551.  
  552. Ch := ReadKey;
  553.  
  554. RestoreCrtMode;
  555. Write ('Save picture? (Y/N) ');
  556.  
  557. REPEAT
  558.    Ch := ReadKey
  559. UNTIL Ch IN Yes_N_No;
  560.  
  561. Writeln (Ch);
  562.  
  563. IF Ch IN Yes THEN
  564.    BEGIN
  565.    IF File_Name<>'' THEN
  566.       BEGIN
  567.       Write ('Save as ', File_Name, '? (Y/N) ');
  568.  
  569.       REPEAT
  570.          Ch := ReadKey
  571.       UNTIL Ch IN Yes_N_No;
  572.  
  573.       Writeln (Ch)
  574.       END {* THEN *}
  575.  
  576.    ELSE
  577.       Ch := 'N';
  578.  
  579.    IF Ch IN No THEN
  580.       BEGIN
  581.       Write ('Enter filename to save it in:  ');
  582.       Readln (File_Name)
  583.       END {* THEN *};
  584.  
  585.    Assign (Screen_File, File_Name);
  586.    Rewrite (Screen_File);
  587.    Write (Screen_File, Data_Line);
  588.  
  589.    FOR X := 0 TO Screen_Data.Start-1 DO
  590.       Write (Screen_File, Screen[X]^);
  591.  
  592.    Close (Screen_File)
  593.    END {* THEN *};
  594.  
  595. Write ('Do another? (Y/N) ');
  596.  
  597. REPEAT
  598.    Ch := ReadKey
  599. UNTIL Ch IN Yes_N_No;
  600.  
  601. Writeln (Ch)
  602. END {* Wrap_Up *};
  603.  
  604. {*******************************************************************}
  605.  
  606. BEGIN {* main *}
  607. Initialize;
  608.  
  609. REPEAT
  610.    Define_Screen;
  611.    Generate;
  612.    Wrap_Up
  613. UNTIL Ch IN No
  614. END.
  615.