[黑马程序员]交通灯系统--自己设计

时间:2023-02-17 18:59:50

看了张老师的交通灯面试题的讲解,收获颇丰。老张的确是牛人。在刚拿到题的时候,我自己想了想,发现没有一个清晰的思路。可是等他讲的时候,我发现很多地方比我想的确实要好。而且思路非常清晰。

那,看完了讲解,能不能按照自己的思路作呢?

我尝试了下,代码如下:

思路(和张老师有些不同):

1。对象的抽取:
	舞台(整个的场景,用来做main的),车,路,交通灯,交通控制系统。
这部分基本一样。

但是,我不是把灯分成12个,而是把路分成12条。

我是这么想的,在实际中,灯有红绿,而一套交通控制系统,只要有两套红绿灯就够了。

而路和交通灯的关系,是通过在场景里设定的,而不是放到路里面,或者灯的本身里面。

这么做,好处是,如果增删路的条数,不会动很大的东西。

关于灯,张老师在做的时候,考虑的是红,绿两种状态,可是,需求里说,“同方向等待车辆,应先放行直行车辆,而后放行左转车辆”,并且考虑到日常生活,如果只有一条车道,直行车和左转的车,如果交叉进入一个车道,那么就不可能达到这个要求,所以,只能是按照2车道设计,即:仅左行车道,和直行车道。

于是,将绿灯分成了左行和直行两种。

2.	对象关系分析:
a)	车,路,灯 都在舞台上
b)	车在马上
c)	灯受控制系统的控制
d)	灯有两个颜色:红,绿
e)	十字路口,所以有2条路,受2组灯控制
f)	红灯后是绿灯
g)	绿灯先放真行,而后放左拐
h)	右行的车辆不受灯的控制
i)	绿灯的总时间和红灯的总时间是一致的,否则,会出现同时为绿灯,或者同时为红灯的情况。
在场景中,共有如下单独的线程:

1。随机增加车辆的线程

2。12条不同方向的路的线程,用来扫描,对比条件,然后去掉排队的车辆。

3。独立的交通控制系统。我灯的变化,和路,车毫无关系。但是,路上的车的情况,要根据我的灯的情况而变化。


3.	情景设计:
a)	右行车不受灯的控制,所以任何时候,只要有车都可以直接通过。
b)	设起始点是E2W方向为红灯
i.	W2E,E2W方向,红灯
ii.	前20秒
1.	N2S方向,直行绿灯
2.	S2N方向,直行绿灯
iii.	后20秒
1.	N2S方向,左转绿灯
2.	S2N方向,左转绿灯
iv.	30秒后,S2N,N2S方向变为红灯
c)	进入第二个场景,S2N,N2S方向变为红灯
i.	S2N,N2S方向变为红灯
ii.	前20秒:	
1.	W2E方向,直行绿灯
2.	E2W方向,直行绿灯
iii.	后10秒
1.	W2E方向,左转绿灯
2.	E2W方向,左转绿灯
iv.	30秒后,回到初始场景(但是每条路的存留车辆不变)
所有的场景,都放到舞台里导演。

关于这一部分,我一直没有把握,感觉有些东西还能抽出来。

其实,我的想法很简单。大概的步骤可以概括如下:

1。有一个舞台:main

2。舞台加入道路

3。舞台加入控制系统

4。在路上加车

5。道路上车的数量,根据控制系统改变


但是这么搞,大量的逻辑都放到了5的里面搞的代码很难看。。。等培训完了,如果有好的思路,再修改吧。搞了一下午,头大了,不想搞了。。。。



下面就是所有的代码:

Vehicle.java

package com.linuxgg.interview.trafic;

public class Vehicle {
	private Direction whereTogo;
	private String name = null;


	// 生成去来自哪里去往何方的车
	public Vehicle(Direction whereTogo, String name) {
		this.whereTogo = whereTogo;
		this.name = name;
	}

