电梯运行程序模拟

​ 日常生活中,大家都坐过电梯,有时候会想想电梯在每个人按下键之后是怎么运行的呢?这是个看起来似乎简单但想清楚却也不容易的问题。

​ 给电梯的运行进行建模。电梯在运行过程中会载人同时接受外部的请求,这样我们可以用两个队列来表示载人信息和请求信息。对于乘客来说,其信息主要是当前楼层和目标楼层,为了方便打印,给每个乘客命名。电梯的运行有三种状态:WAIT(停),UP(上),DOWN(下)。电梯根据载人队列和请求队列来更新自己的状态,在每一层都判断是否可以进人(针对请求队列),出人(针对载人队列)。下面是运行算法图示。

image-20190714143300244

​ 当电梯处于上行/下行状态时,到达新的楼层时(本次循环开始),每次循环检查是否需要有人进出,根据载人列表、请求列表及当前运行状态判断出接下来的状态,如果是上行/下行,沉睡1s作为上行/下行一层楼的时间。算法的特征是,先来先服务,在上行/下行过程中尽可能接到或者放出更多的人,在上行/下行过程中只接受与电梯运行方向一致的人。

​ 代码如下:

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
/*
从文件中读入输入命令及参数
*/
public class Elevator {
    private static List<EleInfo> infoList = new LinkedList<>();

    public static void main(String[] args) throws FileNotFoundException {
        start();
        new EleRunner(infoList).start();
    }

    public static void start() throws FileNotFoundException {
        int minFloor = 0;
        int maxFloor = 0;
        boolean started = false;
        boolean inputValid = false;
        Scanner in = new Scanner(
                new FileInputStream("/Users/macbook/programming/Java/leetcode/src/com/test/input.txt"),"UTF-8");
        PrintWriter out = new PrintWriter(
                new FileOutputStream("/Users/macbook/programming/Java/leetcode/src/com/test/log.txt",true),true);
        while(!inputValid) {
            out.println("电梯模拟运行开始,请输入参数(最低楼层,最高楼层):");
            try {
                minFloor = Integer.parseInt(in.next());
                maxFloor = Integer.parseInt(in.next());
                inputValid = true;
            } catch (Exception e) {
                System.out.println("输入异常!");
            }
        }

        while(true) {
            out.println("请输入命令(up/down/stop/start):");
            String cmd = in.next();
            if(started && cmd.equals("start")) {
                //已经开始但输入命令仍是start, 报错
                System.out.println("已经开始,不能再输入start!");
                continue;
            }
            if(!started && !cmd.equals("start")) {
                //没有开始但是输入命令不是start,报错
                out.println("请输入start开始!");
                continue;
            }
            if (cmd.equals("start")) {//开始
                started = true;
                infoList.add(new EleInfo(null, minFloor, maxFloor, "start"));
            } else if (cmd.equals("stop")) {//结束,跳出循环
                infoList.add(new EleInfo(null, 0, 0, "stop"));
                break;
            } else if(cmd.equals("up") || cmd.equals("down")) {
                String name = in.next();
                try {
                    int curFloor = Integer.parseInt(in.next());
                    int targetFloor = Integer.parseInt(in.next());
                    if (curFloor>=minFloor&&curFloor<=maxFloor&&targetFloor>=minFloor
                            &&targetFloor<=maxFloor&&targetFloor!=curFloor) {
                        if((cmd.equals("up")&&curFloor>=targetFloor) || (cmd.equals("down")&&curFloor<=targetFloor)) {
                            out.println("命令与输入楼层不匹配");
                        } else if(curFloor==targetFloor) {
                            out.println("目标楼层与当前楼层不一致!");
                        } else if(!isNameDuplicated(name)) {
                            out.println("人名重复!");
                        } else {//一切输入合法
                            infoList.add(new EleInfo(name, curFloor, targetFloor, cmd));
                        }
                    } else {
                        if(curFloor < minFloor || curFloor > maxFloor) {
                            out.println("当前楼层不合法!");
                        }
                        if(targetFloor < minFloor || targetFloor > maxFloor) {
                            out.println("目标楼层不合法!");
                        }
                        if(targetFloor==curFloor) {
                            out.println("当前楼层与目标楼层不能相同!");
                        }
                    }
                } catch (Exception e) {
                    out.println("输入楼层异常!");
                }
            } else {
                out.println("输入命令出错!");
            }

        }
        in.close();
    }
  
  private boolean isNameDuplicated(String name) {
    for(EleInfo e:infoList) {
      if(e.name.equals(name)) return true;
    }
  }
}

class EleInfo {
    String name;
    int curFloor;
    int targetFloor;
    String cmd;

    public EleInfo(String name, int curFloor, int targetFloor, String cmd) {
        this.name = name;
        this.curFloor = curFloor;
        this.targetFloor = targetFloor;
        this.cmd = cmd;
    }
}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.*;

/*
电梯运行过程状态变化
*/
public class EleRunner {

    private List<EleInfo> requestList;
    private List<EleInfo> inElevatorList = new LinkedList<>();
    PrintWriter out;
    private ElevatorState state = ElevatorState.WAIT;
    private int curFloor = 0;
    private boolean started = false;
    private boolean stop = false;
    public EleRunner(List<EleInfo> infoList) throws FileNotFoundException {
        this.requestList = infoList;
        out = new PrintWriter(new FileOutputStream("/Users/macbook/programming/Java/leetcode/src/com/test/output.txt",true),true);
    }
    public void start() {
        while(true) {
            if(requestList.isEmpty()) continue;
            while(started) {
                if(requestList.isEmpty()) {
                    state = ElevatorState.WAIT;
                    continue;
                }
                if(requestList.size()==1 && inElevatorList.isEmpty() && requestList.get(0).cmd.equals("stop")) {
                    out.println("电梯停止运行!");
                    requestList.remove(0);
                    started = false;
                    stop = true;
                    break;
                }
                switch(state) {
                    case WAIT:
                        waitProc();
                        break;
                    case UP:
                        upProc();
                        break;
                    case DOWN:
                        downProc();
                        break;
                    default:
                        throw new IllegalArgumentException();
                }

                if(!requestList.isEmpty()) personIn();//状态更新,可能还可以有人进来
                if(state==ElevatorState.UP || state==ElevatorState.DOWN) {
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    curFloor = (state==ElevatorState.UP)?(curFloor+1):(curFloor-1);
                    String stateStr = (state==ElevatorState.UP)?"上升":"下降";
                    out.println("电梯到达"+curFloor+"楼,处于"+stateStr);
                }
            }
            if(stop) break;
            if(requestList.get(0).cmd.equals("start")) {
                started = true;
                curFloor = requestList.get(0).curFloor;
                out.println("电梯启动!");
                requestList.remove(0);
            }
        }
    }

    private void waitProc() {
        if(requestList.isEmpty()&&inElevatorList.isEmpty()) return;
        else {
            //没有请求但是电梯还载着人
            if(!requestList.isEmpty()) personIn();
            if(!inElevatorList.isEmpty()) personOut();
            if(!inElevatorList.isEmpty()) {
                state = inElevatorList.get(0).targetFloor > curFloor ? state = ElevatorState.UP:ElevatorState.DOWN;
            } else if(isOnlyStopReq()){
                state = ElevatorState.WAIT;
                out.println("电梯处于等待状态");
            } else if(!requestList.isEmpty()){
                if(!requestList.get(0).cmd.equals("stop"))
                    state = requestList.get(0).curFloor > curFloor ? state = ElevatorState.UP:ElevatorState.DOWN;
            }
        }
    }

    private void upProc() {
        if(requestList.isEmpty()&&inElevatorList.isEmpty()) {
            state = ElevatorState.WAIT;
        } else {
            if(!requestList.isEmpty()) personIn();//请求队列不空,看是否可以进人
            if(!inElevatorList.isEmpty()) personOut();//在电梯队列不空,看是否可以放人
            if(!inElevatorList.isEmpty()) {
                for(EleInfo e:inElevatorList) {
                    if(e.targetFloor > curFloor) return;
                }
                state = ElevatorState.DOWN;
            } else if(isOnlyStopReq()){
                state = ElevatorState.WAIT;
                out.println("电梯处于等待状态");
            } else if(!requestList.isEmpty()){
                for(EleInfo e:requestList) {
                    if(!e.cmd.equals("stop")&&e.curFloor > curFloor) return;
                }
                state = ElevatorState.DOWN;
            }
        }
    }

    private void downProc() {
        if(requestList.isEmpty()&&inElevatorList.isEmpty()) {
            state = ElevatorState.WAIT;
            out.println("电梯处于等待状态");
        } else {
            if(!requestList.isEmpty()) personIn();
            if(!inElevatorList.isEmpty()) personOut();
            if(!inElevatorList.isEmpty()) {
                for(EleInfo e:inElevatorList) {
                    if(e.targetFloor < curFloor) return;
                }
                state = ElevatorState.UP;
            } else if(isOnlyStopReq()){
                state = ElevatorState.WAIT;
                out.println("电梯处于等待状态");

            } else if(!requestList.isEmpty()){
                for(EleInfo e:requestList) {
                    if(!e.cmd.equals("stop")&&e.curFloor < curFloor) return;
                }
                state = ElevatorState.UP;
            }
        }
    }

    private void personIn() {
        Iterator<EleInfo> iterator = requestList.iterator();
        while(iterator.hasNext()) {//将curFloor等于电梯curFloor的请求删除,并放入inElevatorList中
            EleInfo e = iterator.next();
            if(e.curFloor==curFloor&&(state==ElevatorState.UP?(e.cmd.equals("up")):e.cmd.equals("down"))) {
                out.println(e.name+"在"+curFloor+"楼进电梯了!");
                iterator.remove();
                inElevatorList.add(e);
            }
        }
    }
    private void personOut() {
        Iterator<EleInfo> iterator = inElevatorList.iterator();
        while(iterator.hasNext()) {//首先把在电梯上目标楼层是当前楼层的人放出
            EleInfo e = iterator.next();
            if(e.targetFloor == curFloor) {
                out.println(e.name+"在"+curFloor+"楼出电梯了!");
                iterator.remove();
            }
        }
    }
    private boolean isOnlyStopReq() {
        return requestList.size()==1&&requestList.get(0).cmd.equals("stop");
    }

}


enum ElevatorState {
    WAIT,
    UP,
    DOWN
}


输入示例:

1 20
start
up
hjx 2 10
down
hyk 6 2
up
hyk1 1 8
down
hjx2 15 2
stop

输出结果:

电梯启动!
hyk1在1楼进电梯了!
电梯到达2楼,处于上升
hjx在2楼进电梯了!
电梯到达3楼,处于上升
电梯到达4楼,处于上升
电梯到达5楼,处于上升
电梯到达6楼,处于上升
电梯到达7楼,处于上升
电梯到达8楼,处于上升
hyk1在8楼出电梯了!
电梯到达9楼,处于上升
电梯到达10楼,处于上升
hjx在10楼出电梯了!
电梯到达11楼,处于上升
电梯到达12楼,处于上升
电梯到达13楼,处于上升
电梯到达14楼,处于上升
电梯到达15楼,处于上升
hjx2在15楼进电梯了!
电梯到达14楼,处于下降
电梯到达13楼,处于下降
电梯到达12楼,处于下降
电梯到达11楼,处于下降
电梯到达10楼,处于下降
电梯到达9楼,处于下降
电梯到达8楼,处于下降
电梯到达7楼,处于下降
电梯到达6楼,处于下降
hyk在6楼进电梯了!
电梯到达5楼,处于下降
电梯到达4楼,处于下降
电梯到达3楼,处于下降
电梯到达2楼,处于下降
hjx2在2楼出电梯了!
hyk在2楼出电梯了!
电梯处于等待状态
电梯停止运行!

可以观察一下输入的记录和电梯运行的结果,还是挺符合生活习惯的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容

  • 姓名:李振华 学号:17101223418 【嵌牛导读】:电梯调度算法是一类经典问题,在操作系统的磁盘...
    大华华0504阅读 3,615评论 0 1
  • 速度飞萨芬撒
    rain602阅读 167评论 0 1
  • 关怀生活点滴,培育善美品格 7月10日,“找回天使的翅膀”湖州市智力障碍人群关爱行动暑期社会实践团队来到吴兴区阳光...
    如时阅读 137评论 0 0
  • ——《 天 炙 》 (晒太阳) 出生于1905年的張明珠,她88岁的時候患腸癌,一共做過3次大手术,切除了全...
    小英姐阅读 537评论 0 0
  • 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代...
    莽原奔马668阅读 1,885评论 2 12