python 生命游戏

生命游戏1
在这里插入图片描述

import random

class Cell:
    """
    细胞类,单个细胞
    """
    def __init__(self, ix, iy, is_live):
        self.ix = ix
        self.iy = iy
        self.is_live = is_live
        self.neighbour_count = 0

    def __str__(self):
        return "[{},{},{:5}]".format(self.ix, self.iy, str(self.is_live))

    # 计算周围活的邻居的个数,计算机中屏幕左上角的坐标为(0,0)
    def calc_neighbour_count(self):
        count = 0
        pre_x = self.ix - 1 if self.ix > 0 else 0  # 某元胞左邻居的x值
        for i in range(pre_x, self.ix+1+1):     # 循环的x坐标范围是从某元胞的左邻居到右邻居
            pre_y = self.iy - 1 if self.iy > 0 else 0 # 某元胞上邻居的y值
            for j in range(pre_y, self.iy+1+1): # 循环的y坐标范围是从某元胞的上邻居到下邻居
                # 该元胞是自己,continue,不统计count
                if i == self.ix and j == self.iy:
                    continue
                # 该元胞是无效的,continue,不统计count
                if self.invalidate(i, j):
                    continue
                # CellGrid.cells[i][j].is_live的结果是布尔值,int(True)为1,int(False)为0
                # count统计出的是活的邻居的个数
                count += int(CellGrid.cells[i][j].is_live)
        self.neighbour_count = count
        return count

    def invalidate(self, x, y):
        if x >= CellGrid.cx or y >= CellGrid.cy:  # 元胞x值或y值大于网格范围,无效
            return True
        if x < 0 or y < 0:      # 元胞x值或y值不在网格范围,无效
            return True
        return False

    # 生命游戏规则:
    def rule(self):
        if self.is_live == True:
            if self.neighbour_count > 4 or self.neighbour_count < 2:
                self.is_live = False
        else:
            if self.neighbour_count == 4 or self.neighbour_count == 3:
                self.is_live = True



class CellGrid:
    """
    细胞网格类,所有细胞都处在一个长cx,宽cy的网格中
    """
    cells = []
    cx = 0
    cy = 0

    def __init__(self, cx, cy):
        CellGrid.cx = cx
        CellGrid.cy = cy
        for i in range(cx):
            cell_list = []
            for j in range(cy):
                # random.random() 随机生成的一个实数,它在[0,1)范围内
                cell = Cell(i, j, random.random() > 0.9)
                cell_list.append(cell)  # 在第二层循环把cell放入cell_list,一个cell_list有十个Cell对象
            CellGrid.cells.append(cell_list)  # 在第一层循环把cell_list放入CellGrid.cells,一共有十个cell_list
            # print(cell_list)
            # print(CellGrid.cells)

    # 循环遍历每个元胞判断它的生命状态
    def circulate_rule(self):
        for cell_list in CellGrid.cells:
            # print("【%s】" % cell_list)
            # print(type(cell_list))   # cell_list是一个列表,列表里面装着对象
            for item in cell_list:
                # print("【%s】" % item)
                # print(type(item))  # <class '__main__.Cell'>
                # print(item) # [0,1,True ] item看似是列表,其实是Cell类的对象,故不能用索引取值
                # print(item[2])  # TypeError: 'Cell' object does not support indexing
                item.rule()

    # 循环遍历每个元胞计算它的活的邻居数
    def circulate_nbcount(self):
        for cell_list in CellGrid.cells:
            for item in cell_list:
                item.calc_neighbour_count()


import pygame
import sys
import time
import matplotlib.pyplot as plt
BG = (20, 20, 20)  # 背景色
LIFECOLOR = (31, 97, 189)  # 活细胞颜色
LINECOLOR = (52, 53, 46)  # 网格色
LINE_WIDTH = 3  # 线的宽度
EDGE_WIDTH = 20   # 网格距离背景框边缘的宽度
START_POSX = 20
START_POSY = 20

