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""it looks weird". If, like me, you're curious about the rationale for the change to the C standard read this questionread 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.
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.
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.
Think about the cost of objects
The current code includes this object:
struct WRandmomPolciy { static int getMove(DataBaseType::iterator s) { const int sum = std::accumulate( s -> second.weight, s -> second.weight + 9, 0 ); if( sum == 0 ) return std::find( gameField, gameField + 9, ' ' ) - gameField; std::vector < int > coords; for( int i = 0; i < 9; ++i ) std::fill_n( std::back_inserter( coords ), precCoeff * s ->second.weight[ i ] / sum, i ); return coords[ rand() % coords.size()]; } }; The ultimate effect of this is to create a potentially huge vector just to select one entry and throw the rest away. This is a very inefficient way to do things, in addition to the problem with the random number mentioned earlier. The goal, as I understand it, is to select a move with a probability proportional to its weight. There's a very direct and efficient way to do that in C++11 using std::discrete_distribution
class SmartPolicy { public: int getMove(DataBaseType::iterator s) { const auto &w = s->second.weight; std::discrete_distribution<> dist(w.begin(), w.end()); return dist(gen); } private: std::mt19937 gen; } Note that in my version, TWeight is now a std::array<int, 9>.
Eliminate global variables where practical
Eliminate global variables where practical
Think about the cost of objects
The current code includes this object:
struct WRandmomPolciy { static int getMove(DataBaseType::iterator s) { const int sum = std::accumulate( s -> second.weight, s -> second.weight + 9, 0 ); if( sum == 0 ) return std::find( gameField, gameField + 9, ' ' ) - gameField; std::vector < int > coords; for( int i = 0; i < 9; ++i ) std::fill_n( std::back_inserter( coords ), precCoeff * s ->second.weight[ i ] / sum, i ); return coords[ rand() % coords.size()]; } }; The ultimate effect of this is to create a potentially huge vector just to select one entry and throw the rest away. This is a very inefficient way to do things, in addition to the problem with the random number mentioned earlier. The goal, as I understand it, is to select a move with a probability proportional to its weight. There's a very direct and efficient way to do that in C++11 using std::discrete_distribution
class SmartPolicy { public: int getMove(DataBaseType::iterator s) { const auto &w = s->second.weight; std::discrete_distribution<> dist(w.begin(), w.end()); return dist(gen); } private: std::mt19937 gen; } Note that in my version, TWeight is now a std::array<int, 9>.
Eliminate global variables where practical
Fix the bug
The code marks squares with uppercase letters, but the gameStatus code looks for a lowercase x. The result is that the computer incorrectly concludes that O always wins, which obviously throws off the training a bit. That could have been avoided by following the next suggestion.
Eliminate "magic numbers"
Instead of using 'X' and ' ' and 'O' everywhere, create and use three named constants. Similarly, the number 9 occurs many places and could also be a named constant instead.
Don't use auto_ptr
Don't use auto_ptr
Fix the bug
The code marks squares with uppercase letters, but the gameStatus code looks for a lowercase x. The result is that the computer incorrectly concludes that O always wins, which obviously throws off the training a bit. That could have been avoided by following the next suggestion.
Eliminate "magic numbers"
Instead of using 'X' and ' ' and 'O' everywhere, create and use three named constants. Similarly, the number 9 occurs many places and could also be a named constant instead.