简单行人疏散 Java版

一、整体思路

该程序实现了最简单的一个行人疏散模型,程序模拟行人从一个带有出口的封闭房间疏散,墙壁上有疏散方向标志,行人先移动到墙底,然后按照疏散方向往出口移动。

创建一个矩阵,空位设置为0,行人设置为1,墙壁设置为100,出口设置为1000,墙壁和出口的位置手工设置,本程序墙壁为于场地四周,出口位于上方墙壁的中点。行人的位置由随机产生或者手工设定。



具体规则如下:

1、  房间长m,宽n,行人密度p。

2、  行人在墙壁之外的无法看到出口,只能看到墙。

3、  行人会向离自己最近的墙面移动。

4、  墙面上有疏散方向。

5、  如果2人的下一点位置重合,各有50%的几率占据位置,另一个人则原地等待一步。

6、  行人到达出口时从系统移除。

二、具体程序

(一)、绘图类img.java

在绘图类的构造方法,完成界面的初始化,窗口的大小,关闭按钮的作用,将JPanel作为与矩阵相对应的场地。

    
public Img (){
             //构造方法
        jf = new JFrame("CA");
        jp = new JPanel[m] [n];
        jf.setLayout(new GridLayout(m,n,5,5));//mn 5 5 长m宽n 行间距5 列间距5
        for (int i=0;i<m;i++){
            for (intj=0;j<n;j++){
                jp[i][j]=new JPanel();
                jp[i][j].setBackground(Color.black);//布置背景色
                jf.add(jp[i][j]);//将jp添加到jf
            }
        }
        jf.setSize(500,500); //窗口大小
        jf.setVisible(true);//显示窗口
        jf.addWindowListener(newWindowAdapter() {//关闭按钮的作用
            public voidwindowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }



然后是创建行人位置的方法,也就是在矩阵中产生行人、墙壁、出口的方法。产生行人可以用随机方法creatRomNum,也可以用指定方法creatRegNum。

    

    
public int [][] creatRegNum(inta[][]){
             //手工 创建矩阵
             for(int i=0;i<m;i++){
            for (intj=0;j<n;j++){
                a[0][j]=100;//设置边缘  墙的值为100
                a[i][0]=100;
                a[i][m-1]=100;
                a[n-1][j]=100;
            }
        }
             for(int i=1;i<m-1;i++){
                       for(int j=1;j<n-1;j++){
                                a[i][i]=0;
                       }
             }
             a[3][2]=1;
             //a[3][2]=1;
             //a[5][5]=1;
             a[data.CX][data.CY]=1000;//出口
             returna;
    }
    public int [][] creatRomNum(inta[][]){//随机创造矩阵
         for (inti=0;i<m;i++){
            for (intj=0;j<n;j++){
                a[0][j]=100;//设置边缘  墙的值为100
                a[i][0]=100;
                a[i][m-1]=100;
                a[n-1][j]=100;
            }
        }
         for (inti=1;i<m-1;i++){
            for (intj=1;j<n-1;j++){
                if(Math.random()>p){
                    a [i][j]=1;//行人代表1
                }
                else{
                    a [i][j]=0;//空位代表0
                }  
            }
        }
        a[data.CX][data.CY]=1000;//设置出口 值为1000
        return a;
    }



最后时绘图方法onColor,根据矩阵不同的数值设为不同的颜色。

public void onColor(inta[][]){
             //绘图方法
             for(int i=0;i<data.m;i++){
                       for(int j=0;j<data.n;j++){
                                switch(a[i][j]){//对应矩阵的值添加不同的颜色
                         case 0: //空地为0  白色
                            jp[i][j].setBackground(Color.white);
                             break;
                         case 1: //人为1  红色
                             jp[i][j].setBackground(Color.red);
                             break;
                         case 100: //墙为100 蓝色
                            jp[i][j].setBackground(Color.blue);
                             break;
                         case 1000: //出口为1000 黄色
                             jp[i][j].setBackground(Color.yellow);
                             break;
                         default: //其他为黑色  一般用不到
                            jp[i][j].setBackground(Color.black);
                                }
                       }
             }
       
    }


         (二)、行人类Peo.java

行人类包含移动方法peoMove,行人具体移动方法peoMoveDirection,判断下一点是否有人方法peoMoveDirectionDecect和行人到达出口方法peoMoveExit。

行人类中最为重要的就是移动方法peoMove。在此方法中,用到了3个数组:a[][],c[][]和d[][]。其中a是由绘图类产生并传进来的,用作判断。C是a的复制,采用循环赋值,在做出移动判断后将更改c的值。在移动之前,首先要判断:获取下一点移动的方向,下一点是否为墙或者人,下一点如果墙的话如何处理。最后交给具体移动方法peoMoveDirection来实现。

public int [][] peoMove(inta [][]){
             int c[][]=new int [data.m][data.n];
             int fr;//判断下一点为墙
             int f;//移动方向
             boolean moveOk;
             for (int i=0;i<data.m;i++){ //循环赋值
                       for (int j=0;j<data.n;j++){
                                c[i][j]=a[i][j];
                       }
             }
             for (int i=1;i<data.m-1;i++){
                       for(int j=1;j<data.n-1;j++){
                                //在进行移动之前先判断下一点是否能走
                                //用d的值来判断
                                f=rule.calRange(i, j, data.m, data.n,data.r);//判断方向
                                if(a[i][j]==1){
                                         fr=rule.stopChange(a, i, j);
                                         if(fr==2){//判断墙
                                                   f=rule.calRangeDouble(i,j);
                                                   moveOk=peoMoveDirectionDecect(f,i, j, c);
                                                   if(moveOk){
                                                            c=peoMoveDirection(f,i, j, c);
                                                   }
                                                   else{
                                                            c=peoMoveDirection(5,i, j, c);
                                                   }
                                         }
                                         else{
                                             c=peoMoveDirection(f,i, j, c);
                                         }
                                }
                       }
             }
             return c;
    }


行人具体移动方法peoMoveDirection和判断下一点是否有人方法peoMoveDirectionDecect大概差不多。peoMoveDirection方法是将下一点设置为1,将原来的点设置为0;peoMoveDirectionDecect是判断下一点是否为1,如果是,则返回false。

public int[][] peoMoveDirection(intf,int i,int j,int c [][]){
             //行人移动  传入方向f 改变下一点的值
             switch(f){
        case 1:
            c[i-1][j-1]=1;
            c[i][j]=0;
            break;
        case 2:
            c[i-1][j]=1;                 
            c[i][j]=0;
            break;
        case 3:
            c[i-1][j+1]=1;
            c[i][j]=0;
            break;
        case 4:
            c[i][j-1]=1;
            c[i][j]=0;
            break;
        case 5:
            c[i][j]=1;
            break;
        case 6:
            c[i][j+1]=1;
            c[i][j]=0;
            break;
        case 7:
            c[i+1][j-1]=1;
            c[i][j]=0;
            break;
        case 8:
            c[i+1][j]=1;
            c[i][j]=0;
            break;
        case 9:
            c[i+1][j+1]=1;
            c[i][j]=0;
            break;
                   }
             return c;
    }
    public booleanpeoMoveDirectionDecect(int f,int i,int j,int c[][]){
             //判断行人下一点移动  传入方向f 如果下一点数值为1flag为false
             boolean flag=true;
             switch(f){
        case 1:
                 if(c[i-1][j-1]==1){
                           flag=false;
                 }
            break;
        case 2:
                 if(c[i-1][j]==1){
                           flag=false;
                 }
            break;
        case 3:
                 if(c[i-1][j+1]==1){
                           flag=false;
                 }
            break;
        case 4:
                 if(c[i][j-1]==1){
                           flag=false;
                 }
            break;
        case 5:
            c[i][j]=1;
            break;
        case 6:
                 if(c[i][j+1]==1){
                           flag=false;
                 }
            break;
        case 7:
                 if(c[i+1][j-1]==1){
                           flag=false;
                 }
            break;
        case 8:
                 if(c[i+1][j]==1){
                           flag=false;
                 }
            break;
        case 9:
                 if(c[i+1][j+1]==1){
                           flag=false;
                 }
            break;
                   }
             return flag;
    }


行人到达出口方法peoMoveExit,如果检测到行人在出口,则将行人移除系统。(这里为什么不整合到移动方法中呢?在主方法中,所有步骤运行后会有个赋值语句,将此次的结果覆盖原来的矩阵。如果写到移动方法中,会使出口方法失效)

public int [][] peoMoveExit(inta[][]){
             //行人到达出口方法如果出去  设为0
             boolean exitOk=false;
             int c[][]=new int [data.m][data.n];
             for (int i=0;i<data.m;i++){ //循环赋值
                       for (int j=0;j<data.n;j++){
                                c[i][j]=a[i][j];
                       }
             }
             for(int i=0;i<data.m;i++){
                       for(int j=0;j<data.n;j++){
                                if(a[i][j]==1){
                                         exitOk=rule.exitDose(a, i, j);
                                    if(exitOk){
                                             c[i][j]=0;
                                             System.out.println("跑出去一个");
                                    }
                                }
                               
                       }
             }
             return c;
    }


         (三)、规则类Rule.Java

规则类包含方向判断方法calRange,遇到墙壁的方向判断calRangeDouble,判断墙壁方法stopChange和判断出口方法exitDose。

判断方法calRange,将行人距离四周墙壁的长度存入array中,然后用sort方法排序,取出第一个值,于4个方向的值相比较完成赋值。

public int calRange(int i,intj,int m,int n,int R){
                   //判断方向的方法
                   //将计算[i][j]与四周墙的距离 存入数组  使用sort方法进行排序
                   //首先判断距离出口长度
                   //其此将数组的最小值分别与4个值比较  得到具体方向
        int f=5;
        int north=i;
        int east=m-j;
        int south=n-i;
        int west=j;
        int ran[]=newint[4];
        ran[0]=north;
        ran[1]=east;
        ran[2]=south;
        ran[3]=west;
        Arrays.sort(ran);
            if(ran[0]==north){
                f=2;
            }
            else if(ran[0]==east){
                f=6;
            }
            else if(ran[0]==south){
                f=8;
            }
            else if(ran[0]==west){
                f=4;
            }
        return f;
    }


遇到墙如何走方法calRangeDouble,根据位置不同,直接指定方法。

public int calRangeDouble(inti,int j){
                   //沿着墙走时  判断遇到拐角的方法
                   intf=0;//输出方向
                   if(i==1){//如果行人在最上面
                            if(j==1){//如果在在左边
                                     f=6;//方向向右
                            }
                            elseif(j==data.n-2){//如果在最右边
                                     f=4;
                            }
                            else{
                                     if(j>=data.n/2){//如果在右半部分
                                               f=4;
                                     }
                                     else{//左半边
                                               f=6;
                                     }
                            }
                   }
                   if(i==data.m-2){//在最下面
                            if(j==1){//最左边
                                     f=2;
                            }
                            elseif(j==data.n-2){//最右边
                                     f=2;
                            }
                            else{
                                     if(j>=data.m/2){//右半部分
                                               f=6;
                                              
                                     }
                                     else{//左边部分
                                               f=4;
                                     }
                            }
                   }
                   if(j==1){//在左边
                            if(i==1){//左上角
                                     f=6;
                            }
                            else{
                                     f=2;
                            }
                   }
                   if(j==data.n-2){//在右边
                            if(i==1){//有上交
                                     f=4;
                            }
                            else{
                                     f=2;
                            }
                   }
                   returnf;
         }


判断墙的方法stopChange,遇到墙壁返回2。

public int stopChange(inta[][],int i,int j){
                   //判断墙
                   intfr=0; //fr 为判断下一步是否为墙
                                              
                   if(i==1||j==1||i==data.n-2|| j==data.m-2 ){
                            fr=2;//fr=2 表示下一点为墙
                   }
                   returnfr;
         }


判断出口方法exitDose,遇到出口返回TRUE。


public boolean exitDose(inta[][],int i,int j){
                   //判断是否到达出口  如果到达出口 flag改为TRUE
                   booleanflag=false;
                   intexitId=data.n/2;
                   if(i==1){
                            if(j==exitId){
                                     flag=true;
                            }
                            if(j==exitId+1){
                                     flag=true;
                            }
                            if(j==exitId-1){
                                     flag=true;
                            }
                   }
                   returnflag;
         }


(四)、主方法

       

  public class RunMain {
         public static voidmain(String[] args) {
                   Data data=new Data();
                   Img img=new Img();
                   Peo peo=new Peo();
                    int a[][]=new int[data.m][data.n];
                    int c[][]=new int[data.m][data.n];
                    int d[][]=new int[data.m][data.n];
                    a=img.creatRomNum(data.a);
                    img.onColor(a);
                    try {
             Thread.sleep(15000);
         } catch (Exception e) {
             e.printStackTrace();
         }
                    for (int h=0;h<data.h;h++){
                             c=peo.peoMove(a);
                             d=peo.peoMoveExit(c);
                             img.onColor(d);
                             for (int i=0;i<data.m;i++){
                                      for (int j=0;j<data.n;j++){
                                                a[i][j]=d[i][j];
                                      }
                             }
                             try {
                      Thread.sleep(1000);
                 } catch (Exception e) {
                      e.printStackTrace();
                 }
                             System.out.println("第"+h+"次");
                    }
         }
}

三、总结

经过这次编程,我又重新拾起快遗忘的Java。相对于matlab来说,Java最大的优势就是面向对象,各种方法有机结合。但是对新手不友好,需要先学一大堆Java知识,而matlab入手简单,简单学习就可以使用。

本程序离预定目标还差不少,最关键的是对于行人碰撞的解决不太可行。在房间中间的视野盲区,行人应该按随机方向行走,于是就有可能有2人的下一点在同一位置上,此时2人占据这点的概率应该是50%,但是程序是通过遍历数组来完成绘图的。这就导致位于前面的人就可以优先选择。虽然也可以通过将行人的一下步存到数组f中,然后在对其进行标识,从而产生50%的概率,但是这样做有点麻烦,因此在我想不使用矩阵,直接通过坐标将图绘出来,采用多线程,希望可以解决这个问题。



  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
行人疏散是指在突发事件或紧急情况下,通过合理的措施将人群迅速有序地分散开来,以避免拥挤造成的伤亡和交通堵塞。在处理行人疏散问题时,可以使用MATLAB编写程序来模拟和优化疏散方案。 下面是一个基本的行人疏散模拟程序的框架,具体实现需要根据具体场景和需求进行调整和改进: ``` % 定义行人数量和速度 num_people = 100; % 行人数量 speed = 2; % 行人速度 % 定义行人的初始位置和目标位置 start_pos = rand(num_people,2); % 行人的初始位置,随机生成 target_pos = rand(num_people,2); % 行人的目标位置,随机生成 % 主循环,模拟行人运动直到全部到达目标位置 while ~isempty(find(sqrt(sum((start_pos - target_pos).^2, 2)) > 0.1, 1)) % 计算行人的运动方向和步长 direction = (target_pos - start_pos) ./ sqrt(sum((target_pos - start_pos).^2, 2)); step = direction .* speed; % 更新行人的位置 start_pos = start_pos + step; % 可以在此处添加疏散策略,比如根据目标位置周围的条件调整行人的运动方向/速度 % 绘制当前行人的位置 scatter(start_pos(:,1), start_pos(:,2), 'filled'); xlim([0, 1]); % x轴范围 ylim([0, 1]); % y轴范围 drawnow; end ``` 以上是一个简单行人疏散模拟程序,其中模拟了行人的运动,但没有考虑具体的疏散策略。在实际应用中,可以根据具体情况进行优化和改进,比如添加实时路况、考虑行人之间的影响等 factors。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值