Как я могу заставить черепаху что-то делать, когда она приближается к другой черепахе? - PullRequest
1 голос
/ 06 мая 2020

Добрый день,

Моделирую вирусную эпидемию с помощью черепах. Я придумал следующий код, мой вопрос будет после кода:

import turtle
import random
import time

def make_population(amount):
    """
    Creates a list representing a population with a certain amount of people.
    """
    population = []
    for person in range(amount):
        population.append(turtle.Turtle())
    for person in population:
        person.shape("circle")
        person.shapesize(0.2)
    return population

def random_move(person):
    """
    Makes a turtle move forward a random amount and then turn a random amount.
    """
    person.forward(random.randint(0,20))
    person.right(random.randint(-180,180))

def check_boundary(person):
    """
    Checks if a turtle is still within the given boundaries.
    """
    if -250 <= person.xcor() <= 250 and -250 <= person.ycor() <= 250:
        return
    person.setpos(random.randint(-200,200),random.randint(-200,200))

def infect_random(population):
    """
    Gets a random item from the population list and turns one red
    """
    infected = random.choice(population)
    infected.color("red")
    return infected

def infect_person(person):
    """
    Makes the turtle infected
    """
    infected_person = person.color("red")
    return infected_person

def simulation(amount, moves = 0):
    """
    Simulates a virus outbreak
    """
    border = 500
    window = turtle.Screen()
    turtle.setup(500,500)
    turtle.tracer(0)
    population = make_population(amount)
    for person in population:
        person.penup()
        person.setpos(random.randint(-250,250),random.randint(-250,250))
    turtle.update()
    infected = infect_random(population)
    for move in range(moves):
        turtle.tracer(0)
        for person in population:
            random_move(person)
            if person.distance(infected) < 50:
                infect_person(person)
            check_boundary(person)
        turtle.update()
        time.sleep(0.5)

    window.exitonclick()

Итак, когда начинается симуляция, я заражаю 1 случайного человека, и если другие черепахи приближаются, например, в пределах 50 пикселей, они тоже заразится и покраснеет. Однако эти недавно «инфицированные» черепахи не заразят других черепах, поскольку они не «заражены» по сравнению с исходной черепахой. Я попытался изменить его на зараженный = infect_person (человек), но это вызывало ошибку. Я застрял на какое-то время и хотел бы знать, может ли кто-нибудь помочь. Я также подумал о том, чтобы составить два списка: население и инфицированное_популяция, которые, возможно, могут решить мою проблему, но я не мог понять, как реализовать это в остальной части моего кода.

Заранее спасибо

Ответы [ 2 ]

2 голосов
/ 06 мая 2020

Я считаю, что решение разделяет операции с черепахой низкого уровня на подкласс Person класса Turtle от операций высокого уровня над людьми в симуляции:

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

class Person(Turtle):
    population = []

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

        self.shapesize(0.2)
        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 random_move(self):
        """
        Makes a turtle move forward a random amount and then turn a random amount.
        """

        self.right(randint(-180, 180))
        self.forward(randint(0, 20))

        # checks if turtle is still within the given boundaries.

        if not (-250 < self.xcor() < 250 and -250 < self.ycor() < 250):
            self.undo()  # undo forward()

def make_population(amount):
    """
    Creates a list representing a population with a certain amount of people.
    """

    for _ in range(amount):
        Person()

def infect_random():
    """
    Gets a random item from the population list and turns one red
    """

    person = choice(Person.population)
    person.infect()

def simulation(amount=20, moves=100):
    """
    Simulates a virus outbreak
    """

    make_population(amount)

    infect_random()

    screen.update()

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

            if not person.infected():
                for infected in Person.all_infected():
                    if person.distance(infected) < 50:
                        person.infect()

        screen.update()
        sleep(0.5)

screen = Screen()
screen.setup(500, 500)
screen.tracer(0)

simulation()

screen.exitonclick()

Мы могли бы go дальше с черепахой события таймера, чтобы сделать людей более автономными вместо for _ in range(moves): l oop.

enter image description here

1 голос
/ 06 мая 2020

Думаю, вы привели небольшой пример, но мы упускаем информацию о структуре данных, является ли человек классом?

Вы не назначаете человека как зараженного.

Когда вы заразили первого люди

infected = infect_random(population)

вы назначаете его зараженным, но когда вы заражаете другого человека, которого вы не делаете, вы включаете его в красный цвет, возвращаете человека:

def infect_person(person):
    """
    Makes the turtle infected
    """
    infected_person = person.color("red")
    return infected_person

но курица В вашем коде вы не назначаете его,

infect_person(person)

Я предлагаю либо использовать способ узнать, кто инфицирован, а кто нет. Например: если вы использовали POO:

  • , вы можете добавить поле is_infected

  • , иначе используйте список, в котором хранятся индексы человека быть зараженным?

При этом вам придется изменить способ проверки, заражен ли кто-то поблизости. Для всех людей, находящихся рядом с человеком, если один инфицирован, то заражаюсь я ...

...