Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6027427
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T04:35:30+00:00 2026-05-23T04:35:30+00:00

I have the following code: procedure TCellBlock.GeneratePtoQ; var x,y: integer; i: integer; Change: cardinal;

  • 0

I have the following code:

procedure TCellBlock.GeneratePtoQ;
var
  x,y: integer;
  i: integer;
  Change: cardinal;
begin
  i:= 0;
  //Walk the grid of changed (alive) cells 
  for x:= GridMaxX downto 1 do begin
    for y:= GridMaxY downto 1 do begin
      if Active[cIndexP][x, y] then begin
        Active[cIndexP][x,y]:= false;

        //Put active items on the stack.
        ToDo[i]:= x shl 16 or y;
        Inc(i);
      end; {if}
    end; {for y}
  end; {for x}
  while i > 0 do begin
    Dec(i);
    y:= ToDo[i] and $FFFF;
    x:= ToDo[i] shr 16;

    //Calculate the cell, Change = (oldval XOR newval)
    Change:= Grid[x,y].GeneratePtoQ;

    //Mark the cells in the grid that need to be recalculated next generation.
    Active[cIndexQ][x,y]:= Active[cIndexQ][x,y] or (Change <> 0);
    Active[cIndexQ][x+1,y+1]:= Active[cIndexQ][x+1,y+1] or ((Change and $cc000000) <> 0);
    Active[cIndexQ][x+1,y]:= Active[cIndexQ][x+1,y] or ((Change and $ff000000) <> 0);
    Active[cIndexQ][x,y+1]:= Active[cIndexQ][x,y+1] or ((Change and $cccccccc) <> 0);
  end; {while}
end;

The above is a code snippet of a test program that calculates conway’s game of life.
The code needs to be as fast as possible. And for this purpose I’m trying different approaches.

It walks though a grid of active cells, looks to see which cells are active and puts those
on a stack.
Next it processes the items on the stack and sees which cells have changed.
If a cell has changed it updates the changes into the grid for the next generation.

I store cells in 32bit cardinals (4 bits Y, 8 bits X) and the P (even) generations are offset 1,1 pixel relative to the Q (odd) generations, this way I only have to take 3 neighbors into account instead of 8.

Question
I want to get rid of the grid, I just want to deal with the stack.
How do I implement a stack that eliminates duplicates?

