疫情病毒模拟仿真程序的实现

实现的步骤简单介绍:(具体后面贴代码)
1.通过JFrame设计出展示的窗口;
2.添加一个JPanel面板到窗口中
2.1单独创建了MainPanel类通过继承JPanel,重写JPanel中paint(Graphics g)方法,操作绘图
2.2通过实现Rannable接口开启一个线程用于定时重复的绘图(定义一个产生随机数的数学工具类)
3.人群的创建
3.1人移动实际是坐标的移动,此时创建一个点的对象,定义坐标属性;
3.2 创建人的对象,添加点对象,用于锁定人的位置;
3.3多个人群的实现我们要创建一个List集合用来存储
4.给人的属性添加健康状态,定义常量表示(由于要模拟被感染的情况,所以我们要计算两个人之间的距离,此时在数学工具类添加计算距离的方法。。。直接上代码看注释吧)
疫情病毒模拟仿真程序的实现_第1张图片

1.Main主要是窗口的展示和人的初始化

package com.ty;

import javax.swing.*;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        personInit();
        frameInit();
    }

    /**
     * 创建人群的方法
     */
    private static void personInit(){
        List<Person> persons =PersonPool.getPersonPool().getPersonList();
        for (int i =1;i<=Paramer.TOTAL_SIZE;i++){
            Person p = new Person(MathUtil.getGaussian(60)+250,MathUtil.getGaussian(60)+250);
            p.setType(Person.HEALTH100);//设置人为健康状态
            p.setHealth(new Random().nextInt(20)+80);//设置人的健康值为80-100
            persons.add(p);
        }
        //随机添加一个病原体
        Random r = new Random();
        Person person = persons.get(r.nextInt(Paramer.TOTAL_SIZE));
        person.setType(Person.HEALTH25);
        person.setVirsu(Virsu.getVirsu());
        //将病原对象放到病原集合中
        PersonPool.getPersonPool().getVirusList().add(person);

        //初始化社区人员,保存10个,使用set集合防止挑选的人重复
        Set<Person> tempSet = new HashSet<>();
        //先执行后判断雇用do-while循环
        do{
            int p = r.nextInt(Paramer.TOTAL_SIZE);//所有人员中随机抽选
            Person person1 = persons.get(p);//集合中挑出
            person1.setObserver(true);//设置为社区人员
            tempSet.add(person1);//去重校验
        }while (tempSet.size()<10);
        //加入社区人池集合中
        PersonPool.getPersonPool().getObserverList().addAll(tempSet);
    }

    /**
     * 初始展示窗口的方法
     */
    private static void frameInit() {
        JFrame frame = new JFrame();
        //设置窗体大小
        frame.setSize(Paramer.WIN_WIDTH,Paramer.WIN_HIGHT);
        //设置标题
        frame.setTitle("疫情仿真程序");
        //添加面板用于绘图
        MainPanel panel = new MainPanel();
        frame.add(panel);
        //设置窗口可见
        frame.setVisible(true);
        //设置窗口退出方式
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //启动一个线程用于定时重复绘图
        Thread t = new Thread(panel);
        t.start();
    }
}

2.MainPanel主要执行面板上绘图的操作

package com.ty;

