Java模擬西寶高速公路

@

寫在前面

只是我的Java課程的一個大作業,僅供參考。使用到的Java特性有:封裝、繼承、多態、包、GUI、Swing、集合類。耗時一周,一千行左右。
GUI演示

一、仿真模擬的具體要求

在這裡插入圖片描述

二、類的設計

考慮到程序仿真比較複雜,優先思考類與類之間的關聯,下面用類圖來描述。

2.1 抽象父類PubVehicles

在這裡插入圖片描述

PubVehicles作為抽象父類,有倆個子類分別是Iveco和Volvo,基本的成員變量在右側,抽象方法在左側。

2.2 Expressway類

在這裡插入圖片描述
Expressway類,放置在Expressway.java文件中,包含需要使用的變量,以及main方法和initialization方法。

2.3 Passenger類

在這裡插入圖片描述
Passenger類,有構造方法、上車等方法。右側是成員變量,分別是是否在寶雞站和目的地。

2.4 Timer類

在這裡插入圖片描述

Timer類,用於記錄時間,以及刷新GUI界面,從而實現運動的畫面。左側是相關的方法,右側是一些基本成員變量。

2.5 DisplayToolkit類

在這裡插入圖片描述
DisplayToolkit類主要運用GUI和Swing的組件,創建可視化用戶界面。

三、圖像顯示

這裡主要是讓小車運動起來的實現,小車的PNG圖片如下(背景透明)
在這裡插入圖片描述
images文件夾與src文件夾放置在同一目錄下即可。
具體放置到GUI界面中基本上是八股文代碼,如下所示(僅供演示)

//right變量  圖片路徑
public Image right=Toolkit.getDefaultToolkit().createImage("images/Iveco_Right.png");
//lb和ii,將圖片放置到JLabel上
JLabel lb=new JLabel();
ImageIcon ii=new ImageIcon(right);
//設置
ii.setImage(ii.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));//縮放到80x80
lb.setToolTipText("Iveco "+this.number);//鼠標移到上面有信息顯示
lb.setVisible(true);
lb.setIcon(ii);
Expressway.panel_cars.add(lb);

四、代碼實現

完整代碼、PNG素材、類圖設計,請在公眾號私信回復 [西寶高速公路] 獲取,下面超長,最好不要翻閱。

4.1 Expressway.java

package Expressway;

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

public class Expressway {
	
	//專門查看汽車運動狀態的面板 980x720  路長設定為870像素(174千米)
	public static DisplayPanel panel_cars=new DisplayPanel(0,0,980,100,new Color(255,250,250));
	
	//專門放置公路的面板980x100
	public static DisplayPanel panel_road=new DisplayPanel(0,100,980,100,new Color(255,250,250));

	//專門給自己設置的面板300x100
	private static DisplayPanel panelformyself=new DisplayPanel(980,100,300,100,new Color(35,35,35));
	private static Label personalinfo=null;
	
	//日誌面板
	//西安和寶雞站點的車輛和乘客數目信息版
	public static DisplayDialogPanel panel_xian_station=new DisplayDialogPanel(965,200,300,520,new Color(255,250,250));
	public static DisplayDialog XNStation=new DisplayDialog("Xi'An Station",50,50,0,0,300,520);
	public static DisplayDialogPanel panel_baoji_station=new DisplayDialogPanel(665,200,300,520,new Color(255,250,250));
	public static DisplayDialog BJStation=new DisplayDialog("BaoJi Station",50,50,0,0,300,520);
	
	//在高速路上的車輛的信息
	public static DisplayDialogPanel panel_on_way=new DisplayDialogPanel(315,200,350,520,new Color(255,250,250));
	public static DisplayDialog OntheWayInfo=new DisplayDialog("On The Expressway",50,50,0,0,350,520);
	
	//Console終端,記錄發車,產生乘客等信息
	public static DisplayDialogPanel panel_console=new DisplayDialogPanel(0,200,315,520,new Color(255,250,250));
	public static DisplayDialog console=new DisplayDialog("Console",50,50,0,0,315,520);
	
	//創建Frame
	public static DisplayFrame display=new DisplayFrame("Expressway");
	
	//用於計時的面板 和 標籤
	public static DisplayPanel panel_timer=new DisplayPanel(980,0,300,100,new Color(35,35,35));
	public static Label timer=null;
	
	
	//XN和BJ在仿真開始時擁有的客車數量XNW、XNY、BJW和BJY。可先按XNW=5,XNY=12,BJW=4,BJY=15進行
	public static int XN_Volvo = 5;
	public static int XN_Iveco = 12;
	public static int BJ_Volvo = 4;
	public static int BJ_Iveco = 15;
	
	//這裡新建公共汽車
	public static Iveco ivecos[]=new Iveco[XN_Iveco+BJ_Iveco];//包含了在西安點的,在寶雞點的
	public static Volvo volvos[]=new Volvo[XN_Volvo+BJ_Volvo];
	
	//這裡是到達終點站後即將反轉的車輛隊列,隊列FIFO,排隊按照規則發車
	public static Queue<Volvo> BjVolvoQ=new LinkedList<Volvo>();
	public static Queue<Volvo> XnVolvoQ=new LinkedList<Volvo>();
	public static Queue<Iveco> BjIvecoQ=new LinkedList<Iveco>();
	public static Queue<Iveco> XnIvecoQ=new LinkedList<Iveco>();
	
