home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Snippets / LifeEdit 1.0 / LifeEdit.p < prev    next >
Encoding:
Text File  |  1995-02-08  |  10.4 KB  |  459 lines  |  [TEXT/PJMM]

  1. program Precog; {but I think LifeEdit is a better description /Ingemar}
  2.  
  3. {• An itty bitty bytes™ revival project, updated by Kenneth A. Long.}
  4. {• Made to run in Symantec's THINK C™ on 27 December 1994.}
  5. {• Original author unknown.  Original source for Aztec C.}
  6.  
  7. {More fun with Pascal! And simpler code! And update events! And draggable window!}
  8. {Fixed by Ingemar jan 1995. No color support, though.}
  9.  
  10.     const
  11.         lastMenu = 3;
  12.         appleMenu = 1;
  13.         fileMenu = 2;
  14.         optMenu = 3;
  15.         iQuit = 1;
  16.         windowID = 260;
  17.  
  18.     const
  19.         hSize = 36;
  20.         vSize = 36;
  21.         hSizePlus1 = 37;
  22.         vSizePlus1 = 37;
  23.         hSpace = 169 + 8;
  24.         vSpace = 158;
  25.         pixSize = 4;
  26.  
  27.     function max (a, b: Integer): Integer;
  28.     begin
  29.         if a > b then
  30.             max := a
  31.         else
  32.             max := b;
  33.     end;
  34.     function min (a, b: Integer): Integer;
  35.     begin
  36.         if a < b then
  37.             min := a
  38.         else
  39.             min := b;
  40.     end;
  41.  
  42.     var
  43.         myMenus: array[1..lastMenu] of MenuHandle;
  44.         userDone: Boolean;
  45.         screenPort: GrafPtr;
  46.         myWindow: WindowPtr;
  47.         myEvent: EventRecord;
  48.         whichWindow: WindowPtr;
  49.         windowCode: Integer;
  50.  
  51.     type
  52.         GenArr = array[0..vSizePlus1, 0..hSizePlus1] of Boolean;
  53.  
  54.     var
  55.         gen1, gen2, gen3, gen4, gen5, gen6: GenArr;
  56.         mouseLoc: Point;
  57.         textRect: Rect;
  58.         oldX, oldY: LongInt;
  59.  
  60.  
  61. {*** SetUpMenus - set up menus.}
  62.  
  63.     procedure SetUpMenus;
  64.         var
  65.             i: Integer;
  66.     begin
  67.         for i := 1 to lastMenu do
  68.             myMenus[i] := GetMenu(i);
  69.  
  70.         AddResMenu(myMenus[appleMenu], 'DRVR');
  71.  
  72.         for i := 1 to lastMenu do
  73.             InsertMenu(myMenus[i], 0);
  74.  
  75.         DrawMenuBar;
  76.     end; {SetUpMenus}
  77.  
  78.  
  79. {*** SetUp - init toolbox and the window.}
  80.  
  81.     procedure SetUp;
  82.     begin
  83. {$ifc undefined THINK_PASCAL}
  84.         InitGraf(@thePort);
  85.         InitFonts;
  86.         InitWindows;
  87.         InitMenus;
  88.         TEInit;
  89.         InitDialogs(nil);
  90. {$endc}
  91.         InitCursor;
  92.         SetEventMask(everyEvent - keyUpMask);
  93.         SetUpMenus;
  94.         myWindow := GetNewWindow(windowID, nil, WindowPtr(-1));
  95.         SetPort(myWindow);
  96.     end; {SetUp}
  97.  
  98.  
  99. {*** Life - process one step of the Life algorithm.}
  100.  
  101.     function Life (h, v: Integer; genPtr: GenArr): Boolean;
  102.         var
  103.             neighbor: Integer;
  104.     begin
  105.         neighbor := 0;
  106.         if genPtr[v - 1, h - 1] then
  107.             neighbor := neighbor + 1;
  108.         if genPtr[v - 1, h] then
  109.             neighbor := neighbor + 1;
  110.         if genPtr[v - 1, h + 1] then
  111.             neighbor := neighbor + 1;
  112.         if genPtr[v, h - 1] then
  113.             neighbor := neighbor + 1;
  114.         if genPtr[v, h + 1] then
  115.             neighbor := neighbor + 1;
  116.         if genPtr[v + 1, h - 1] then
  117.             neighbor := neighbor + 1;
  118.         if genPtr[v + 1, h] then
  119.             neighbor := neighbor + 1;
  120.         if genPtr[v + 1, h + 1] then
  121.             neighbor := neighbor + 1;
  122.  
  123.         Life := (neighbor = 3) or (genPtr[v][h] and (neighbor = 2));
  124.     end; {Life}
  125.  
  126.  
  127. {*** NextGeneration - Process a rectangle with the Life algorithm}
  128.  
  129.     procedure NextGeneration (minH, minV, maxH, maxV: Integer; var srcGen, destGen: GenArr);
  130.         var
  131.             left, right, up, down: Integer;
  132.             i, j: Integer;
  133.     begin
  134.         left := max(minH, 1);
  135.         right := min(maxH, hSize);
  136.         up := max(minV, 1);
  137.         down := min(maxV, vSize);
  138.         for i := up to down do
  139.             for j := left to right do
  140.                 destGen[i, j] := Life(j, i, srcGen);
  141.     end; {NextGeneration}
  142.  
  143.  
  144. {*** DrawGen - Draw all or part of a generation array}
  145.  
  146.     procedure DrawGen (minH, minV, maxH, maxV: Integer; var gen: GenArr; offH, offV: Integer; drawWhite: Boolean);
  147.         var
  148.             left, right, up, down: Integer;
  149.             i, j: Integer;
  150.             patPtr2: Pattern;
  151.             cell: Rect;
  152.     begin
  153.         left := max(minH, 1);
  154.         right := min(maxH, hSize);
  155.         up := max(minV, 1);
  156.         down := min(maxV, vSize);
  157.         for i := up to down do
  158.             for j := left to right do
  159.                 begin
  160.                     if not gen[i, j] then
  161.                         patPtr2 := white
  162.                     else
  163.                         patPtr2 := black;
  164.                     if gen[i, j] or drawWhite then
  165.                         begin
  166.                             cell.top := i * pixSize + offV;
  167.                             cell.left := j * pixSize + offH;
  168.                             cell.bottom := i * pixSize + offV + pixSize - 1;
  169.                             cell.right := j * pixSize + offH + pixSize - 1;
  170.                             FillRect(cell, patPtr2);
  171.                         end;
  172.                 end;
  173.     end; {DrawGen}
  174.  
  175.  
  176. {*** Update - handle update events.}
  177.  
  178.     procedure Update;
  179.         var
  180.             i, j: Integer;
  181.             box: Rect;
  182.     begin
  183.         BeginUpdate(myWindow);
  184.         EraseRect(myWindow^.portRect);
  185.         for i := 1 to 2 do
  186.             for j := 1 to 3 do
  187.                 begin
  188.                     SetRect(box, hSpace * (j - 1) + 2, vSpace * (i - 1) + 2, hSpace * (j - 1) + hSize * pixSize + 5, vSpace * (i - 1) + vSize * pixSize + 5);
  189.                     FrameRect(box);
  190.                 end;
  191.         DrawGen(1, 1, hSize, vSize, gen1, 0, 0, false);
  192.         DrawGen(1, 1, hSize, vSize, gen2, hSpace, 0, false);
  193.         DrawGen(1, 1, hSize, vSize, gen3, hSpace * 2, 0, false);
  194.         DrawGen(1, 1, hSize, vSize, gen4, 0, vSpace, false);
  195.         DrawGen(1, 1, hSize, vSize, gen5, hSpace, vSpace, false);
  196.         DrawGen(1, 1, hSize, vSize, gen6, hSpace * 2, vSpace, false);
  197.         EndUpdate(myWindow);
  198.     end; {Update}
  199.  
  200.  
  201. {*** Clear - erase everything.}
  202.  
  203.     procedure Clear;
  204.         var
  205.             i, j: Integer;
  206.     begin
  207.         for i := 0 to vSize + 1 do
  208.             for j := 0 to hSize + 1 do
  209.                 begin
  210.                     gen1[i][j] := false;
  211.                     gen2[i][j] := false;
  212.                     gen3[i][j] := false;
  213.                     gen4[i][j] := false;
  214.                     gen5[i][j] := false;
  215.                     gen6[i][j] := false;
  216.                 end;
  217.         InvalRect(myWindow^.portRect);
  218. {Update;}
  219.     end; {Clear}
  220.  
  221.  
  222. {*** DoAbout - show the About message.}
  223.  
  224.     procedure DoAbout;
  225.         const
  226.             line01 = 'An itty bitty bytes™ revival project, brought back from the dead by';
  227.             line02 = 'Kenneth A. Long on 27 December 1994.';
  228.             line03 = 'Author unknown - found in a file on:';
  229.             line04 = 'ftp mrcnext.cso.uiuc.edu /pub/mac/MUG, called "life editor"';
  230.             line05 = 'Added DoAbout routine and fixed up the mouse position';
  231.             line06 = 'indicator (no need for ANSI lib) and modernized the code (a little).';
  232.             line07 = 'Click to return.';
  233.             line08 = 'Improved further, in a couple of ways, by Ingemar january 1995.';
  234.     begin
  235.         EraseRect(myWindow^.portRect);
  236.         MoveTo(20, 20);
  237.         DrawString(line01);
  238.         MoveTo(20, 30);
  239.         DrawString(line02);
  240.  
  241.         MoveTo(20, 50);
  242.         DrawString(line03);
  243.         MoveTo(20, 60);
  244.         DrawString(line04);
  245.  
  246.         MoveTo(20, 80);
  247.         DrawString(line05);
  248.         MoveTo(20, 90);
  249.         DrawString(line06);
  250.  
  251.         MoveTo(20, 120);
  252.         DrawString(line07);
  253.  
  254.         MoveTo(20, 180);
  255.         DrawString(line08);
  256.  
  257.         while not Button do
  258.             ;
  259.         InvalRect(myWindow^.portRect);
  260.         Update;
  261.     end; {DoAbout}
  262.  
  263.  
  264. {*** DoCommand - handle menu selections.}
  265.  
  266.     function DoCommand (mResult: LongInt): Boolean;
  267.         var
  268.             refNum: Integer;
  269.             theMenu: Integer;
  270.             theItem: Integer;
  271.             name: Str255;
  272.             savePort: GrafPtr;
  273.             returns: Boolean;
  274.  
  275.     begin
  276.         returns := false;
  277.         theMenu := HiWord(mResult); {• Menu.}
  278.         theItem := LoWord(mResult); {• Item.}
  279.         case theMenu of
  280.             0: 
  281.                 ;
  282.             appleMenu: 
  283.                 if theItem = 1 then
  284.                     DoAbout
  285.                 else
  286.                     begin
  287.                         GetPort(savePort);
  288.                         GetItem(myMenus[appleMenu], theItem, name);
  289.                         refNum := OpenDeskAcc(name);
  290.                         SetPort(savePort);
  291.                     end;
  292.             fileMenu: 
  293.                 returns := true;
  294.             optMenu: 
  295.                 Clear;
  296.         end; {case}
  297.         HiliteMenu(0);
  298.         DoCommand := returns;
  299.     end; {DoCommand}
  300.  
  301.  
  302. {*** Edit - process a mouse down in the editable area.}
  303.  
  304.     procedure Edit;
  305.         var
  306.             cell: Rect;
  307.             h, v: Integer;
  308.             newColor: Boolean;
  309.             patPtr1{, patPtr2, patPtr3, patPtr4, patPtr5, patPtr6}
  310.             : Pattern;
  311.     begin
  312.         GetMouse(mouseLoc);
  313.         h := mouseLoc.h div pixSize;
  314.         v := mouseLoc.v div pixSize;
  315.         if (v > vSize) or (v < 1) or (h > hSize) or (h < 1) then
  316.             begin
  317.                 SysBeep(5);
  318.                 exit(Edit);
  319.             end;
  320.         gen1[v][h] := not gen1[v][h];
  321.         if gen1[v][h] then
  322.             patPtr1 := black
  323.         else
  324.             patPtr1 := white;
  325.         newColor := gen1[v][h];
  326.  
  327.         repeat
  328.             cell.top := v * pixSize;
  329.             cell.left := h * pixSize;
  330.             cell.bottom := v * pixSize + 3;
  331.             cell.right := h * pixSize + 3;
  332.             FillRect(cell, patPtr1);
  333.             gen1[v][h] := newColor;
  334.  
  335.         {Process the parts of the arrays that might change}
  336.             NextGeneration(h - 1, v - 1, h + 1, v + 1, gen1, gen2);
  337.             NextGeneration(h - 2, v - 2, h + 2, v + 2, gen2, gen3);
  338.             NextGeneration(h - 3, v - 3, h + 3, v + 3, gen3, gen4);
  339.             NextGeneration(h - 4, v - 4, h + 4, v + 4, gen4, gen5);
  340.             NextGeneration(h - 5, v - 5, h + 5, v + 5, gen5, gen6);
  341.  
  342.     {Update the parts that might have changed}
  343. {DrawGen(h - 0, v - 0, h + 0, v + 0, gen1, 0, 0, true); - not necessary}
  344.             DrawGen(h - 1, v - 1, h + 1, v + 1, gen2, hSpace, 0, true);
  345.             DrawGen(h - 2, v - 2, h + 2, v + 2, gen3, hSpace * 2, 0, true);
  346.             DrawGen(h - 3, v - 3, h + 3, v + 3, gen4, 0, vSpace, true);
  347.             DrawGen(h - 4, v - 4, h + 4, v + 4, gen5, hSpace, vSpace, true);
  348.             DrawGen(h - 5, v - 5, h + 5, v + 5, gen6, hSpace * 2, vSpace, true);
  349.  
  350.             GetMouse(mouseLoc);
  351.             h := mouseLoc.h div pixSize;
  352.             v := mouseLoc.v div pixSize;
  353.  
  354.             if (v > vSize) or (v < 1) or (h > hSize) or (h < 1) then
  355.                 begin
  356.                     SysBeep(5);
  357.                     exit(Edit);
  358.                 end;
  359.  
  360.         until not Button;
  361.     end; {Edit}
  362.  
  363.  
  364. {*** MainEventLoop - standard event processing. A few things are still missing, though.}
  365.  
  366.     procedure MainEventLoop;
  367.         var
  368.             xPos, yPos: LongInt;
  369.             mousePos: array[0..19] of char;
  370.             mouseX, mouseY: Str255;
  371.     begin
  372.         FlushEvents(everyEvent, 0);
  373.         repeat
  374.             SystemTask;
  375.             if (GetNextEvent(everyEvent, myEvent)) then
  376.                 case myEvent.what of
  377.                     mouseDown: 
  378.                         begin
  379.                             windowCode := FindWindow(myEvent.where, whichWindow);
  380.                             case windowCode of
  381.                                 inSysWindow: 
  382.                                     SystemClick(myEvent, whichWindow);
  383.  
  384.                                 inMenuBar: 
  385.                                     userDone := DoCommand(MenuSelect(myEvent.where));
  386.  
  387.                                 inContent: 
  388.                                     if (Button) then
  389.                                         Edit;
  390.  
  391.                                 inDrag: 
  392.                                     begin
  393.                                         if (whichWindow <> FrontWindow) and (BitAnd(myEvent.modifiers, cmdKey) = 0) then
  394.                                             SelectWindow(whichWindow);
  395.                                         DragWindow(whichWindow, myEvent.where, screenBits.bounds);
  396.                                     end;
  397.  
  398.                             end; {case windowCode}
  399.                         end; {mouseDown}
  400.  
  401.                     keyDown, autoKey: 
  402.                         if BAnd(myEvent.modifiers, cmdKey) <> 0 then
  403.                             userDone := DoCommand(MenuKey(char(BAnd(myEvent.message, charCodeMask))));
  404.  
  405.                     updateEvt: 
  406.                         Update;
  407.  
  408.                 end; {case myEvent.what}
  409.  
  410.             GetMouse(mouseLoc);
  411.             xPos := mouseLoc.h div pixSize;
  412.             yPos := mouseLoc.v div pixSize;
  413.             if (xPos <> oldX) or (yPos <> oldY) then
  414.                 begin
  415.                     EraseRect(textRect);
  416.                     if (xPos >= 1) and (xPos <= hSize) and (yPos >= 1) and (yPos <= vSize) then
  417.                         begin
  418.                             NumToString(xPos, mouseX);
  419.                             MoveTo(5, 158);
  420.                             DrawString('X:');
  421.                             MoveTo(17, 158);
  422.                             DrawString(mouseX);
  423.  
  424.                             NumToString(yPos, mouseY);
  425.                             MoveTo(40, 158);
  426.                             DrawString('Y:');
  427.                             MoveTo(52, 158);
  428.                             DrawString(mouseY);
  429.                         end; {if xPos >=1…}
  430.                     oldX := xPos;
  431.                     oldY := yPos;
  432.                 end {if xPos<>oldX…}
  433.         until userDone;
  434.     end; {MainEventLoop}
  435.  
  436.  
  437. {*** Init - set the cursor to a cross and init the text rect.}
  438.  
  439.     procedure Init;
  440.         var
  441.             cross: CursHandle;
  442.             i: Integer;
  443.     begin
  444.         cross := GetCursor(crossCursor);
  445.         SetCursor(cross^^);
  446.  
  447.         TextSize(9);
  448.         SetRect(textRect, 0, 149, 75, 159);
  449.     end; {Init}
  450.  
  451.  
  452. {*** main program}
  453.  
  454. begin
  455.     SetUp;
  456.     Init;
  457.     Clear;
  458.     MainEventLoop;
  459. end.