class Game:
    screen = None

    def __init__(self, width, height, cx, cy):
        self.width = width
        self.height = height
        self.cx_rate = int((width - 2*EDGE_WIDTH) / cx)   # 一个元胞的宽度
        self.cy_rate = int((height - 2*EDGE_WIDTH) / cy)  # 一个元胞的高度
        # pygame.display.set_mode() 初始化一个准备显示的窗口或屏幕(宽*高)
        self.screen = pygame.display.set_mode([width, height])
        self.cells = CellGrid(cx, cy)

    # 在屏幕上显示出活的生命
    def show_life(self):

        # pygame.draw.line(Surface, color, start_pos, end_pos, width=1)
        for i in range(self.cells.cx + 1):
            pygame.draw.line(self.screen, LINECOLOR, (START_POSX, START_POSY + i * self.cy_rate),
                             (START_POSX + self.cells.cx * self.cx_rate, START_POSY + i * self.cy_rate), LINE_WIDTH)  # 画网格横线
            pygame.draw.line(self.screen, LINECOLOR, (START_POSX + i * self.cx_rate, START_POSY),
                             (START_POSX + i * self.cx_rate, START_POSY + self.cells.cx * self.cy_rate), LINE_WIDTH)  # 画网格竖线

        for cell_list in self.cells.cells:
            for item in cell_list:
                x = item.ix
                y = item.iy
                if item.is_live:
                    """
                    pygame.draw.rect(Surface, color, Rect, width=0)
                    在Surface上绘制矩形,第二个参数是线条(或填充)的颜色,第三个参数Rect的
                    形式是((x, y), (width, height)),表示的是所绘制矩形的区域,其中第一个
                    元组(x, y)表示的是该矩形左上角的坐标,第二个元组 (width, height)表示的
                    是矩形的宽度和高度。width表示线条的粗细,单位为像素;默认值为0,表示填充
                    矩形内部。
                    """
                    pygame.draw.rect(self.screen, LIFECOLOR,
                                     [START_POSX+x * self.cx_rate+ (LINE_WIDTH - 1),
                                      START_POSY+y * self.cy_rate+ (LINE_WIDTH - 1),
                                      self.cx_rate- LINE_WIDTH, self.cy_rate- LINE_WIDTH])


def main():
    pygame.init()   # 初始化所有导入的pygame模块
    pygame.display.set_caption("Game of Life")  # 设置当前窗口的标题栏
    game = Game(500, 500, 50, 50)

    clock = pygame.time.Clock()   # 实例化一个Clock对象
    plt.figure()

    draw_data = []
    while True:

        game.screen.fill(BG)
        # clock.tick(1)  # 每秒循环1次(帧率)
        # time.sleep(0.3)
        for event in pygame.event.get():   # pygame.event.get() 从队列中获取事件
            if event.type == pygame.QUIT:
                sys.exit()

        # game是Game类的一个实例化对象,game.cells是CellGrid类的一个实例化对象
        game.cells.circulate_nbcount()  # 先计算邻居存活数
        game.cells.circulate_rule()     # 再按规则判断自己的生命状态

        game.show_life()
        pygame.display.flip()  # 更新整个待显示的 Surface 对象到屏幕上

        # 打印每个元胞
        live_num = 0
        for i in game.cells.cells:
            for j in i:
                if(j.is_live):
                    live_num += 1
        print(live_num)
        draw_data.append(live_num)
        if(len(draw_data) > 200):
            draw_data.pop(0)
        draw_num = [i for i in range(len(draw_data))]
        plt.clf()  # 清除之前画的图
        plt.plot(draw_num, draw_data)
        plt.pause(0.1)  # 暂停一秒

if __name__ == "__main__":
    main()

生命游戏2
在这里插入图片描述

#@photon_123 
import tkinter as tk
import tkinter.ttk as ttk
import random
 
# 定义细胞的状态
DEAD = 0
ALIVE = 1
 
# 定义细胞的颜色
COLORS = {
    DEAD: "white",
    ALIVE: "black"
}
 
pran =0.1  #初始随机概率
speed = 1  #初始演化速度
class GameOfLife:
    def __init__(self, width, height, cell_size=20):
        self.width = width
        self.height = height
        self.cell_size = cell_size
        self.board = [[DEAD for _ in range(height)] for _ in range(width)]
        self.running = True   #运行状态标志位
        self.onestepp = False #单步演化标志位
 
