首页 > 解决方案 > 如何使用turtle python进行可控的病毒模拟

问题描述

嗯,我的任务是使用 python turtle 为学校项目进行可控的 Covid-19 模拟。所以我做的是一堆随机移动的海龟,随机挑选的“被感染”和随机挑选的“感染”海龟。我试图用箭头键控制“被附身”的乌龟,如果前一个被感染,我还会选择另一只“健康”的乌龟。问题是,我不知道如何分离控件,因为它们都被标记在“Person”类下。我也不知道如何让它在被感染时选择另一只健康的乌龟。这是凌乱的代码。抱歉英语不好。

from turtle import Screen, Turtle
"""
This imports the screen and turtle from the turtle module
"""
from random import randint, choice
"""
This is to use the random integer function and the random choosing of the infected
"""
from time import sleep
posessed = 0
class Person(Turtle):
    population = []

    def __init__(self):
        super().__init__(shape='circle')

        self.shapesize(0.4)
        self.penup()
        self.setpos(randint(-250, 250), randint(-250, 250))

        Person.population.append(self)

    @classmethod
    def all_infected(cls):
        return [person for person in cls.population if person.infected()]

    def infect(self):
        self.color('red')

    def infected(self):
        return self.pencolor() == 'red'
    def all_infected(cls):
        return [person for person in cls.population if person.posessed()]

    def posess(self):
        self.color('yellow')

    def posessed(self):
        return self.pencolor() == 'yellow'


    def random_move(self):
        self.right(randint(-180,180))
        self.forward(randint(0,10))
        if not (-250 < self.xcor() <250 and -250 < self.ycor() < 250):
            self.undo() # this will undo forward()

def make_population(amount):

    for _ in range(amount):
        Person()

def posess_random():
    person = choice(Person.population)
    person.posess()
    posessed+1

def infect_random():
    person = choice(Person.population)
    person.infect()

def simulation():
    """ This will simulate the virus outbreak scenarios (quarantine, or not quarantine) """
    amount=int(input("Enter amount of people within the area: " ))
    moves=int(input("Enter the amount of moves these people will do: "))
    print("Entered amount of people: ", amount)
    print("Entered amount of movements: ", moves)
    make_population(amount)

    infect_random()
    posess_random()

    screen.update()
    for _ in range(moves):
        for person.infected in Person.population:
            person.random_move()

            if not person.infected():
                for infected in Person.all_infected():
                    if person.distance(infected) < 30:
                        person.infect()
                        #this is used to set distance to get infected. In this case I did 30

        screen.update()
        sleep(0.1)


screen = Screen()
screen.setup(500,500)
screen.tracer(0)
screen.bgcolor(str(input("Enter desired background color: ")))
simulation()

screen.exitonclick()
               #this should do it

手前的Tysm

标签: pythonpython-3.xpython-turtle

解决方案


所以我做的是一堆随机移动的海龟

首先,这段代码没有像发布的那样运行——我必须修复至少三个错误才能让它运行。令人惊讶的是,因为它对我的返工只有很小的改动,@LST_2020 的代码,前者运行良好。并且没有返回该代码的信用/链接!继续:

下面是我对我们代码的修改,以修复引入的错误,并使被附身者手动移动。(在此过程中修正了“拥有”的拼写。)如果被附身者与感染者接触,无论是通过他们自己的动作还是被感染者的动作,被附身者会被感染,并且随机的健康人,如果有的话,被附身并可以手动移动:

from turtle import Screen, Turtle
from random import randint, choice
from functools import partial
from time import sleep

INFECTION_DISTANCE = 30
PERSON_RADIUS = 8
WIDTH, HEIGHT = 500, 500
CURSOR_SIZE = 20

possessed = 0

class Person(Turtle):
    population = []

    def __init__(self):
        super().__init__(shape='circle')

        self.shapesize(PERSON_RADIUS / CURSOR_SIZE)
        self.penup()
        self.setpos(randint(-WIDTH/2, WIDTH/2), randint(-HEIGHT/2, HEIGHT/2))

        Person.population.append(self)

    @classmethod
    def all_infected(cls):
        return [person for person in cls.population if person.infected()]

    def infect(self):
        self.color('red')

    def infected(self):
        return self.pencolor() == 'red'

    @classmethod
    def all_healthy(cls):
        return [person for person in cls.population if not person.infected()]

    def possess(self):
        self.color('green')

    def possessed(self):
        return self.pencolor() == 'green'

    def random_move(self):
        self.right(randint(-90, 90))
        self.forward(randint(0, 10))

        x, y = self.position()

        if not (PERSON_RADIUS - WIDTH/2 < x < WIDTH/2 - PERSON_RADIUS and PERSON_RADIUS - HEIGHT/2 < y < HEIGHT/2 - PERSON_RADIUS):
            self.undo()  # this will undo forward()

def make_population(amount):
    for _ in range(amount):
        Person()

def possess_random():
    possessed = None

    healthy = Person.all_healthy()

    if healthy:
        possessed = choice(healthy)
        possessed.possess()

        screen.onkey(partial(move_up, possessed), 'Up')
        screen.onkey(partial(move_down, possessed), 'Down')
        screen.onkey(partial(move_right, possessed), 'Right')
        screen.onkey(partial(move_left, possessed), 'Left')

    return possessed

def infect_random():
    person = None

    healthy = Person.all_healthy()

    if healthy:
        person = choice(healthy)
        person.infect()

    return person

def check_infection(person):
    for infected in Person.all_infected():
        if person.distance(infected) < INFECTION_DISTANCE:
            is_possessed = person.possessed()

            person.infect()

            if is_possessed:
                possess_random()

def simulation(amount, moves):
    """ This will simulate the virus outbreak scenarios (quarantine, or not quarantine) """
    make_population(amount)

    infect_random()
    possess_random()
    screen.update()

    for _ in range(moves):
        for person in Person.population:
            if not person.possessed():
                person.random_move()

            if not person.infected():
                check_infection(person)

        screen.update()
        sleep(0.1)

def move_up(possessed):
    y = possessed.ycor() + 10

    if y < HEIGHT/2 - PERSON_RADIUS:
        possessed.sety(y)
        check_infection(possessed)

def move_down(possessed):
    y = possessed.ycor() - 10

    if y > PERSON_RADIUS - HEIGHT/2:
        possessed.sety(y)
        check_infection(possessed)

def move_right(possessed):
    x = possessed.xcor() + 10

    if x < WIDTH/2 - PERSON_RADIUS:
        possessed.setx(x)
        check_infection(possessed)

def move_left(possessed):
    x = possessed.xcor() - 10

    if x > PERSON_RADIUS - WIDTH/2:
        possessed.setx(x)
        check_infection(possessed)

amount = int(input("Enter amount of people within the area: "))
moves = int(input("Enter the amount of moves these people will do: "))

screen = Screen()
screen.setup(WIDTH, HEIGHT)

screen.listen()
screen.tracer(False)

simulation(amount, moves)

screen.tracer(True)
screen.exitonclick()

我将拥有的颜色更改为绿色,因为在默认的海龟背景颜色下我无法轻易看到黄点。我将输入问题移到第一个 turtle 调用之前,这样用户就不必点击返回控制台来回答它们。

正如我在原件中所指出的,您应该考虑使用海龟计时器事件来使人们更加自主,而不是for _ in range(moves): loop同时阻止一些海龟事件。


推荐阅读