Skip to content

Commit 60035bb

Browse files
committed
diffusion simulator
1 parent b4b1718 commit 60035bb

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# 引入pygame和sys模块
2+
import pygame, sys
3+
import math
4+
from pygame.locals import *
5+
import time
6+
import people
7+
8+
WIDTH = 500
9+
HEIGHT = 500
10+
11+
RADIUS = 25
12+
POINT_RADIUS = 5
13+
14+
BLACK = (0,0,0)
15+
WHITE = (255,255,255)
16+
PINK = (255,192,203)
17+
RED = (255,0,0)
18+
19+
# 初始化pygame
20+
pygame.init()
21+
22+
# 设置窗口与窗口标题
23+
windowSurface = pygame.display.set_mode((WIDTH,HEIGHT),0,8)
24+
pygame.display.set_caption('疫情模拟')
25+
26+
# 初始化人群
27+
p = people.People(600, 1)
28+
29+
COLORS = [BLACK, PINK, RED]
30+
31+
# 事件循环
32+
while True:
33+
for event in pygame.event.get():
34+
if event.type == QUIT:
35+
pygame.quit()
36+
sys.exit()
37+
38+
windowSurface.fill(WHITE) # 设置画布背景 起到擦除的作用
39+
40+
for i in range(len(p._status)): # 健康
41+
x_point = p._people[i][0]
42+
y_point = p._people[i][1]
43+
pygame.draw.circle(windowSurface,COLORS[p._status[i]],(int(x_point), int(y_point)), POINT_RADIUS)
44+
45+
# 绘制窗口到屏幕上
46+
pygame.display.update()
47+
time.sleep(0.1)
48+
p.update()
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
4+
5+
class People(object):
6+
def __init__(self, count=1000, first_infected_count=3):
7+
self.count = count
8+
self.first_infected_count = first_infected_count
9+
self.init()
10+
11+
def init(self):
12+
self._people = np.random.normal(250, 100, (self.count, 2)) # 产生中值为1,幅度为正负100的,count组样本,每个样本有两个值 作为位置
13+
self.reset()
14+
15+
def reset(self):
16+
self._round = 0 # 表示哪一次循环
17+
self._status = np.array([0] * self.count)
18+
self._timer = np.array([0] * self.count)
19+
self.random_people_state(self.first_infected_count, 1)
20+
21+
def random_people_state(self, num, state=1):
22+
"""随机挑选人设置状态
23+
"""
24+
assert self.count > num
25+
# TODO:极端情况下会出现无限循环
26+
n = 0
27+
while n < num:
28+
i = np.random.randint(0, self.count)
29+
if self._status[i] == state:
30+
continue
31+
else:
32+
self.set_state(i, state)
33+
n += 1
34+
35+
def set_state(self, i, state):
36+
self._status[i] = state
37+
# 记录状态改变的时间
38+
self._timer[i] = self._round # 哪次循环中状态发生在哪次循环中
39+
40+
def move(self, width=1, x=.0):
41+
movement = np.random.normal(0, width, (self.count, 2))
42+
43+
normal = np.random.normal(0, 1, self.count)
44+
switch = np.where(normal < x, 1, 0)
45+
movement[switch == 0] = 0 # 随机产生不移动的情况
46+
self._people = self._people + movement # 位置发生变换
47+
48+
def change_state(self): # 设置成为确证
49+
dt = self._round - self._timer
50+
# 必须先更新时钟再更新状态
51+
d = np.random.randint(3, 7)
52+
# print("change_state:", (self._status == 1) & ((dt == d) | (dt > 14)))
53+
self._timer[(self._status == 1) & ((dt == d) | (dt > 14))] = self._round
54+
self._status[(self._status == 1) & ((dt == d) | (dt > 14))] += 1
55+
56+
def affect(self, safe_distance=5):
57+
"""感染最接近的健康人"""
58+
# np.vstack((self._people[self._status == 1],self._people[self._status == 2]))
59+
for inf in self._people[(self._status == 1) | (self._status == 2)]: # self.infected:
60+
dm = (self._people - inf) ** 2
61+
d = dm.sum(axis=1) ** 0.5 # 计算一个欧氏距离 (x1,y1) (x2,y2) ==> ((x1-x2)^2 + (y1-y2)^2)^(1/2)
62+
sorted_index = d.argsort()
63+
for i in sorted_index:
64+
if d[i] >= safe_distance:
65+
break # 超出范围,不用管了
66+
if self._status[i] > 0: # 已经感染的排除掉
67+
continue
68+
self._status[i] = 1
69+
# 记录状态改变的时间
70+
self._timer[i] = self._round
71+
break # 只传 1 个
72+
73+
def update(self):
74+
"""每一次迭代更新"""
75+
self.change_state()
76+
self.affect()
77+
self.move(3, 1.99)
78+
self._round += 1

0 commit comments

Comments
 (0)