import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class MainPanel extends JPanel implements Runnable {
    //调用人群集合显示在面板
    private  List<Person> persons = PersonPool.getPersonPool().getPersonList();
    private  List<Person> observers = PersonPool.getPersonPool().getObserverList();

    //重写画图方法
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        //设置背景色
        this.setBackground(new Color(0x444444));
        Color[] colors = {Color.white,Color.green,Color.yellow,Color.red,null,Color.black};
        for(Person person:persons) {
            //判断如果是隔离状态的人不在移动
            if(person.getType()==Person.ISOLATION){
                continue;
            }
            //调用人移动的方法
            person.move();
            //调用健康结算的方法
            person.doHealth();
            //画出人在的位置
//            程序优化,通过数组来代替
//            if(person.getType()==Person.HEALTH100){
//                g.setColor(Color.white);
//            }else if(person.getType()==Person.HEALTH25){
//                g.setColor(Color.red);
//            }
            g.setColor(colors[person.getType()]);
            g.fillOval(person.getPoint().getX(), person.getPoint().getY(), 3, 3);
        }


        //打印信息
        g.setColor(Color.white);
        g.drawString("总人数:"+Paramer.TOTAL_SIZE,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y);
        g.setColor(Color.white);
        g.drawString("健康人数:"+(Paramer.TOTAL_SIZE-1-Paramer.HEALTH50_COUNT-Paramer.HEALTH90_COUNT),Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+20);
        g.setColor(Color.green);
        g.drawString("疑似人数:"+(Paramer.HEALTH50_COUNT+Paramer.HEALTH90_COUNT-Paramer.dealth_Count),Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+40);
        g.setColor(Color.red);
        g.drawString("发病人数:"+1,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+60);
        g.setColor(Color.red);
        g.drawString("死亡人数:"+Paramer.dealth_Count,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+80);

        g.setColor(Color.white);
        g.drawString("世界时间:"+Paramer.time,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+100);
        //发布通告在一定的世界时间
        if(Paramer.time>40) {
            Publish.publish(40, "通告:非常时期,大家保持警惕,继续居家隔离,减少外出活动!", g);
            if(Paramer.time==60){
                Paramer.move_Wish=0.6f;
            }
        }
        //发布疫情通告在世界时间60
        if(Paramer.time>60) {
            Publish.publish2(60, "通告:火神山医院建成并投入使用!", g);
        }
        //调用画医院方法
        if(Paramer.time>70) {
            Hospital.getHospital().paintHospital(g);
        }
        //画出社区人员的监测范围
        if(Paramer.time>80) {
            g.setColor(new Color(0x79AEAC9D, true));
            for (Person p : observers) {
                //如果社区人员被隔离,不在执行画图
                if(p.getType()==Person.ISOLATION){
                    continue;
                }
                int x = p.getPoint().getX() - 25;
                int y = p.getPoint().getY() - 25;
                g.fillOval(x, y, 50, 50);
            }
        }

    }

    //定义一个执行任务的内部类
    class MyTask extends TimerTask{

        @Override
        public void run() {
            //绘图操作
            repaint();
            //显示的世界世界++
            Paramer.time++;
        }
    };

    @Override
    public void run() {
        //此线程用于定时绘图
        Timer timer = new Timer();
        timer.schedule(new MyTask(),0,100);

    }
}

3.人相关的类

3.1定义人的位置Point类封装坐标属性

package com.ty;

public class Point {

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

3.2Person包括人的行为等等的封装

package com.ty;

import java.util.Random;

public class Person {
    //定义常量代表人健康的状态
    public static final int HEALTH100=0;   //健康
    public static final int HEALTH90=1;    //接触未感染,疑似
    public static final int HEALTH50=2;    //接触感染,疑似
    public static final int HEALTH25=3;    //病源
    public static final int ISOLATION=4;    //被隔离
    public static final int DEATH=5;       //死亡
    //人的状态属性
    private int type;
    //人的健康值100作为上限
    private int health;

    public int getHealth() {
        return health;
    }

    public void setHealth(int health) {
        this.health = health;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }
    //人的坐标点
    private Point point;
    //病毒对象
    private Virsu virsu;
    //社区人员标记
    private boolean observer;

    public boolean isObserver() {
        return observer;
    }

    public void setObserver(boolean observer) {
        this.observer = observer;
    }

    public Virsu getVirsu() {
        return virsu;
    }

    public void setVirsu(Virsu virsu) {
        this.virsu = virsu;
    }

    public Point getPoint() {
        return point;
    }

    public void setPoint(Point point) {
        this.point = point;
    }

    public Person(int x,int y) {
        this.point = new Point(x,y);
    }

