{* ** John Conway's Game of Life, written in ACE BASIC. ** ** Author: David J Benn ** Date: 24th-26th December 1994 ** ** Future enhancements: Circular world option; speed increase; ** Life projects (shell and Wb args); ** variable grid size. ** ** Try evolving the following pattern anywhere on the Life grid: ** ** x ** x ** xxx ** ** Try also loading and evolving the file "GliderGun.pat". *} DEFINT a-z STRING version SIZE 26 version = "$VER: Life 1.0 (26.12.94)" {* ** General constants. *} CONST true = -1& CONST false = 0& CONST null = 0& CONST scrWidth = 640 CONST scrHeight = 200 {* ** Life constants. *} CONST maxX = 40 CONST maxY = 15 CONST cellX = 14& CONST cellY = 7& CONST dead = 0& CONST alive = 1& {* ** Color constants. *} CONST black = 0 CONST white = 1 CONST red = 2 CONST green = 3 CONST blue = 4 {* ** Menu constants. *} CONST sDisable = 0 CONST sEnable = 1 CONST sCheck = 2 CONST mProject = 1 CONST iProject = 0 CONST iLoad = 1 CONST iStore = 2 CONST iModify = 3 CONST iGenerate = 4 CONST iRandom = 5 CONST iClear = 6 CONST iSep1.1 = 7 CONST iAbout = 8 CONST iQuit = 9 {* ** Global variable declarations. *} '..Main and auxillary life matrices. DIM L(maxX,maxY), X(maxX,maxY) '..Modes. Modifying = true Generating = false '..Other globals. GenCount = 0 Changed = false xOff = (scrWidth - (maxX*cellX + 3*cellX)) \ 2 yOff = (scrHeight - (maxY*cellY + 5*cellY)) \ 2 {* ** Enable event trapping. *} ON MENU GOSUB handle_menu MENU ON {* ** Library function declarations. *} CONST leave = -1& LIBRARY "intuition.library" DECLARE FUNCTION SetWindowTitles(wdw&,wdw_title$,scr_title$) LIBRARY intuition {* ** Subprogram definitions. *} SUB SetupMenus MENU mProject,iProject,sEnable, "Project" MENU mProject,iLoad,sEnable, " Load..." MENU mProject,iStore,sEnable, " Store..." MENU mProject,iModify,sEnable, " Modify Grid Contents", "M" MENU mProject,iGenerate,sEnable, " Evolve Life Pattern", "E" MENU mProject,iRandom,sEnable, " Create Random Pattern", "R" MENU mProject,iClear,sEnable, " Clear Grid", "C" MENU mProject,iSep1.1,sDisable, "------------------------------" MENU mProject,iAbout,sEnable, " About..." MENU mProject,iQuit,sEnable, " Quit", "Q" END SUB SUB SetMode(SHORTINT Mode) SHARED Modifying, Generating IF Mode = iModify THEN Modifying = true MENU mProject,iModify,sCheck Generating = false MENU mProject,iGenerate,sEnable EXIT SUB END IF IF Mode = iGenerate THEN Generating = true MENU mProject,iGenerate,sCheck Modifying = false MENU mProject,iModify,sEnable EXIT SUB END IF END SUB SUB DrawGridLines SHARED xOff, yOff COLOR blue '..Vertical lines. FOR i=1 TO maxX+1 LINE (i*cellX+xOff,cellY+yOff)-(i*cellX+xOff,maxY*cellY+cellY+yOff) NEXT '..Horizontal lines. FOR i=1 TO maxY+1 LINE (cellX+xOff,i*cellY+yOff)-(maxX*cellX+cellX+xOff,i*cellY+yOff) NEXT END SUB SUB ShowGenCount SHARED GenCount STRING wdwTitle SIZE 81 wdwTitle = "The Game of Life"+SPACE$(17)+"Generation:"+STR$(GenCount) SetWindowTitles(WINDOW(7),wdwTitle,leave) END SUB SUB ClearGrid SHARED X, L SHARED GenCount, Changed SHARED xOff, yOff MENU mProject,iProject,sDisable FOR i=1 TO maxX FOR j=1 TO maxY X(i,j) = dead L(i,j) = dead LINE (i*cellX+1+xOff,j*cellY+1+yOff)- ~ (i*cellX+(cellX-1)+xOff,j*cellY+(cellY-1)+yOff),black,bf NEXT j NEXT i Changed = false GenCount = 0 ShowGenCount MENU mProject,iProject,sEnable END SUB SUB Msg(STRING theMsg) SetWindowTitles(WINDOW(7),"The Game of Life",leave) MSGBOX theMsg, "Continue" ShowGenCount END SUB SUB LoadPattern SHARED X, L SHARED GenCount SHARED Changed SHARED xOff, yOff STRING theFile SIZE 80 theFile = FILEBOX$("Load Life Pattern...") IF theFile = "" THEN Msg("No file selected.") ELSE OPEN "I",#1,theFile IF HANDLE(1) = null THEN Msg("Unable to open "+theFile+".") ELSE IF EOF(1) THEN Msg(theFile+" is empty!") CLOSE #1 ELSE INPUT #1,x$ IF x$ <> "#LIFE PATTERN#" THEN Msg("Incorrect file format.") CLOSE #1 ELSE ClearGrid GenCount = 0 ShowGenCount Changed = true IF EOF(1) THEN Msg("Unexpected end of file.") ELSE INPUT #1,columns,rows WHILE NOT EOF(1) INPUT #1,a,b IF a >= 1 AND a <= columns AND b >= 1 AND b <= rows THEN X(a,b) = alive : L(a,b) = alive LINE (a*cellX+1+xOff,b*cellY+1+yOff)- ~ (a*cellX+(cellX-1)+xOff,b*cellY+(cellY-1)+yOff),red,bf ELSE Msg("Invalid Coordinate: ("+STR$(a)+","+STR$(b)+" )") END IF WEND CLOSE #1 Msg(theFile+" loaded.") END IF END IF END IF END IF END IF END SUB SUB StorePattern SHARED L STRING theFile SIZE 80 theFile = FILEBOX$("Store Life Pattern...") IF theFile = "" THEN Msg("No file selected.") ELSE OPEN "O",#1,theFile IF HANDLE(1) = null THEN Msg("Unable to open "+theFile+".") ELSE WRITE #1,"#LIFE PATTERN#" WRITE #1,maxX,maxY FOR i=1 TO maxX FOR j=1 TO maxY IF L(i,j) = alive THEN WRITE #1,i,j NEXT j NEXT i CLOSE #1 SetWindowTitles(WINDOW(7),"The Game of Life",leave) Msg("Pattern stored in "+theFile+".") ShowGenCount END IF END IF END SUB SUB ModifyGrid SHARED X, L SHARED Modifying, Generating SHARED GenCount SHARED xOff, yOff GenCount = 0 ShowGenCount WHILE Modifying '..Await left mouse button press. WHILE Modifying AND NOT MOUSE(0):SLEEP:WEND IF Modifying THEN mouseX = MOUSE(1) - xOff mouseY = MOUSE(2) - yOff IF mouseX > cellX AND mouseX < maxX*cellX+cellX AND ~ mouseY > cellY AND mouseY < maxY*cellY+cellY THEN i = mouseX\cellX j = mouseY\cellY IF X(i,j) = dead THEN L(i,j) = alive X(i,j) = alive LINE (i*cellX+1+xOff,j*cellY+1+yOff)- ~ (i*cellX+(cellX-1)+xOff,j*cellY+(cellY-1)+yOff),red,bf ELSE L(i,j) = dead X(i,j) = dead LINE (i*cellX+1+xOff,j*cellY+1+yOff)- ~ (i*cellX+(cellX-1)+xOff,j*cellY+(cellY-1)+yOff),black,bf END IF END IF '..Await left mouse button release. WHILE Modifying AND MOUSE(0):SLEEP:WEND END IF WEND END SUB SUB GenerateLife SHARED X, L SHARED Generating SHARED GenCount, Changed SHARED xOff, yOff REPEAT Changed = false i=1 WHILE i <= maxX j=1 WHILE j <= maxY '..Reset neighbour counter. s = 0 '..Compute effect of 8 neighbours. '..Ignore cells that are off the grid. IF i-1 >= 1 AND j-1 >= 1 THEN s = s+L(i-1,j-1) IF i+1 <= maxX AND j+1 <= maxY THEN s = s+L(i+1,j+1) IF i-1 >= 1 AND j+1 <= maxY THEN s = s+L(i-1,j+1) IF i+1 <= maxX AND j-1 >= 1 THEN s = s+L(i+1,j-1) IF i-1 >= 1 THEN s = s+L(i-1,j) IF j-1 >= 1 THEN s = s+L(i,j-1) IF i+1 <= maxX THEN s = s+L(i+1,j) IF j+1 <= maxY THEN s = s+L(i,j+1) '..Determine life/death status of cell. IF L(i,j) = alive THEN IF s <> 2 AND s <> 3 THEN X(i,j) = dead Changed = true END IF ELSE IF s = 3 THEN X(i,j) = alive Changed = true END IF END IF ++j WEND ++i WEND '..Don't allow pattern to be modified/stored until '..the Life matrix is in a consistent state. MENU mProject,iModify,sDisable MENU mProject,iStore,sDisable '..Refresh main life matrix and display '..current generation. FOR i=1 TO maxX FOR j=1 TO maxY L(i,j) = X(i,j) IF L(i,j) = alive THEN colr = red ELSE colr = black LINE (i*cellX+1+xOff,j*cellY+1+yOff)- ~ (i*cellX+(cellX-1)+xOff,j*cellY+(cellY-1)+yOff),colr,bf NEXT j NEXT i '..Increment generation counter. IF Changed THEN ++GenCount ShowGenCount END IF '..Allow pattern to be modified/stored now that '..the Life matrix is in a consistent state. MENU mProject,iModify,sEnable MENU mProject,iStore,sEnable UNTIL NOT Generating OR NOT Changed '..Switch generation mode off. MENU mProject,iGenerate,sEnable Generating = false END SUB SUB RandomPattern SHARED X, L SHARED GenCount, Changed SHARED xOff, yOff MENU mProject,iProject,sDisable FOR i=1 TO maxX FOR j=1 TO maxY IF RND <= .1 THEN status = alive ELSE status = dead X(i,j) = status L(i,j) = status IF L(i,j) = alive THEN colr = red ELSE colr = black LINE (i*cellX+1+xOff,j*cellY+1+yOff)- ~ (i*cellX+(cellX-1)+xOff,j*cellY+(cellY-1)+yOff),colr,bf NEXT j NEXT i Changed = true GenCount = 0 ShowGenCount MENU mProject,iProject,sEnable END SUB SUB AboutLife SetWindowTitles(WINDOW(7),"Life - written in ACE BASIC",leave) MsgBox "Version 1.0 by David Benn, 12/94", "Continue" ShowGenCount END SUB {* ** Main. *} RANDOMIZE TIMER SCREEN 1,scrWidth,scrHeight,3,2 WINDOW 1,"",(0,0)-(scrWidth,scrHeight),0,1 PALETTE black,0,0,0 PALETTE white,1,1,1 PALETTE red,1,0,0 PALETTE green,0,1,0 PALETTE blue,0,0,1 SetupMenus ClearGrid DrawGridLines SetMode(iModify) ModifyGrid HavingFun = true WHILE HavingFun SLEEP WEND END {* ** Event handlers. *} handle_menu: theMenu = MENU(0) theItem = MENU(1) IF theMenu = mProject THEN CASE theItem = iLoad : LoadPattern theItem = iStore : StorePattern theItem = iModify : IF NOT Modifying THEN SetMode(iModify) ModifyGrid ELSE Modifying = false MENU mProject,iModify,sEnable END IF theItem = iGenerate : IF NOT Generating THEN SetMode(iGenerate) GenerateLife ELSE Generating = false MENU mProject,iGenerate,sEnable END IF theItem = iRandom : RandomPattern theItem = iClear : ClearGrid theItem = iAbout : AboutLife theItem = iQuit : WINDOW CLOSE 1:SCREEN CLOSE 1:STOP END CASE END IF RETURN