5
\$\begingroup\$

Just for fun I have written a Conway's Game of Life in cmd batch file. I like writing in batch - its restrictions and limits are its appeal.

However - it is slow, very slow on a large grid. Any tips to speed it up?

I think the slowest part is the function GETNCOUNT - this gets the count of the neighbouring 'live' cells so it is called once per cell.

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION

IF "%3"=="" GOTO HELP
SET WIDTH=%1
SET HEIGHT=%2
SET DENSITY=%3
SET LIFECYCLE=0

::::::::::::::::::::
:: Generate Grid 'A'
:: Also for safety, delete any Grid 'B' cells that might be in memory
FOR /L %%h IN (1, 1, %HEIGHT%) DO (
        FOR /L %%w IN (1, 1, %WIDTH%) DO (

            SET /A RAND=!RANDOM!*100/32768
            SET /A RAND=!RAND!+1

            IF !DENSITY! GEQ !RAND! (
                SET A[%%w][%%h]=@
            ) ELSE (
                SET "A[%%w][%%h]= "
            )

            SET B[%%w][%%h]=
        )   
)


::::::::::::::::::::::::::::::
:: TOP OF MAIN PROCESSING LOOP
::
:: Loop through all the Grid 'A' cells
::  - Count number of neighbours
::  - Check if alive or not
::  - If required assign new alive/dead status in Grid 'B'
::
:PROCESS
SET /A LIFECYCLE=%LIFECYCLE%+1

CLS
ECHO Conway's Game of Life. 
CALL :DISPLAY
ECHO Current lifecycle: %LIFECYCLE%

FOR /L %%h IN (1, 1, %HEIGHT%) DO (
        FOR /L %%w IN (1, 1, %WIDTH%) DO (

            CALL :GETNCOUNT %%w %%h
            IF "!A[%%w][%%h]!"=="@" (SET ALIVE=Y) ELSE (SET ALIVE=N)

            IF "!ALIVE!"=="Y" (
                IF !NCOUNT! LSS 2 (
                    SET "B[%%w][%%h]= "
                )
                IF !NCOUNT! EQU 2 (
                    SET B[%%w][%%h]=@
                )
                IF !NCOUNT! EQU 3 (
                    SET B[%%w][%%h]=@
                )
                IF !NCOUNT! GTR 3 (
                    SET "B[%%w][%%h]= "
                )
            )

            IF "!ALIVE!"=="N" (
                IF !NCOUNT! EQU 3 (
                    SET B[%%w][%%h]=@
                )
            )           
        )   
)

:: Now check if we have any Grid 'B' cells 
:: If so, assign these to Grid 'A' cells
FOR /L %%h IN (1, 1, %HEIGHT%) DO (
        FOR /L %%w IN (1, 1, %WIDTH%) DO (

            IF DEFINED B[%%w][%%h] (
                IF "!B[%%w][%%h]!"==" " (
                    SET "A[%%w][%%h]= "
                )
                IF "!B[%%w][%%h]!"=="@" (
                    SET A[%%w][%%h]=@
                )
            )       
        )   
)

:: loop back to the top of process to start again
GOTO PROCESS
::::::::::::::::::::::::::
:: BOTTOM OF PROCESS LOOP
::::::::::::::::::::::::::


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: THIS FUNCTION COUNTS THE NUMBER OF NEIGHBOURS FOR THE GIVEN X AND Y CO-ORDINATES
:: THE COUNT IS STORED IN VARIABLE 'NCOUNT'
::
:: TL | TM | TR
:: ML |    | MR
:: BL | BM | BR
::
:: %1=x %2=y
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GETNCOUNT
SET NCOUNT=0

::::::
:: TOP
IF %2 EQU 1 (SET Y=%HEIGHT%) ELSE (SET /A Y=%2-1)
:: TOP-LEFT
IF %1 EQU 1 (SET X=%WIDTH%) ELSE (SET /A X=%1-1)
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)
:: TOP-MIDDLE
SET X=%1
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)
:: TOP-RIGHT
IF %1 EQU %WIDTH% (SET X=1) ELSE (SET /A X=%1+1)
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)