    public Person() {
    }
    //定义人移动行为
    public void move(){
        //社区人员的巡检操作
        if(this.isObserver()&&Paramer.time>80){
            //检验辖区范围内每一个人
            for(Person p : PersonPool.getPersonPool().getPersonList()){
                //判断距离
                int x = this.getPoint().getX();
                int y = this.getPoint().getY();
                int x1 = p.getPoint().getX();
                int y1 = p.getPoint().getY();
                if(Math.abs(x-x1)<25&&Math.abs(y-y1)<25){
                    //判断状态
                    if(p.getType()==Person.HEALTH50||p.getType()==Person.HEALTH90){
                        //送医院就诊
                        Hospital.getHospital().receieve(p,this);
                        return;//发现对象,停止监测
                    }
                }
            }
        }
        //判断如果死亡的人不在移动
        if(this.getType()==Person.DEATH){
            return;
        }
        //移动前根据意愿判断行为
        //社区人员不受移动意愿的控制
        if(Math.random()>Paramer.move_Wish && !this.isObserver()){
            return;
        }
        //如果是社区人员,移动范围扩大
        if(this.isObserver()){
            int x =  this.getPoint().getX() + MathUtil.getGaussian(4);
            int y = this.getPoint().getY() + MathUtil.getGaussian(4);
        }
        int x =  this.getPoint().getX() + MathUtil.getGaussian(2);
        int y = this.getPoint().getY() + MathUtil.getGaussian(2);
        //控制人活动的范围
        x=x>Paramer.AREA_WIDTH?Paramer.AREA_WIDTH:x;
        x=x<0?0:x;
        y=y>Paramer.AREA_HIGHT?Paramer.AREA_HIGHT:y;
        y=y<0?0:y;

        this.getPoint().setX(x);
        this.getPoint().setY(y);

        //2.1如果距离在传染范围则被传染,停止比对并加入病原集合
        //0.排除已经被感染人群的比对
        if(getType()>1){
            return;
        }
        //1.使用每一个人与带病的人进行比对
        for(Person p :PersonPool.getPersonPool().getVirusList()){
            //2.计算两者之间的距离
            double distance = MathUtil.getDistance(this,p);
            if(distance>5){
                //放行检测下一个
                continue;
            }
            //添加概率判断暂且定位40%的命中率
            if(Math.random()<0.4f){
                //接触未感染,再次被检测感染时要从源数据减去
                if(this.getType()==Person.HEALTH90){
                    Paramer.HEALTH90_COUNT--;
                }
                //2.1范围内被感染修改状态
                this.setType(Person.HEALTH50);
                //病毒加载到病人身上
                this.setVirsu(Virsu.getVirsu());
                //2.2加入病原人群
                PersonPool.getPersonPool().getVirusList().add(this);
                //2.3计算传染的数量
                Paramer.HEALTH50_COUNT++;
                //2.4已经传染无需再比对,终止循环
                break;
            }else{
                //接触,未感染,终止
                if(this.getType()==Person.HEALTH90){
                    continue;
                }
                //计算接触未感染数量
                Paramer.HEALTH90_COUNT++;
                this.setType(Person.HEALTH90);
            }

        }
    }
    Random r = new Random();
    //健康结算
    public void doHealth(){
        //无病毒的人不结算
       if(this.getVirsu()==null) {
           return;
       }
       //已经死亡的人不结算
        if(this.getType()==Person.DEATH){
            return;
        }
        //获取健康值-病毒的伤害保存到人健康属性中
       this.setHealth( this.getHealth()-this.getVirsu().getDamage());
        //免疫力的设定
        this.setHealth( this.getHealth()+r.nextInt(7));
        //判断健康值不能超过100
        if (this.getHealth()>=100){
            this.setHealth(100);//健康值设为100
            this.setVirsu(null);//去掉病毒
            //数据统计
            if(this.getType()==Person.HEALTH50){
                Paramer.HEALTH50_COUNT--;
            }
            //状态变为健康的状态
            this.setType(Person.HEALTH100);
            //从疑似病毒集合移除
            PersonPool.getPersonPool().getVirusList().remove(this);
        }

        //判断如果健康值低于0需要去除病毒并修改人的状态
        if(this.getHealth()<=0){
            this.setVirsu(null);
            this.setType(Person.DEATH);
            //如果是社区人员,要从社区集合移除
            if(this.isObserver()){
                PersonPool.getPersonPool().getObserverList().remove(this);
            }
            //将死亡的人从病毒集合中移除
            PersonPool.getPersonPool().getVirusList().remove(this);
            //死亡数量要++
            Paramer.dealth_Count++;
        }

    }
}

3.3PersonPool

package com.ty;

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

public class PersonPool {
    private static PersonPool personPool = new PersonPool();
    private PersonPool(){}
    public static PersonPool getPersonPool(){
        return personPool;
    }
    //健康人的集合
    private List<Person> personList = new ArrayList<>();
    //病源集合
    private List<Person> virusList = new ArrayList<>();
    //社区人员的集合
    private List<Person> observerList = new ArrayList<>();

