大家好我们都知道自然界大多数现象都属于正态分布,或者说是高斯分布;

人员的流动也是一样的,也满足高斯分布特征,我们将设计这样的一个程序模拟人员流动情况:

我们先来看一下我们实现的效果,请看视频:
视频加载中...
看完视频过后我把我的核心的代码实现放在下面吧:
这是一个常量类:
public class Constants {
/**
* 初始感染数量
*/
public static int ORIGINAL_COUNT = 50;
/**
* 传播率
*/
public static float BROAD_RATE = 0.8f;
/**
* 潜伏时间
*/
public static float SHADOW_TIME = 140;
/**
* 医院收治响应时间
*/
public static int HOSPITAL_RECEIVE_TIME = 100;
/**
* 医院床位
*/
public static int BED_COUNT = 250;
/**
* 流动意向平均值
*/
public static float u = -0.99f;
}
这是程序的主入口:
public class Main {
public static void main(String[] args) {
MyPanel p = new MyPanel();
Thread panelThread = new Thread(p);
JFrame frame = new JFrame();
frame.add(p);
frame.setSize(1000, 800);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panelThread.start();
List<Person> people = PersonPool.getInstance().getPersonList();
for(int i=0;i< Constants.ORIGINAL_COUNT;i++){
int index = new Random().nextInt(people.size()-1);
Person person = people.get(index);
while (person.isInfected()){
index = new Random().nextInt(people.size()-1);
person = people.get(index);
}
person.beInfected();
}
}
}
这是一个人员类:
public class Person {
private City city;
private int x;
private int y;
private MoveTarget moveTarget;
int sig=1;
double targetXU;
double targetYU;
double targetSig=50;
public Person(City city, int x, int y) {
this.city = city;
this.x = x;
this.y = y;
targetXU = 100*new Random().nextGaussian()+x;
targetYU = 100*new Random().nextGaussian()+y;
}
public boolean wantMove(){
double value = sig*new Random().nextGaussian()+ Constants.u;
return value>0;
}
private int state= State.NORMAL;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
int infectedTime=0;
int confirmedTime=0;
public boolean isInfected(){
return state>= State.SHADOW;
}
public void beInfected(){
state = State.SHADOW;
infectedTime= MyPanel.worldTime;
}
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;
}
private void moveTo(int x,int y){
this.x+=x;
this.y+=y;
}
private void action(){
if(state== State.FREEZE){
return;
}
if(!wantMove()){
return;
}
if(moveTarget==null||moveTarget.isArrived()){
double targetX = targetSig*new Random().nextGaussian()+targetXU;
double targetY = targetSig*new Random().nextGaussian()+targetYU;
moveTarget = new MoveTarget((int)targetX,(int)targetY);
}
int dX = moveTarget.getX()-x;
int dY = moveTarget.getY()-y;
double length=Math.sqrt(Math.pow(dX,2)+Math.pow(dY,2));
if(length<1){
moveTarget.setArrived(true);
return;
}
int udX = (int) (dX/length);
if(udX==0&&dX!=0){
if(dX>0){
udX=1;
}else{
udX=-1;
}
}
int udY = (int) (dY/length);
if(udY==0&&udY!=0){
if(dY>0){
udY=1;
}else{
udY=-1;
}
}
if(x>700){
moveTarget=null;
if(udX>0){
udX=-udX;
}
}
moveTo(udX,udY);
// if(wantMove()){
// }
}
private float SAFE_DIST = 2f;
public void update(){
if(state>= State.FREEZE){
return;
}
if(state== State.CONFIRMED&& MyPanel.worldTime-confirmedTime>= Constants.HOSPITAL_RECEIVE_TIME){
Bed bed = Hospital.getInstance().pickBed();
if(bed==null){
System.out.println("设置的隔离区已经没有空床位");
}else{
state= State.FREEZE;
x=bed.getX();
y=bed.getY();
bed.setEmpty(false);
}
}
if(MyPanel.worldTime-infectedTime> Constants.SHADOW_TIME&&state== State.SHADOW){
state= State.CONFIRMED;
confirmedTime = MyPanel.worldTime;
}
action();
List<Person> people = PersonPool.getInstance().personList;
if(state>= State.SHADOW){
return;
}
for(Person person:people){
if(person.getState()== State.NORMAL){
continue;
}
float random = new Random().nextFloat();
if(random< Constants.BROAD_RATE&&distance(person)<SAFE_DIST){
this.beInfected();
}
}
}
}
这是我们的人员的状态类:
public interface State{
int NORMAL = 0; // 正常状态
int SUSPECTED = NORMAL+1; // 有嫌疑
int SHADOW = SUSPECTED+1; // 潜伏期
int CONFIRMED = SHADOW+1; // 被确诊
int FREEZE = CONFIRMED+1; // 严重状
int CURED = FREEZE+1; // 治愈出院
}
这是医院类:
public class Hospital {
private int x=800;
private int y=110;
private int width;
private int height=606;
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
private static Hospital hospital = new Hospital();
public static Hospital getInstance(){
return hospital;
}
private Point point = new Point(800,100);
private List<Bed> beds = new ArrayList<>();
private Hospital() {
if(Constants.BED_COUNT==0){
width=0;
height=0;
}
int column = Constants.BED_COUNT/100;
width = column*6;
for(int i=0;i<column;i++){
for(int j=10;j<=610;j+=6){
Bed bed = new Bed(point.getX()+i*6,point.getY()+j);
beds.add(bed);
}
}
}
public Bed pickBed(){
for(Bed bed:beds){
if(bed.isEmpty()){
return bed;
}
}
return null;
}
}
这是我们绘制的面板:
public class MyPanel extends JPanel implements Runnable {
private int pIndex=0;
public MyPanel() {
this.setBackground(new Color(0x444444));
}
@Override
public void paint(Graphics arg0) {
super.paint(arg0);
//draw border
arg0.setColor(new Color(0x00ff00));
// 绘制一个医院的隔离区
arg0.drawRect(Hospital.getInstance().getX(),Hospital.getInstance().getY(),
Hospital.getInstance().getWidth(),Hospital.getInstance().getHeight());
List<Person> people = PersonPool.getInstance().getPersonList();
if(people==null){
return;
}
people.get(pIndex).update();
for(Person person:people){
switch (person.getState()){
case State.NORMAL:{
arg0.setColor(new Color(0xdddddd));
}break;
case State.SHADOW:{
arg0.setColor(new Color(0xffee00));
}break;
case State.CONFIRMED:
case State.FREEZE:{
arg0.setColor(new Color(0xff0000));
}break;
}
person.update();
arg0.fillOval(person.getX(), person.getY(), 3, 3);
}
pIndex++;
if(pIndex>=people.size()){
pIndex=0;
}
}
public static int worldTime=0;
@Override
public void run() {
while (true) {
this.repaint();
try {
Thread.sleep(100);
worldTime++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
上面的程序我简单进行说明一下,我用swing创建了一个面板,用于不停绘制人员的流动情况,然后人员的状态在不断迁移,通过常量控制各项指标。代码的演示在上面的视频里面已经很清楚了,
代码地址:
https://github.com/shezhanjun/WuHan-ComeOn.git