	//在路上的車輛
	public static LinkedList<Iveco> ivecosOnRoad=new LinkedList<Iveco>();
	public static LinkedList<Volvo> volvosOnRoad=new LinkedList<Volvo>();
	//用於記錄在路上車輛的數目
	public static int ivecosOnRoadNum=0;
	public static int volvosOnRoadNum=0;
	
	//乘客相關的數據
	//分別在西安站和寶雞站等車的乘客隊列
	public static Queue<Passenger> XnPassengerQ=new LinkedList<Passenger>();
	public static Queue<Passenger> BjPassengerQ=new LinkedList<Passenger>();
	//每分鐘到達乘客的人數上限
	public static int Pn=2;
	
	
	
	public static void initialization() {
		//初始化
		for(int i=0;i<ivecos.length;i++) {//編號就按照寶雞優先編號了
			if(i < BJ_Iveco) {
				//寶雞站出發的一共有BJ_Iveco個,也就是向右行駛
				ivecos[i]=new Iveco(true,i,7,21,20);
				BjIvecoQ.add(ivecos[i]);
			}else {
				//西安站出發的一共有XN_Iveco個,也就是向左行駛
				ivecos[i]=new Iveco(false,i,7,21,20);
				XnIvecoQ.add(ivecos[i]);
			}
		}
		for(int i=0;i<volvos.length;i++) {
			if(i<BJ_Volvo) {
				volvos[i]=new Volvo(true,i,10,40,60);
				BjVolvoQ.add(volvos[i]);
			}else {
				volvos[i]=new Volvo(false,i,10,40,60);
				XnVolvoQ.add(volvos[i]);
			}
		}
		
		//面板放置到display frame
		display.add(panel_cars);
		display.add(panel_timer);
		display.add(panelformyself);
		display.add(panel_road);
		display.add(panel_xian_station);
		display.add(panel_baoji_station);
		display.add(panel_on_way);
		display.add(panel_console);
		
		//創建時間顯示揭界面
		timer=new Label();
		timer.setText(Timer.getTime());
		timer.setFont(new Font(null,Font.PLAIN,25));
		timer.setBounds(0,0,300,100);
		timer.setForeground(new Color(255,255,255));
		panel_timer.add(timer);
		timer.setVisible(true);
		
		//創建作者信息
		personalinfo=new Label();
		personalinfo.setText("Iamnotphage");
		personalinfo.setFont(new Font(null,Font.PLAIN,25));
		personalinfo.setBounds(0,0,300,100);
		personalinfo.setForeground(new Color(255,255,255));
		panelformyself.add(personalinfo);
		personalinfo.setVisible(true);
		
		//日誌部分
		panel_xian_station.setViewportView(XNStation);
		panel_baoji_station.setViewportView(BJStation);

		panel_on_way.setViewportView(OntheWayInfo);
		console.setFont(new Font("黑體",Font.BOLD,15));
		panel_console.setViewportView(console);
		
		
		//鋪路
		//這裡取60 原因:汽車最左邊的左上角x坐標為20 汽車圖片長80,取汽車幾何中心為質點,也就是40的長度,這樣起點就是20+40=60
		RoadButton BJ_GZ=new RoadButton("BaoJi to GaoZhen",60,0,120);//長120像素
		RoadButton GZ_CP=new RoadButton("GaoZhen to CaijiaPo",180,0,105);//長105像素
		RoadButton CP_WG=new RoadButton("CaijiaPo to WuGong",285,0,310);//長310像素
		RoadButton WG_XP=new RoadButton("WuGong to XingPin",595,0,105);;
		RoadButton XP_XY=new RoadButton("XingPin to Xianyang",700,0,120);
		RoadButton XY_XN=new RoadButton("XianYang to XiAn",820,0,110);
		
		panel_road.add(BJ_GZ);
		panel_road.add(GZ_CP);
		panel_road.add(CP_WG);
		panel_road.add(WG_XP);
		panel_road.add(XP_XY);
		panel_road.add(XY_XN);
		
		//面板刷新一下 以解決初次運行程序需要拖動Frame才能正常顯示面板的問題
		panel_cars.setVisible(false);
		panel_cars.setVisible(true);
		panel_road.setVisible(false);
		panel_road.setVisible(true);
		panel_xian_station.setVisible(false);
		panel_xian_station.setVisible(true);
		panel_baoji_station.setVisible(false);
		panel_baoji_station.setVisible(true);
		
	}
	
	public static void main(String[] args) {
		
		initialization();
		
		//主循環
		while(true) {
			
			
			Timer.FreshTime(timer);//調用Timer類裏面的FreshTime進行時間刷新
			
		}
	}

}

4.2 Timer.java

package Expressway;

import java.awt.Label;
import java.util.Random;

//Timer類,用於記錄虛擬的時間,機器時間1秒等於虛擬時間1分鐘
//一切都是由時間變化引起的變化
public class Timer {
	public static int day=0;
	public static int hour=7;
	public static int min=25;
	public static final int period=1000;
	
	public static String getTime() {
		if(min==60) {
			hour++;
			min=0;
		}
		if(hour==20 && min==15) {//由於工作時間是7:30到18:00,這裡設置可見時間為7:15至18:15
			hour=7;
			min=15;
			day++;
			Expressway.XnPassengerQ.clear();
			Expressway.BjPassengerQ.clear();
		}
		String str=new String("Now: Day "+day+" Time: "+hour+" : "+min+" ");
		return str;
	}