	// 根据需求,车辆过路口要花1秒时间
	public void move() {
		System.out.println("车的信息:" + name + " Direction [" + whereTogo.name()
				+ "], Bye !!");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public Direction getWhereTogo() {
		return whereTogo;
	}

	public void setWhereTogo(Direction whereTogo) {
		this.whereTogo = whereTogo;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Lamp.java

package com.linuxgg.interview.trafic;

public enum Lamp {
	Red(30), GreenAhead(20), GreenLeft(10);

	private Lamp(int i) {
		this.time = i;
	}

	public int getTime() {
		return time;
	}

	public void setTime(int time) {
		this.time = time;
	}

	private int time = 0;
}

Road.java

package com.linuxgg.interview.trafic;

import java.util.*;

public class Road {

	// 路的方向
	private Direction direction = null;
	// 路上车的队列
	public List<Vehicle> roadQueue = new ArrayList<Vehicle>();

	// 构造函数用来生成去往理的路线
	public Road(Direction direction) {
		System.out.println("生成去往" + direction.name() + "方向的路线。");
		this.direction = direction;
	}

	// 在这个路线上再增加一两车
	public Boolean add(Vehicle vehicle) {
		 System.out.println("开往方向[" + direction + "]的路上,增加了一辆车:["
		 +vehicle.getWhereTogo() +":"+vehicle.getName() + "]");
		return roadQueue.add(vehicle);

	}

	// 从路的队列里删掉一辆车
	public void remove(int i) {
		//System.out.println("Start to remove.");
		if (roadQueue.size() > 0) {
			// 先开走小车,没啥实际意义,好玩儿而已,按照需求,开走需要1秒
			roadQueue.get(i).move();
			System.out.println("移出的车辆:[" + this.getDirection().name() + "]: "
					+ roadQueue.remove(0).getWhereTogo());
		} else {
			//System.out.println("[" + this.getDirection() + "]: 当前没有车");
		}

	}

	public List<Vehicle> getRoadQueue() {
		return roadQueue;
	}

	public void setRoadQueue(List<Vehicle> roadQueue) {
		this.roadQueue = roadQueue;
	}

	public Direction getDirection() {
		return direction;
	}

	public void setDirection(Direction direction) {
		this.direction = direction;
	}

}

Stage.java -->main

package com.linuxgg.interview.trafic;

import java.util.*;

public class Stage {
	// 步骤:
	// 搞好舞台,演员开始上场
	// 设定路
	// 添加交控制系统
	// 添加车

	/**
	 * @param args
	 */
	// 控制系统只有一套,所以直接给了静态
	static TraficControlSystem tf;
	// 道路只有一套,所以直接给了静态
	static List<Road> roadList = new ArrayList<Road>();

	public static void main(String[] args) {

		System.out.println("舞台搞好,演员开始上场");

		// 加载道路
		for (int i = 0; i < Direction.values().length; i++) {
			roadList.add(new Road(Direction.values()[i]));
		}

		// 加载交通控制系统 done
		tf = new TraficControlSystem();
		new Thread(new Runnable() {
			@Override
			public void run() {
				tf.start(false, 10);

			};
		}).start();

		// 把车放到路上,随机。done

		new Thread(new Runnable() {
			@Override
			public void run() {
				addVehicles2Road(roadList);
			}
		}).start();

		// 根据roadList中的路,创建所有路的线程。
		// 将每一条路当作一个线程,然后2秒扫描一次,如果发现有车,且符合条件,就删除
		// 下面是路的分类
		// NS方向 直行
		// N2S,S2N
		// NS方向,左行
		// N2E,S2W
		// WE方向 直行
		// W2E,E2W
		// WE方向,左行
		// W2N,E2S
		// 右行
		// S2E,E2N,N2W,W2S
		for (final Road r : roadList) {

			new Thread(new Runnable() {
				public void run() {
					while (true) {
						try {
							// 每条路,每格200毫秒扫描一次
							Thread.sleep(10);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						// System.out.println(r.toString());
						// System.out.println("Start checking..."
						// + r.getDirection());

						// 还有四种情况是右转,只要队列里有车就减少,和灯无关
						if (r.getDirection().name() == "S2E"
								|| r.getDirection().name() == "E2N"
								|| r.getDirection().name() == "N2W"
								|| r.getDirection().name() == "W2S") {
							r.remove(0);
							// 如果是NS方向为红灯
						} else if (tf.lampForNS.equals(Lamp.Red)) {
							// WE方向直行
							if ((r.getDirection().name() == "W2E" || r
									.getDirection().name() == "E2W")
									&& tf.lampForWE.equals(Lamp.GreenAhead)) {
								r.remove(0);
								// WE方向左行
							} else if ((r.getDirection().name() == "W2N" || r
									.getDirection().name() == "E2S")
									&& tf.lampForWE.equals(Lamp.GreenLeft)) {

								r.remove(0);
							} else {
								// System.out.println("这条路上的车没被执行:"
								// + r.getDirection().name());
							}
							// 如果NS方向不为红灯,也就是绿灯
						} else {
							// NS方向直行
							if ((r.getDirection().name() == "N2S" || r
									.getDirection().name() == "S2N")
									&& tf.lampForNS.equals(Lamp.GreenAhead)) {

								r.remove(0);
								// NS方向左行
							} else if ((r.getDirection().name() == "N2E" || r
									.getDirection().name() == "S2W")
									&& tf.lampForNS.equals(Lamp.GreenLeft)) {
								r.remove(0);
							} else {
								// System.out.println("这条路上的车没被执行:"
								// + r.getDirection().name());
							}

						}

					}
				}

			}).start();

		}

	}

	// 加载车到对应的路面上 done
	private static void addVehicles2Road(List<Road> roadList) {
		while (true) {
			try {
				Thread.sleep(100);

				// 获取随机数量-〉路的数量
				int roadListRandom = new Random().nextInt(roadList.size());
				// 根据路的方向,添加相应的车
				roadList.get(roadListRandom).add(
						new Vehicle(
								roadList.get(roadListRandom).getDirection(),
								"开往["
										+ roadList.get(roadListRandom)
												.getDirection() + "]的车["
										+ System.currentTimeMillis() + "]"));
				// System.out.println(roadList.get(i).getRoadQueue().size());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			showCountFromRoad(roadList);

		}
	}

	// 显示每条路的状态
	private static void showCountFromRoad(List<Road> roadList) {
		// 添加之后,显示当前的每条路上的车的情况
		Iterator<Road> it = roadList.iterator();
		while (it.hasNext()) {
			Road r = (Road) it.next();
			// System.out.println(r.getDirection());
			System.out.print("[" + r.getDirection() + ":"
					+ r.getRoadQueue().size() + "] ");

		}
		System.out.println();
	}
}



TraficControlSystem.java

 

/*灯的分组:
 * 两块灯组:
 * WE, SN 分别控制东西方向和南北方向。
 * 
 * 关系:
 * 1.WE为红,则SN必然为绿
 * 2.30秒替换一次红绿
 * 3.绿色的时候,先20秒直行,然后10秒左转
 * 
 */



package com.linuxgg.interview.trafic;

public class TraficControlSystem {

	// 默认两套灯,都是红的
	Lamp lampForNS = Lamp.Red;
	Lamp lampForWE = Lamp.Red;

	// 希望这套控制系统运行多少次,默认是永久执行
	public void start(boolean endless, int loopTime) {
		if (endless) {
			while (true) {
				changeLamp();
			}
		} else {
			for (int i = 0; i < loopTime; i++) {
				changeLamp();
			}
		}
	}

	// 灯的色彩开始变化
	private void changeLamp() {
		int lampTime = 0;
		// 一共有多少个灯,顺次闪亮
		for (int i = 0; i < Lamp.values().length; i++) {
			lampForNS = Lamp.values()[i];
			System.out.println("NS方向,当前的灯是[" + lampForNS.name() + "].");
			// 根据当前的灯的颜色判断需要变化多少秒
			try {
				lampTime = lampForNS.getTime();
				while (lampTime > 0) {
					// 因为红灯与绿灯总合的时间相同,所以,去掉left的时间,就是直行的时间,又因为直行在前,所以,是和left的设定时间做比较.
					if (lampForNS.equals(Lamp.Red)) {
						lampForWE = Lamp.GreenAhead;
						if (lampTime <= Lamp.GreenLeft.getTime()) {
							// 在NS方向的红灯时间内,且去掉了直行绿灯的时间,剩下的,就是左转绿灯的时间。
							lampForWE = Lamp.GreenLeft;
						}
					}
					System.out.println("[NS]方向的[" + lampForNS.name() + "]灯还剩["
							+ (lampTime) + "]秒. 此时WE方向的灯为[" + lampForWE.name()
							+ "]");
					lampTime--;

					Thread.sleep(1000);
				}

				// 当NS方向的灯不是红色的时候,WE方向的灯必然为红色
				if (lampForNS.equals(Lamp.Red)) {
					lampForWE = Lamp.Red;
				}

			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

	
/*
	public static void main(String[] args) {
		final TraficControlSystem tf = new TraficControlSystem();
		new Thread(new Runnable() {
			@Override
			public void run() {
				tf.start(false, 2);
			}
		}).start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println("-----NS:" + tf.lampForNS.name()
							+ "  WE:" + tf.lampForWE.name());
				}
			}
		}).start();

	}
*/
}

Vehicle.java, 本来为了更有意思,想完善它,不过现在真的搞不动了。。。还得吃饭啊。。。

package com.linuxgg.interview.trafic;

public class Vehicle {
	private Direction whereTogo;
	private String name = null;


	// 生成去来自哪里去往何方的车
	public Vehicle(Direction whereTogo, String name) {
		this.whereTogo = whereTogo;
		this.name = name;
	}

	// 根据需求,车辆过路口要花1秒时间
	public void move() {
		System.out.println("车的信息:" + name + " Direction [" + whereTogo.name()
				+ "], Bye !!");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public Direction getWhereTogo() {
		return whereTogo;
	}

	public void setWhereTogo(Direction whereTogo) {
		this.whereTogo = whereTogo;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}


代码跑了一段时间之后的结果:

[黑马程序员]交通灯系统--自己设计


可以清楚的发现,

在12条道路增加车辆的几率基本一致的情形下:

1。右行车道,交通毫无压力,基本为空

2。4条左行车道数量要高于4条直行道,因为直行的绿灯时间要长于左行。


顺便感叹一下双井桥的红绿灯,擦,兄弟,你要是不会,赶紧来黑马学吧!!! 一套交通系统搞毛阿。。。你的算法绝对有问题!


今天又回头看了一下,发现里面的有些注释不太对,呵呵,那个是写的时候搞的,后来又调试着玩儿,所以作了些改动,注释没更新,都很简单,可以忽略。这个题,比银行那个排号的确实繁琐。。。