private DecodeMoveReturnCode decodeMove(String moveString) {
        String[] maybeMoveDecoded = moveString.split(":");
        int index;
        char marker;

        // Ensure the length is correct
        if(maybeMoveDecoded.length != 2) {
            return DecodeMoveReturnCode.WRONG_FORMATTING;
        }

        // Ensure that we can decode the index
        try {
            index = Integer.parseInt(maybeMoveDecoded[0]);
        }
        catch(NumberFormatException e) {
            return DecodeMoveReturnCode.UNPARSABLE_INDEX;
        }

        // Ensure the index is in range
        if (index < 0 || index > gameString.length()) {
            return DecodeMoveReturnCode.INDEX_OUT_OF_RANGE;
        }

        // Ensure the index is not already taken
        if (gameString.charAt(index) != String.valueOf(index).charAt(0)) {
            return DecodeMoveReturnCode.INDEX_TAKEN;
        }
        // Index is good now
        // Ensure the marker is the correct length
        if (maybeMoveDecoded[1].length() != 1) {
            return DecodeMoveReturnCode.INVALID_MARKER_LENGTH;
        }

        marker = maybeMoveDecoded[1].charAt(0);

        // Ensure that the marker is an X or an O
        if (marker != 'X' && marker != 'O') {
            return DecodeMoveReturnCode.INVAILD_MARKER_TOKEN;
        }

        // Ensure that it is the proper marker's turn
        if (lastMarker == marker) {
            return DecodeMoveReturnCode.TWO_SEQUENTIAL_MOVES_WITH_SAME_TOKEN;
        }

        currentIndex = index;
        currentMarker = marker;

        return DecodeMoveReturnCode.OK;
    }