public Mazewar(int serverPort, String serverName, int listenPort) {
                super("ECE419 Mazewar");
                consolePrintLn("ECE419 Mazewar started!");
                
				// Set up globals for server communication
				this.serverName = serverName;
				this.serverPort = serverPort;

                // Create the maze
                maze = new MazeImpl(new Point(mazeWidth, mazeHeight), mazeSeed);
                assert(maze != null);
                
                // Have the ScoreTableModel listen to the maze to find
                // out how to adjust scores.
                ScoreTableModel scoreModel = new ScoreTableModel();
                assert(scoreModel != null);
                maze.addMazeListener(scoreModel);
                
                // Throw up a dialog to get the GUIClient name.
                String name = JOptionPane.showInputDialog("Enter your name");
                if((name == null) || (name.length() == 0)) {
                  Mazewar.quit(1);
                }
                
                // You may want to put your network initialization code somewhere in
                // here.

				int tempID = -1; // This isn't necessary anymore, but I don't want to change it
				ConcurrentSkipListMap<Integer, Client> existingPlayers = new ConcurrentSkipListMap<Integer, Client>();
				
				try {

					Socket sendSocket = new Socket(serverName, serverPort);
					ServerSocket listenSocket = new ServerSocket(listenPort);

					PlayerPacket cRequest = new PlayerPacket();
					PlayerPacket cResponse;

					// Set up the initial registration packet for the server,
					// we will block on this until we recevie a confirmation
					// reply from the server
					cRequest.type = PlayerPacket.PLAYER_REGISTER;
					cRequest.hostName = java.net.InetAddress.getLocalHost().getHostName();
					cRequest.playerName = name;
					cRequest.listenPort = listenPort;
					cRequest.uID = -1;

					ObjectOutputStream toServer = new ObjectOutputStream(sendSocket.getOutputStream());

					toServer.writeObject(cRequest);

					Socket receiveSocket = listenSocket.accept();
					ObjectInputStream fromServer = new ObjectInputStream(receiveSocket.getInputStream());

					while( (cResponse = (PlayerPacket) fromServer.readObject()) != null) {

						// This particular type of packet is only sent to players
						// who are not the very first player. This ensures that the
						// random number generator places everyone in the same positions
						// on the map. We basically draw all players in the order
						// that they joined based on a unique ID assigned by the server
						if (cResponse.type == PlayerPacket.PLAYER_REGISTER_UPDATE) {
							Client newClient = new RemoteClient(cResponse.playerName);
							maze.addClient(newClient);

							// Add the client to our playerList so we can keep track
							// of them when we update the map in the future
							existingPlayers.put(cResponse.uID, newClient);

							continue;
						} else if (cResponse.type == PlayerPacket.PLAYER_REGISTER_REPLY) {
							tempID = cResponse.uID; // Save the uID

							break;
						} else {
							continue;
						}
					}

					toServer.close();
					fromServer.close();
					receiveSocket.close();
					listenSocket.close();
					sendSocket.close();

					// Spawn a thread to handle broadcasted updates from the server
					new ClientUpdateHandler(maze, listenPort).start();
							
				} catch (IOException e) {
					e.printStackTrace();
					System.err.println("ERROR: Issue binding to server socket!");
					System.exit(-1);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
					System.exit(-1);
				}

				if(tempID == -1) {
					System.err.println("ERROR: Issue identifying player with remote server!");
					System.exit(-1);
				}

				uID = tempID;
			
				System.out.println("Player " + name + " registered.");

                // Create the GUIClient and connect it to the KeyListener queue
                guiClient = new GUIClient(name);
                maze.addClient(guiClient);
                this.addKeyListener(guiClient);

				ClientUpdateHandler.playerList.put(uID, guiClient);

				// Add all existing users who joined before us to the playerList.
				// This is used by the ClientUpdateHandlerThread
				for (Map.Entry<Integer, Client> ePlayer : existingPlayers.entrySet()) {
					ClientUpdateHandler.playerList.put(ePlayer.getKey(), ePlayer.getValue());
				}
                
                // Use braces to force constructors not to be called at the beginning of the
                // constructor.
                /*{
                        maze.addClient(new RobotClient("Norby"));
                        maze.addClient(new RobotClient("Robbie"));
                        maze.addClient(new RobotClient("Clango"));
                        maze.addClient(new RobotClient("Marvin"));
                }*/

                
                // Create the panel that will display the maze.
                overheadPanel = new OverheadMazePanel(maze, guiClient);
                assert(overheadPanel != null);
                maze.addMazeListener(overheadPanel);
                
                // Don't allow editing the console from the GUI
                console.setEditable(false);
                console.setFocusable(false);
                console.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder()));
               
                // Allow the console to scroll by putting it in a scrollpane
                JScrollPane consoleScrollPane = new JScrollPane(console);
                assert(consoleScrollPane != null);
                consoleScrollPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Console"));
                
                // Create the score table
                scoreTable = new JTable(scoreModel);
                assert(scoreTable != null);
                scoreTable.setFocusable(false);
                scoreTable.setRowSelectionAllowed(false);

                // Allow the score table to scroll too.
                JScrollPane scoreScrollPane = new JScrollPane(scoreTable);
                assert(scoreScrollPane != null);
                scoreScrollPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Scores"));
                
                // Create the layout manager
                GridBagLayout layout = new GridBagLayout();
                GridBagConstraints c = new GridBagConstraints();
                getContentPane().setLayout(layout);
                
                // Define the constraints on the components.
                c.fill = GridBagConstraints.BOTH;
                c.weightx = 1.0;
                c.weighty = 3.0;
                c.gridwidth = GridBagConstraints.REMAINDER;
                layout.setConstraints(overheadPanel, c);
                c.gridwidth = GridBagConstraints.RELATIVE;
                c.weightx = 2.0;
                c.weighty = 1.0;
                layout.setConstraints(consoleScrollPane, c);
                c.gridwidth = GridBagConstraints.REMAINDER;
                c.weightx = 1.0;
                layout.setConstraints(scoreScrollPane, c);
                                
                // Add the components
                getContentPane().add(overheadPanel);
                getContentPane().add(consoleScrollPane);
                getContentPane().add(scoreScrollPane);
                
                // Pack everything neatly.
                pack();

                // Let the magic begin.
                setVisible(true);
                overheadPanel.repaint();
                this.requestFocusInWindow();
        }