####创建GUI界面##############################################################################################################################################################################################################################################
 
        self.root = tk.Tk()
        self.root.title("康威生命游戏")
        self.canvas = tk.Canvas(self.root, width=width*cell_size, height=height*cell_size)
        self.canvas.pack()
        self.canvas.bind("<Button-1>", self.handle_click)
        self.start_button = tk.Button(self.root, text="开始", fg='white',bg='#4CAF50',font=('黑体',self.cell_size),command=self.start)
        self.start_button.place(relheight=0.05,relwidth=0.16,relx=0.02,rely=0.9)
        self.pause_button = tk.Button(self.root, text="暂停", fg='white',bg='#FE5E08',font=('黑体',self.cell_size),command=self.pause)
        self.pause_button.place(relheight=0.05,relwidth=0.1,relx=0.18,rely=0.9)
        self.clear_button = tk.Button(self.root, text="清空", fg='white',bg='#555555',font=('黑体',self.cell_size),command=self.clear)
        self.clear_button.place(relheight=0.05,relwidth=0.1,relx=0.28,rely=0.9)
        self.random_button = tk.Button(self.root, text="随机",fg='white',bg='#5677FC',font=('黑体',self.cell_size), command=self.random)
        self.random_button.place(relheight=0.05,relwidth=0.1,relx=0.38,rely=0.9)
        var = tk.StringVar()
        ls = ['滑翔机','太空船','高斯帕滑翔机枪','蜂王梭','慨影']
        self.combobox = ttk.Combobox(self.root, textvariable=var, values=ls,font=('黑体',self.cell_size))
        self.combobox.place(relheight=0.05,relwidth=0.25,relx=0.7,rely=0.9)
        self.combobox.bind('<<ComboboxSelected>>',self.anli)
 
        var2 = tk.DoubleVar()
        def adjust1(event):
            global pran
            pran = var2.get()      
        self.scale = tk.Scale(self.root,from_=0.1,to=1,resolution=0.01,bg='#A9A9A9',orient=tk.HORIZONTAL,length=200,variable=var2)
        self.scale.bind('<ButtonRelease-1>',adjust1)
        self.scale.place(relx=0.66,rely=0.03)
        self.labe1 = tk.Label(self.root,text='随机概率',font=('黑体',15))
        self.labe1.place(relx=0.9,rely=0.03)
 
        var3 = tk.IntVar()
        def adjust2(event):
            global speed
            speed = var3.get()
        self.scale2 = tk.Scale(self.root,from_=1,to=100,resolution=1,bg='#A9A9A9',orient=tk.HORIZONTAL,length=200,variable=var3)
        self.scale2.bind('<ButtonRelease-1>',adjust2)
        self.scale2.place(relx=0.66,rely=0.1)
        self.labe2 = tk.Label(self.root,text='演化频率',font=('黑体',15))
        self.labe2.place(relx=0.9,rely=0.1)
 
####菜单相关#################################################################################################################################################################################################################################################
 
        def rule():
            rulewin = tk.Toplevel(self.root)
            rulewin.geometry('700x200')
            rulewin.title('游戏规则')
            lab = tk.Label(rulewin,text='''1. 每个细胞的状态由该细胞及周围八个细胞上一次的状态所决定;\n
2. 如果一个细胞周围有3个细胞为生,则该细胞由死转生或保持生;\n
3. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;\n
4. 在其它情况下,该细胞由生转死或保持死''',fg='black',font=('黑体',15))
            lab.pack()
        def about():
            abowin = tk.Toplevel(self.root)
            abowin.geometry('700x200')
            abowin.title('关于游戏')
            lab2 = tk.Label(abowin,text='''---一个不太聪明的Python小程序---\n
                -young 2023.6''',fg='black',font=('黑体',15))
            lab2.place(relx=0.25,rely=0.3)
        def onestep():
            self.onestepp = True
            self.running = True
            self.evolve()
        self.menu = tk.Menu(self.root,relief=tk.SUNKEN)
        menufile = tk.Menu(self.menu)
        self.menu.add_cascade(label='菜单',menu=menufile)
        menufile.add_command(label='游戏规则',command=rule)
        menufile.add_command(label='关于',command=about)
        menufile.add_command(label='运行一步',command=onestep)
        self.root.config(menu=self.menu)
    
