火出B站的冠状病毒传播模拟仿真程序代码解析来啦

整理 | 夕颜

代码解析部分来源于 | xuyuanwai(ID:xxuyuanwai)

近日,有一位B站up主上传了一段视频,用计算机仿真程序模拟了冠状病毒传播的场景,并提醒大众不要出门活动。这个视频一经推出就得到大家的关注,让人们感受到计算机程序在这场抗疫战争中可以做出的贡献。

不久后,这条视频的up主Ele实验室又放出了本程序的GitHub开源链接,公布了这个程序的相关代码。目前,这个名为VirusBroadcast的项目已获得1000多star,作者也在简介中强调了这个基于java的模拟仿真程序由于启动仓促,还有一些不足,如果有好的想法或者能提供相关数据支持的朋友可以请提issues。

B站地址:https://www.bilibili.com/video/av86478875

GitHub地址:https://github.com/KikiLetGo/VirusBroadcast

此后,有人解析了VirusBroadcast的程序代码,下面我们就来看看它是如何一步步实现的吧:

这个程序主要利用“高斯分布”算法,简单的模拟病毒传播的场景。

它由以下程序片段构成

1、病毒对象

public class Virus {}

2、床位【隔离对象】

public class Bed extends Point{ public Bed(int x, int y) { super(x, y); } private boolean isEmpty=true; public boolean isEmpty { return isEmpty; } public void setEmpty(boolean empty) { isEmpty = empty; }}

3、主要参数【初始状态】,假设没有隔离,潜伏期为一天

public class Constants { public static int ORIGINAL_COUNT=50;//初始感染数量 public static float BROAD_RATE = 0.8f;//传播率 public static float SHADOW_TIME = 1;//潜伏时间 public static int HOSPITAL_RECEIVE_TIME=10;//医院收治响应时间 public static int BED_COUNT=0;//医院床位 public static float u=0.99f;//流动意向平均值}

4、医院对象,随机分布,产生床位

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 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 for(int j=10;j 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 ; }}

5、流动目的地

public class MoveTarget { private int x; private int y; private boolean arrived=false; public MoveTarget(int x, int y) { this.x = x; this.y = y; } 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; } public boolean isArrived { return arrived; } public void setArrived(boolean arrived) { this.arrived = arrived; }}

6、人员【流动及感染】

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 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 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==||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 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=; if(udX>0){ udX=-udX; } } moveTo(udX,udY); } 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==){ 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 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 this.beInfected; } } }}

7、汇总人数

public class PersonPool { private static PersonPool personPool = new PersonPool; public static PersonPool getInstance{ return personPool; } List personList = new ArrayList; public List getPersonList { return personList; } private PersonPool { City city = new City(400,400); for (int i = 0; i  Random random = new Random; int x = (int) (100 * random.nextGaussian + city.getCenterX); int y = (int) (100 * random.nextGaussian + city.getCenterY); if(x>700){ x=700; } Person person = new Person(city,x,y); personList.add(person); } }}

8、分布点

public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } 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; }}

9、显示面板,设置色块【红色:感染 黄色:潜伏 绿色:安全】

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 people = PersonPool.getInstance.getPersonList; if(people==){ return; } people.get(pIndex).update; for(Person person:people){ switch (person.getState){ case Person.State.NORMAL:{ arg0.setColor(new Color(0xdddddd)); }break; case Person.State.SHADOW:{ arg0.setColor(new Color(0xffee00)); }break; case Person.State.CONFIRMED: case Person.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; } } }}

10、主程序【运行】

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; frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); panelThread.start; List people = PersonPool.getInstance.getPersonList; for(int i=0;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; } }}

首先,假设某个城市初始感染人数为50,医院床位为0【人员可随意流动】,那么城市很快会被感染,感染分布如下:

此时修改流动参数,控制人员流动,则疫情传播较慢,但也会传播开来

如果此时建立隔离区,将医院的床位数设为200张,并不随意走动则疫情很快得到有效控制

如果此时建立隔离区,将医院的床位数设为200张,但随意走动则隔离床位会很快被用完,病毒又开始扩散

此时,我们隔离区变得足够大,医务人员增加床位数到1000,则病毒也会得到有效控制

这位解析者还提醒大家,不随意走动是建立隔离区是在短时间内有效控制病毒的最好方式,现在病毒防疫进入关键时期,此时此刻我们一定要听从党中央的安排,好好呆在家里,不要随意跟人接触,早日打赢病毒阻击战,让我们的生活步入正轨。

免责声明:非本网注明原创的信息,皆为程序自动获取互联网,目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责;如该页面侵犯到您的权益,请给站长发送邮件,并提供相关证明(版权证明、身份证正反面、侵权链接),站长将在收到邮件12小时内删除。