Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Person state改为状态机 #66

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Main.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import life.Person;
import nonliving.Hospital;
import nonliving.PersonPool;
import starter.Constants;
import starter.MyPanel;

import javax.swing.*;

import java.util.List;
Expand Down
78 changes: 40 additions & 38 deletions src/MathUtil.java → src/Util/MathUtil.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import java.util.Random;

/**
* 数学算法工具类
*
* @ClassName: MathUtil
* @Description: 数学算法工具类
* @author: Bruce Young
* @date: 2020年02月06日 11:27
*/
public class MathUtil {
/**
* 仅仅使用一个随机数生成器
*/
private static final Random randomGen = new Random();

/**
* 标准正态分布化
* <p>
* 流动意愿标准化后判断是在0的左边还是右边从而决定是否流动。
* <p>
* 设X随机变量为服从正态分布,sigma是影响分布形态的系数 u值决定正态分布均值
* <p>
* <p>
* 推导:
* StdX = (X-u)/sigma
* X = sigma * StdX + u
*
* @param sigma 正态标准差sigma值
* @param u 正态均值参数mu
* @return
*/
public static double stdGaussian(double sigma, double u) {
double X = randomGen.nextGaussian();
return sigma * X + u;
}

}
package Util;

import java.util.Random;

/**
* 数学算法工具类
*
* @ClassName: Util.MathUtil
* @Description: 数学算法工具类
* @author: Bruce Young
* @date: 2020年02月06日 11:27
*/
public class MathUtil {
/**
* 仅仅使用一个随机数生成器
*/
private static final Random randomGen = new Random();

/**
* 标准正态分布化
* <p>
* 流动意愿标准化后判断是在0的左边还是右边从而决定是否流动。
* <p>
* 设X随机变量为服从正态分布,sigma是影响分布形态的系数 u值决定正态分布均值
* <p>
* <p>
* 推导:
* StdX = (X-u)/sigma
* X = sigma * StdX + u
*
* @param sigma 正态标准差sigma值
* @param u 正态均值参数mu
* @return
*/
public static double stdGaussian(double sigma, double u) {
double X = randomGen.nextGaussian();
return sigma * X + u;
}

}
76 changes: 57 additions & 19 deletions src/Person.java → src/life/Person.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
package life;

import nonliving.*;
import Util.MathUtil;
import starter.MyPanel;
import starter.Constants;
import state.*;

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

/**
* 能够随机运动的民众
*
* @ClassName: Person
* @ClassName: life.Person
* @Description: 能够随机运动的民众
* @author: Bruce Young
* @date: 2020年02月02日 17:05
*/