############################################################################################################################################################################################################################################################
 
 
    def anli(self,event):
        #经典案例导入
        suoyin = {'滑翔机':1,'太空船':2,'高斯帕滑翔机枪':3,'蜂王梭':4,'慨影':5}
        suo = suoyin [self.combobox.get()]
        m,n = self.height//2,self.width//2
        
        self.clear()
        if suo ==1:
            for (p,q) in {(0,1),(0,-1),(-1,-1),(1,-1),(1,0)}:
                self.board[m+p][n-q] = ALIVE
                self.running = False
        elif suo ==2:
            for (p,q) in {(-2,0),(-2,1),(-1,0),(-1,1),(-1,2),(0,-1),(0,1),(0,2),(1,-1),(1,0),(1,1),(2,0)}:
                self.board[m+p][n-q] = ALIVE
                self.running = False
        elif suo ==3:
            for (p,q) in {(1,5),(1,6),(2,5),(2,6),(11,5),(11,6),(11,7),
            (12,4),(12,8),(13,3),(13,9),(14,3),(14,9),(15,6),(16,4),(16,8),
            (17,5),(17,6),(17,7),(18,6),(21,3),(21,4),(21,5),(22,3),(22,4),
            (22,5),(23,2),(23,6),(25,1),(25,2),(25,6),(25,7),(35,3),(35,4),
            (36,3),(36,4)}:
                self.board[p][q] = ALIVE
                self.running = False
        elif suo ==4:
            for (p,q) in {(-9,0),(-9,-1),(-8,0),(-8,-1),(-4,0),(-3,-1),(-3,1),
            (-2,-2),(-2,2),(-1,-1),(-1,0),(-1,1),(0,-2),(0,-3),(0,2),(0,3),
            (11,-1),(11,0),(12,-1),(12,0)}:
                self.board[m+p][n-q] = ALIVE
                self.running = False
        elif suo ==5:
            for (p,q) in {(-1,2),(-1,3),(-1,6),(-1,-3),(-1,-4),(-1,-7),(0,1),
            (0,2),(0,3),(0,7),(0,-2),(0,-3),(0,-4),(0,-8),
            (1,2),(1,3),(1,6),(1,-3),(1,-4),(1,-7)}:
                self.board[m+p][n-q] = ALIVE
                self.running = False
        self.draw_board()
 
####游戏逻辑相关#############################################################################################################################################################################################################################################
 
    def handle_click(self, event):
        # 处理鼠标点击事件,设置细胞状态
        x, y = event.x // self.cell_size, event.y // self.cell_size
        if self.board[x][y] == DEAD:
            self.board[x][y] = ALIVE
        else:
            self.board[x][y] = DEAD
        self.draw_board()
 
    def draw_board(self):
        # 绘制游戏界面
        self.canvas.delete("all")
        for x in range(self.width):
            for y in range(self.height):
                color = COLORS[self.board[x][y]]
                self.canvas.create_rectangle(x*self.cell_size, y*self.cell_size,
                                             (x+1)*self.cell_size, (y+1)*self.cell_size,
                                             fill=color, outline="gray")
 
    def start(self):
        # 开始演化
        self.running = True
        self.evolve()
 
    def pause(self):
        # 暂停演化
        self.running = False
 
    def clear(self):
        # 清空细胞
        self.board = [[DEAD for _ in range(self.height)] for _ in range(self.width)]
        self.draw_board()
 
    def random(self):
        # 随机生成初始细胞
        global pran
        for i in range(self.height):
            for j in range(self.width):
                rnd = random.random()
                if rnd > 1-pran:
                    self.board[i][j]=ALIVE
        self.draw_board()
 
    def count_neighbors(self, x, y):
        # 计算某个细胞周围的活细胞数量
        count = 0
        for i in range(-1, 2):
            for j in range(-1, 2):
                if i == 0 and j == 0:  #除去自身
                    continue
                if x+i < 0 or x+i >= self.width or y+j < 0 or y+j >= self.height: #边界处理
                    continue
                if self.board[x+i][y+j] == ALIVE:
                    count += 1
        return count
 
    def evolve(self):
        # 演化一次
        if not self.running:
            return
        new_board = [[DEAD for _ in range(self.height)] for _ in range(self.width)]
        for x in range(self.width):
            for y in range(self.height):
                count = self.count_neighbors(x, y)
                if self.board[x][y] == ALIVE:
                    if count < 2 or count > 3:
                        new_board[x][y] = DEAD
                    else:
                        new_board[x][y] = ALIVE
                else:
                    if count == 3:
                        new_board[x][y] = ALIVE
        self.board = new_board
        self.draw_board()
        if not self.onestepp:
            global speed
            self.root.after(1000//speed, self.evolve)#100ms演化一次
        else:
            self.onestepp = False
 
    def run(self):
        # 运行游戏
        self.draw_board()
        self.root.mainloop()
 
############################################################################################################################################################################################################################################################
 
game = GameOfLife(60,60,15)
game.run()
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿Q学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值