真菌元胞自动机Python实现

2021年美赛A题真菌元胞自动机Python实现

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


def save_fungi_ca_gif():  # save the gif file to the path
    target_gif_path = "E:/engineering space/figure/gif format/"
    target_gif_name = "aggressive_ca.gif"
    target_gif_full = target_gif_path + target_gif_name
    anim_1.save(target_gif_full, writer='pillow')  # save the animation
    print('Saved')


def calculate_random_neighbour(stay, left, up, right, down, no_reproduce):  # get the relative location of the newly
    total_rate = stay + left + up + right + down + no_reproduce  # reproduced fungi cell
    if total_rate == 0.0:
        total_rate = 1
    cap1 = stay / total_rate  # cap 1 to 5 is the boundary of probability area
    cap2 = cap1 + left / total_rate
    cap3 = cap2 + up / total_rate
    cap4 = cap3 + right / total_rate
    cap5 = cap4 + down / total_rate
    rnd = random.random()
    if 0 <= rnd < cap1:
        return 0
    elif cap1 <= rnd < cap2:  # divide the range into 6 parts
        return 1
    elif cap2 <= rnd < cap3:  # randomly select one part
        return 2
    elif cap3 <= rnd < cap4:
        return 3
    elif cap4 <= rnd < cap5:
        return 4
    else:
        return 5


def get_extension_parameters(i_get_extension_parameters):  # get the extension parameters
    extension_parameters = extension_rate_list[fungi_list[i_get_extension_parameters][3]]
    return extension_parameters


def get_random_neighbour(i_get_random_neighbour):  # calculate the density of neighbour mesh as well as self mesh
    extension_rate_get_random_neighbour = get_extension_parameters(i_get_random_neighbour)
    stay_density = my_board[fungi_list[i_get_random_neighbour][0], fungi_list[i_get_random_neighbour][1]] / one_mesh_max
    stay_rate = extension_rate_get_random_neighbour - stay_density
    if fungi_list[i_get_random_neighbour][1] != 0:
        left_density = my_board[fungi_list[i_get_random_neighbour][0], fungi_list[i_get_random_neighbour][1] - 1] \
                       / one_mesh_max
        left_rate = extension_rate_get_random_neighbour * (
                    1 - left_density + 0.1)  # further calculate the transferring rate of
        # the new fungi
    else:
        left_density = 0.5
        left_rate = 0

    if fungi_list[i_get_random_neighbour][0] != 0:
        up_density = my_board[fungi_list[i_get_random_neighbour][0] - 1, fungi_list[i_get_random_neighbour][1]] \
                     / one_mesh_max
        up_rate = extension_rate_get_random_neighbour * (1 - up_density + 0.1)
    else:
        up_density = 0.5
        up_rate = 0

    if fungi_list[i_get_random_neighbour][1] != patch_size - 1:
        right_density = my_board[
                            fungi_list[i_get_random_neighbour][0], fungi_list[i_get_random_neighbour][1] + 1] \
                        / one_mesh_max
        right_rate = extension_rate_get_random_neighbour * (1 - right_density + 0.1)
    else:
        right_density = 0.5
        right_rate = 0

    if fungi_list[i_get_random_neighbour][0] != patch_size - 1:
        down_density = my_board[fungi_list[i_get_random_neighbour][0] + 1, fungi_list[i_get_random_neighbour][1]] \
                       / one_mesh_max
        down_rate = extension_rate_get_random_neighbour * (1 - down_density + 0.1)
    else:
        down_density = 0.5
        down_rate = 0

    total_density = stay_density + left_density + up_density + right_density + down_density
    no_reproduce_rate = total_density / 8
    neighbour_location = calculate_random_neighbour(stay_rate, left_rate, up_rate, right_rate, down_rate,
                                                    no_reproduce_rate)
    return neighbour_location