public class Person extends Point {
//人员状态机
private State confirmState;
private State deathState;
private State freezeState;
private State normalState;
private State shadowState;
private State suspectedState;

private State state; //人员的当前状态

public State getState() {
return state;
}

public void setState(State state) {
this.state = state;
}

private City city;

private MoveTarget moveTarget;
Expand All @@ -31,7 +57,7 @@ public class Person extends Point {
* 市民的状态
* <p>
* 市民状态应该需要细分,虽然有的状态暂未纳入模拟,但是细分状态应该保留
*/
*//*
public interface State {
int NORMAL = 0;//正常人,未感染的健康人
int SUSPECTED = NORMAL + 1;//有暴露感染风险
Expand All @@ -42,7 +68,7 @@ public interface State {
//已治愈出院的人转为NORMAL即可,否则会与作者通过数值大小判断状态的代码冲突
int DEATH = FREEZE + 1;//病死者
//int CURED = DEATH + 1;//治愈数量用于计算治愈出院后归还床位数量,该状态是否存续待定
}
}*/

public Person(City city, int x, int y) {
super(x, y);
Expand All @@ -51,6 +77,14 @@ public Person(City city, int x, int y) {
targetXU = MathUtil.stdGaussian(100, x);
targetYU = MathUtil.stdGaussian(100, y);

//状态机初始化
confirmState = new ConfirmState(this);
deathState = new DeathState(this);
freezeState = new FreezeState(this);
normalState = new NormalState(this);
shadowState = new ShadowState(this);
suspectedState = new SuspecteState(this);
state = new NormalState(this);
}

/**
Expand All @@ -73,27 +107,31 @@ public boolean wantMove() {
return MathUtil.stdGaussian(sig, Constants.u) > 0;
}

private int state = State.NORMAL;
/*private int state = State.NORMAL;

public int getState() {
return state;
}

public void setState(int state) {
this.state = state;
}
}*/

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


public boolean isInfected() {
return state >= State.SHADOW;
return state instanceof ShadowState
|| state instanceof ConfirmState
|| state instanceof FreezeState
|| state instanceof DeathState;
}

public void beInfected() {
state = State.SHADOW;
shadowState.beShadow();

infectedTime = MyPanel.worldTime;
}

Expand All @@ -111,15 +149,15 @@ public double distance(Person person) {
* 住院
*/
private void freezy() {
state = State.FREEZE;
freezeState.beFreeze();
}

/**
* 不同状态下的单个人实例运动行为
*/
private void action() {

if (state == State.FREEZE || state == State.DEATH) {
if (state instanceof FreezeState || state instanceof DeathState) {
return;//如果处于隔离或者死亡状态,则无法行动
}
if (!wantMove()) {
Expand Down Expand Up @@ -195,12 +233,12 @@ private void action() {
public void update() {
//@TODO找时间改为状态机

if (state == State.FREEZE || state == State.DEATH) {
if (state instanceof FreezeState || state instanceof DeathState) {
return;//如果已经隔离或者死亡了,就不需要处理了
}

//处理已经确诊的感染者(即患者)
if (state == State.CONFIRMED && dieMoment == 0) {
if (state instanceof ConfirmState && dieMoment == 0) {

int destiny = new Random().nextInt(10000) + 1;//幸运数字,[1,10000]随机数
if (1 <= destiny && destiny <= (int) (Constants.FATALITY_RATE * 10000)) {
Expand All @@ -216,7 +254,7 @@ public void update() {
//TODO 暂时缺失治愈出院市民的处理。需要确定一个变量用于治愈时长。由于案例太少,暂不加入。


if (state == State.CONFIRMED
if (state instanceof ConfirmState
&& MyPanel.worldTime - confirmedTime >= Constants.HOSPITAL_RECEIVE_TIME) {
//如果患者已经确诊,且(世界时刻-确诊时刻)大于医院响应时间,即医院准备好病床了,可以抬走了
Bed bed = Hospital.getInstance().pickBed();//查找空床位
Expand All @@ -227,36 +265,36 @@ public void update() {
} else {
//安置病人
useBed = bed;
state = State.FREEZE;
freezeState.beFreeze();
setX(bed.getX());
setY(bed.getY());
bed.setEmpty(false);
}
}

//处理病死者
if ((state == State.CONFIRMED || state == State.FREEZE) && MyPanel.worldTime >= dieMoment && dieMoment > 0) {
state = State.DEATH;//患者死亡
if ((state instanceof ConfirmState || state instanceof FreezeState) && MyPanel.worldTime >= dieMoment && dieMoment > 0) {
deathState.beDeath();//患者死亡
Hospital.getInstance().returnBed(useBed);//归还床位
}

//增加一个正态分布用于潜伏期内随机发病时间
double stdRnShadowtime = MathUtil.stdGaussian(25, Constants.SHADOW_TIME / 2);
//处理发病的潜伏期感染者
if (MyPanel.worldTime - infectedTime > stdRnShadowtime && state == State.SHADOW) {
state = State.CONFIRMED;//潜伏者发病
if (MyPanel.worldTime - infectedTime > stdRnShadowtime && state instanceof ShadowState) {
confirmState.beConfirmed();//潜伏者发病
confirmedTime = MyPanel.worldTime;//刷新时间
}
//处理未隔离者的移动问题
action();
//处理健康人被感染的问题
List<Person> people = PersonPool.getInstance().personList;
if (state >= State.SHADOW) {
if (isInfected()) {
return;
}
//通过一个随机幸运值和安全距离决定感染其他人
for (Person person : people) {
if (person.getState() == State.NORMAL) {
if (person.getState() instanceof NormalState) {
continue;
}
float random = new Random().nextFloat();
Expand Down
4 changes: 3 additions & 1 deletion src/Bed.java → src/nonliving/Bed.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package nonliving;

/**
* 床位
*
*
* @ClassName: Bed
* @ClassName: nonliving.Bed
* @Description: 床位
* @author: Bruce Young
* @date: 2020年02月02日 21:00
Expand Down
4 changes: 3 additions & 1 deletion src/City.java → src/nonliving/City.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package nonliving;

/**
* 城市描述对象
*
* @ClassName: City
* @ClassName: nonliving.City
* @Description: 城市描述对象
* @author: Bruce Young
* @date: 2020年02月02日 17:48
Expand Down
7 changes: 5 additions & 2 deletions src/Hospital.java → src/nonliving/Hospital.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package nonliving;

import starter.Constants;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
* 医院
* <p>
* 床位容量
*
* @ClassName: Hospital
* @ClassName: nonliving.Hospital
* @Description: 医院,包含床位容量
* @author: Bruce Young
* @date: 2020年02月02日 20:58
Expand Down
4 changes: 3 additions & 1 deletion src/MoveTarget.java → src/nonliving/MoveTarget.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package nonliving;

/**
* 位移目标对象
*
* @ClassName: MoveTarget
* @ClassName: nonliving.MoveTarget
* @Description: 位移目标对象
* @author: Bruce Young
* @date: 2020年02月02日 17:47
Expand Down
19 changes: 11 additions & 8 deletions src/PersonPool.java → src/nonliving/PersonPool.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package nonliving;

import life.Person;
import starter.Constants;
import state.State;

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

/**
* 区域人群对象池
*
* @ClassName: PersonPool
* @ClassName: nonliving.PersonPool
* @Description: 区域人群对象池,该地区假设为一个近似封闭的环境,拥有几乎不变的民众数量
* @author: Bruce Young
* @date: 2020年02月02日 17:21
Expand All @@ -17,24 +23,21 @@ public static PersonPool getInstance() {
return personPool;
}

List<Person> personList = new ArrayList<Person>();
public List<Person> personList = new ArrayList<Person>();

public List<Person> getPersonList() {
return personList;
}


/**
* @param state 市民类型 Person.State的值,若为-1则返回当前总数目
* @param state 市民类型 life.Person.State的值,若为-1则返回当前总数目
* @return 获取指定人群数量
*/
public int getPeopleSize(int state) {
if (state == -1) {
return personList.size();
}
public int getPeopleSize(State state) {
int i = 0;
for (Person person : personList) {
if (person.getState() == state) {
if (person.getState().getClass() == state.getClass()) {
i++;
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/Point.java → src/nonliving/Point.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package nonliving;

/**
* 位置坐标基类
*
* @ClassName: Point
* @ClassName: nonliving.Point
* @Description: 位置坐标基类
* @author: Bruce Young
* @date: 2020年02月02日 20:59
Expand Down
Loading