	public static void FreshTime(Label timer) {//刷新時間的同時,刷新汽車運動狀態
		min++;
		timer.setText(getTime());//設置時間顯示
		//延遲1秒後刷新狀態
		//需要刷新的有: 各個車輛的位置 面板信息 乘客行為
		try {
			//產生乘客
			ProducePassengerstoBaoJi();
			ProducePassengerstoXiAn();
			
			//發車前
			LetPassengersAboardVolvo();
			LetPassengersAboardIveco();
			
			
			for(int i=0;i<Expressway.ivecosOnRoad.size();i++) {
				Expressway.ivecosOnRoad.get(i).Stop(Expressway.ivecosOnRoad.get(i).CheckStop());
			}
			for(int i=0;i<Expressway.volvosOnRoad.size();i++) {
				Expressway.volvosOnRoad.get(i).Stop(Expressway.volvosOnRoad.get(i).CheckStop());
			}
			
			//發車&車輛移動
			CarMovingWithTime();
			
			//刷新面板信息
			FreshStationInfo();
			FreshOnTheWayInfo();
			
			
			
			Thread.sleep(period);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void CarMovingWithTime() {
		
		//依維柯發車
		if(Expressway.BjIvecoQ.peek()!=null) {//寶雞的依維柯發車
			Expressway.BjIvecoQ.peek().launch();
			if(Expressway.BjIvecoQ.peek().isLaunched) {
				Expressway.ivecosOnRoad.add(Expressway.BjIvecoQ.poll());
				Expressway.console.append("\n["+hour+":"+min+"]Iveco "+Expressway.ivecosOnRoad.get(Expressway.ivecosOnRoadNum).number+" Launched from BaoJi");
				Expressway.ivecosOnRoad.get(Expressway.ivecosOnRoadNum).lb.setVisible(true);
				Expressway.ivecosOnRoadNum++;
			}
		}
		if(Expressway.XnIvecoQ.peek()!=null) {//西安的依維柯發車
			Expressway.XnIvecoQ.peek().launch();
			if(Expressway.XnIvecoQ.peek().isLaunched) {
				Expressway.ivecosOnRoad.add(Expressway.XnIvecoQ.poll());
				Expressway.console.append("\n["+hour+":"+min+"]Iveco "+Expressway.ivecosOnRoad.get(Expressway.ivecosOnRoadNum).number+" Launched from Xi'An");
				Expressway.ivecosOnRoad.get(Expressway.ivecosOnRoadNum).lb.setVisible(true);
				Expressway.ivecosOnRoadNum++;
			}
		}
		for(int i=0;i<Expressway.ivecosOnRoadNum;i++) {//遍歷路上車輛,移動
			if(Expressway.ivecosOnRoad.get(i).isLaunched) {
				Expressway.ivecosOnRoad.get(i).CarMoving();
			}
		}
		
		//沃爾沃發車
		if(Expressway.BjVolvoQ.peek()!=null) {//寶雞的沃爾沃發車
			Expressway.BjVolvoQ.peek().launch();
			if(Expressway.BjVolvoQ.peek().isLaunched) {
				Expressway.volvosOnRoad.add(Expressway.BjVolvoQ.poll());
				Expressway.console.append("\n["+hour+":"+min+"]Volvo "+Expressway.volvosOnRoad.get(Expressway.volvosOnRoadNum).number+" Launched from BaoJi");
				Expressway.volvosOnRoad.get(Expressway.volvosOnRoadNum).lb.setVisible(true);
				Expressway.volvosOnRoadNum++;
			}
		}
		if(Expressway.XnVolvoQ.peek()!=null) {//西安的沃爾沃發車
			Expressway.XnVolvoQ.peek().launch();
			if(Expressway.XnVolvoQ.peek().isLaunched) {
				Expressway.volvosOnRoad.add(Expressway.XnVolvoQ.poll());
				Expressway.console.append("\n["+hour+":"+min+"]Volvo "+Expressway.volvosOnRoad.get(Expressway.volvosOnRoadNum).number+" Launched from Xi'An");
				Expressway.volvosOnRoad.get(Expressway.volvosOnRoadNum).lb.setVisible(true);
				Expressway.volvosOnRoadNum++;
			}
		}
		for(int i=0;i<Expressway.volvosOnRoadNum;i++) {//遍歷路上車輛,移動
			if(Expressway.volvosOnRoad.get(i).isLaunched) {
				Expressway.volvosOnRoad.get(i).CarMoving();
			}
		}
	}
	
	public static void FreshStationInfo() {
		//西安站面板的信息顯示
		Expressway.XNStation.setText("Xi'An Station");
		for(Volvo i:Expressway.XnVolvoQ) {
			Expressway.XNStation.append("\n Volvo: "+i.number);
		}
		for(Iveco i:Expressway.XnIvecoQ) {
			Expressway.XNStation.append("\n Iveco: "+i.number);
		}
		Expressway.XNStation.append("\n候車乘客數: "+Expressway.XnPassengerQ.size());
		
		//寶雞站面板的信息顯示
		Expressway.BJStation.setText("BaoJi Station");
		for(Volvo i:Expressway.BjVolvoQ) {
			Expressway.BJStation.append("\n Volvo: "+i.number);
		}
		for(Iveco i:Expressway.BjIvecoQ) {
			Expressway.BJStation.append("\n Iveco: "+i.number);
		}
		Expressway.BJStation.append("\n候車乘客數: "+Expressway.BjPassengerQ.size());
		
	}
	public static void FreshOnTheWayInfo() {
		Expressway.OntheWayInfo.setText("On The Expressway");
		for(Volvo i:Expressway.volvosOnRoad) {
			Expressway.OntheWayInfo.append("\n Volvo: "+i.number+"乘客人數: "+i.ps.size());
		}
		for(Iveco i:Expressway.ivecosOnRoad) {
			Expressway.OntheWayInfo.append("\n Iveco: "+i.number+"乘客人數: "+i.ps.size());
		}
	}
	
	//生成 在西安站 前往寶雞站的乘客
	public static void ProducePassengerstoBaoJi() {
		//上午7點30到下午17點59 才產生乘客
		if(hour*60+min<450 || hour*60+min >1079) {
			return;
		}
		Random r=new Random();
		//每分鐘隨機生成0~Pn個乘客 [0,Pn]
		int PassengerNum=r.nextInt(Expressway.Pn+1);
		//用均勻分佈產生不同終點[0,5]
		//也就是[0,6) 012345
		for(int i=0;i<PassengerNum;i++) {
			Expressway.XnPassengerQ.add(new Passenger(false,(int)(Math.random()*6)));
		}
		if(PassengerNum!=0) {
			//Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+PassengerNum+"Passengers "+"Wait at Xi'An Station");
		}
	}
	
	//生成 在寶雞站 前往西安站的乘客
	public static void ProducePassengerstoXiAn() {
		//上午7點30到下午17點59 才產生乘客
		if(hour*60+min<450 || hour*60+min >1079) {
			return;
		}
		Random r=new Random();
		//每分鐘隨機生成0~Pn個乘客 [0,Pn]
		int PassengerNum=r.nextInt(Expressway.Pn+1);
		//用均勻分佈產生不同終點[1,6]
		//[1,7) 也就是123456

		for(int i=0;i<PassengerNum;i++) {
			Expressway.BjPassengerQ.add(new Passenger(true,(int)(Math.random()*6+1)));	
		}
		if(PassengerNum!=0) {
			//Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+PassengerNum+"Passengers "+"Wait at BaoJi Station");
		}
	}

	//安排乘客上Iveco車,即遍歷乘客隊列
	public static void LetPassengersAboardIveco() {
		
		//寶雞站
		for(int i=0;i<Expressway.BjPassengerQ.size();i++) {
			if(Expressway.BjPassengerQ.peek()!=null) {
				if(Expressway.BjPassengerQ.peek().AboardIveco()) {
					Expressway.BjPassengerQ.poll();
				}else {
					//隊首上車失敗直接break
					break;
				}
			}
		}
		//西安站
		for(int i=0;i<Expressway.XnPassengerQ.size();i++) {
			if(Expressway.XnPassengerQ.peek()!=null) {
				if(Expressway.XnPassengerQ.peek().AboardIveco()) {
					Expressway.XnPassengerQ.poll();
				}else {
					break;
				}
			}
		}
	}
	
	public static void LetPassengersAboardVolvo() {
		//寶雞站
		for(int i=0;i<Expressway.BjPassengerQ.size();i++) {
			if(Expressway.BjPassengerQ.peek()!=null) {
				if(Expressway.BjPassengerQ.peek().AboardVolvo()) {
					Expressway.BjPassengerQ.poll();
				}else {
					break;
				}
			}
		}
		//西安站
		for(int i=0;i<Expressway.XnPassengerQ.size();i++) {
			if(Expressway.XnPassengerQ.peek()!=null) {
				if(Expressway.XnPassengerQ.peek().AboardVolvo()) {
					Expressway.XnPassengerQ.poll();
				}else {
					break;
				}
			}
		}		
	}

}

4.3 DisplayToolkit.java

package Expressway;

import java.awt.Button;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

//顯示界面
class DisplayFrame extends JFrame{
	//自動生成的序列版本號
	private static final long serialVersionUID = 1L;
	//窗口屬性區域
	private static final int WIDTH=1280;
	private static final int HEIGHT=720;
	
	DisplayFrame(String title){
		super(title);
		this.setSize(WIDTH,HEIGHT);
		this.setBackground(new Color(51,51,51));
		
		this.setResizable(false);
		
		this.setLayout(null);//不使用布局管理器
		this.setLocationRelativeTo(null);
		this.setVisible(true);
		//關閉窗口的事件
		this.addWindowListener(new WindowAdapter() {
          public void windowClosing(WindowEvent e) {
              System.exit(0);
          }
      });
		
	}
}

//顯示面板
class DisplayPanel extends JPanel{
	//自動生成的序列版本號
	private static final long serialVersionUID = 1L;
	DisplayPanel(int x,int y,int width,int height,Color c){
		super(null);
		this.setBounds(x,y,width,height);
		this.setBackground(c);
	}
}

//顯示公路
class RoadButton extends Button{
	//默認序列號
	private static final long serialVersionUID = 1L;

	public RoadButton(String str,int x,int y,int w) {
		super(str);
		this.setBackground(Color.black);
		this.setForeground(new Color(255,255,255));
		this.setBounds(x,y,w,50);
	}
}
class DisplayRoad extends JPanel{


	private static final long serialVersionUID = 1L;
	//公路長 870像素,即174千米
	DisplayRoad(int x,int y,int width,int height,Color c){
		super(null);
		this.setBounds(x,y,width,height);
		this.setBackground(c);
	}
		
}
class DisplayDialogPanel extends JScrollPane{
	private static final long serialVersionUID = 1L;
	
	DisplayDialogPanel(int x,int y,int width,int height,Color c){
		super(null);
		this.setBounds(x,y,width,height);
		this.setBackground(c);
	}
}
class DisplayDialog extends JTextArea{
	//默認序列號
	private static final long serialVersionUID = 1L;

	
	DisplayDialog(String str,int row,int col,int x,int y,int w,int h){
		super(str,row,col);
		this.setBounds(x,y,w,h);
		this.setBackground(new Color(15,15,15));
		this.setForeground(new Color(0,255,0));
		this.setFont(new Font("黑體",Font.BOLD,20));
	}
}
public class DisplayToolkit {
	
}

4.4 Vehicles.java

package Expressway;

import java.awt.*;
import java.util.LinkedList;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

abstract class PubVehicles{
	public static final int LEFT_BOUND=20;//車的運動邊界,x方向上 20~890  高速公路長870像素
	public static final int RIGHT_BOUND=890;
	protected boolean isRight;//是否向右行駛
	protected boolean isLaunched=false;//是否發車了
	protected int currentP;//當前的位置
	protected int number;//公交車的編號
	protected int speed;//車速
	protected int capacity;//容量
	protected LinkedList<Passenger> ps=new LinkedList<Passenger>();//乘客鏈表,記錄車上的各個乘客信息  到終點站記得清空
	protected int duration;//發車的間隔
	protected JLabel lb;//用於存圖的JLabel
	protected ImageIcon ii;//圖片
	
	PubVehicles(boolean isRight,int number,int speed,int capacity,int duration){
		this.isRight=isRight;
		this.number=number;
		this.speed=speed;
		this.capacity=capacity;
		this.duration=duration;
	}
	
	abstract protected void headReverse();//到達終點站調頭
	abstract protected void display(int x,int y);//顯示在panel_car面板上
	abstract protected void launch();//每隔一段時間發車
	abstract protected void CarMoving();//車輛移動
	abstract protected int CheckStop();//檢查車上是否有乘客即將到站 如果沒有,返回-1,如果有,返回當前站點的編號0,1,2,3,4,5,6
	abstract protected void Stop(int index);//靠index站停車,等待乘客下車
}

//依維柯 速度是7像素每秒,也就是1.4公里每分鐘  容量21
//上午8:00開始,每20分鐘一班,最後一班為下午6:00
class Iveco extends PubVehicles{
	
	private int temp=0;//用於停2分鐘的臨時變量
	
	public Image right=Toolkit.getDefaultToolkit().createImage("images/Iveco_Right.png");
	public Image left=Toolkit.getDefaultToolkit().createImage("images/Iveco_Left.png");
	
	//初始化
	Iveco(boolean isRight,int number, int speed, int capacity,int duration) {
		super(isRight,number, speed,capacity,duration);
		lb=new JLabel();
		ii=null;
		//選擇車頭朝向
		if(isRight) {//如果車頭向右
			ii=new ImageIcon(this.right);	
			this.currentP=LEFT_BOUND;
		}else {
			ii=new ImageIcon(this.left);
			this.currentP=RIGHT_BOUND;
		}
		ii.setImage(ii.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));//縮放到80x80
		lb.setToolTipText("Iveco "+this.number);//鼠標移到上面有信息顯示
		lb.setVisible(true);
		lb.setIcon(ii);
		Expressway.panel_cars.add(lb);
	}

	@Override
	protected void display(int x, int y) {
		//顯示在panel_cars
		if( (this.isRight && x>=RIGHT_BOUND) || (!this.isRight && x<=LEFT_BOUND)) {
			if(this.isRight) {//到達終點後,終點隊列的尾部中添加該車,路上的車鏈表刪除該車,並減少在路上車輛的計數器
				Expressway.XnIvecoQ.add(this);
				Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Iveco "+this.number+" Arrived at Xi'An");
			}else{
				Expressway.BjIvecoQ.add(this);
				Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Iveco "+this.number+" Arrived at BaoJi");
			}
			for(int i=0;i<Expressway.ivecosOnRoadNum;i++) {
				if(this.number==Expressway.ivecosOnRoad.get(i).number) {
					Expressway.ivecosOnRoad.remove(i);
					Expressway.ivecosOnRoadNum--;
					this.isLaunched=false;
					this.lb.setVisible(isLaunched);
					break;
				}
			}
			
			this.headReverse();
		}
		lb.setBounds(x,y,80,80);
		
	}

	@Override
	protected void headReverse() {
		// TODO Auto-generated method stub
		//掉頭之前清空乘客鏈表ps
		this.ps.clear();
		
		this.isRight=!this.isRight;
		if(this.isRight){
			ii=new ImageIcon(this.right);
			ii.setImage(ii.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));//縮放到80x80
			lb.setIcon(ii);
			Expressway.panel_cars.add(lb);
		}else{
			ii=new ImageIcon(this.left);
			ii.setImage(ii.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));//縮放到80x80
			lb.setIcon(ii);
			Expressway.panel_cars.add(lb);
			
		}
		
	}

	@Override
	protected void launch() {
		if( (Timer.hour>=8 && Timer.hour<=17 && Timer.min%20==0) || (Timer.hour==18&&Timer.min==0)) {//8點整第一班 每20分鐘發一次 18點最後一班 
			this.isLaunched=true;
			return;
		}else {
			return;
		}
		
	}

	@Override
	protected void CarMoving() {//要伴隨着Timer使用,每min移動一次
		// TODO Auto-generated method stub
		this.display(this.currentP,0);
		if(this.isRight) {
			this.currentP += this.speed;
		}else {
			this.currentP -= this.speed;
		}
	}

	@SuppressWarnings("unused")
	@Override
	protected int CheckStop() {//檢查乘客是否即將到站
		// TODO Auto-generated method stub
		//只有快到站才檢查,否則浪費時間
		int index=-1;
		if(this.isRight) {
			//前往西安方向各坐標近似取20 139 244 552 657 783 889
			if(this.currentP==139||this.currentP==244||this.currentP==552||this.currentP==657||this.currentP==783||this.currentP==889) {
				for(int i=0;i<this.ps.size();i++) {
					if(this.ps.get(i).destination==1&&this.currentP==139) {
						index=1;
						return index;
					}else if(this.ps.get(i).destination==2&&this.currentP==244) {
						index=2;
						return index;
					}else if(this.ps.get(i).destination==3&&this.currentP==552) {
						index=3;
						return index;
					}else if(this.ps.get(i).destination==4&&this.currentP==657) {
						index=4;
						return index;
					}else if(this.ps.get(i).destination==5&&this.currentP==783) {
						index=5;
						return index;
					}else if(this.ps.get(i).destination==6&&this.currentP==889) {
						index=6;
						return index;
					}else {
						return -1;
					}
				}
			}else {
				return -1;
			}
		}else {
			//前往寶雞方向的各個坐標近似取22 141 246 554 659 778 890
			if(this.currentP==22||this.currentP==141||this.currentP==246||this.currentP==554||this.currentP==659||this.currentP==778) {
				for(int i=0;i<this.ps.size();i++) {
					if(this.ps.get(i).destination==0&&this.currentP==22) {
						index=0;
						return index;
					}else if(this.ps.get(i).destination==1&&this.currentP==141) {
						index=1;
						return index;
					}else if(this.ps.get(i).destination==2&&this.currentP==246) {
						index=2;
						return index;
					}else if(this.ps.get(i).destination==3&&this.currentP==554) {
						index=3;
						return index;
					}else if(this.ps.get(i).destination==4&&this.currentP==659) {
						index=4;
						return index;
					}else if(this.ps.get(i).destination==5&&this.currentP==778) {
						index=5;
						return index;
					}else {
						return -1;
					}
				}
			}else {
				return -1;
			}
		}
		return index;//如果是-1表示不需要停車
		
	}

	@Override
	protected void Stop(int index) {//CheckStop返回index不是-1,就執行Stop,在index站點等待兩分鐘,並且讓乘客下車
		// TODO Auto-generated method stub
		//停2分鐘的部分
		if(index==-1&&this.temp==0) {//如果沒有執行過stop並且index是-1,說明不需要停車
			return;//第一次執行stop後,ps鏈表中已經沒有需要下車的乘客了,下一分鐘再執行checkstop後返回-1,但此時temp已經是1,所以函數不會返回
		}
		this.isLaunched=false;
		Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+"Iveco"+this.number+" Stops");
		this.temp++;
		if(this.temp==2) {
			this.temp=0;
			this.isLaunched=true;//isLaunched來控制汽車是否移動
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+"Iveco"+this.number+" ReLauched!");
			return;
		}
		//利用index來判斷ps鏈表中哪些乘客需要下車
		int count=0;//用來計數下車的乘客,最終輸出到console中避免繁瑣
		//這裡直接遍歷ps鏈表,注意size會減少的情況
		for(int i=0;i<this.ps.size();i++) {
			if(this.ps.get(i).destination==index) {
				this.ps.remove(i--);//必須減減,否則size()變小,遍歷不全
				count++;
			}
		}
		//根據index輸出
		switch(index) {
		case 0:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at BaoJi Station");
			break;
		case 1:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at GaoZhen Station");
			break;
		case 2:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at CaijiaPo Station");
			break;
		case 3:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at WuGong Station");
			break;
		case 4:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at XingPin Station");
			break;
		case 5:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at XianYang Station");
			break;
		case 6:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at Xi'An Station");
			break;
		}
	}
	
}