def reproduce_one_cell(i_reproduce_one_cell):  # reproduce a single fungi cell
    iterations = 0
    while True:  # loop until the random neighbour meets the boundary conditions
        iterations += 1
        # print('iteration:', iterations)
        reproduce_location = get_random_neighbour(i_reproduce_one_cell)
        # the followings are boundary conditions
        if iterations < 3:
            if reproduce_location == 0:  # stay in one mesh
                current_mesh_num = my_board[fungi_list[i_reproduce_one_cell][0], fungi_list[i_reproduce_one_cell][1]]
                if current_mesh_num < one_mesh_max:
                    # haven't arrived the maximum of one mesh
                    break  # this is the location wanted
                else:
                    # print(iterations)  # how many loops have been taken
                    continue  # random again

            if reproduce_location == 1:  # go to left mesh
                if fungi_list[i_reproduce_one_cell][1] == 0:  # reaches the left boundary
                    # print(iterations)
                    continue  # random again
                elif my_board[fungi_list[i_reproduce_one_cell][0], fungi_list[i_reproduce_one_cell][1] - 1] \
                        < one_mesh_max:
                    break  # this is the location wanted
                else:
                    continue

            if reproduce_location == 2:  # go to up mesh
                if fungi_list[i_reproduce_one_cell][0] == 0:  # reaches the up boundary
                    # print(iterations)
                    continue  # random again
                elif my_board[fungi_list[i_reproduce_one_cell][0] - 1, fungi_list[i_reproduce_one_cell][1]] \
                        < one_mesh_max:
                    break  # this is the location wanted
                else:
                    continue

            if reproduce_location == 3:  # go to right mesh
                if fungi_list[i_reproduce_one_cell][1] == patch_size - 1:  # reaches the right boundary
                    # print(iterations)
                    continue  # random again
                elif my_board[fungi_list[i_reproduce_one_cell][0], fungi_list[i_reproduce_one_cell][1] + 1] \
                        < one_mesh_max:
                    break  # this is the location wanted
                else:
                    continue

            if reproduce_location == 4:  # go to down mesh
                if fungi_list[i_reproduce_one_cell][0] == patch_size - 1:  # reaches the down boundary
                    continue
                    # print(iterations)
                elif my_board[fungi_list[i_reproduce_one_cell][0] + 1, fungi_list[i_reproduce_one_cell][1]] \
                        < one_mesh_max:
                    break  # this is the location wanted
                else:
                    continue
        else:
            reproduce_location = 5
            break

    global fungi_num
    # take reproducing activity
    if reproduce_location != 5:
        if reproduce_location == 0:
            fungi_list.append([fungi_list[i_reproduce_one_cell][0], fungi_list[i_reproduce_one_cell][1], 0, fungi_list[
                i_reproduce_one_cell][3]])
            # print('Stayed')
        if reproduce_location == 1:
            fungi_list.append([fungi_list[i_reproduce_one_cell][0], fungi_list[i_reproduce_one_cell][1] - 1, 0,
                               fungi_list[i_reproduce_one_cell][3]])
        if reproduce_location == 2:
            fungi_list.append([fungi_list[i_reproduce_one_cell][0] - 1, fungi_list[i_reproduce_one_cell][1], 0,
                               fungi_list[i_reproduce_one_cell][3]])
        if reproduce_location == 3:
            fungi_list.append([fungi_list[i_reproduce_one_cell][0], fungi_list[i_reproduce_one_cell][1] + 1, 0,
                               fungi_list[i_reproduce_one_cell][3]])
        if reproduce_location == 4:
            fungi_list.append([fungi_list[i_reproduce_one_cell][0] + 1, fungi_list[i_reproduce_one_cell][1], 0,
                               fungi_list[i_reproduce_one_cell][3]])

        fungi_list[i_reproduce_one_cell][2] += 1  # the reproduced time of a fungi
        if fungi_list[i_reproduce_one_cell][2] == reproduce_time_to_die_list[fungi_list[i_reproduce_one_cell][3]]:
            # when reproduced an exact times to die
            my_board[fungi_list[i_reproduce_one_cell][0]][fungi_list[i_reproduce_one_cell][1]] -= 1  # remove fungi
            # in number board
            del fungi_list[i_reproduce_one_cell]  # the death of a fungi
        fungi_num = len(fungi_list)
        update_board(fungi_num)  # get a board according to the new fungi reproduced
    else:
        fungi_list[i_reproduce_one_cell][2] += 1  # the life span of a fungi


