ytgui / temp

0 stars 0 forks source link

Conway's Game of Life #28

Closed ytgui closed 5 years ago

ytgui commented 5 years ago

https://stackoverflow.com/questions/40485/optimizing-conways-game-of-life

ytgui commented 5 years ago

Naive

import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

class Coord(list):
    def __init__(self, x, y):
        list.__init__(self, (x, y))

    @property
    def x(self):
        return self.__getitem__(0)

    @x.setter
    def x(self, x):
        self.__setitem__(0, x)

    @property
    def y(self):
        return self.__getitem__(1)

    @y.setter
    def y(self, y):
        self.__setitem__(1, y)

class Size(list):
    def __init__(self, height, width):
        list.__init__(self, (height, width))

    @property
    def height(self):
        return self.__getitem__(0)

    @height.setter
    def height(self, height):
        self.__setitem__(0, height)

    @property
    def width(self):
        return self.__getitem__(1)

    @width.setter
    def width(self, width):
        self.__setitem__(0, width)

class Conway:
    def __init__(self, size=Size(90, 120), cell_probability=0.5, block_probability=0.1):
        self.size = size
        self.map = np.zeros(shape=size, dtype=np.uint8)
        self.cell_probability = cell_probability

        # generate and fill sub block
        block_size = Size(int(np.sqrt(block_probability) * size.height),
                          int(np.sqrt(block_probability) * size.width))
        src = Coord(random.randrange(size.width - block_size.width),
                    random.randrange(size.height - block_size.height))
        dst = Coord(src.x + block_size.width, src.y + block_size.height)
        self.random_fill(src, dst)

    def random_fill(self, src, dst):
        for y in range(src.y, dst.y):
            for x in range(src.x, dst.x):
                if random.random() < self.cell_probability:
                    self.map[y, x] = 1
                else:
                    self.map[y, x] = 0

    def init_replace_mode(self):
        # 0: 0 -> 0
        # 1: 0 -> 1
        # 2: 1 -> 0
        # 3: 1 -> 1
        self.map = np.multiply(self.map, 3)

    def conway_step(self):
        table =[[0, 0, 0, 1, 0, 0, 0, 0, 0],
                [2, 2, 3, 3, 2, 2, 2, 2, 2]]

        def get_count(xx, yy):
            summed = 0
            for vx, vy in [(-1, 0), (1, 0), (0, -1), (0, 1),
                           (-1, -1), (-1, 1), (1, -1), (1, 1)]:
                cur_x, cur_y = xx + vx, yy + vy
                if cur_x < 0 or cur_x > self.size.width - 1:
                    continue
                if cur_y < 0 or cur_y > self.size.height - 1:
                    continue
                if cur_x > xx and cur_y > yy:
                    summed += self.map[cur_y, cur_x] % 2
                else:
                    summed += self.map[cur_y, cur_x] // 2
            return summed

        for y in range(self.size.height):
            for x in range(self.size.width):
                n_neighbors = get_count(x, y)
                self.map[y, x] = table[self.map[y, x] % 2][n_neighbors]

    def finish_replace_mode(self):
        self.map = np.mod(self.map, 2)

class ConwayAnimation(Conway):
    def __init__(self):
        Conway.__init__(self)
        # ready for canvas
        self.fig = plt.figure()
        _ = animation.FuncAnimation(self.fig,
                                    func=self.on_draw,
                                    init_func=self.on_init,
                                    interval=100,
                                    blit=True)
        plt.show()

    def on_init(self):
        self.im = plt.imshow(self.map, cmap='gray', animated=True)
        return self.im,

    def on_draw(self, frame_id):
        print(frame_id)
        self.init_replace_mode()
        self.conway_step()
        self.finish_replace_mode()
        self.im.set_array(self.map)
        return self.im,

def main():
    ConwayAnimation()

if __name__ == "__main__":
    main()
ytgui commented 4 years ago
import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

class Coord(list):
    def __init__(self, x, y):
        list.__init__(self, (x, y))

    @property
    def x(self):
        return self.__getitem__(0)

    @x.setter
    def x(self, x):
        self.__setitem__(0, x)

    @property
    def y(self):
        return self.__getitem__(1)

    @y.setter
    def y(self, y):
        self.__setitem__(1, y)

class Size(list):
    def __init__(self, height, width):
        list.__init__(self, (height, width))

    @property
    def height(self):
        return self.__getitem__(0)

    @height.setter
    def height(self, height):
        self.__setitem__(0, height)

    @property
    def width(self):
        return self.__getitem__(1)

    @width.setter
    def width(self, width):
        self.__setitem__(0, width)

class Conway:
    def __init__(self, size=Size(90, 120), cell_probability=0.5, block_probability=0.1):
        self.size = size
        self.map = np.zeros(shape=size, dtype=np.uint8)
        self.cell_probability = cell_probability

        # generate and fill sub block
        block_size = Size(int(np.sqrt(block_probability) * size.height),
                          int(np.sqrt(block_probability) * size.width))
        src = Coord(random.randrange(size.width - block_size.width),
                    random.randrange(size.height - block_size.height))
        dst = Coord(src.x + block_size.width, src.y + block_size.height)
        self.random_fill(src, dst)

    def random_fill(self, src, dst):
        for y in range(src.y, dst.y):
            for x in range(src.x, dst.x):
                if random.random() < self.cell_probability:
                    self.map[y, x] = 1
                else:
                    self.map[y, x] = 0

    def init_replace_mode(self):
        # 0: 00
        # 1: 01
        # 2: 10
        # 3: 11
        # self.map = np.multiply(self.map, 3)
        pass

    def conway_step(self):
        # n_neighbor  status
        # 2           keep
        # 3           live
        # others      died
        table =[[0, 0, 0, 1, 0, 0, 0, 0, 0],
                [0, 0, 1, 1, 0, 0, 0, 0, 0]]

        def get_count(xx, yy):
            summed = 0
            for vx, vy in [(-1, 0), (1, 0), (0, -1), (0, 1),
                           (-1, -1), (-1, 1), (1, -1), (1, 1)]:
                cur_x, cur_y = xx + vx, yy + vy
                # out of border
                cur_x = (cur_x + self.size.width) % self.size.width
                cur_y = (cur_y + self.size.height) % self.size.height
                #
                summed += self.map[cur_y, cur_x] & 0x1
            return summed

        for y in range(self.size.height):
            for x in range(self.size.width):
                n_neighbors = get_count(x, y)
                self.map[y, x] += table[self.map[y, x] % 2][n_neighbors] << 1

    def finish_replace_mode(self):
        self.map = np.right_shift(self.map, 1)

class ConwayAnimation(Conway):
    def __init__(self):
        Conway.__init__(self)
        # ready for canvas
        self.fig = plt.figure()
        _ = animation.FuncAnimation(self.fig,
                                    func=self.on_draw,
                                    init_func=self.on_init,
                                    interval=0,
                                    blit=True)
        plt.show()

    def on_init(self):
        self.im = plt.imshow(self.map, cmap='gray', animated=True)
        return self.im,

    def on_draw(self, frame_id):
        print(frame_id)
        self.init_replace_mode()
        self.conway_step()
        self.finish_replace_mode()
        self.im.set_array(self.map)
        return self.im,

def main():
    ConwayAnimation()

if __name__ == "__main__":
    main()