Note that it needs to be as fast as possible and I’m not above using dirty tricks to get that.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T04:35:31+00:00Added an answer on May 23, 2026 at 4:35 am

    I’ve been thinking about it and I think I have a solution.

    some background

    Here’s how the data is in laid out in memory

    00 A  08  B  10   18     The bits of Individual int32's are layout like this:
    01 |  09  |  11   19     00 04 08 0C 10 14 18 1C    // N-Mask: $33333333
    02 |  0A  |  12   1A     01 05 09 0D 11 15 19 1D    // S-Mask: $cccccccc
    03 |  0B  |  13   1B     02 06 0A 0E 12 16 1A 1E    // W-Mask: $000000ff
    04 |  0C  |  14   1C     03 07 0B 0F 13 17 1B 1F    // E-Mask: $ff000000
    05 |  0D  |  15   1D                                //SE-Mask: $cc000000
    06 |  0E  |  16   1E                                //NW-Mask: $00000033
    07 V  0F  V  17   1F     I can mask of different portions if need be.
    
    -- Figure A: Grid --     -- Figure B: cell --       -- Table C: masks --
    

    I haven’t decided on the size of the building block, but this is the general idea.

    Even generations are called P, odd generations are called Q.

    They are staggered like this

     +----------------+<<<<<<<< P         00 04  08  0C  //I use a 64K lookup
     |+---------------|+                  01 05* 09* 0D  //table to lookup
     ||               ||                  02 06* 0A* 0E  //the inner* 2x2 bits from
     ||               ||                  03 07  0B  0F  //a 4x4 grid.
     +----------------+|                  //I need to do 8 lookups for a 32 bit cell
      +----------------+<<<<<<<< Q
    
     - Figure D: Cells are staggered -   -- Figure E: lookup --
    

    This way when generating P -> Q, I only need to look at P itself and its S, SE, E neighbors, instead of all 8 neighbors, ditto for Q -> P. I need only look at Q itself and its N, NW and W neighbors.
    Also notice that the staggering saves me time in translating the result of the lookup, because I have to do less bit shifting to put the results in place.

    When I loop though a grid (Figure A) I walk though the cells (Figure B) in the order shown in figure A. Always in strictly increasing order in a P-cycle and always in decreasing order in a Q-cycle.
    In fact the Q cycle works in exactly the opposite order from the P-cycle, this speeds things up by reusing the cache as much as possible.

    I want to minimize using pointers as much as possible, because pointers cannot be predicted and are not accessed sequentially (they jump all over the place) So I want to use arrays, stacks and queues as much as possible.

    What data do to need to keep track of
    I need to keep track of only the cells that change. If a cell (that is an int32) does not change from one generation to the next I remove it from consideration.
    This is what the code in the question does. It uses a grid to keep track of the changes, but I want to use a stack, not a grid; and I only want to deal with active cells I don’t want to know about stable or dead cells.

    Some background on the data
    Notice how the cell itself is always monotonically increasing. As is its S-neighbor, as well as the E and SE-neighbor. I can use this info to cheat.

    The solution
    I use a stack to keep track of the cell itself and its S neighbor and a queue to keep track of its E and SE neighbor and when I’m done I merge the two.

    Suppose in the Grid the following cells come out as active after I’ve calculated them:

    00, 01, 08 and 15
    I make the following two stacks:
    
    stack A    stack B
    00         08      a)  -A: Cell 00 itself in stack A and its E-neighbor in B
    01         09      a)      Cell 00's S neighbor in stack A and its SE-n'bor in B
    02         0A      b)  -B: Cell 01 is already in the stack, we only add S/SE
    08         10      c)  -C: Cell 08 goes into the stack as normal
    09         11      c)      We'll sort out the merge later.
    15         1D      d)  -D: Cell 15 and neighbors go on as usual.
    16         1E      d)
    
    Now I push members from stack A and B onto a new stack C so that stack C has
    no duplicates and it strictly increasing:
    
    Here's the pseudo code to process the two queues:  
    
    a:= 0; b:= 0; c:=0;
    while not done do begin
      if stack[a] <= stack[b] then begin
        stack[c]:= stack[a]; inc(a); inc(c);
        if stack[a] = stack[b] then inc(b);
      end
      else begin
        stack[c]:= stack[b]; inc(b); inc(c);
      end;
    end; {while}
    

    And even better
    I don’t have to actually do the two stacks and the merging as two separate steps, if I make A a stack and B a queue, I can do the second step described in the pseudo code and the building of the two stacks in one pass.

    Note
    As a cell changes its S, E or SE border does not necessary need to change, but I can test for that using the masks in table C, and only add the cells that really need checking in the next generation to the list.

    Benefits

    1. Using this scheme, I only ever have to walk through one stack with active cells when calculating cells, so I don’t waste time looking at dead or inactive cells.
    2. I only do sequential memory accesses, maximizing cache usage.
    3. Building the stack with new changes for the next generations only requires one extra temporary queue, which I process in strictly sequential order.
    4. I do no sorting and the minimum of comparisons.
    5. I don’t have to keep track of the neighbors of each individual cells (int32), I only need to keep track of the neighbors (S,E,SE, N,W,NW) of the grids, this keeps the memory overhead to a minimum.
    6. I don’t need to keep track of a cells status, I only need to count dead cells (A cell is either dead, because it was dead before, or because it changed into dead. All the active cells are in my TODO stack, this saves bookkeeping time and memory space.
    7. The algorithm runs in o(n) time where (n) is the number of active cells, it excludes dead cells, stable cells and cells that oscillate with period 2.
    8. I only ever deal with 32 bit cardinals, which is the much faster than using int16’s.
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have the following code called on WM_MOVE procedure TForm15.WMMove(var Message: TMessage); begin if(
I have created the following stored procedure.. CREATE PROCEDURE [dbo].[UDSPRBHPRIMBUSTYPESTARTUP] ( @CODE CHAR(5) ,
I have the following code within a stored procedure. WHERE WPP.ACCEPTED = 1 AND
Stuck again. :( I have the following code crammed into a procedure invoked when
I have the following code snippet: var matchingAuthors = from authors in DB.AuthorTable where
I have following stored procedure code when i execute it gives an error saying
I have the following code that executes a Stored Procedure in Sybase throught VBA.
I have the following c# code to call stored procedure testproc , but when
I Have following code: Controller: public ActionResult Step1() { return View(); } [AcceptVerbs(HttpVerbs.Post)] public
I have following Code Block Which I tried to optimize in the Optimized section

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.