jjjzw 发表于 2021-4-20 19:34

【python】Game of Life 生命游戏——初学面向对象试水

本帖最后由 jjjzw 于 2021-4-20 19:42 编辑

python终于学到了面向对象这块,感觉有点难度{:1_924:}
学了半天迷迷糊糊,决定动手写点什么来理解一下这些概念

生命游戏规则:每个细胞死或活的状态由它周围的八个细胞所决定。

之所以选这个游戏,是它有比较明显的对象类:细胞、规则等
用比较熟悉的pygame库来显示界面

细胞类:cell.py
class Cell:
    def __init__(self, neighbour, is_live, position, charge):
      self.neighbour = neighbour
      self.is_live = is_live
      self.position = position
      self.charge = charge

    def change(self):
      if self.neighbour == 3:
            self.is_live = 1
      elif self.neighbour == 2:
            pass
      else:
            self.is_live = 0

    def convert(self):
      if self.is_live == 0:
            self.is_live = 1
      else:
            self.is_live = 0


规则类:rule.py
from cell import Cell

cell_list = []


class Rule:
    def __init__(self, width, height, wow, state):
      self.width = width
      self.height = height
      self.wow = wow
      self.state = state

    def run(self):
      for i in range(0, self.width//self.wow):
            for j in range(0, self.height//self.wow):
                new_cell = Cell(0, 0, (i, j), 0)
                cell_list.append(new_cell)

    @staticmethod
    def get_neighbour():
      for cell in cell_list:
            cell.neighbour = 0
            x = cell.position - 1
            y = cell.position - 1
            for i in range(0, 3):
                for j in range(0, 3):
                  if (i, j) != (1, 1):
                        for cell2 in cell_list:
                            if cell2.position == (x + i, y + j):
                              if cell2.is_live == 1:
                                    cell.neighbour = cell.neighbour + 1


界面:main.py
import pygame
import time
import random
from rule import *

global x, y, pos


class World:
    def __init__(self, width, height, wow, x1, y1):
      self.width = width
      self.height = height
      self.wow = wow
      self.x = x1
      self.y = y1

    def divide(self):
      global pos
      for i in range(0, self.width//self.wow):
            if i < x/self.wow < i + 1:
                self.x = i
      for j in range(0, self.height//self.wow):
            if j < y/self.wow < y + 1:
                self.y = j
      pos = self.x, self.y
      return pos


def draw(path, position):
    screen.blit(path, position)


def update():
    pygame.display.update()


def color(num):
    if num == 0:
      return black
    elif num == 1:
      return white


if __name__ == "__main__":
    pygame.init()
    World_width = 800
    World_height = 500
    Cell_size = 20
    rule = Rule(World_width, World_height, Cell_size, 0)
    world = World(World_width, World_height, Cell_size, 0, 0)
    # 创建铺满的细胞
    rule.run()
    size = rule.width, rule.height + 60
    screen = pygame.display.set_mode(size)
    pygame.display.set_caption("Game of Life")
    time_running = 0

    Black = pygame.color.Color("black")
    white = pygame.image.load("picture/white.png")
    white = pygame.transform.smoothscale(white, (rule.wow, rule.wow))
    black = pygame.image.load("picture/black.png")
    black = pygame.transform.smoothscale(black, (rule.wow, rule.wow))
    red = pygame.image.load("picture/red.png")
    red = pygame.transform.smoothscale(red, (rule.wow, rule.wow))
    green = pygame.image.load("picture/green.png")
    green = pygame.transform.smoothscale(green, (rule.wow, rule.wow))
    blue = pygame.image.load("picture/blue.png")
    blue = pygame.transform.smoothscale(blue, (World_width, 60))
    draw(blue, (0, World_height))
    txt_state_0 = pygame.font.Font("font/Arial.ttf", 20).render("Creating Mode(print R to run)", True, Black)
    txt_state_0_1 = pygame.font.Font("font/Arial.ttf", 20).render("Print Q to create randomly", True, Black)
    txt_state_1 = pygame.font.Font("font/Arial.ttf", 20).render("Running···(print SPACE to modify)", True, Black)

    while True:
      x, y = pygame.mouse.get_pos()
      for cell in cell_list:
            if cell.charge == 0:
                dest = (cell.position * rule.wow, cell.position * rule.wow)
                draw(color(cell.is_live), dest)
            cell.charge = 0
      if rule.state == 0:
            draw(blue, (0, World_height))
            draw(txt_state_0, ((World_width - txt_state_0.get_width())/2, World_height))
            draw(txt_state_0_1, ((World_width - txt_state_0_1.get_width())/2, World_height + 30))
      elif rule.state == 1:
            draw(blue, (0, World_height))
            draw(txt_state_1, ((World_width - txt_state_0.get_width())/2, World_height))
            txt_time = pygame.font.Font("font/Arial.ttf", 20).render("Time: " + str(time_running), True, Black)
            draw(txt_time, ((World_width - txt_time.get_width())/2, World_height + 30))
      update()
      for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit()
            if event.type == pygame.MOUSEBUTTONDOWN and rule.state == 0:
                # 获取坐标pos = (x, y)
                world.divide()
                for cell in cell_list:
                  if cell.position == pos:
                        cell.convert()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                  rule.state = 1
                if event.key == pygame.K_SPACE:
                  rule.state = 0
                if event.key == pygame.K_q:
                  for cell in cell_list:
                        cell.is_live = random.randint(0, 1)

      if rule.state == 1:
            rule.get_neighbour()
            for cell in cell_list:
                cell.change()
            time_running = time_running + 1
            # time.sleep(1)
      if rule.state == 0:
            world.divide()
            for cell in cell_list:
                if cell.position == pos:
                  cell.charge = 1
                  dest = (cell.position * rule.wow, cell.position * rule.wow)
                  if cell.is_live == 0:
                        draw(green, dest)
                        update()
                  elif cell.is_live == 1:
                        draw(red, dest)
                        update()


运行:



运行下来还是比较顺利的,但是能明显感觉到一些问题:
1、遍历算法实在效率太低{:1_908:},能感觉到计算量有点大(如果能从编号直接访问类产生的对象,应该能好很多)
2、面向对象的方法确实很强,(比如只加了三行代码就添加了随机图案功能)
但是初步运用,思路还比较混乱,没法摆脱刻在DNA里的面向过程的思考方式(笑)
对于pygame这种东西,还不是很清楚怎么用面向对象的思想来编程,代码中的不足希望大佬帮忙指出,感激不尽!

完整代码及其他附件:
创造模式:q随机图案,r开始运行
运行模式下:空格暂停、修改

列明 发表于 2021-4-20 20:25

面向對象編程?
你在做夢?
你得先有個對象!

璐璐诺 发表于 2021-4-20 19:52

过来学习学习大佬了!

狐白本白 发表于 2021-4-20 20:15

虽然你说很粗糙,但是,对于我这种小白,真是牛批,多谢分享

zqguang3708 发表于 2021-4-20 20:34

元胞自动机{:1_893:}
页: [1]
查看完整版本: 【python】Game of Life 生命游戏——初学面向对象试水