//沃爾沃 速度是10像素每分鐘,也就是2公里每分鐘  容量40
//上午8:30開始,每小時一班,最後一班為下午5:30
class Volvo extends PubVehicles{
	private int temp=0;
	public Image right=Toolkit.getDefaultToolkit().createImage("images/Volvo_Right.png");
	public Image left=Toolkit.getDefaultToolkit().createImage("images/Volvo_Left.png");
	
	Volvo(boolean isRight,int number, int speed, int capacity,int duration) {
		super(isRight,number, speed,capacity,duration);
		lb=new JLabel();
		ImageIcon ii=null;
		//選擇車頭朝向
		if(isRight) {//如果車頭向右
			ii=new ImageIcon(this.right);	
			this.currentP=LEFT_BOUND;
		}else {
			ii=new ImageIcon(this.left);
			this.currentP=RIGHT_BOUND;
		}
		ii.setImage(ii.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));//縮放到80x80
		lb.setToolTipText("Volvo "+this.number);//鼠標移到上面有信息顯示
		lb.setVisible(true);
		lb.setIcon(ii);
		Expressway.panel_cars.add(lb);
	}

	@Override
	protected void display(int x, int y) {
		//顯示在panel_cars
		if( (this.isRight && x>=RIGHT_BOUND) || (!this.isRight && x<=LEFT_BOUND)) {
			if(this.isRight) {//到達終點後,終點隊列的尾部中添加該車,路上的車鏈表刪除該車,並減少在路上車輛的計數器
				Expressway.XnVolvoQ.add(this);
				Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Volvo "+this.number+" Arrived at Xi'An");
			}else{
				Expressway.BjVolvoQ.add(this);
				Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Volvo "+this.number+" Arrived at BaoJi");
			}
			for(int i=0;i<Expressway.volvosOnRoadNum;i++) {
				if(this.number==Expressway.volvosOnRoad.get(i).number) {
					Expressway.volvosOnRoad.remove(i);
					Expressway.volvosOnRoadNum--;
					this.isLaunched=false;
					this.lb.setVisible(false);
					break;
				}
			}
			this.headReverse();
		}
		lb.setBounds(x,y,80,80);
				
	}

	@Override
	protected void headReverse() {
		// TODO Auto-generated method stub
		//掉頭之前清空ps鏈表
		this.ps.clear();
		
		this.isRight=!this.isRight;
		if(this.isRight){
			ii=new ImageIcon(this.right);
			ii.setImage(ii.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));//縮放到80x80
			lb.setIcon(ii);
			Expressway.panel_cars.add(lb);
		}else{
			ii=new ImageIcon(this.left);
			ii.setImage(ii.getImage().getScaledInstance(80, 80, Image.SCALE_DEFAULT));//縮放到80x80
			lb.setIcon(ii);
			Expressway.panel_cars.add(lb);
			
		}
	}

	@Override
	protected void launch() {
		// TODO Auto-generated method stub
		if(Timer.min==30 && Timer.hour>=8 && Timer.hour<=17) {//8點30第一班,每小時一班,最後一班17點30
			this.isLaunched=true;
			return;
		}else {
			return;
		}
	}

	@Override
	protected void CarMoving() {//要伴隨着Timer使用,每min移動一次
		// TODO Auto-generated method stub
		this.display(this.currentP,0);
		if(this.isRight) {
			this.currentP += this.speed;
		}else {
			this.currentP -= this.speed;
		}
	}

	@SuppressWarnings("unused")
	@Override
	protected int CheckStop() {
		// TODO Auto-generated method stub
		//只有快到站才檢查,否則浪費時間
		int index=-1;
		if(this.isRight) {
			//前往西安方向各坐標近似取20 140 (240,250) (550,560) 660 780 890
			if(this.currentP==140||this.currentP==240||this.currentP==550||this.currentP==660||this.currentP==780||this.currentP==890) {
				for(int i=0;i<this.ps.size();i++) {
					if(this.ps.get(i).destination==1&&this.currentP==140) {
						index=1;
						return index;
					}else if(this.ps.get(i).destination==2&&this.currentP==240) {
						index=2;
						return index;
					}else if(this.ps.get(i).destination==3&&this.currentP==550) {
						index=3;
						return index;
					}else if(this.ps.get(i).destination==4&&this.currentP==660) {
						index=4;
						return index;
					}else if(this.ps.get(i).destination==5&&this.currentP==780) {
						index=5;
						return index;
					}else if(this.ps.get(i).destination==6&&this.currentP==890) {
						index=6;
						return index;
					}else {
						return -1;
					}
				}
			}else {
				return -1;
			}
		}else {
			//前往寶雞方向的各個坐標近似取20 140 (240,250) (550,560) 660 780 890
			if(this.currentP==20||this.currentP==140||this.currentP==250||this.currentP==560||this.currentP==660||this.currentP==780) {
				for(int i=0;i<this.ps.size();i++) {
					if(this.ps.get(i).destination==0&&this.currentP==20) {
						index=0;
						return index;
					}else if(this.ps.get(i).destination==1&&this.currentP==140) {
						index=1;
						return index;
					}else if(this.ps.get(i).destination==2&&this.currentP==250) {
						index=2;
						return index;
					}else if(this.ps.get(i).destination==3&&this.currentP==560) {
						index=3;
						return index;
					}else if(this.ps.get(i).destination==4&&this.currentP==660) {
						index=4;
						return index;
					}else if(this.ps.get(i).destination==5&&this.currentP==780) {
						index=5;
						return index;
					}else {
						return -1;
					}
				}
			}else {
				return -1;
			}
		}
		return index;//如果是-1表示不需要停車		
	}

	@Override
	protected void Stop(int index) {
		// TODO Auto-generated method stub
		//停2分鐘的部分
		if(index==-1&&this.temp==0) {//如果沒有執行過stop並且index是-1,說明不需要停車
			return;//第一次執行stop後,ps鏈表中已經沒有需要下車的乘客了,下一分鐘再執行checkstop後返回-1,但此時temp已經是1,所以函數不會返回
		}
		this.isLaunched=false;
		Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+"Volvo"+this.number+" Stops");
		this.temp++;
		if(this.temp==2) {
			this.temp=0;
			this.isLaunched=true;//isLaunched來控制汽車是否移動
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+"Volvo"+this.number+" ReLauched!");
			return;
		}
		//利用index來判斷ps鏈表中哪些乘客需要下車
		int count=0;//用來計數下車的乘客,最終輸出到console中避免繁瑣
		//這裡直接遍歷ps鏈表,注意size會減少的情況
		for(int i=0;i<this.ps.size();i++) {
			if(this.ps.get(i).destination==index) {
				this.ps.remove(i--);//必須減減,否則size()變小,遍歷不全
				count++;
			}
		}
		//根據index輸出
		switch(index) {
		case 0:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at BaoJi Station");
			break;
		case 1:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at GaoZhen Station");
			break;
		case 2:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at CaijiaPo Station");
			break;
		case 3:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at WuGong Station");
			break;
		case 4:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at XingPin Station");
			break;
		case 5:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at XianYang Station");
			break;
		case 6:
			Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]"+count+"Passengers"+" Arrived at Xi'An Station");
			break;
		}
	}
}

