Search code examples
pythonmultithreadingalgorithmautomata

Cellular Automata algorithm doesn't seem to work


I'm currently working on an electronics simulation software (something really basic) using Python and libTCOD (just to "render" the board). So, I've got a 78x47 2D list which stores the board information (cell type, id, state, coords...) and a simple algorithm to simulate wires (wireworld). Everything seems to be going fine, except for one thing: The "electrons" only move towards the left side of the wires. So I thought it may be something related to the way it runs the algorithm.

WireWorld wires have three possible states: Conductor, tail or head.

  • Head: State "2", changes to Tail in the next step
  • Tail: State "1", changes to Conductor in the next step
  • Conductor: State "0", is the default state, changes to Head if there are any Heads at a 1 cell range

Here's how the simulation should go (H for head, t for tail, - for wire):

  • Step 1: ----H----
  • Step 2: ---HtH---
  • Step 3: --Ht-tH--
  • Step 4: -Ht---tH-
  • Step 5: Ht-----tH
  • Step 6: t-------t
  • Step 7: ---------

But this is what currently happens:

  • Step 1: ----H----
  • Step 2: ---Ht----
  • Step 3: --Ht-----
  • Step 4: -Ht------
  • Step 5: Ht-------
  • Step 6: t--------
  • Step 7: ---------

See? The electron head only moves towards the left side of the wires.

That's my current algorithm code:

def run(self):
    for DX, DY in ((-1,-1), (-1,+0), (-1,+1), (+0,-1), (+0,+1), (+1,-1), (+1,+0), (+1,+1)):
        if BOARD[self.Y+DY][self.X+DX].STATE == 2 and self.STATE == 0:
            self.STATE = 2
            return True

        if self.STATE == 2:
            self.STATE = 1
        elif self.STATE == 1:
            self.STATE = 0

And that's how I run the simulation steps:

for y in range(BOARD_HEIGHT):
    for x in range(BOARD_WIDTH):
        BOARD[y][x].run()

Do I need to simulate each cell in an independent thread?


Solution

  • There's no need for multithreading, you just have to make sure that more than one '- -> H'-transitions are possible in each simulation step.

    I've coded a minimal example starting from your code (but with slightly different class layout):

    class Simul(object):
    
        def __init__(self, width, height):
            board_1 = [[None for _ in range(width)] for _ in range(height)]
            board_2 = [[None for _ in range(width)] for _ in range(height)]
            self.boards = [board_1, board_2]
            self.current = 0
            self.pretty = {None: ' ', 0: '-', 1: 't', 2: 'H'}
            self.w = width
            self.h = height
    
        def print_board(self):
            for row in self.boards[self.current]:
                for cell in row:
                    print(self.pretty[cell], end='')
                print()
    
        def run(self):
            BOARD = self.boards[self.current]
            other_board = self.boards[- self.current + 1]
            for row in range(self.h):
                for col in range(self.w):
                    cur_cell = BOARD[row][col]
                    set_h = False
                    for DX, DY in ((-1,-1), (-1,+0), (-1,+1), (+0,-1), (+0,+1),  (+1,-1), (+1,+0), (+1,+1)):
                        try:
                            if BOARD[row+DY][col+DX] == 2 and cur_cell == 0:
                                other_board[row][col] = 2
                                set_h = True
                                break
                        except IndexError:
                            pass
    
                    if set_h:
                        continue
    
                    if cur_cell == 2:
                        other_board[row][col] = 1
                    elif cur_cell == 1:
                        other_board[row][col] = 0
                    elif cur_cell == 0:
                        other_board[row][col] = 0
            self.current = - self.current + 1
    
    
    
    
    if __name__ == '__main__':
        simul = Simul(10, 5)
        for col in range(10):
            simul.boards[0][3][col] = 0
        for row in range(3):
            simul.boards[0][row][4] = 0
        simul.boards[0][3][4] = 2
        simul.print_board()
        simul.run()
        simul.print_board()
    

    Output:

        -     
        -     
        -     
    ----H-----
    
        -     
        -     
        H     
    ---HtH----