def reproduce_round():  # reproduce all the current fungi cells
    for i_reproduce_round in range(fungi_num):
        reproduce_one_cell(i_reproduce_round)  # reproduce a single fungi cell


def update_board(fungi_num_update_board):  # get a number board according to the new fungi
    my_board[fungi_list[fungi_num_update_board - 1][0]][fungi_list[fungi_num_update_board - 1][1]] += 1


def get_rgb_board():
    paint_rgb_board = [[[1.0 for k in range(3)] for j in range(patch_size)] for i in range(patch_size)]  # initialize
    global red_fungi_num
    global green_fungi_num
    global blue_fungi_num
    red_fungi_num = 0
    green_fungi_num = 0
    blue_fungi_num = 0
    # color board
    for i_paint_rgb_board in range(fungi_num):
        if fungi_list[i_paint_rgb_board][3] == 0:
            red_fungi_num += 1
            paint_rgb_board[fungi_list[i_paint_rgb_board][0]][fungi_list[i_paint_rgb_board][1]][1] -= (0.99
                                                                                                       / one_mesh_max)
            paint_rgb_board[fungi_list[i_paint_rgb_board][0]][fungi_list[i_paint_rgb_board][1]][2] -= (0.99
                                                                                                       / one_mesh_max)
        elif fungi_list[i_paint_rgb_board][3] == 1:
            green_fungi_num += 1
            paint_rgb_board[fungi_list[i_paint_rgb_board][0]][fungi_list[i_paint_rgb_board][1]][0] -= (0.99
                                                                                                       / one_mesh_max)
            paint_rgb_board[fungi_list[i_paint_rgb_board][0]][fungi_list[i_paint_rgb_board][1]][2] -= (0.99
                                                                                                       / one_mesh_max)
        else:
            blue_fungi_num += 1
            paint_rgb_board[fungi_list[i_paint_rgb_board][0]][fungi_list[i_paint_rgb_board][1]][0] -= (0.99
                                                                                                       / one_mesh_max)
            paint_rgb_board[fungi_list[i_paint_rgb_board][0]][fungi_list[i_paint_rgb_board][1]][1] -= (0.99
                                                                                                       / one_mesh_max)
    return paint_rgb_board


def attack_round():
    global fungi_num
    for i_attack_round in range(fungi_num):
        if i_attack_round == fungi_num - 1:
            break
        if fungi_list[i_attack_round][2] >= reproduce_time_to_die_list[fungi_list[i_attack_round][3]]:
            # when reproduced an exact times to die
            my_board[fungi_list[i_attack_round][0]][fungi_list[i_attack_round][1]] -= 1  # remove fungi in number board
            del fungi_list[i_attack_round]  # the death of a fungi
            fungi_num = len(fungi_list)
            # update_board(fungi_num)  # get a board according to the new fungi reproduced
        else:
            continue


def update():  # update the board information and fungi list in a round
    reproduce_round()  # reproduce all the current fungi cells
    rgb_board_update = get_rgb_board()  # get a color board after a round of reproduction
    attack_round()
    return rgb_board_update


def calculate_initial_position():  # calculate the initial position of cells for fair competition
    radius_calculate_initial_position = patch_size / 6  # distance between initial cells
    middle_point_initial_position = patch_size / 2
    for i_calculate_initial_position in range(initial_fungi_num):
        rotation_degree = i_calculate_initial_position / initial_fungi_num * 2 * np.pi
        x_initial_position = middle_point_initial_position + np.cos(rotation_degree) * radius_calculate_initial_position
        y_initial_position = middle_point_initial_position + np.sin(rotation_degree) * radius_calculate_initial_position
        x_initial_list.append(int(round(x_initial_position)))
        y_initial_list.append(int(round(y_initial_position)))


