Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/KikiLetGo/VirusBroadcast in…
Browse files Browse the repository at this point in the history
…to KikiLetGo-master
  • Loading branch information
ChangingSelf committed Feb 6, 2020
2 parents cb6c17f + 2b4eb4f commit 44b16e3
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 40 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# VirusBroadcast
一个基于java的模拟仿真程序,由于启动的时候时间仓促,数据不足,所以模型和推演过程过于简单,如果有好的想法或者能提供相关数据支持的朋友请提issues。
如果您也是一名java程序员,可以直接修改并给我提交pr,我之前已经启动每日疫情数据的每日抓取工作,希望在疫情结束后有机会通过这些精准的的数据做一个复盘。
11 changes: 9 additions & 2 deletions src/Bed.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
/**
* 床位
*
*
* @ClassName: Bed
* @Description: TODO
* @Description: 床位
* @author: Bruce Young
* @date: 2020年02月02日 21:00
*/
public class Bed extends Point {
public Bed(int x, int y) {
super(x, y);
}
private boolean isEmpty=true;

/**
* 是否占用了该床位
*/
private boolean isEmpty = true;

public boolean isEmpty() {
return isEmpty;
Expand Down
4 changes: 3 additions & 1 deletion src/City.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* 城市描述对象
*
* @ClassName: City
* @Description: TODO
* @Description: 城市描述对象
* @author: Bruce Young
* @date: 2020年02月02日 17:48
*/
Expand Down
4 changes: 3 additions & 1 deletion src/Constants.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* 模拟参数
*
* @ClassName: Constants
* @Description: TODO
* @Description: 模拟参数
* @author: Bruce Young
* @date: 2020年02月02日 21:40
*/
Expand Down
25 changes: 21 additions & 4 deletions src/Hospital.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
import java.util.List;

/**
* 医院
* <p>
* 床位容量
*
* @ClassName: Hospital
* @Description: TODO
* @Description: 医院,包含床位容量
* @author: Bruce Young
* @date: 2020年02月02日 20:58
*/
Expand Down Expand Up @@ -48,6 +52,8 @@ private Hospital() {
width = 0;
height = 0;
}
//根据医院床位数量计算医院宽度
//因为高度定了只能装载100个床位
int column = Constants.BED_COUNT / 100;
width = column * 6;
//根据第一个床位坐标初始化其他床位的坐标
Expand All @@ -56,15 +62,15 @@ private Hospital() {
for (int j = 10; j <= 610; j += 6) {
Bed bed = new Bed(point.getX() + i * 6, point.getY() + j);
beds.add(bed);

}

}
}

/**
* 获取下一个空床位
* @return 下一个空床位
* 使用床位
*
* @return
*/
public Bed pickBed() {
for (Bed bed : beds) {
Expand All @@ -74,4 +80,15 @@ public Bed pickBed() {
}
return null;
}

/**
* 死亡或痊愈出院空出床位
*
* @param bed
* @return
*/
public Bed returnBed(Bed bed) {
bed.setEmpty(false);
return bed;
}
}
9 changes: 8 additions & 1 deletion src/Main.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import javax.swing.*;

import java.util.List;
import java.util.Random;

/**
* 模拟程序主入口
*
* @author
* @comment GinRyan
*/
public class Main {


Expand All @@ -18,7 +25,7 @@ private static void initPanel(){
Thread panelThread = new Thread(p);
JFrame frame = new JFrame();
frame.add(p);
frame.setSize(1000, 800);
frame.setSize(1100, 800);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setTitle("瘟疫传播模拟");
Expand Down
4 changes: 3 additions & 1 deletion src/MoveTarget.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* 位移目标对象
*
* @ClassName: MoveTarget
* @Description: TODO
* @Description: 位移目标对象
* @author: Bruce Young
* @date: 2020年02月02日 17:47
*/
Expand Down
11 changes: 8 additions & 3 deletions src/MyPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
import java.util.TimerTask;

/**
* 主面板。
*
* @ClassName: MyPanel
* @Description: TODO
* @Description: 主面板
* @author: Bruce Young
* @date: 2020年02月02日 17:03
*/
public class MyPanel extends JPanel implements Runnable {

private int pIndex = 0;//人口池PersonPool的下标,用于遍历每个人


public MyPanel() {
super();
this.setBackground(new Color(0x444444));
Expand All @@ -31,7 +34,7 @@ public void paint(Graphics g) {
g.drawString("医院", Hospital.getInstance().getX() + Hospital.getInstance().getWidth() / 4, Hospital.getInstance().getY() - 16);
//绘制代表人类的圆点
List<Person> people = PersonPool.getInstance().getPersonList();
if (people == null) {
if(people==null){
return;
}
people.get(pIndex).update();
Expand Down Expand Up @@ -83,7 +86,9 @@ public void paint(Graphics g) {
g.drawString("病死人数:" + PersonPool.getInstance().getPeopleSize(Person.State.DEATH), 16, 184);
g.setColor(new Color(0xffffff));
g.drawString("世界时间(天):" + (int)(worldTime/10.0), 16, 208);


g.setColor(new Color(0xCFE3C0));
g.drawString("病毒扩散时间:" + worldTime + " 单位", 16, 232);
}

public static int worldTime = 0;//世界时间
Expand Down
89 changes: 65 additions & 24 deletions src/Person.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import java.util.Random;

/**
* 能够随机运动的民众
*
* @ClassName: Person
* @Description: TODO
* @Description: 能够随机运动的民众
* @author: Bruce Young
* @date: 2020年02月02日 17:05
*/
Expand All @@ -12,20 +14,30 @@ public class Person {
private int x;
private int y;
private MoveTarget moveTarget;
int sig = 1;//移动意愿的正态分布方差sigma
/**
* 人群流动意愿影响系数:正态分布方差sigma
*/
int sig = 1;

//正态分布相关参数N(mu,sigma)
/**
* 正态分布N(mu,sigma)随机位移目标位置
*/
double targetXU;//x方向的均值mu
double targetYU;//y方向的均值mu
double targetSig = 50;//方差sigma


public interface State {//市民状态
int NORMAL = 0;//未被感染
int SHADOW = NORMAL + 1;//潜伏者

int CONFIRMED = SHADOW + 1;//感染者
int FREEZE = CONFIRMED + 1;//已隔离
/**
* 市民的状态
*
* 市民状态应该需要细分,虽然有的状态暂未纳入模拟,但是细分状态应该保留
*/
public interface State {
int NORMAL = 0;//正常人,未感染的健康人
int SUSPECTED = NORMAL + 1;//有暴露感染风险
int SHADOW = SUSPECTED + 1;//潜伏期
int CONFIRMED = SHADOW + 1;//发病且已确诊为感染病人
int FREEZE = CONFIRMED + 1;//隔离治疗,禁止位移
//已治愈出院的人转为NORMAL即可,否则会与作者通过数值大小判断状态的代码冲突
int DEATH = FREEZE + 1;//病死者
}

Expand All @@ -40,12 +52,22 @@ public Person(City city, int x, int y) {
}

/**
* 根据想要移动的意愿的平均值来进行正态分布计算
* @return 是否想要移动
* 流动意愿标准化
* <p>
* 流动意愿标准化后判断是在0的左边还是右边从而决定是否流动。
* <p>
* 设X随机变量为服从正态分布,sigma是影响分布形态的系数,从而影响整体人群流动意愿分布
* u值决定正态分布的中轴是让更多人群偏向希望流动或者希望懒惰。
* <p>
* value的推导:
* StdX = (X-u)/sigma
* X = sigma * StdX + u
*
* @return
*/
public boolean wantMove() {
//产生N(a,b)的数:Math.sqrt(b)*random.nextGaussian()+a
double value = sig * new Random().nextGaussian() + Constants.u;
double stdX = new Random().nextGaussian();
double value = sig * stdX + Constants.u;
return value > 0;
}

Expand Down Expand Up @@ -77,7 +99,8 @@ public void setY(int y) {

int infectedTime = 0;//感染时刻
int confirmedTime = 0;//确诊时刻
int dieMoment = 0;//死亡时刻
int dieMoment = 0;//死亡时刻,为0代表未确定,-1代表不会病死


public boolean isInfected() {
return state >= State.SHADOW;
Expand All @@ -88,22 +111,36 @@ public void beInfected() {
infectedTime = MyPanel.worldTime;
}

/**
* 计算两点之间的直线距离
*
* @param person
* @return
*/
public double distance(Person person) {
return Math.sqrt(Math.pow(x - person.getX(), 2) + Math.pow(y - person.getY(), 2));
}

/**
* 住院
*/
private void freezy() {
state = State.FREEZE;
}

/**
* 位移
*
* @param x
* @param y
*/
private void moveTo(int x, int y) {
this.x += x;
this.y += y;
}

/**
* 处理未隔离者的移动问题
*
* 不同状态下的单个人实例运动行为
*/
private void action() {
if (state == State.FREEZE || state == State.DEATH) {
Expand All @@ -112,6 +149,7 @@ private void action() {
if (!wantMove()) {
return;
}
//存在流动意愿的,将进行流动,流动位移仍然遵循标准正态分布
if (moveTarget == null || moveTarget.isArrived()) {
//在想要移动并且没有目标时,将自身移动目标设置为随机生成的符合正态分布的目标点
//产生N(a,b)的数:Math.sqrt(b)*random.nextGaussian()+a
Expand All @@ -121,7 +159,7 @@ private void action() {

}


//计算运动位移
int dX = moveTarget.getX() - x;
int dY = moveTarget.getY() - y;
double length = Math.sqrt(Math.pow(dX, 2) + Math.pow(dY, 2));//与目标点的距离
Expand All @@ -131,16 +169,18 @@ private void action() {
moveTarget.setArrived(true);
return;
}
int udX = (int) (dX / length);//符号为沿x轴前进方向
int udX = (int) (dX / length);//x轴移动步长,符号为沿x轴前进方向
if (udX == 0 && dX != 0) {
if (dX > 0) {
udX = 1;//TODO:移动步长为1,如果要调整移动步长可以看一下这里
udX = 1;
} else {
udX = -1;
}
}
int udY = (int) (dY / length);//符号为沿y轴前进方向
if (udY == 0 && udY != 0) {

int udY = (int) (dY / length);//y轴移动步长,符号为沿x轴前进方向
//FIXED: 修正一处错误
if (udY == 0 && dY != 0) {
if (dY > 0) {
udY = 1;
} else {
Expand Down Expand Up @@ -170,8 +210,8 @@ private void action() {
* 对各种状态的人进行不同的处理
*/
public void update() {
//TODO:找时间改为状态机
if (state >= State.FREEZE) {
//@TODO找时间改为状态机
if (state == State.FREEZE || state == State.DEATH) {
return;//如果已经隔离或者死亡了,就不需要处理了
}
//处理已经确诊的感染者(即患者)
Expand All @@ -190,6 +230,7 @@ public void update() {

}
//*/

if (state == State.CONFIRMED && MyPanel.worldTime - confirmedTime >= Constants.HOSPITAL_RECEIVE_TIME) {
//如果患者已经确诊,且(世界时刻-确诊时刻)大于医院响应时间,即医院准备好病床了,可以抬走了
Bed bed = Hospital.getInstance().pickBed();//查找空床位
Expand Down
4 changes: 3 additions & 1 deletion src/PersonPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import java.util.Random;

/**
* 区域人群对象池
*
* @ClassName: PersonPool
* @Description: TODO
* @Description: 区域人群对象池,该地区假设为一个近似封闭的环境,拥有几乎不变的民众数量
* @author: Bruce Young
* @date: 2020年02月02日 17:21
*/
Expand Down
4 changes: 3 additions & 1 deletion src/Point.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* 位置坐标基类
*
* @ClassName: Point
* @Description: TODO
* @Description: 位置坐标基类
* @author: Bruce Young
* @date: 2020年02月02日 20:59
*/
Expand Down
4 changes: 3 additions & 1 deletion src/Virus.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* 病毒对象
*
* @ClassName: Virus
* @Description: TODO
* @Description: 病毒对象
* @author: Bruce Young
* @date: 2020年02月02日 17:04
*/
Expand Down

0 comments on commit 44b16e3

Please sign in to comment.