public Mazewar() {
        super("ECE419 Mazewar");
        consolePrintLn("ECE419 Mazewar started!");

        // 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);

        // Ask for where the server is.
        String server_hostname = JOptionPane.showInputDialog("Enter the hostname of the server");
        if((server_hostname == null) || (server_hostname.length() == 0)) {
            Mazewar.quit();
        }
        String server_port_str = JOptionPane.showInputDialog("Enter the port of the server");
        int server_port = -1;
        if((server_port_str == null) || (server_port_str.length() == 0)) {
            Mazewar.quit();
        }
        try {
            server_port = Integer.parseInt(server_port_str);
        } catch (NumberFormatException e) {
            Mazewar.quit(); // user didn't enter a number
        }

        final ServerConnection servConn = new ServerConnection(server_hostname, server_port);
        System.out.println("Established connection with server!");

        // Ask for client information
        String name = JOptionPane.showInputDialog("Enter your name");
        if((name == null) || (name.length() == 0)) {
            Mazewar.quit();
        }

        // We now have enough information to begin exchanging messages with server
        guiClient = new GUIClient(name);

        ClientEngineSender sender = new ClientEngineSender(guiClient, servConn);
        ClientEngineReceiver receiver = new ClientEngineReceiver(guiClient, servConn);
        ClientEngineWorker worker = new ClientEngineWorker(guiClient, maze, this);

        new Thread(sender).start();
        new Thread(receiver).start();
        new Thread(worker).start();

        // Register myself on the server
        guiClient.register();

        // We can set up a prompt in another thread for the user to say he's ready
        class ReadyPrompt implements Runnable{
            @Override
            public void run() {
                String ready = "";
                while (!ready.equals("ready") && !guiClient.initialized.get()) {
                    ready = JOptionPane.showInputDialog("Type ready to start game!");
                }

                System.out.println("User signaled ready. Waiting for initialization");
                guiClient.signalReady();
            }
        }
        new Thread(new ReadyPrompt()).start();

        // Now we'll wait here until the game starts
        System.out.println("Waiting for start of game");
        while (!guiClient.gameStarted.get()) {
            //spin
        }

        // 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();
    }