    public List<Person> getObserverList() {
        return observerList;
    }

    public void setObserverList(List<Person> observerList) {
        this.observerList = observerList;
    }

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

    public void setPersonList(List<Person> personList) {
        this.personList = personList;
    }

    public List<Person> getVirusList() {
        return virusList;
    }

    public void setVirusList(List<Person> virusList) {
        this.virusList = virusList;
    }
}

4.工具类

4.1MathUtil计算距离等封装

package com.ty;

import java.util.Random;

public class MathUtil {
    private static Random r = new Random();
    //通过高斯获取一个随机数
    public static int getGaussian(int range){
        return (int)(r.nextGaussian()*range);
    }
    //计算两个人距离的方法
    public static double getDistance(Person p1,Person p2){
        Point point1 = p1.getPoint();
        Point point2 = p2.getPoint();

        int x = point1.getX()-point2.getX();
        int y = point1.getY()-point2.getY();
        return Math.sqrt(x*x+y*y);
    }
}

4.4publish发布公告信息的类

package com.ty;

import java.awt.*;

public class Publish {
    public static void publish(int time,String msg, Graphics g){

        //公告栏的显示
        msg = "        "+msg+"        ";
        if((Paramer.time-time)/Paramer.MSG_SHOW_SPEED+20<msg.length()) {
            String showMsg = msg.substring((Paramer.time-time) / Paramer.MSG_SHOW_SPEED, (Paramer.time-time) / Paramer.MSG_SHOW_SPEED + 20);
            g.drawString(showMsg , Paramer.MSG_BASE_X, Paramer.MSG_BASE_Y + 120);
        }
    }

    public static void publish2(int time, String msg, Graphics g) {
        //公告栏的显示
        msg = "        "+msg+"        ";
        if((Paramer.time-time)/Paramer.MSG_SHOW_SPEED+20<msg.length()) {
            String showMsg = msg.substring((Paramer.time-time) / Paramer.MSG_SHOW_SPEED, (Paramer.time-time) / Paramer.MSG_SHOW_SPEED + 20);
            g.drawString(showMsg , Paramer.MSG_BASE_X, Paramer.MSG_BASE_Y + 140);
        }
    }
}

5.疫情主角

5.1病毒类Virsu描述新冠的威力

package com.ty;

import java.util.Random;

public class Virsu {
    private static Virsu virsu = new Virsu();
    private Virsu(){}
    public static Virsu getVirsu(){
        return virsu;
    }
    private int damage;
    Random r = new Random();
    //随机产生15-30的杀伤力
    public int getDamage() {
        return r.nextInt(3)+2;
    }

    public void setDamage(int damage) {
        this.damage = damage;
    }
}

5.2Bed给医院提供的床位

package com.ty;

import java.awt.*;

public class Bed {
    private int x;
    private int y;

    private Person person;

    private Color bedColor = Color.GREEN;

    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 Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
        if(person==null){
            this.bedColor = Color.green;
            return;
        }
        if(person.getType()==Person.DEATH){
            this.bedColor = Color.orange;
            return;
        }
        if(person!=null && person.isObserver()){
            this.bedColor = Color.blue;
            return;
        }
        this.bedColor = Color.red;
    }

    public Color getBedColor() {
        return bedColor;
    }

    public void setBedColor(Color bedColor) {
        this.bedColor = bedColor;
    }
}

5.3医院Hospital

package com.ty;

import java.awt.*;
import java.util.Random;

