程序模拟冠状病毒 (python模拟冠状病毒扩散)

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

编程模拟冠状病毒,计算机模拟冠状病毒

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

编程模拟冠状病毒,计算机模拟冠状病毒

我们先来看一下我们实现的效果,请看视频:

视频加载中...

看完视频过后我把我的核心的代码实现放在下面吧:

这是一个常量类:

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