@Override
    public void run() {
        //get the socket's output stream for writing
        try {
            writer = new PrintStream(socket.getOutputStream());
        } catch(IOException e) {
            System.err.println("Error getting writer: " + e);
        }
        
        //get the socket's input stream for reading
        try {
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));    
        } catch(IOException e) {
            System.err.println("Error getting reader: " + e);
        }
        
        //get the game data shared singleton to ensure that the game data tree is constructed before beginning and set currentNode to the root of the tree
        currentNode = GameData.getInstance().getRoot();
        
        //ask for the user's username
        try {
            write(script.get("name"));
            username = read();
        } catch(SocketTimeoutException e) {
            System.err.println("Socket timeout: " + e);
        }
        
        //gameplay loop
        while(true) {
            //check for a quit signal
            try {
                if(makeAMove() == Response.QUIT) {
                    break;
                }
            } catch(SocketTimeoutException e) {
                System.err.println("Socket timeout: " + e);
            }
        }
        
        //close the reader and writer
        try{
            reader.close();
            writer.close();            
        } catch(IOException e) {
            System.err.println("Error closing reader or writer: " + e);
        }
    }