public class Hospital {
    private static Hospital hospital = new Hospital();
    private Hospital(){}
    public static Hospital getHospital(){
        return hospital;
    }
    //定义一个二维数组,模拟床位
    Bed[][] beds = new Bed[43][32];
    //给床设置坐标
    {
        for(int i=0;i<beds.length;i++){
            for(int j=0;j<beds[i].length;j++){
                beds[i][j] = new Bed();
                beds[i][j].setX(i);
                beds[i][j].setY(j);

            }
        }
    }
    //绘制医院的方法
    public void paintHospital(Graphics g) {
        g.setColor(Color.green);
        g.drawString("雷火医院",580,175);
        g.drawRect(520,180,160,260);
        for(int i=0;i<beds.length;i++){
            for(int j=0;j<beds[i].length;j++){
               /* g.drawLine(522+j*5,183+i*6,524+j*5,183+i*6);
                g.drawLine(522+j*5,184+i*6,524+j*5,184+i*6);*/
                g.setColor(beds[i][j].getBedColor());
                g.fillRect(522+j*5,183+i*6,3,2);

            }
        }
    }
    //接收病人的方法
    public void receieve(Person target,Person src){
        //疑似病例判断,若感染,治疗
        if(isHaveVirsu(target)){
            treat(target);
        }
        //社区人员判断,若感染,治疗
        if(isHaveVirsu(src)){
            treat(src);
        }else {
            //回去继续工作
        }
    }
    //治疗的方法
    private void treat(Person p ){
        //分配病床
        out :
        for(int i=0;i<beds.length;i++){
            for(int j=0;j<beds[i].length;j++){
               if(beds[i][j].getPerson()==null){
                   beds[i][j].setPerson(p);
                   //病人的状态修改为隔离状态
                   p.setType(Person.ISOLATION);
                   break out;//停止继续寻找
               }
            }
        }
    }
    //治疗情况的计算方法
    Random r = new Random();
    //健康结算
    public void doHealth(){
        for(int i=0;i<beds.length;i++){
            for(int j=0;j<beds[i].length;j++){
                Bed b =  beds[i][j];
                Person p = b.getPerson();
                //判断床位是否有病人,无直接下一个
                if(p==null){
                    continue;
                }
                //如果死病床的也不结算
                if(p.getType()==Person.DEATH){
                    continue;
                }

               //健康值的计算
                int health = p.getHealth();
                //病毒的杀伤力,判断排除掉疑似为感染病范
                if(p.getVirsu()!=null){
                    health -= p.getVirsu().getDamage();
                }
                //免疫力
                health += r.nextInt(6);
                //医院的治疗
                health += r.nextInt(3)-30;
                p.setHealth(health);
                //判断健康值不能超过100
                if (p.getHealth()>=100){
                    p.setHealth(100);//健康值设为100
                    p.setVirsu(null);//去掉病毒
                    //状态变为健康的状态
                    p.setType(Person.HEALTH100);
                    //从疑似病毒集合移除
                    PersonPool.getPersonPool().getVirusList().remove(p);
                    //出院的腾出床位
                    b.setPerson(null);
                }
                //判断如果健康值低于0需要去除病毒并修改人的状态
                if(p.getHealth()<=0){
                    p.setVirsu(null);
                    p.setType(Person.DEATH);
                    //如果是社区人员,要从社区集合移除
                    if(p.isObserver()){
                        PersonPool.getPersonPool().getObserverList().remove(p);
                    }
                    //将死亡的人从病毒集合中移除
                    PersonPool.getPersonPool().getVirusList().remove(p);
                    //死亡数量要++
                    Paramer.dealth_Count++;
                    b.setPerson(p);
                }
            }
        }
    }

        //判断状态是否感染的方法
    private boolean isHaveVirsu(Person p ){
        return p.getType()==Person.HEALTH50||p.getType()==Person.HEALTH25;
    }

}

6.提取了公共数据的参数类Paramer

package com.ty;

public class Paramer {
    //疑似不带病人的数量
    public static  int HEALTH90_COUNT = 0;
    //疑似带病人的数量
    public static  int HEALTH50_COUNT = 0;
    //已经死亡人的数量
    public static int dealth_Count = 0;

    //定义一个世界时间
    public static int time =0;

    //移动意愿的定义
    public static float move_Wish = 0.9f;
    //定义消息显示的基本坐标
    public static final int MSG_BASE_X=520;
    public static final int MSG_BASE_Y=20;
    //定义消息滚动速度(1最快)
    public static final int MSG_SHOW_SPEED=5;

    //设置窗口的宽和高
    public static final int WIN_WIDTH =700;
    public static final int WIN_HIGHT =500;
    //设置总人数
    public static final int TOTAL_SIZE =2000;
    //设置区域的宽高
    public static final int AREA_WIDTH=500;
    public static final int AREA_HIGHT=500;

}

最后效果图疫情病毒模拟仿真程序的实现_第2张图片

你可能感兴趣的:(java基础的综合练习)