home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / mbug / mbug150.arc / LIFE2.PAS < prev    next >
Pascal/Delphi Source File  |  1979-12-31  |  17KB  |  597 lines

  1. Program Life;
  2.  
  3. Label 100;
  4.  
  5.  
  6.    Const
  7.       Height = 23;
  8.       Width = 60;
  9.       MinBound = - 1;
  10.       Lively = '+';
  11.       Deadly = ' ';
  12.  
  13.    Type
  14.       State = (Alive, Dead);
  15.       Cell =
  16.          Record
  17.             LooksLikeItIs: State;
  18.             Nearby: Integer;
  19.          End;
  20.       Edges =
  21.          Record
  22.             Left, Right, Top, Bottom: Integer
  23.          End;
  24.       ScreenLine = String [80];
  25.  
  26.    Var
  27.       Ch: Char;
  28.       yes_no: char;
  29.       Edge: Edges;
  30.       Births, Deaths, Generation, Pause, Population: Integer;
  31.       Board: Array [MinBound..Width, MinBound..Height] of Cell;
  32.  
  33.  
  34.    Function Yes(Line: ScreenLine): Boolean;
  35.  
  36.       Var
  37.          Ch: Char;
  38.  
  39.       Begin
  40.          Write(Line, '? ');
  41.          Repeat
  42.             Read(Kbd, Ch)
  43.          Until UpCase(Ch) in ['Y', 'N'];
  44.          Yes := UpCase(Ch) = 'Y'
  45.       End;
  46.  
  47.  
  48.    Function Min(a, b: Integer): Integer;
  49.  
  50.       Begin
  51.          If a <= b then
  52.             Min := a
  53.          else
  54.             Min := b
  55.       End;
  56.  
  57.  
  58.    Function Max(a, b: Integer): Integer;
  59.  
  60.       Begin
  61.          If a >= b then
  62.             Max := a
  63.          else
  64.             Max := b
  65.       End;
  66.  
  67.  
  68.    Procedure ResetEdges;
  69.  
  70.       Begin
  71.          With Edge do
  72.             Begin
  73.             Top := Height - 1;
  74.             Right := MinBound + 1;
  75.             Left := Width - 1;
  76.             Bottom := MinBound + 1
  77.             End
  78.  
  79.       End;
  80.  
  81.   {$I Instrns.inc}
  82.  
  83.  
  84.    Procedure Initialize;
  85.  
  86.       Var
  87.          Across, Down: Integer;
  88.  
  89.       Begin
  90.          For Across := MinBound to Width do
  91.             For Down := MinBound to Height do
  92.                With Board[Across, Down] do
  93.                   Begin
  94.                   LooksLikeItIs := Dead;
  95.                   Nearby := 0
  96.                   End;
  97.  
  98.          ResetEdges
  99.       End;
  100.  
  101.  
  102.    Procedure Limits(Across, Down: Integer);
  103.  
  104.       Begin
  105.          With Edge do
  106.             Begin
  107.             Left := Min(Left, Across);
  108.             Right := Max(Right, Across);
  109.             Top := Min(Top, Down);
  110.             Bottom := Max(Bottom, Down)
  111.             End
  112.  
  113.       End;
  114.  
  115.  
  116.    Procedure ClearNearby;
  117.  
  118.       Var
  119.          Across, Down: Integer;
  120.  
  121.       Begin
  122.          With Edge do
  123.             For Across := Left - 1 to Right + 1 do
  124.                For Down := Top - 1 to Bottom + 1 do
  125.                   Board[Across, Down].Nearby := 0
  126.  
  127.       End;
  128.  
  129.  
  130.    Procedure CountNeighbors;
  131.  
  132.       Var
  133.          Across, DeltAcross, DeltaDown, Down: Integer;
  134.  
  135.       Begin
  136.          ClearNearby;
  137.          With Edge do
  138.             For Across := Left - 1 to Right + 1 do
  139.                For Down := Top - 1 to Bottom + 1 do
  140.                   If Board[Across, Down].LooksLikeItIs = Alive then
  141.                      For DeltAcross := - 1 to 1 do
  142.                         For DeltaDown := - 1 to 1 do
  143.                            With Board[Across + DeltAcross, Down +
  144.                                 DeltaDown] do
  145.                               Nearby := Succ(Nearby)
  146.  
  147.       End;
  148.  
  149.  
  150.    Procedure UpDate;
  151.  
  152.       Var
  153.          LocalEdge: Edges;
  154.          Across, Down: Integer;
  155.  
  156.       Begin
  157.          Births := 0;
  158.          Deaths := 0;
  159.          LocalEdge := Edge;
  160.          ResetEdges;
  161.          For Across := Max(MinBound + 1, LocalEdge.Left - 1) to Min(Width - 1,
  162.            LocalEdge.Right + 1) do
  163.             For Down := Max(MinBound + 1,
  164.               LocalEdge.Top - 1) to Min(Height - 1, LocalEdge.Bottom + 1) do
  165.                With Board[Across, Down] do
  166.                   Case LooksLikeItIs of
  167.                      Dead:
  168.                         If Nearby = 3 then
  169.                            Begin
  170.                            LooksLikeItIs := Alive;
  171.                            GotoXY(Across + 1, Down + 1);
  172.                            Write(Lively);
  173.                            Limits(Across, Down);
  174.                            Births := Births + 1
  175.                            End;
  176.                      Alive:
  177.                         If (Nearby = 3) or (Nearby = 4) then
  178.                            Limits(Across, Down)
  179.                         else
  180.                            Begin
  181.                            LooksLikeItIs := Dead;
  182.                            GotoXY(Across + 1, Down + 1);
  183.                            Write(Deadly);
  184.                            Deaths := Deaths + 1
  185.                            End
  186.                      End;
  187.  
  188.          Generation := Generation + 1;
  189.          Population := Population + Births - Deaths;
  190.          GotoXY(Width + 15, 16);
  191.          Write(Generation: 5);
  192.          GotoXY(Width + 15, 17);
  193.          Write(Population: 5);
  194.          GotoXY(Width + 15, 18);
  195.          Write(Births: 5);
  196.          GotoXY(Width + 15, 19);
  197.          Write(Deaths: 5)
  198.       End;
  199.  
  200.  
  201.    Procedure DrawScreen;
  202.  
  203.       Var
  204.          Index: Integer;
  205.  
  206.       Begin
  207.          GotoXY(Width + 1, 1);
  208.          Write('+');
  209.          For Index := 2 to Height do
  210.             Begin
  211.             GotoXY(Width + 1, Index);
  212.             Write('|')
  213.             End;
  214.          GotoXY(1, Height + 1);
  215.          For Index := 1 to Width do
  216.             Write('-');
  217.          Write('+');
  218.          GotoXY(Width + 4, 1);
  219.          Write('The Game of Life.');
  220.          GotoXY(Width + 7, 2);
  221.          Write('Version 2.0');
  222.          GotoXY(Width + 11, 3);
  223.          Write('by');
  224.          GotoXY(Width + 7, 4);
  225.          Write('Cyrus Patel');
  226.          GotoXY(Width + 6, 6);
  227.          Write('^     ^     ^');
  228.          GotoXY(Width + 7, 7);
  229.          Write('\    |    /');
  230.          GotoXY(Width + 8, 8);
  231.          Write('\   |   /');
  232.          GotoXY(Width + 9, 9);
  233.          Write('7  8  9');
  234.          GotoXY(Width + 4, 10);
  235.          Write('<--- 4  *  6 --->');
  236.          GotoXY(Width + 9, 11);
  237.          Write('1  2  3');
  238.          GotoXY(Width + 8, 12);
  239.          Write('/   |   \');
  240.          GotoXY(Width + 7, 13);
  241.          Write('/    |    \');
  242.          GotoXY(Width + 6, 14);
  243.          Write('v     v     v');
  244.          GotoXY(Width + 4, 16);
  245.          Write('Generation:');
  246.          GotoXY(Width + 15, 16);
  247.          Write(0: 5);
  248.          GotoXY(Width + 4, 17);
  249.          Write('Population:');
  250.          GotoXY(Width + 15, 17);
  251.          Write(0: 5);
  252.          GotoXY(Width + 8, 18);
  253.          Write('Births:');
  254.          GotoXY(Width + 15, 18);
  255.          Write(0: 5);
  256.          GotoXY(Width + 8, 19);
  257.          Write('Deaths:');
  258.          GotoXY(Width + 15, 19);
  259.          Write(0: 5);
  260.          GotoXY(Width + 9, 20);
  261.          Write('Speed:');
  262.          GotoXY(Width + 15, 20);
  263.          Write(0: 5);
  264.          GotoXY(Width + 5, 23);
  265.          Write('ESC to     t.')
  266.       End;
  267.  
  268.  
  269.    Procedure LoadScreen;
  270.  
  271.       Var
  272.          InFile: Text;
  273.          Error: Boolean;
  274.          FileName: String [14];
  275.          Across, Down: Integer;
  276.  
  277.       Begin
  278.          GotoXY(Width + 3, 21);
  279.          If Yes('Reset screen') then
  280.             Begin
  281.             For Across := MinBound to Width do
  282.                For Down := MinBound to Height do
  283.                   With Board[Across, Down] do
  284.                      If LooksLikeItIs = Alive then
  285.                         Begin
  286.                         GotoXY(Across + 1, Down + 1);
  287.                         Write(' ');
  288.                         LooksLikeItIs := Dead;
  289.                         Nearby := 0
  290.                         End;
  291.  
  292.             ResetEdges;
  293.             Population := 0;
  294.             GotoXY(Width + 15, 17);
  295.             Write(Population: 5)
  296.             End;
  297.          GotoXY(Width + 3, 21);
  298.          Write('File name to load:');
  299.          GotoXY(Width + 5, 22);
  300.          BufLen := 14;
  301.          ReadLn(FileName);
  302.          GotoXY(Width + 3, 21);
  303.          ClrEol;
  304.          GotoXY(Width + 5, 22);
  305.          ClrEol;
  306.          If FileName <> '' then
  307.             Begin
  308.             GotoXY(Width + 6, 22);
  309.             Write('Loading...');
  310.             Assign(InFile, FileName);
  311.             Error := IOResult <> 0;
  312.             If Not Error then
  313.                begin
  314.                Reset(InFile);
  315.                Error := IOResult <> 0
  316.                End;
  317.             If Not Error then
  318.                Repeat
  319.                   ReadLn(InFile, Across, Down);
  320.                   If (Across >= MinBound) and (Down >= MinBound) and
  321.                      (Down <= Height) and (Across <= Width) then
  322.                      With Board[Across, Down] do
  323.                         Begin
  324.                         Limits(Across, Down);
  325.                         If LooksLikeItIs = Dead then
  326.                            Begin
  327.                            GotoXY(Across + 1, Down + 1);
  328.                            Write(Lively);
  329.                            LooksLikeItIs := Alive;
  330.                            Population := Population + 1;
  331.                            GotoXY(Width + 15, 17);
  332.                            Write(Population: 5)
  333.                            End
  334.                         End;
  335.  
  336.                   Error := IOResult <> 0
  337.                Until (Eof(InFile)) or (Error);
  338.             Close(InFile);
  339.             If Not Error then
  340.                Error := IOResult <> 0;
  341.             GotoXY(Width + 6, 22);
  342.             If Error then
  343.                Write('Loading Error!', Chr(7))
  344.             else
  345.                ClrEol
  346.             End
  347.       End;
  348.  
  349.  
  350.    Procedure SaveScreen;
  351.  
  352.       Var
  353.          OutFile: Text;
  354.          Error: Boolean;
  355.          FileName: String [14];
  356.          Across, Down: Integer;
  357.  
  358.       Begin
  359.          GotoXY(Width + 3, 21);
  360.          Write('File name to save:');
  361.          GotoXY(Width + 5, 22);
  362.          BufLen := 14;
  363.          ReadLn(FileName);
  364.          GotoXY(Width + 3, 21);
  365.          ClrEol;
  366.          GotoXY(Width + 5, 22);
  367.          ClrEol;
  368.          If FileName <> '' then
  369.             Begin
  370.             GotoXY(Width + 6, 22);
  371.             Write('Saving...');
  372.             Assign(OutFile, FileName);
  373.             Error := IOResult <> 0;
  374.             If Not Error then
  375.                Begin
  376.                ReWrite(OutFile);
  377.                Error := IOResult <> 0
  378.                End;
  379.             If Not Error then
  380.                For Across := MinBound to Width do
  381.                   For Down := MinBound to Height do
  382.                      With Board[Across, Down] do
  383.                         If LooksLikeItIs = Alive then
  384.                            If Not Error then
  385.                               Begin
  386.                               WriteLn(OutFile, Across: 1, ' ', Down: 1);
  387.                               Error := IOResult <> 0
  388.                               End;
  389.  
  390.             Close(OutFile);
  391.             If Not Error then
  392.                Error := IOResult <> 0;
  393.             If Error then
  394.                Erase(OutFile);
  395.             GotoXY(Width + 6, 22);
  396.             ClrEol
  397.             End
  398.       End;
  399.  
  400.  
  401.    Procedure GetPositions;
  402.  
  403.       Var
  404.          Ch: Char;
  405.          Across, Down, Index: Integer;
  406.  
  407.       Begin
  408.          Down := 0;
  409.          Across := 0;
  410.          GotoXY(Width + 12, 23);
  411.          Write('star');
  412.          Repeat
  413.             GotoXY(Across + 1, Down + 1);
  414.             Index := - 15000;
  415.             If Not KeyPressed then
  416.                Repeat
  417.                   If Index <= 32767 then
  418.                      Index := Index + 1;
  419.                   If Index = 0 then
  420.                      Begin
  421.                      GotoXY(Width + 6, 22);
  422.                      ClrEol;
  423.                      GotoXY(Across + 1, Down + 1)
  424.                      End
  425.                   else If Index = 32767 then
  426.                      Begin
  427.                      GotoXY(Width + 6, 22);
  428.                      Write(Chr(7), 'Hurry up!!');
  429.                      GotoXY(Across + 1, Down + 1);
  430.                      Index := - 30000
  431.                      End
  432.                Until KeyPressed;
  433.             Read(Kbd, Ch);
  434.             If (Ch = Chr(27)) and (KeyPressed) then
  435.                Begin
  436.                Read(Kbd, Ch);
  437.                Case Ord(Ch) of
  438.                   71:
  439.                      Ch := '7';
  440.                   72:
  441.                      Ch := '8';
  442.                   73:
  443.                      Ch := '9';
  444.                   75:
  445.                      Ch := '4';
  446.                   77:
  447.                      Ch := '6';
  448.                   79:
  449.                      Ch := '1';
  450.                   80:
  451.                      Ch := '2';
  452.                   81:
  453.                      Ch := '3'
  454.                   end
  455.                End;
  456.             If Ch = ' ' then
  457.                Ch := '5';
  458.             If Index < 1 then
  459.                Begin
  460.                GotoXY(Width + 6, 22);
  461.                ClrEol;
  462.                GotoXY(Across + 1, Down + 1)
  463.                End;
  464.             Case Ch of
  465.                ^L:
  466.                   LoadScreen;
  467.                ^S:
  468.                   SaveScreen;
  469.                '1':
  470.                   Begin
  471.                   Across := Pred(Across);
  472.                   Down := Succ(Down)
  473.                   End;
  474.                '2':
  475.                   Down := Succ(Down);
  476.                '3':
  477.                   Begin
  478.                   Across := Succ(Across);
  479.                   Down := Succ(Down)
  480.                   End;
  481.                '4':
  482.                   Across := Pred(Across);
  483.                '5':
  484.                   With Board[Across, Down] do
  485.                      Begin
  486.                      Limits(Across, Down);
  487.                      If LooksLikeItIs = Alive then
  488.                         Begin
  489.                         Write(Deadly);
  490.                         LooksLikeItIs := Dead;
  491.                         Population := Population - 1
  492.                         End
  493.                      else
  494.                         Begin
  495.                         Write(Lively);
  496.                         LooksLikeItIs := Alive;
  497.                         Population := Population + 1
  498.                         End;
  499.                      GotoXY(Width + 15, 17);
  500.                      Write(Population: 5)
  501.                      End;
  502.  
  503.                '6':
  504.                   Across := Succ(Across);
  505.                '7':
  506.                   Begin
  507.                   Across := Pred(Across);
  508.                   Down := Pred(Down)
  509.                   End;
  510.                '8':
  511.                   Down := Pred(Down);
  512.                '9':
  513.                   Begin
  514.                   Across := Succ(Across);
  515.                   Down := Pred(Down)
  516.                   End
  517.                End;
  518.             If Across > Width - 1 then
  519.                Begin
  520.                Across := 0;
  521.                Down := Succ(Down)
  522.                End
  523.             else If Across < 0 then
  524.                Begin
  525.                Across := Width - 1;
  526.                Down := Pred(Down)
  527.                End;
  528.             If Down > Height - 1 then
  529.                Down := 0
  530.             else If Down < 0 then
  531.                Down := Height - 1
  532.          Until Ch = Chr(27);
  533.          GotoXY(Width + 12, 23);
  534.          Write('abor')
  535.       End;
  536.  
  537.    Begin
  538.    100:
  539.       Initialize;
  540.       Instructions;
  541.       DrawScreen;
  542.       Population := 0;
  543.       Generation := 0;
  544.       Pause := 32;
  545.       GetPositions;
  546.       GotoXY(Width + 15, 20);
  547.       Write(Pause Div 16: 5);
  548.       Repeat
  549.          CountNeighbors;
  550.          UpDate;
  551.          If Pause <> 0 then
  552.             For Ch := 'A' to 'Z' do
  553.                Delay(Pause);
  554.          If KeyPressed then
  555.             Begin
  556.             Read(Kbd, Ch);
  557.             Case Ch of
  558.                ^M:
  559.                   GetPositions;
  560.                ^[:
  561.                   If Not KeyPressed then
  562.                      Population := 0;
  563.                '>', '.':
  564.                   Pause := Min(Pause + 16, 255);
  565.                '<', ',':
  566.                   Pause := Max(Pause - 16, 0)
  567.                End;
  568.             If Ch in ['>', '.', '<', ','] then
  569.                Begin
  570.                GotoXY(Width + 15, 20);
  571.                If Pause = 0 then
  572.                   Write(Pause: 5)
  573.                else
  574.                   Write(Pause Div 16: 5)
  575.                End
  576.             End
  577.       Until (Population = 0) or ((Births = 0) and (Deaths = 0));
  578.       GotoXY(Width + 5, 23);
  579.       ClrEol;
  580.       If Ch = Chr(27) then
  581.          Write('   Aborted!!')
  582.       else If Population = 0 then
  583.          Begin
  584.          GotoXY(Width + 3, 22);
  585.          Write('This colony has');
  586.          GotoXY(Width + 6, 23);
  587.          Write('died out.')
  588.          End;
  589.       GotoXY(1, 24);
  590.       clrscr;
  591.       writeln('ANOTHER RUN? Y/N');
  592.       readln(yes_no);
  593.       yes_no := upcase(yes_no);
  594.       if yes_no = 'Y'
  595.         then goto 100;
  596.    End.
  597.