I see a number of things that may help you improve your program.
Don't use auto_ptr
Since C++11, std::auto_ptr is deprecated and it will completely disappear in C++17. Anyway, in this particular case, it adds nothing but complication. Instead of this:
std::auto_ptr<RandomPlayer> r(new RandomPlayer( 'O' ) ); std::auto_ptr<HumanPlayer> h(new HumanPlayer( 'O' ) ); std::auto_ptr<CompPlayer> s(new CompPlayer( 'X' ) ); write this:
RandomPlayer r{'O'}; HumanPlayer h{'O'}; CompPlayer s{'X'}; Note that this uses the C++11 initialization syntax. If your compiler doesn't support that, my first advice would be to update the compiler. Only if that's not possible for some very compelling reason should you limit yourself to C++03 syntax.
Consider using a better random number generator
You are currently using
gameField[ v[ rand() % v.size() ] ] = symbol; There are two problems with this approach. One is that the low order bits of the random number generator are not particularly random, so neither is your result. On my machine, there's a slight but measurable bias toward 0 with that. The second problem is that unless RAND_MAX happens to be an integral multiple of v.size(), this will not result in a uniform distribution. A better solution, if your compiler and library supports it, would be to use the C++11 std::uniform_int_distribution.
Eliminate global variables where practical
The code declares and uses several global variables. Global variables obfuscate the actual dependencies within code and make maintainance and understanding of the code that much more difficult. It also makes the code harder to reuse. For all of these reasons, it's generally far preferable to eliminate global variables and to instead pass pointers to them. That way the linkage is explicit and may be altered more easily if needed. The constants are not so bad, but gameField really should be inside of main rather than global.
Use objects
The gameField has both data and logic associated with it. This strongly suggests an object. I'd propose something like this:
class GameField { public: enum OUTCOME { XS, OS, DRAW, UNFINISHED }; GameField::OUTCOME gameStatus() const; void print() const; void play(Player& xp, Player& op, bool verbose); bool move(int location, char symbol); bool occupied(int location) const; int firstFree() const; friend TField; private: char gameField[ 9 ]; }; Naturally, you'll have to also adjust places within the code which assume access to a global variable.
Use better variable names
The variable name gameField is good, but the name s is not. The first name explains something about what the variable means within the context of the code, but the latter is too short to convey much of anything.
Think about the user
It's not immediately obvious to the human player that the machine is expecting input, nor is it obvious that it numbers the squares starting with zero. A little explanatory message would be nice for the user.
Fix spelling errors
The code has WRandmomPolciy instead of RandomPolicy and LearningPolciy instead of LearningPolicy. These kinds of typos don't bother the compiler at all, but they will bother human readers of the code and make it a little more difficult to understand and maintain.
Don't use std::endl if you don't really need it
The difference betweeen std::endl and '\n' is that '\n' just emits a newline character, while std::endl actually flushes the stream. This can be time-consuming in a program with a lot of I/O and is rarely actually needed. It's best to only use std::endl when you have some good reason to flush the stream and it's not very often needed for simple programs such as this one. Avoiding the habit of using std::endl when '\n' will do will pay dividends in the future as you write more complex programs with more I/O and where performance needs to be maximized.
Omit return 0
When a C or C++ program reaches the end of main the compiler will automatically generate code to return 0, so there is no need to put return 0; explicitly at the end of main.
Note: when I make this suggestion, it's almost invariably followed by one of two kinds of comments: "I didn't know that." or "That's bad advice!" My rationale is that it's safe and useful to rely on compiler behavior explicitly supported by the standard. For C, since C99; see ISO/IEC 9899:1999 section 5.1.2.2.3:
[...] a return from the initial call to the
mainfunction is equivalent to calling theexitfunction with the value returned by themainfunction as its argument; reaching the}that terminates themainfunction returns a value of 0.
For C++, since the first standard in 1998; see ISO/IEC 14882:1998 section 3.6.1:
If control reaches the end of main without encountering a return statement, the effect is that of executing return 0;
All versions of both standards since then (C99 and C++98) have maintained the same idea. We rely on automatically generated member functions in C++, and few people write explicit return; statements at the end of a void function. Reasons against omitting seem to boil down to "it looks weird". If, like me, you're curious about the rationale for the change to the C standard read this question. Also note that in the early 1990s this was considered "sloppy practice" because it was undefined behavior (although widely supported) at the time.
So I advocate omitting it; others disagree (often vehemently!) In any case, if you encounter code that omits it, you'll know that it's explicitly supported by the standard and you'll know what it means.