:::::::::
:: MIDDLE
SET Y=%2
:: MIDDLE-LEFT
IF %1 EQU 1 (SET X=%WIDTH%) ELSE (SET /A X=%1-1)
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)
:: MIDDLE-RIGHT
IF %1 EQU %WIDTH% (SET X=1) ELSE (SET /A X=%1+1)
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)

:::::::::
:: BOTTOM
IF %2 EQU %HEIGHT% (SET Y=1) ELSE (SET /A Y=%2+1)
:: BOTTOM-LEFT
IF %1 EQU 1 (SET X=%WIDTH%) ELSE (SET /A X=%1-1)
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)
:: BOTTOM-MIDDLE
SET X=%1
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)
:: BOTTOM-RIGHT
IF %1 EQU %WIDTH% (SET X=1) ELSE (SET /A X=%1+1)
IF !A[%X%][%Y%]! EQU @ (SET /A NCOUNT=!NCOUNT!+1)
::ECHO BR=X:%X% Y:%Y%

GOTO EOF


::::::::::::::::::::::::::::::::::::::::::::
:: THIS FUNCTION DISPLAYS GRID 'A' ON SCREEN 
::::::::::::::::::::::::::::::::::::::::::::
:DISPLAY
SET TOP=
SET BOT=
FOR /L %%h IN (1, 1, %height%) DO (

    IF %%h EQU 1 (FOR /L %%w IN (1, 1, %width%) DO (SET TOP=_!TOP!))
    IF %%h EQU 1 ECHO .!TOP!.

    SET ROW=
    FOR /L %%w IN (1, 1, %WIDTH%) DO (
            SET ROW=!ROW!!A[%%w][%%h]!
    )

    ECHO ^|!ROW!^|

    IF %%h EQU %height% (FOR /L %%w IN (1, 1, %width%) DO (SET BOT=~!BOT!))
    IF %%h EQU %height% ECHO `!BOT!'    
)
GOTO EOF


:HELP
ECHO/
ECHO 'Conway's Game of Life' - Batch Edition - Chazjn 25/02/2017
ECHO ===========================================================
ECHO Usage is as follows:
ECHO    life [width] [height] [%%density]
ECHO E.g.
ECHO    life 8 5 25
ECHO/
ECHO For more infomation visit: https://en.wikipedia.org/wiki/Conway's_Game_of_Life

GOTO EOF


:EOF
\$\endgroup\$
3
\$\begingroup\$

Ok so it turns out that the using CALL in a batch script is very slow. So calling a function once per cell was very expensive time-wise.

So I knew I had to move the logic from the function GETNCOUNT into the main processing loop. However the main issue I ran into here was variable expansion.

I am storing each cell value in a variable named A[x][y] e.g. A[1][1], A[1][2], A[1][3] etc. So after I had calculated the x and y value of the neighbouring cell that I wanted to check, I had to get the value of that variable somehow.

I tried all kinds of double-expansion-nested syntax, e.g. !A[!X!][!Y!]! but this just resulted in XY because the script was trying to expand variables !A[! !][! !]!.

In the end I tried a FOR loop and this worked very nicely. E.g.:

FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (ECHO !A[%%a][%%b]!)

So what this is doing is expanding and assigning !X! and !Y! to variables local to the FOR loop %%a and %%b. Thus I can inject them into my cell variable and expand this to get the value its assigned.

So here is the 'final' code, it works much much faster than before. I am pretty satisfied with the performance now, I don't think I can get much more speed out of it.

What I would like to do next is figure out a way to exit gracefully as the only way currently is to press CTRL+C. But that's for another time...

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION

IF "%3"=="" GOTO HELP
SET WIDTH=%1
SET HEIGHT=%2
SET DENSITY=%3
SET GENERATION=0
SET /A CELLCOUNT=%WIDTH%*%HEIGHT%
SET ALIVECOUNT=0

::::::::::::::::::::
:: Generate grid 'A'. This grid holds the cell layout for display
:: Also for safety, delete any grid 'B' cells that might be in memory
:: Grid 'B' used to store temporary cell values before they are assigned to grid 'A' 
FOR /L %%h IN (1, 1, %HEIGHT%) DO (
        FOR /L %%w IN (1, 1, %WIDTH%) DO (

            SET /A RAND=!RANDOM!*100/32768

            IF !DENSITY! GEQ !RAND! (
                SET A[%%w][%%h]=@
                SET /A ALIVECOUNT=!ALIVECOUNT!+1
            ) ELSE (
                SET "A[%%w][%%h]= "
            )

            SET B[%%w][%%h]=
        )   
)

::::::::::::::::::::::::::::::
:: TOP OF MAIN PROCESSING LOOP
::
:: Display grid 'A'
:: Loop through all the Grid 'A' cells:
::  - Get values neighbouring cells
::  - Get count of alive neighbours 
::  - Apply 'Game of Life' rules and store resulting value in grid 'b' cell
:: Assign grid 'b' cell values to grid 'a' cell values
:: Loop back to start process again
:PROCESS
SET /A GENERATION=%GENERATION%+1
CLS
ECHO Conway's Game of Life. 
ECHO Generation: %GENERATION%
ECHO Live Cells: %ALIVECOUNT%/%CELLCOUNT%
CALL :DISPLAY

IF "%ALIVECOUNT%"=="0" (GOTO EOF)

SET ALIVECOUNT=0
SET COUNTER=0
FOR /L %%h IN (1, 1, %HEIGHT%) DO (
    FOR /L %%w IN (1, 1, %WIDTH%) DO (

        SET /A COUNTER=!COUNTER!+1
        TITLE Calculating Cell !COUNTER!/%CELLCOUNT%

        SET X=0
        SET Y=0
        SET NCOUNT=0

        REM Find the 3 cells above this cell
        IF %%h EQU 1 (SET Y=%HEIGHT%) ELSE (SET /A Y=%%h-1)
        IF %%w EQU 1 (SET X=%WIDTH%) ELSE (SET /A X=%%w-1)
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))  
        SET X=%%w
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))
        IF %%w EQU %WIDTH% (SET X=1) ELSE (SET /A X=%%w+1)
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))

        REM Find the 2 cells left and right of this cell
        SET Y=%%h
        IF %%w EQU 1 (SET X=%WIDTH%) ELSE (SET /A X=%%w-1)
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))
        IF %%w EQU %WIDTH% (SET X=1) ELSE (SET /A X=%%w+1)
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))

        REM Find the 3 cells below this cell
        IF %%h EQU %HEIGHT% (SET Y=1) ELSE (SET /A Y=%%h+1)
        IF %%w EQU 1 (SET X=%WIDTH%) ELSE (SET /A X=%%w-1)
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))
        SET X=%%w
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))
        IF %%w EQU %WIDTH% (SET X=1) ELSE (SET /A X=%%w+1)
        FOR /F "tokens=1,2" %%a IN ("!X! !Y!") DO (IF "!A[%%a][%%b]!"=="@" (SET /A NCOUNT=!NCOUNT!+1))  

        REM Check if this cell is alive or not
        IF "!A[%%w][%%h]!"=="@" (
            SET ALIVE=Y
            SET /A ALIVECOUNT=!ALIVECOUNT!+1
        ) ELSE (
            SET ALIVE=N
        )

        REM Assign live status to grid 'B' based on rules
        IF "!ALIVE!"=="Y" (
            IF !NCOUNT! LSS 2 (
                SET "B[%%w][%%h]= "
            )
            IF !NCOUNT! EQU 2 (
                SET B[%%w][%%h]=@
            )
            IF !NCOUNT! EQU 3 (
                SET B[%%w][%%h]=@
            )
            IF !NCOUNT! GTR 3 (
                SET "B[%%w][%%h]= "
            )
        )

        REM Assign dead status to grid 'B' based on rules
        IF "!ALIVE!"=="N" (
            IF !NCOUNT! EQU 3 (
                SET B[%%w][%%h]=@
            )
        )   
    )   
)

:: Now check if we have set any Grid 'B' cells 
:: If so, assign these cell values to Grid 'A' cells
FOR /L %%h IN (1, 1, %HEIGHT%) DO (
        FOR /L %%w IN (1, 1, %WIDTH%) DO (

            IF DEFINED B[%%w][%%h] (
                IF "!B[%%w][%%h]!"==" " (
                    SET "A[%%w][%%h]= "
                )
                IF "!B[%%w][%%h]!"=="@" (
                    SET A[%%w][%%h]=@
                )
            )       
        )   
)

:: Loop back to the top of process to start again
GOTO PROCESS


::::::::::::::::::::::::::::::::::::::::::::
:: THIS FUNCTION DISPLAYS GRID 'A' ON SCREEN 
::::::::::::::::::::::::::::::::::::::::::::
:DISPLAY
SET TOP=
SET BOT=
FOR /L %%h IN (1, 1, %height%) DO (

    IF %%h EQU 1 (FOR /L %%w IN (1, 1, %width%) DO (SET TOP=_!TOP!))
    IF %%h EQU 1 ECHO .!TOP!.

    SET ROW=
    FOR /L %%w IN (1, 1, %WIDTH%) DO (
            SET ROW=!ROW!!A[%%w][%%h]!
    )

    ECHO ^|!ROW!^|

    IF %%h EQU %height% (FOR /L %%w IN (1, 1, %width%) DO (SET BOT=~!BOT!))
    IF %%h EQU %height% ECHO `!BOT!'    
)
GOTO EOF