public class Vehicles extends JPanel{
	/**
	 * 默認生成的序列號
	 */
	private static final long serialVersionUID = 1L;
	
	
	
}

4.5 Passenger.java

package Expressway;

public class Passenger {
	public boolean isBaoJi;//根據要求,只能在西安站或者寶雞站等車
	public int destination;//目的地,可以取一些離散的值 站點在Frame上坐標,分別是
	/*20 140 245 555 660 780 890
	 *由於車輛速度不一,而且只能取整數
	 *對於Volvo:10像素每分鐘,各個站點的坐標近似是
	 *20 140 (240,250) (550,560) 660 780 890
	 *對於Iveco: 7像素每分鐘,各個站點的坐標近似是
	 *20 (139,146) (244,251) (552,559) (657,664) (776,783) (889,896) 
	 *890 (785,778) (666,659) (561,554) (246,239) (141,134) (22,15)
	 *
	 *於是前往西安方向的各站點坐標近似取
	 *20 139 244 552 657 783 889
	 *前往寶雞方向的個站點坐標近似取
	 *22 141 246 554 659 778 890
	 *
	 * 
	 * destination取值規定為Random類產生[0,6]的整數,分別代表寶雞...西安
	 * 
	 */
	
	
	public Passenger(boolean isBaoji,int destination){
		this.isBaoJi=isBaoji;
		this.destination=destination;
		System.out.println("["+Timer.hour+":"+Timer.min+"]"+"乘客創建成功 是否在寶雞站:"+this.isBaoJi+" 目的地: "+this.destination);
	}
	public boolean AboardIveco() {//成功上車返回true
		//如果是在寶雞站
		if(this.isBaoJi) {
			//上車的步驟,在發車前的瞬間上車
			//在該站發車的車輛隊列 中檢查隊首的車的 ps鏈表是否滿,如果沒有就上車,如果有就暫不執行
			if((Timer.hour>=8 && Timer.hour<=17 && Timer.min%20==0) || (Timer.hour==18&&Timer.min==0)) {//Iveco發車時間,在執行launch之前執行該方法
				if(Expressway.BjIvecoQ.peek()!=null) {//非空,避免異常
					if(Expressway.BjIvecoQ.peek().ps.size() < Expressway.BjIvecoQ.peek().capacity) {//車上乘客數小於容量
						Expressway.BjIvecoQ.peek().ps.add(this);
						//System.out.println("size()"+Expressway.BjIvecoQ.peek().ps.size());
						//Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Passenger Aboard the Iveco"+Expressway.BjIvecoQ.peek().number+"in BaoJi");
						return true;
					}
				}
			}
			
		}else {
			if((Timer.hour>=8 && Timer.hour<=17 && Timer.min%20==0) || (Timer.hour==18&&Timer.min==0)) {//Iveco發車時間,在執行launch之前執行該方法
				if(Expressway.XnIvecoQ.peek()!=null) {
					if(Expressway.XnIvecoQ.peek().ps.size() < Expressway.XnIvecoQ.peek().capacity) {//車上乘客數小於容量
						Expressway.XnIvecoQ.peek().ps.add(this);
						//Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Passenger Aboard the Iveco"+Expressway.XnIvecoQ.peek().number+"in Xi'An");
						return true;
					}
				}
			}
		}
		return false;
	}
	public boolean AboardVolvo() {//成功上車返回true
		//如果是在寶雞站
		if(this.isBaoJi) {
			//上車的步驟,在發車前的瞬間上車
			//在該站發車的車輛隊列 中檢查隊首的車的 ps鏈表是否滿,如果沒有就上車,如果有就暫不執行
			if(Timer.min==30 && Timer.hour>=8 && Timer.hour<=17) {//Volvo發車時間,在執行launch之前執行該方法
				if(Expressway.BjVolvoQ.peek()!=null) {
					if(Expressway.BjVolvoQ.peek().ps.size() < Expressway.BjVolvoQ.peek().capacity) {//車上乘客數小於容量
						Expressway.BjVolvoQ.peek().ps.add(this);
						//Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Passenger Aboard the Volvo"+Expressway.BjVolvoQ.peek().number+"in BaoJi");
						return true;
					}
				}
				
			}
			
		}else {
			if(Timer.min==30 && Timer.hour>=8 && Timer.hour<=17) {//Iveco發車時間,在執行launch之前執行該方法
				if(Expressway.XnVolvoQ.peek()!=null) {
					if(Expressway.XnVolvoQ.peek().ps.size() < Expressway.XnVolvoQ.peek().capacity) {//車上乘客數小於容量
						Expressway.XnVolvoQ.peek().ps.add(this);
						//Expressway.console.append("\n["+Timer.hour+":"+Timer.min+"]Passenger Aboard the Volvo"+Expressway.XnVolvoQ.peek().number+"in Xi'An");
						return true;
					}
				}
			}
		}
		return false;
	}
}

最後

感興趣的可以關注我的微信公眾號,第一時間收到動態
在這裡插入圖片描述

Tags: