public PandemicGame() {

		// Initialize the global game state variables
		d_moveNo = 0;
		d_turnNo = 1;
		d_activePlayer = 0;

		// Read in the city data from a flat text data file
		d_cityList = City.readCities();
		City startCity = d_cityList.get(City.getStartCityIndex());

		// Generate list of players
		d_playerList = Player.generatePlayers(startCity);
		d_playerHandDisplay = new boolean[Player.numPlayers()];
		d_deckDisplay = false;

		// Generate player cards based on the cities
		d_playerDeck = PlayerCard.generateDeck(d_cityList);
		PlayerCard.dealStartingHands(d_playerDeck, d_playerList);
		PlayerCard.seedEpidemicCards(d_playerDeck);
		
		// Set up the infection manager
		d_infectionManager = new InfectionManager(d_cityList);
		
		// Set up the content pane
		d_contentPane = new JLayeredPane();
		d_contentPane.setLayout(null);
		d_contentPane.setOpaque(true);
		d_contentPane.setPreferredSize(new Dimension(MAP_WIDTH + MENU_WIDTH, MAP_HEIGHT));

		// Read in the map image file and set up a link to the cities
		d_mapPanel = new MapPanel(this, d_cityList, d_playerList);
		d_mapPanel.setLocation(200,0);
		d_mapPanel.setSize(MAP_WIDTH, MAP_HEIGHT);
		d_contentPane.add(d_mapPanel, JLayeredPane.DEFAULT_LAYER);

		// Set up the user interface buttons

		PlayerCardPanel.readPlayerCardImages();
		InfectionCardPanel.readInfectCardImage();

		d_gameStatePanel = new GameStatePanel(this);
		d_gameStatePanel.setLocation(1, 1);
		d_gameStatePanel.setSize(MENU_WIDTH - 2, MAP_HEIGHT - 9 * BUTTON_HEIGHT - 2);
		d_contentPane.add(d_gameStatePanel, JLayeredPane.DEFAULT_LAYER);
		
		d_actionButton = new ButtonPanel[9];
		d_actionButton[0] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_DRIVE, "Drive / Ferry");
		d_actionButton[1] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_DIRECTFLIGHT, "Direct Flight");
		d_actionButton[2] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_CHARTERFLIGHT, "Charter Flight");
		d_actionButton[3] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_SHUTTLEFLIGHT, "Shuttle Flight");
		d_actionButton[4] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_TREATDISEASE, "Treat Disease");
		d_actionButton[5] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_SHAREKNOWLEDGE, "Share Knowledge");
		d_actionButton[6] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_BUILDSTATION, "Build Research Station");
		d_actionButton[7] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_DISCOVERCURE, "Discover A Cure");
		d_actionButton[8] = new ButtonPanel(this, ButtonPanel.ButtonType.ACTION_PASS, "Pass");
		for (int i = 0; i < 9; i++) {
			d_actionButton[i].setLocation(1, MAP_HEIGHT - (9 - i) * BUTTON_HEIGHT);
			d_actionButton[i].setSize(MENU_WIDTH - 2, BUTTON_HEIGHT - 1);
			d_contentPane.add(d_actionButton[i], JLayeredPane.DEFAULT_LAYER);
		}
		
		d_confirmHandButton = new ButtonPanel(this, ButtonPanel.ButtonType.CARDS_SELECTED, "OK");
		d_confirmHandButton.setLocation(MENU_WIDTH + MAP_WIDTH - 50 - 20, 20);
		d_confirmHandButton.setSize(50, 30);
		d_contentPane.add(d_confirmHandButton, JLayeredPane.POPUP_LAYER);
		d_confirmHandButton.setVisible(false);

		d_cancelActionButton = new ButtonPanel(this, ButtonPanel.ButtonType.CANCEL_ACTION, "CANCEL MOVE");
		d_cancelActionButton.setLocation((MENU_WIDTH + MAP_WIDTH - POPUP_WIDTH) / 2, (MAP_HEIGHT + POPUP_HEIGHT) / 2 + 20);
		d_cancelActionButton.setSize(100, 30);
		d_contentPane.add(d_cancelActionButton, JLayeredPane.POPUP_LAYER);
		d_cancelActionButton.setVisible(false);

		d_playerButton = new ButtonPanel[Player.numPlayers()];
		for (int i = 0; i < Player.numPlayers(); i++) {
			switch(i) {
			case 0:
				d_playerButton[i] = new ButtonPanel(this, ButtonPanel.ButtonType.PLAYER_1, d_playerList.get(i).getRoleName());
				break;
			case 1:
				d_playerButton[i] = new ButtonPanel(this, ButtonPanel.ButtonType.PLAYER_2, d_playerList.get(i).getRoleName());
				break;
			case 2:
				d_playerButton[i] = new ButtonPanel(this, ButtonPanel.ButtonType.PLAYER_3, d_playerList.get(i).getRoleName());
				break;
			case 3:
				d_playerButton[i] = new ButtonPanel(this, ButtonPanel.ButtonType.PLAYER_4, d_playerList.get(i).getRoleName());
				break;
			}
			d_playerButton[i].setSize(100, 30);			
			d_contentPane.add(d_playerButton[i], JLayeredPane.POPUP_LAYER);
			d_playerButton[i].setVisible(false);
		}
		
		// Allocate the card panels even though they will not be part of the default display
		d_playerCardPanel = new PlayerCardPanel[Player.numPlayers()][13];
		d_handTrayPanel = new JPanel[Player.numPlayers()];

		for (int i = 0; i < Player.numPlayers(); i++) {
			
			d_handTrayPanel[i] = new JPanel();
			d_handTrayPanel[i].setBackground(d_playerList.get(i).color());
			d_handTrayPanel[i].setSize(15 + 2 * (PLAYER_CARD_WIDTH + 5), 20);
			d_handTrayPanel[i].setVisible(false);
			d_contentPane.add(d_handTrayPanel[i], JLayeredPane.POPUP_LAYER);
			for (int j = 0; j < 13; j++) {
				
				d_playerCardPanel[i][j] = new PlayerCardPanel(this);
				d_playerCardPanel[i][j].setVisible(false);
				d_contentPane.add(d_playerCardPanel[i][j], JLayeredPane.POPUP_LAYER);
			}
		}
		
		updateHandPositionsForActivePlayer();

		d_deckDisplayPanel = new DeckDisplayPanel(d_playerDeck, d_infectionManager.getInfectionDeck(), d_infectionManager.getDiscardPile());
		d_deckDisplayPanel.setLocation(MENU_WIDTH,  MAP_HEIGHT - PLAYER_CARD_HEIGHT - 40);
		d_deckDisplayPanel.setSize(MAP_WIDTH, PLAYER_CARD_HEIGHT + 40);
		d_deckDisplayPanel.setVisible(false);
		d_contentPane.add(d_deckDisplayPanel, JLayeredPane.POPUP_LAYER);
		
		d_popupPanel = new PopupPanel(this);
		d_popupPanel.setLocation((MENU_WIDTH + MAP_WIDTH - POPUP_WIDTH) / 2, (MAP_HEIGHT - POPUP_HEIGHT) / 2);
		d_popupPanel.setSize(POPUP_WIDTH, POPUP_HEIGHT);
		d_popupPanel.setVisible(false);
		d_contentPane.add(d_popupPanel, JLayeredPane.MODAL_LAYER);
		
		d_instructionPanel = new InstructionPanel();
		d_instructionPanel.setLocation(0, 0);
		d_instructionPanel.setVisible(false);
		d_contentPane.add(d_instructionPanel, JLayeredPane.POPUP_LAYER);

		d_selectedCity = null;
		d_selectedCard = null;
		d_selectedCards = new ArrayList<PlayerCard>();
		d_selectedPlayer = null;
		d_nextState = GameInputState.SETUP;
		advanceGameState();
	}