:HELP
ECHO/
ECHO 'Conway's Game of Life' - Batch Edition - Chazjn 01/03/2017
ECHO ===========================================================
ECHO Usage is as follows:
ECHO    life [width] [height] [%%density]
ECHO E.g.
ECHO    life 15 10 25
ECHO/
ECHO For more infomation visit: https://en.wikipedia.org/wiki/Conway's_Game_of_Life
GOTO EOF

:EOF
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

A few years late to the party, but there are some more things that can be done to improve efficiency.

  • Move your display logic into the primary loop
  • Utilise an "infinite" For /L loop as opposed to the slower Goto :label loop
    • Note : requires delayed expansion to be enabled and !expansion! must be used for any dynamic non For loop variable.
    For /L %%. in () Do (
        Loop Commands
    )

  • The number of conditional tests applied to the live / dead checks and rules implementation can be further reduced
  • logic for calculating adjacent cell locations can be further minimised

What you refer to as Grid A and Grid B is more commonly referred to as Arrays, and the transfer of values From 'Grid B' to 'Grid A' can also be reduced significantly

For further reference to the above points, This is my own version:

@ECHO OFF & Setlocal EnableDelayedExpansion
    TITLE Game of Life
    Set "SaveDir=%~dp0CGOL_Saves"
    IF not exist "%SaveDir%" MD "%SaveDir%"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Build concept:
::: Nested array Pos[y,x] containing _O / _I (Alive / Dead) values
::: Calculate offset values for adjacent Cells. EG: Pos[1,3] (using For /L %%Y %%X values as starting point, and N E S W NE NW SE SW as offset Variables.)
::: If statements to test value of neighbour cells N,E,S,W,NE,NW,SE,SW and counter to indicate how many cells are _O / _I and update status accordingly
::: Use intermediary array variables - vPos[x,y] for the above to prevent values changing before all cells in current generation iterated over
::: Transfer value to real cell, then destroy value of virtual cell.
::: { Creates variable /AE = Ascii-27 escape code.
::: - http://www.dostips.com/forum/viewtopic.php?t=1733
::: - https://stackoverflow.com/a/34923514/12343998
:::
::: - /AE can be used  with and without DelayedExpansion.
    Setlocal
    For /F "tokens=2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
        Endlocal
        Set "/AE=%%a"
    )
::: }
If /I "%~1"=="load" Goto :Load_In
REM Time suffix for saving initial state
    Set DateString=%Date:~4,10%
    Set DateString=%DateString:/=%
    Set Filetime=%Time::=_%
    Set Filetime=%Filetime: =0%
    Set Filetime=%DateString%_at%Filetime:~,-3%
REM Folder to save initial state in.
    Set "SaveDir=%~dp0CGOL_Saves"
    IF not exist "%SaveDir%" (
        MD "%SaveDir%"
        PUSHD "%SaveDir%"
        Goto :Dimensions
    )
    PUSHD "%SaveDir%"
    IF Not "%~2"=="" (Goto :Dimensions)

        IF Exist "%SaveDir%\*.bat" (
            ECHO(%/AE%[33m && CLS
            CHOICE /N /C yn /M "Load previous? N/Y"
            If Errorlevel 2 (
                CLS
                Goto :Dimensions
            )
        ) Else (Goto :Dimensions)
    Explorer.exe "%SaveDir%"
:selectFile
    Set /P "source=%/AE%[35m{%/AE%[36mSelect file: }%/AE%[33m<%/AE%[37m"
    IF exist "!source!" (
        FOR /F "delims=" %%L in ("!source!") DO (Start "" "%%~L" & Exit)
    ) Else (Goto :selectFile)
:Dimensions
REM define grid dimensions. Batch can be called or started with parameters for Width and Hieght, and Density.
    IF Not "%~2"=="" (
        Set /A width=%~1,hieght=%~2
        Goto :Populate
    ) Else (
        Set /P width=%/AE%[35m{%/AE%[36mWidth %/AE%[34m[%/AE%[33m30 %/AE%[34m~ %/AE%[33m125%/AE%[34m]%/AE%[37m
        Set /P hieght=%/AE%[35m{%/AE%[36mHieght %/AE%[34m[%/AE%[33m15 %/AE%[34m~ %/AE%[33m40%/AE%[34m]%/AE%[37m
    )
    For /L %%A IN (30,1,125) Do (IF "!width!"=="%%A" (For /L %%B IN (15,1,40) Do (IF "!hieght!"=="%%B" (Goto :Populate))))
    ECHO(%/AE%[31mInvalid Dimensions.
Goto :Dimensions
:Populate
REM populate grid array with _I cells
    For /L %%Y In (1,1,!hieght!) Do (
        For /L %%X In (1,1,!width!) Do (    
            Set "Pos[%%Y_%%X]=_I"
        )
    )
REM randomly populate grid array with living cells. Density can be selected using a 3rd parameter when calling the batch.
    IF Not "%~3"=="" (
        For /L %%Y In (1,1,!hieght!) Do (
            For /L %%X In (1,1,!width!) Do (
                Set /A "density=!random! %%%~3 + 1"
                If "!density!"=="2" (Set "Pos[%%Y_%%X]=_O")
            )
        )
    ) Else (
        For /L %%Y In (1,1,!hieght!) Do (
            For /L %%X In (1,1,!width!) Do (
                Set /A "density=!random! %%9 + 1"
                If "!density!"=="2" (Set "Pos[%%Y_%%X]=_O")
            )
        )
    )
REM Option to store the initial state.
    CHOICE /N /C ny /M "Save Initial State? N/Y"
    If Errorlevel 2 (
        ECHO(%/AE%[36mSaving...%/AE%[0m
        >"CGOLfile%Filetime%.bat" (
            ECHO(@Echo OFF
            ECHO(Set "width=!width!"
            ECHO(Set "hieght=!hieght!"
            For /L %%Y in (1,1,!hieght!) DO For /L %%X in (1,1,!width!) Do (ECHO.Set "Pos[%%Y_%%X]=!Pos[%%Y_%%X]!")
            Echo(CD ..
            Echo(%~n0 Load
        )
    )
:Load_In
REM define display characteristics of _O (living) or _I (dead) cells
    Set /A Color=!random! %%7 + 31
    Set "_I=%/AE%[31m%/AE%[7m+%/AE%[0m"
    REM Set "_O=%/AE%[!Color!m%/AE%[7m %/AE%[0m"
    Set tick=0
REM Adjust display size, extra line for cursor overflow.
    Set /A hieght+=1
    Mode Con: cols=%width% lines=%hieght%
    Set /A hieght-=1
    (For /L %%Y In (1,1,!hieght!) Do (
        For /L %%X In (1,1,!width!) Do (
            For %%A in (!Pos[%%Y_%%X]!) DO (Echo(%/AE%[%%Y;%%XH!_I!)                
        )
    ))>"%SaveDir%\BGScreen.txt"
    Set /A Color=!random! %%4 + 34
    (For /F "USEBACKQ Tokens=1,2 Delims==" %%A in (`"Set Pos["`) Do (
        Set ".Y=%%~A"
        Set ".Y=!.Y:Pos[=!"
        Set ".X=!.Y:*_=!"
        Set ".X=!.X:]=!"
        For %%V in (_!.X!]) Do Set ".Y=!.Y:%%V=!"
        If /I "%%~B" == "_O" (Set /A Color=!random! %%4 + 34 & Echo.%/AE%[!.Y!;!.X!H%/AE%[!Color!m%/AE%[7m@%/AE%[0m)
    ))>"%SaveDir%\Screen.txt"
    TYPE "%SaveDir%\BGScreen.txt"
    TYPE "%SaveDir%\Screen.txt"
REM loop to cycle through generations (otherwise known as ticks) 
For /L %%. in () Do (
    Set /A tick+=1
    TITLE !TIME:~3,8! !tick!
REM determine _O / _I status for each cells next generation and assign to virtual cells ready for transfer.
    For /L %%Y In (1,1,!hieght!) Do (
        For /L %%X In (1,1,!width!) Do (
    REM calculate positions of nieghbour cells
            Set /A N=%%Y,E=%%X,S=%%Y,W=%%X,B_North=0,B_South=!hieght!,B_East=!width!,B_West=0
            Set /A N-=1,E+=1,S+=1,W-=1,B_East+=1,B_South+=1
    REM horizontal, vertical and diagonal Screen Wrapping. REM prior to below If conditions Disables wrapping.
        REM IF "!N!"=="!B_North!" Set N=!hieght!
        REM IF "!E!"=="!B_East!" Set E=1
        REM IF "!S!"=="!B_South!" Set S=1
        REM IF "!W!"=="!B_West!" Set W=!width!
            Set "NE=!N!_!E!"
            Set "NW=!N!_!W!"
            Set "SE=!S!_!E!"
            Set "SW=!S!_!W!"
            Set "N=!N!_%%X"
            Set "E=%%Y_!E!"
            Set "S=!S!_%%X"
            Set "W=%%Y_!W!"
        REM reset living neighbour cells count
            Set count=0
        REM iterate over each neighbour cell
            For %%A in (Pos[!N!],Pos[!E!],Pos[!S!],Pos[!W!],Pos[!NE!],Pos[!NW!],Pos[!SE!],Pos[!SW!]) Do (
        REM increment count for each live neighbour
                IF /I "!%%~A!"=="_O" (Set /A count+=1)
            )
REM Game rule implementation
        REM Any cell not meeting the following two critea dies.
            Set "vPos[%%Y_%%X]=_I"
        REM A living Cell with exactly two living neighbours survives
            IF "!count!"=="2" (IF /I "!Pos[%%Y_%%X]!"=="_O" (Set vPos[%%Y_%%X]=_O))
        REM Any cell with exactly three living neighbours is concieved / survives.
            IF "!count!"=="3" (Set vPos[%%Y_%%X]=_O)
        )
    )
REM Build Foreground screen to display current living generation, Transfer array values and 'Undefine' Calculation array variables
    (For /F "USEBACKQ Tokens=1,2 Delims==" %%A in (`"Set vPos["`) Do (
        Set ".Y=%%~A"
        Set ".Y=!.Y:vPos[=!"
        Set ".X=!.Y:*_=!"
        Set ".X=!.X:]=!"
        For %%V in (_!.X!]) Do Set ".Y=!.Y:%%V=!"
        Set "Pos[!.Y!_!.X!]=%%~B"
        If /I "%%~B" == "_O" (Set /A Color=!random! %%4 + 34 & Echo.%/AE%[!.Y!;!.X!H%/AE%[!Color!m%/AE%[7m@%/AE%[0m)
        Set %%~A=
    ))>"%SaveDir%\Screen.txt"
    TYPE "%SaveDir%\BGScreen.txt"
    TYPE "%SaveDir%\Screen.txt"
)
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ For a Grid size of 30x15 (450 Cells), the above approach completes each generation 20% faster \$\endgroup\$ – T3RR0R May 24 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.