def animate_func(frame_sequence):  # depict the animation
    ax_1.imshow(update())
    update_extension_rate()
    # ax_1.text(patch_size / 12, patch_size / 12, frame_sequence, color='white', size=20)
    print('total:', fungi_num, 'red:', red_fungi_num, 'green:', green_fungi_num, 'blue:', blue_fungi_num)
    print('frame number:', frame_sequence + 1)


def update_extension_rate():
    global extension_rate_list
    red_fungi_rate = red_fungi_num / fungi_num
    green_fungi_rate = green_fungi_num / fungi_num
    blue_fungi_rate = blue_fungi_num / fungi_num
    if red_fungi_rate <= rate_limit:
        extension_rate_list[0] = fungi_num / red_fungi_num
        # total_extension_rate = sum(extension_rate_list)
        # extension_rate_list = extension_rate_list / total_extension_rate
    elif green_fungi_rate <= rate_limit:
        extension_rate_list[1] = fungi_num / green_fungi_num
        # total_extension_rate = sum(extension_rate_list)
        # extension_rate_list = extension_rate_list / total_extension_rate
    elif blue_fungi_rate <= rate_limit:
        extension_rate_list[2] = fungi_num / blue_fungi_num
        # total_extension_rate = sum(extension_rate_list)
        # extension_rate_list = extension_rate_list / total_extension_rate


if __name__ == '__main__':
    patch_size = 25  # size of our patch
    # frame_number = 30  # number of frames
    one_mesh_max = 7  # the maximum number of fungi cells in a single mesh
    initial_fungi_num = 3  # the initial number of fungi cells as well as species
    fungi_list = []  # list of cells
    my_board = np.zeros((patch_size, patch_size))  # initialize number board
    x_initial_list = []  # the x, y position of initial cells
    y_initial_list = []
    # calculate_initial_position()  # calculate the initial position of cells for fair competition
    red_fungi_num = 1  # number of each species of fungi
    green_fungi_num = 1
    blue_fungi_num = 1
    rate_limit = 0.01
    for i_initial in range(initial_fungi_num):  # initialize fungi list
        x_initial = np.random.randint(patch_size)  # int(patch_size / 10) + i_initial * int(8 * patch_size / 10)  #
        y_initial = np.random.randint(patch_size)  # x_initial  #
        # fungi_list.append([x_initial_list[i_initial], y_initial_list[i_initial], 0, i_initial])  # the indexes are
        # x, y,
        fungi_list.append([x_initial, y_initial, 0, i_initial])
        # reproduce time and species num
        update_board(i_initial + 1)
    fungi_num = initial_fungi_num
    extension_rate_list = [0.6, 0.2, 0.2]  #
    extension_rate_list = np.array(extension_rate_list)
    # different species of fungi have different extension rate
    attack_parameter_list = [0.3, 0.1, 0.5]  # density parameter of different species of fungi
    reproduce_time_to_die_list = [2, 2, 2]  # each cell reproduce two times until death
    rgb_board = [[[1.0 for k in range(3)] for j in range(patch_size)] for i in range(patch_size)]  # initialize color
    # board
    fig_1 = plt.figure(1)  # create a plot
    ax_1 = fig_1.add_subplot(1, 1, 1)  # create an axes
    # ims = []  # prepared for the frames to put in
    # anim_1 = animation.ArtistAnimation(fig_1, ims, repeat=False)  # create an animation
    # save_fungi_ca_gif()  # save the gif file
    anim_2 = animation.FuncAnimation(fig_1, animate_func)
    plt.show()
    # print(my_board)

效果图

 

Guess you like

Origin blog.csdn.net/joshua_shi_t/article/details/121132699