// class MailDeliveryApp.java //:Assignment 4: //:Student Name: Duo Zhou //:Studnet Number: 722452 /**FileName: MailDeliveryApp.java * Date: July, 27, 2000 * Purpose: Learn how to use JFrame, JPanel, Synchronized method, creating * multithread, the basic idea of creating GUI * Name of Files: This assignment include Building.java, ConnectedWall.java, * Elevator.java, ElevatorFrame.java, ElevatorPanel.java, * Floor.java, MailDeliveryApp.java, MailPiece.java, * Position.java, Robot.java * Description: This is also the main application; * This class instantiates objects for the Building, Elevator, and Robot. * * In order to construct the building it needs to also build Floor objects * one per each floor. Each floor object needs a floor layoutArray. This is * a two-dimensional array of characters holding the floor layout characters * taken from the layouts shown in the assignment handout. * * In order to provide the robot with the mail to be delivered this class * randomly generates and sorts 10 MailPiece objects for each of the 4 * floors (a total of 40). * * Because a Building contains Floor objects, Elevator objects and a Robot * object these are instantiated and references to them are stored inside * the Building object. References to the Building object are also * included within the Robot object and the Elevator objects. This * cross-referencing allows those objects to access information about the * building floors, and elevator position. For example the Robot can send * messages to(i.e. invoke methods on) the elevator to request movement * to a given floor by accessing the elevator through the building. Similarly * the elevator can access the robot coordinates to verify that the robot * passenger is inside the elevator. * Additional Feature: this is also used to create a main GUI of the floor * layout and robot movement 2D graph, it create the base * JFrame to invoke GUI of the elevator; */ import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.awt.geom.*; import java.util.*; import javax.swing.*; import javax.swing.border.*; import java.lang.*; public class MailDeliveryApp extends JFrame implements ActionListener{ static final int MAX_MAIL_PIECES = 10; static final int MAX_HUMANS = 10; static final int MAX_ROOM_WIDTH = 6; static final int MAX_ROOM_HEIGHT = 4; static char[][] floor1 = new char[Floor.MAX_ROWS][Floor.MAX_COLS]; static String[] firstLayout = new String[Floor.MAX_ROWS]; static char[][] floor2 = new char[Floor.MAX_ROWS][Floor.MAX_COLS]; static String[] secondLayout = new String[Floor.MAX_ROWS]; static char[][] floor3 = new char[Floor.MAX_ROWS][Floor.MAX_COLS]; static String[] thirdLayout = new String[Floor.MAX_ROWS]; static char[][] floor4 = new char[Floor.MAX_ROWS][Floor.MAX_COLS]; static String[] fourthLayout= new String[Floor.MAX_ROWS]; static Floor[] floors = new Floor[Building.MAX_FLOORS]; static private MailPiece mail[][] = new MailPiece[Building.MAX_FLOORS][Floor.MAX_ROOMS]; // This array contains positions where robot should start following a wall // and where Robot should stop following the wall and try to move on to next wall // Currently they are the same for the two floors having two walls, i.e. 1 and 2 // Otherwise it should be initialized with the connected wall info for each floor. // Specific content for each floor, should be at least one connected wall. static ConnectedWall[] connectedWalls; static int index = 0; public static Building building; public static Robot robot; public static char[][] layout = new char[Floor.MAX_ROWS][Floor.MAX_COLS]; public static int currentFloorNum; private JButton button_1, button_2, button_3, button_4; //create four buttons to indicate //which floor user want to go; private JFrame elevatorFrame; public MailDeliveryApp(){ super("Mail Application GUI"); setSize(Floor.MAX_COLS*20, Floor.MAX_ROWS*20+100); //set the size of the JFrame; Container myPanel=getContentPane(); //Create a Container; myPanel.setLayout(new BorderLayout()); //set Layout to BorderLayout; //********** Nothing is changed from here to the next "***" sign; int i, j,k,l,m,n; for(i = 0; i < Building.MAX_FLOORS; i++){ currentFloorNum=i; switch(i){ case 0: firstLayout = getFirstFloor(); for(j=0; j < Floor.MAX_ROWS; j++){ floor1[j] = firstLayout[j].toCharArray(); } floors[i] = new Floor(floor1); // The directory provides the physical (row,col) position for mailBox floors[i].directory = new Position[]{ new Position(22,30),new Position(18,30),new Position(14,30),new Position(10,30), new Position(6,30),new Position(4,27),new Position(4,21),new Position(4,15), new Position(4,9),new Position(6,6),new Position(10,6),new Position(14,6), new Position(18,6),new Position(22,6),new Position(26,6),new Position(28,9), new Position(28,15),new Position(28,21),new Position(28,27),new Position(24,15), new Position(18,12),new Position(14,12),new Position(8,15),new Position(10,24), new Position(14,24),new Position(18,24),new Position(22,24) }; floors[i].connectedWalls = new ConnectedWall[]{ new ConnectedWall(new Position(24,29), // start pos new Position(27,28), Robot.NORTH ), // stop pos, start direct new ConnectedWall(new Position(25,23), // start pos new Position(23,25), Robot.WEST ) // stop pos, start direct }; generateMail(i); generateHumans(i); break; case 1: secondLayout = getSecondFloor(); for(j=0; j < Floor.MAX_ROWS; j++){ floor2[j] = secondLayout[j].toCharArray(); } floors[i] = new Floor(floor2); floors[i].directory = new Position[] { new Position(28,27),new Position(22,30),new Position(18,30),new Position(14,30), new Position(10,30),new Position(6,30),new Position(4,27),new Position(4,21), new Position(4,15),new Position(4,9),new Position(6,6),new Position(8,9), new Position(8,15),new Position(8,21),new Position(16,21),new Position(16,15), new Position(16,9),new Position(18,6),new Position(22,6),new Position(26,6), new Position(28,8),new Position(28,15),new Position(28,21),new Position(24,21), new Position(20,15) }; floors[i].connectedWalls = new ConnectedWall[]{ new ConnectedWall(new Position(24,29), // start pos 1st wall new Position(27,28),Robot.NORTH ), // stop pos, start direct new ConnectedWall(new Position(25,23), // start pos 2nd wall new Position(23,25),Robot.WEST ) // stop pos, start direct }; generateMail(i); generateHumans(i); break; case 2: thirdLayout = getThirdFloor(); for(j=0; j < Floor.MAX_ROWS; j++){ floor3[j] = thirdLayout[j].toCharArray(); } floors[i] = new Floor(floor3); floors[i].directory = new Position[]{ new Position(22,30),new Position(18,30),new Position(14,30),new Position(10,30), new Position(6,30),new Position(4,27),new Position(4,21),new Position(6,18), new Position(8,21),new Position(14,24),new Position(16,15),new Position(10,12), new Position(4,9),new Position(6,6),new Position(10,6),new Position(14,6), new Position(18,6),new Position(22,6),new Position(24,6),new Position(28,9), new Position(26,12),new Position(20,15),new Position(22,24),new Position(28,21), new Position(28,27) }; floors[i].connectedWalls = new ConnectedWall[]{ new ConnectedWall(new Position(24,29), // start pos 1st wall new Position(27,28), Robot.NORTH ), // stop pos null }; // no second wall generateMail(i); generateHumans(i); break; case 3: fourthLayout = getFourthFloor(); for(j=0; j < Floor.MAX_ROWS; j++){ floor4[j] = fourthLayout[j].toCharArray(); } floors[i] = new Floor(floor4); floors[i].directory = new Position[]{ new Position(22,30),new Position(18,30),new Position(14,30),new Position(10,30), new Position(6,30),new Position(4,27),new Position(4,21),new Position(4,15), new Position(4,9),new Position(6,6),new Position(10,6),new Position(14,6), new Position(16,9),new Position(14,12),new Position(8,15),new Position(10,24), new Position(14,24),new Position(18,18),new Position(20,21),new Position(24,15), new Position(22,6),new Position(26,6),new Position(28,9),new Position(28,15), new Position(28,21) }; floors[i].connectedWalls = new ConnectedWall[]{ new ConnectedWall(new Position(24,29), // start pos 1st wall new Position(27,28),Robot.NORTH ), // stop pos null }; // no second wall generateMail(i); generateHumans(i); break; }// end of switch() }// end of for() ////////////////////////////////////////////////////////////////// // Now we have all the pieces to construct the Building object. // Note that the building object itself will instantiate the elevatorFrame // object and pass (a reference to) itself to the elevator // constructor so that the elevator can invoke methods on the building // floors. System.out.println("Creating building object."); building = new Building(floors); ////////////////////////////////////////////////////////////////// // The Robot will be constructed next and a reference to it // stored inside the building using a mutator method on the // building class. The robot receives through its constructor // argument the reference to the building object. System.out.println("Creating Robot object."); //*************************** Nothing is changed up to now; ************************** ////////////////////////////////////////////////////////////////////////////////////// //******************************* Create the JFrame ********************************** //robot has the same feature as before, in addition, it is also a JPanel, a robot = new Robot(this, building); // let robot hold reference to building robot.setMail(mail); //pass the mails argument to the robot; building.setRobot(robot); // let the building hold reference to robot //robot.deliverMail(); // cause we have put the deliverMail into //a thread in Robot.java, in order to make it move with currency //with the elevator and the display of the main JFrame; System.out.println("Robot loaded with mail"); //pause(1.0); System.out.println("Now letting the Robot loose!!!"); myPanel.add(robot, BorderLayout.CENTER); //add the Panel, set it to center; JPanel menuPanel=new JPanel(); //create another Panel to hold the buttons; button_1=new JButton("Basement"); button_2 =new JButton("1st floor"); button_3 = new JButton ("2nd floor"); button_4 = new JButton ("3rd floor"); //Add actionListener to the buttons, add the button to the south of the BorderLayout; button_1.addActionListener(this); menuPanel.add(button_1, BorderLayout.SOUTH); button_2.addActionListener(this); menuPanel.add(button_2, BorderLayout.SOUTH); button_3.addActionListener(this); menuPanel.add(button_3,BorderLayout.SOUTH); button_4.addActionListener(this); menuPanel.add(button_4,BorderLayout.SOUTH); myPanel.add(menuPanel, BorderLayout.SOUTH); WindowListener wndCloser = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; addWindowListener(wndCloser); //add WindowListener to respond to Window event; pack(); setResizable(false); //not resizable; setVisible(true); //set visiable; } //********************************** if some button is clicked; ************************************** public void actionPerformed(ActionEvent evt) { Object source = evt.getSource(); if (source==button_1){ //button_1 is clicked, means user want to get to the basement; index=0; //set target floor to 0; building.getElevator(); //hold the elevator; elevatorFrame = ElevatorFrame.getElevator(building.getElevator().getFloorNum(), index, building); //*** get a new JFrame or still keep the old JFrame; } if (source ==button_2) { //button_2 is clicked, means user want to get to the 2nd floor; index=1; //set target floor to 1; building.getElevator(); //hold the elevator; elevatorFrame = ElevatorFrame.getElevator(building.getElevator().getFloorNum(), index, building); } if (source == button_3) { //button_3 is clicked, means user want to get to the 3rd floor; index=2; //set target floor to 2; building.getElevator(); //hold the elevator; elevatorFrame = ElevatorFrame.getElevator(building.getElevator().getFloorNum(), index, building); } if (source == button_4) { //button_4 is clicked, means user want to get to the 4th floor; index=3; //set target floor to 3; building.getElevator(); //hold the elevator; elevatorFrame = ElevatorFrame.getElevator(building.getElevator().getFloorNum(), index, building); } } public static void main(String[] args) { MailDeliveryApp t=new MailDeliveryApp(); //Create a new Frame; }// end of main() ////////////////////////////////////////////////////////////////////// // Now we randomly generate the mailPieces that will go into the Robot // mail bag. The bag is organized as an array with one reference for // each mail box and where each reference without a mailPiece // will hold a null value, while others will refer to a MailPiece. // Note that we code the mailBox number starting at 0 for convinience // Any sub-sequent printout method should adjust that by adding 1. static void generateMail(int floorNum){ Position[] directory = floors[floorNum].directory; int count, mailBox; for(count=0; count < MAX_MAIL_PIECES ; ){ mailBox = (int)(((double)(directory.length))*Math.random()); pause(0.5); if(mail[floorNum][mailBox] == null){ mail[floorNum][mailBox] = /* place into mail bag */ new MailPiece(floorNum, mailBox, directory[mailBox], "MailMessage for mailBox# " + mailBox); // System.out.println("MailPiece for floor# "+floorNum+" and mailbox# "+mailBox); count++; }else{ continue; // no mailpiece added, so do not increment i } }// end of for() loop } // end of generateMail() ////////////////////////////////////////////////////////////////////// // Now lets randomly insert MAX_HUMANS into the building making sure they // do not fall inside rooms. We will exploit the fact that rooms are at // most twice the size of a 6x4 tile array. So if we are inside a room no // wall should be more than 2*6 cells away from us. static void generateHumans(int floorNum){ int count; // keep count of how many humans are placed. int row, col; Position pos; for(count =0; count < MAX_HUMANS; ){ row = (int)((Floor.MAX_ROWS)*Math.random()); // fetch a random position col = (int)((Floor.MAX_COLS)*Math.random()); pos = new Position(row,col); // human location to be evaluated // verify position is not on a wall nor blocking a mailBox location // nor inside a room Floor floor = floors[floorNum]; // get the floor if( !floor.isWall(new Position(row,col) ) && !floor.inElevator(new Position(row,col) ) && !floor.isStartStop(new Position(row,col) ) && !floor.isHuman(new Position(row+1,col+1) ) && !floor.isHuman(new Position(row-1,col-1) ) && !floor.isHuman(new Position(row+1,col-1) ) && !floor.isHuman(new Position(row,col+1) ) && !floor.isHuman(new Position(row+1,col) ) && !floor.isHuman(new Position(row,col-1) ) && !floor.isHuman(new Position(row-1,col) ) && !floor.isMailBox(new Position(row+1,col)) && !floor.isMailBox(new Position(row-1,col)) && !floor.isMailBox(new Position(row,col+1)) && !floor.isMailBox(new Position(row,col-1)) && ( (pos.distance(floor.findWall(pos,Robot.NORTH))>2*MAX_ROOM_WIDTH)|| (pos.distance(floor.findWall(pos,Robot.SOUTH))>2*MAX_ROOM_WIDTH)|| (pos.distance(floor.findWall(pos,Robot.EAST ))>2*MAX_ROOM_WIDTH)|| (pos.distance(floor.findWall(pos,Robot.WEST ))>2*MAX_ROOM_WIDTH) ) ){ // Place the human by marking the floor layout with an H floor.floorLayout[row][col] = 'H'; count++; }else{ continue; // no human placed at position so do not increment count } }// end of for() loop } // end of generateHumans() ////////////////////////////////////////////////////////////////////// // The pause function introduces a delay equal to the time in seconds // or fractions of a second passed as the floating point argument static void pause(double seconds){ try{ Thread.sleep((long)(seconds*1000.0)); }catch(InterruptedException e){ } } /////////////////////////////////////////////////////////////////////// /// The following four functions return an array of strings where each /// string is one text line from the text containing the layout of each building. static String[] getFirstFloor(){ // only static methods can be called from // main() String[] stringLayout1 = { "+-----+-----+-----+-----+-----+-----+", //string containing first row of layout "| | | | | |", //string " second " " " "| | | | | |", // etc.... "| | M9 | M8 | M7 | M6 |", "+ +--*--+--*--+--*--+--*--+-----+", "| | | |", "| M10* *M5 |", "| | | |", "+-----+ +--*--+-----+ +-----+", "| | | M23 | | | |", "| M11* | | M24* *M4 |", "| | | | | | |", "+-----+ +-----+-----+ +-----+", "| | | | | | |", "| M12* *M22 | M25* *M3 |", "| | | | | | |", "+-----+ +-----+-----+ +-----+", "| | | | | | |", "| M13* *M21 | M26* *M2 |", "| | | | | | |", "+-----+ +-----+-----+ +-----+", "| | | | | | |", "| M14* | | M27* *M1 |", "| | | M20| | | |", "+-----+ +--*--+-----+ +-----+", "| | |", "| M15* |", "| | |", "+-----+--*--+--*--+--*--+--*--+-----+", "| M16 | M17 | M18 | M19 |", "| | | | |", "| | | | |", "+-----+-----+-----+-----+-----+-----+" }; // end of stringLayout1 initialization return stringLayout1; } // end of getFirstFloor() static String[] getSecondFloor(){ String[] stringLayout2 = { "+-----+-----+-----+-----+-----+-----+", "| | | | | |", "| | | | | |", "| | M10| M9 | M8 | M7 |", "+ +--*--+--*--+--*--+--*--+-----+", "| | | |", "| M11* *M6 |", "| | | |", "+-----+--*--+--*--+--*--+ +-----+", "| M12 | M13 | M14 | | |", "| | | | *M5 |", "| | | | | |", "+-----+-----+-----+-----+ +-----+", "| | | | | |", "| | | | *M4 |", "| M17 | M16 | M15 | | |", "+-----+--*--+--*--+--*--+ +-----+", "| | | |", "| M18* *M3 |", "| | | |", "+-----+ +--*--+-----+ +-----+", "| | | M25 | | | |", "| M19* | | | *M2 |", "| | | | M24 | | |", "+-----+ +-----+--*--+ +-----+", "| | |", "| M20* |", "| | |", "+-----+--*--+--*--+--*--+--*--+-----+", "| M21 | M22 | M23 | M1 |", "| | | | |", "| | | | |", "+-----+-----+-----+-----+-----+-----+" }; // end of stringLayout2 initialization return stringLayout2; }// end of getSecondFloor() static String[] getThirdFloor(){ String[] stringLayout3 = { "+-----+-----+-----+-----+-----+-----+", "| | | | | | |", "| | | | | | |", "| | M13 | | M7 | M6 | |", "+ +--*--+ +--*--+--*--+ +", "| | | | | |", "| M14* | M8* *M5 |", "| | | | | |", "+-----+ +-----+--*--+ +-----+", "| | | | M9 | | |", "| M15* *M12 | | *M4 |", "| | | | | | |", "+-----+ +-----+-----+ +-----+", "| | | | | | |", "| M16* | | M10* *M3 |", "| | | M11 | | | |", "+-----+ +--*--+-----+ +-----+", "| | | |", "| M17* *M2 |", "| | | |", "+-----+ +--*--+-----+ +-----+", "| | | M22 | | | |", "| M18* | | M23* *M1 |", "| | | | | | |", "+-----+ +-----+-----+ +-----+", "| | | | |", "| M19* *M21 | |", "| | | | |", "+-----+--*--+-----+--*--+--*--+-----+", "| M20 | | M24 | M25 |", "| | | | |", "| | | | |", "+-----+-----+-----+-----+-----+-----+" }; // end of stringLayout3 initialization return stringLayout3; }// end of getThirdFloor() static String[] getFourthFloor(){ String[] stringLayout4 = { "+-----+-----+-----+-----+-----+-----+", "| | | | | |", "| | | | | |", "| M9 | M8 | M7 | M6 | |", "+-----+--*--+--*--+--*--+--*--+ +", "| | | |", "| M10* *M5 |", "| | | |", "+-----+ +--*--+-----+ +-----+", "| | | M15 | | | |", "| M11* | | M16* *M4 |", "| | | | | | |", "+-----+ +-----+-----+ +-----+", "| | | | | | |", "| M12* *M14 | M17* *M3 |", "| | | | | | |", "+-----+--*--+-----+-----+ +-----+", "| M13 | | | |", "| | M18* *M2 |", "| | | | |", "+-----+-----+-----+--*--+ +-----+", "| | | | M19 | | |", "| M21* | | | *M1 |", "| | | M20 | | | |", "+-----+ +--*--+-----+ +-----+", "| | |", "| M22* |", "| | |", "+-----+--*--+--*--+--*--+--*--+-----+", "| | M23 | M24 | M25 | M26 |", "| | | | | |", "| | | | | |", "+-----+-----+-----+-----+-----+-----+" }; // end of stringLayout4 initialization return stringLayout4; }// end of getFourthFloor() } // end of MailDeliveryApp class