交通灯管理系统学习笔记
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
。。。
信号灯忽略黄灯,只考虑红灯和绿灯。
应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
先把题目贴上,刚开始没看张老师讲解这道题目之前是完全摸不着头脑,感觉这个题目非常的复杂,看了视频后发现如果思想对了也没有想象中的复杂,这种功底不是一天两天能够做得到的,而是经过常年累月的积累的沉淀。
1:大概思路:题目要求是要模拟一个十字路口的真实的交通灯,因为路口有东、西、南、北四个方向,而无论你站在那个方向,你前面都会有3条路线可以走(向左,向右,向前),所以总共会有12条路线。
然后我们可以假设每条路线的前面都有一个灯,如果是绿灯就前进,如果是红灯就停下,但是无乱是哪个路口的右转弯都是不需要红灯的,所以可以把这个方向的灯设置为常绿,所以只有8条路线要进行红绿灯的切换,让我们在思考一下,因为每个灯都有一个相对应的灯,比如说从南向北的灯是绿,那摩从北向南的灯也应该是绿,对面的灯是跟着这边的等切换的,所以这样子以来右将题目简化了许多,只要在4个路线上的灯进行轮流切换就可以了。
假设要切换的灯分别是(S2N,S2W,E2W,E2N),这4盏灯的对面的灯分别是(N2S,N2E,W2E,W2N),常绿的四盏灯分别为(S2E,E2N,N2W,W2S)。
2:既然已经知道了是只要在4盏灯之间进行切换,那切换的顺序是怎么样的呢?因为我们都经常过十字路口,现在假设由南向北跟由北向南的方向变红了,那摩接下来应该是由南向西跟又北向东的车要开始走了,搞清了这点之后就基本上知道这些灯之间的切换了。
假设这四个方向的灯随便哪一个是绿的,那摩在它变绿时必须也将自己对面的灯变绿,当自己变红时必须将自己对面的灯也变红,另外还要将自己的下一盏灯变绿。
3:考虑清楚了路线之间的切换后就要考虑车辆的前行了,如果某辆车它在的路线的灯是绿的,那摩它就可以前行,这里还需要考虑到一个问题就是如果这辆车前面还有车呢,岂不是要跟前面的车相撞了,所有车辆前行的另外一个条件就是它必须是这条路上的第一辆车。
4:既然路上的车会因穿过路口而减少,那摩路上的车也会不断的进行增加,可以在这里设个时间的随机数,因为什么时候来一辆车世间是不确定的,不管这条路上的灯是什么颜色,这条路上的车都必须不断的增加。可以把路看作是一个ArrayList集合,路上的车都是这个集合中的元素,可以把车看做是一个字符串,当车辆穿过路口时,就好比这个集合中少了一个字符串对象,增加一辆车辆时,就往集合中增加一个字符串,因此就不要考虑车这个对象了,又进一步将问题简单化了。用路来控制这些车,路有一个增加车辆和减少车辆的方法。
基本思路搞清楚之后就是代码的具体实现了:
public class Load {
private String name;
private List
Load(String name){
定义一个Load类,在Load类的构造方法中接收一个name的参数
this.name=name;
ExecutorService pools=Executors.newFixedThreadPool(1); 创建了一个线程池,用这个线程池中的一个线程去每隔一段时间就往集合中添加一辆车。
pools.execute(new Runnable() {
public void run() {
for(int x=0;x<1000;x++)
{
try {
Thread.sleep(((int)(Math.random()*10)+1)*1000); 添加车的时间间隔是个1到10之间的随机数。
} catch (InterruptedException e) {
e.printStackTrace();
}
vechicles.add(Load.this.name+"..."+x); 添加的车的名字是路的名字加车的编号。
}
}
});
ScheduledExecutorService time= Executors.newSingleThreadScheduledExecutor(); 创建了一个单线程执行程序,调用一个定时器方法,每隔多长时间会执行要执行的程序。
time.scheduleAtFixedRate(new Runnable() { 这个方法接收4个参数,第一个参数是Runnable接口,也就是要执行的程序。
public void run() {
if(vechicles.size()>0){
boolean lighted=true;
if(lighted)
{
System.out.println(vechicles.remove(0) + "车开走了");
}
}
}
},
1, 第二个参数是首次执行的延迟时间
1, 第三个参数是连续执行之间的时间周期
TimeUnit.SECONDS); 第四个参数是这2个时间的类型,是一个枚举类,有秒,时,分等。
上面这段代码用到了一个跟线程有关的类Executors,这个类中的创建线程的方法之前没有接触过,不过好像很有用。
定义一个枚举,枚举的实例对象是12盏灯。
package cn.itcast.interview.traffic;
public enum Lamp {
S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false),
//这里为什么要将灯的名字作为字符串传递进来,因为他在调用对面的灯时,
//对面的灯还没产生,所以可以将灯的名字传递进来
N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false),
//需要轮流转换的灯的对面4盏灯也没有下一盏灯跟对面的灯,初始化是按的
S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true);
//4个右转弯的灯没有下一个灯跟对面的灯,而且一直是绿的
private Lamp(String opposite,String nextLamp,boolean lighted)
{
this.opposite=opposite;
this.nextLamp=nextLamp;
this.lighted=lighted;
}
private Lamp(){}
private boolean lighted;
private String opposite;
private String nextLamp;
public boolean isLighted()
{
return lighted;
}
public void light()
{
this.lighted=true;
if(opposite!=null)
Lamp.valueOf(opposite).light();
//在这里需要将灯的字符串作为参数传递给枚举类,枚举类将其转换为枚举的实例对象后在调用将灯变绿的方法。
}
public Lamp black()
{
this.lighted=false;
if(opposite!=null) //这里为什么要判断对面的是否为空呢,因为我们只需要让4盏灯有对应的灯即可。
//在这里需要将灯的字符串作为参数传递给枚举类,枚举类将其转换为枚举的实例对象后在调用将灯变红的方法。
Lamp.valueOf(opposite).black();
Lamp next=Lamp.valueOf(nextLamp);
if(nextLamp!=null) //同上
next.light();
return next;
}
}
定义一个控制灯的类
public class LampController {
private Lamp currentLamp;
public LampController(){
currentLamp=Lamp.E2N; 让当前灯为E2N,然后让他变亮。
currentLamp.light();
ScheduledExecutorService time=Executors.newSingleThreadScheduledExecutor();
定义一个定时器每隔10秒钟就切换一次,将当前等变黑,将下一盏灯变绿
time.scheduleAtFixedRate(new Runnable() {
public void run() {
currentLamp=currentLamp.black();
}
} ,
10,
10,
TimeUnit.SECONDS);
}
}
在主函数中创建路的实例对象,创建12条路,路的名字跟灯的名字相同,然后启动控制灯的系统,整个交通路口就跑起来了!!
public static void main(String[] args) {
String[] s={"S2N"," S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};
for(String ss:s)
{
new Road(ss);
}
new LampController();
}
运行结果正常,以上代码是参照老师的代码自己写的,题目是理解了,但是如果下次换个难度相同的题目的话估计还是很难做出来,
只能慢慢来。
详细请查看:http://edu.csdn.net/heima/