00001
00002
00003
00004 #ifndef EVAL_ML_OPENMIDENDINGEVAL_H
00005 #define EVAL_ML_OPENMIDENDINGEVAL_H
00006
00007 #include "osl/eval/weights.h"
00008 #include "osl/eval/ptypeEval.h"
00009 #include "osl/eval/evalStagePair.h"
00010 #include "osl/eval/evalTraits.h"
00011 #include "osl/eval/ptypeEval.h"
00012 #include "osl/numEffectState.h"
00013 #include "osl/progress.h"
00014 #include "osl/bits/align16New.h"
00015 #include "osl/oslConfig.h"
00016 #include <cstring>
00017
00018 #define USE_TEST_PROGRESS
00019
00020 #define LEARN_TEST_PROGRESS
00021
00022 namespace osl
00023 {
00024 namespace eval
00025 {
00026 namespace ml
00027 {
00028 using namespace osl::progress::ml;
00029 class OpenMidEndingPtypeTable : public PtypeEvalTable
00030 {
00031 public:
00032 OpenMidEndingPtypeTable();
00033 };
00034
00035 struct OpenMidEndingEvalDebugInfo
00036 {
00037 enum StageFeature
00038 {
00039 KING_PIECE_RELATIVE,
00040 PIECE_STAND,
00041 KING25_EFFECT_EACH,
00042 PTYPEX,
00043 PTYPEY,
00044 ROOK_MOBILITY,
00045 BISHOP_MOBILITY,
00046 LANCE_MOBILITY,
00047 ROOK_EFFECT,
00048 BISHOP_EFFECT,
00049 PIECE_STAND_COMBINATION,
00050 PIECE_STAND_TURN,
00051 ROOK_PAWN,
00052 PAWN_DROP,
00053 PIECE_STAND_Y,
00054 KNIGHT_CHECK,
00055 PAWN_ADVANCE,
00056 PAWN_PTYPEO,
00057 PROMOTED_MINOR_PIECE,
00058 KING_PIECE_RELATIVE_NOSUPPORT,
00059 NON_PAWN_ATTACKED,
00060 NON_PAWN_ATTACKED_PTYPE,
00061 PTYPE_YY,
00062 KING3PIECES,
00063 BISHOP_HEAD,
00064 KNIGHT_HEAD,
00065 ROOK_PROMOTE_DEFENSE,
00066 PTYPE_COUNT,
00067 LANCE_EFFECT_PIECE,
00068 PTYPE_Y_PAWN_Y,
00069 BISHOP_AND_KING,
00070 PIECE_FORK_TURN,
00071 ROOK_SILVER_KNIGHT,
00072 BISHOP_SILVER_KNIGHT,
00073 KING25_EFFECT_SUPPORTED,
00074 KING_ROOK_BISHOP,
00075 KING_X_BLOCKED3,
00076 GOLD_RETREAT,
00077 SILVER_RETREAT,
00078 ALL_GOLD,
00079 ALL_MAJOR,
00080 KING25_EFFECT_DEFENSE,
00081 ANAGUMA_EMPTY,
00082 NO_PAWN_ON_STAND,
00083 NON_PAWN_PIECE_STAND,
00084 PIN_PTYPE_ALL,
00085 KING_MOBILITY,
00086 GOLD_AND_SILVER_NEAR_KING,
00087 PTYPE_COMBINATION,
00088 KING25_BOTH_SIDE,
00089 KING25_MOBILITY,
00090 BISHOP_STAND_FILE5,
00091 MAJOR_CHECK_WITH_CAPTURE,
00092 SILVER_ADVANCE26,
00093 KING25_EFFECT3,
00094 BISHOP_BISHOP_PIECE,
00095 ROOK_ROOK,
00096 ROOK_ROOK_PIECE,
00097 KING25_EFFECT_COUNT_COMBINATION,
00098 NON_PAWN_ATTACKED_PTYPE_PAIR,
00099 ATTACK_MAJORS_IN_BASE,
00100 STAGE_FEATURE_LIMIT
00101 };
00102 enum ProgressIndependentFeature
00103 {
00104 PIECE,
00105 BISHOP_EXCHANGE_SILVER_KING,
00106 ENTER_KING_DEFENSE,
00107 KING25_EFFECT_ATTACK,
00108 PIECE_PAIR,
00109 PIECE_PAIR_KING,
00110 PROGRESS_INDEPENDENT_FEATURE_LIMIT
00111 };
00112 int value;
00113 int progress;
00114 CArray<int, PROGRESS_INDEPENDENT_FEATURE_LIMIT> progress_independent_values;
00115 CArray<MultiInt, STAGE_FEATURE_LIMIT> stage_values;
00116
00117 static const char *name(ProgressIndependentFeature);
00118 static const char *name(StageFeature);
00119 };
00120
00121 class OpenMidEndingEval
00122 #if OSL_WORDSIZE == 32
00123 : public misc::Align16New
00124 #endif
00125 {
00126 private:
00127 enum { INVALID=EvalTraits<BLACK>::MAX_VALUE+1 };
00128 enum {
00130 ProgressIndependentValueLimit = 4000
00131 };
00132 enum LoadStatus { Zero=0, Loaded, Random };
00133 static volatile LoadStatus initialized_flag;
00134 static Weights piece_pair_weights;
00135 typedef osl::progress::ml::NewProgress progress_t;
00136 progress_t progress;
00137 MultiIntPair kingx_blocked, king25_effect_each;
00138 MultiIntPair king25_both_side,king_rook_bishop;
00139 MultiIntPair piece_stand_turn, non_pawn_attacked,
00140 non_pawn_attacked_ptype, piece_fork_turn;
00141 MultiInt ptypey, ptypex, king_table_value;
00142 MultiInt piece_stand_value, recalculated_stage_value, pawn_advance;
00143 MultiInt rook_mobility, bishop_mobility, lance_mobility;
00144 MultiInt knight_advance, pawn_drop, promoted_minor_piece, rook_pawn,
00145 rook_effect, bishop_effect, bishop_head, nosupport, ptype_yy, king3pieces;
00146 MultiInt rook_promote_defense;
00147 MultiInt piece_stand_combination, piece_stand_y, knight_check,
00148 knight_head, pawn_ptypeo, ptype_count_value, lance_effect_piece,
00149 ptype_y_pawn_y, bishop_and_king, rook_silver_knight, bishop_silver_knight;
00150 CArray<BoardMask, 2> knight_fork_squares;
00151 CArray<PieceMask, 2> effect25;
00152 CArray<PieceMask, 2> effect25_supported;
00153 CArray<PieceMask, 2> effected_mask;
00154 CArray<PieceMask, 2> effected_mask_for_attacked;
00155 CArray<PieceMask, 40> attacked_mask;
00156 CArray<int, 5> black_vertical, white_vertical,
00157 black_king_vertical, white_king_vertical;
00158
00159 CArray<int,2> piece_pair_king_value;
00160 CArray<int, 2> non_pawn_stand_count;
00161 CArray2d<int, 2, 3> gs_near_king_count;
00162 CArray2d<int, 2, PTYPE_SIZE> ptype_count, ptype_board_count;
00163 CArray<std::pair<Square,int>, 2> knight_drop, silver_drop, bishop_drop, rook_drop;
00164 CArray2d<int, 2, 9> pawns;
00165 int progress_independent_value,
00166 recalculated_value, piece_pair_value;
00167 int black_pawn_count;
00168 int black_major_count, black_gold_count;
00169 int black_attack_effect, black_attack_piece,
00170 white_attack_effect, white_attack_piece,
00171 black_attack_supported_piece, white_attack_supported_piece;
00172 int black_defense_effect, black_defense_piece,
00173 white_defense_effect, white_defense_piece;
00174 mutable int cache;
00175 Player turn;
00176 unsigned int ptypeo_mask;
00177 CArray<bool, 2> can_check;
00178 bool use_progress_independent_value_limit;
00179 static const int ROUND_UP = 2;
00180 static int roundUp(int v)
00181 {
00182 return v & (~(ROUND_UP-1));
00183 }
00184 void updateGoldSilverNearKing(const NumEffectState &state)
00185 {
00186 const CArray<Square,2> kings = {{
00187 state.kingSquare(BLACK),
00188 state.kingSquare(WHITE),
00189 }};
00190 gs_near_king_count.fill(0);
00191 for (int i = PtypeTraits<GOLD>::indexMin;
00192 i < PtypeTraits<GOLD>::indexLimit; ++i)
00193 {
00194 const Piece p = state.pieceOf(i);
00195 if (p.isOnBoard())
00196 {
00197 const Square pos = p.square();
00198 const int y_diff = std::abs(pos.y() - kings[p.owner()].y());
00199 const int x_diff = std::abs(pos.x() - kings[p.owner()].x());
00200 if (y_diff <= 2 && x_diff <= 3)
00201 {
00202 ++gs_near_king_count[p.owner()][std::max(x_diff, y_diff) - 1];
00203 }
00204 }
00205 }
00206 for (int i = PtypeTraits<SILVER>::indexMin;
00207 i < PtypeTraits<SILVER>::indexLimit; ++i)
00208 {
00209 const Piece p = state.pieceOf(i);
00210 if (p.isOnBoard())
00211 {
00212 const Square pos = p.square();
00213 const int y_diff = std::abs(pos.y() - kings[p.owner()].y());
00214 const int x_diff = std::abs(pos.x() - kings[p.owner()].x());
00215 if (y_diff <= 2 && x_diff <= 3)
00216 {
00217 ++gs_near_king_count[p.owner()][std::max(x_diff, y_diff) - 1];
00218 }
00219 }
00220 }
00221 }
00222 public:
00223 explicit OpenMidEndingEval
00224 (const NumEffectState &state=NumEffectState(),
00225 bool limit_progress_independent_value=! OslConfig::hasByoyomi());
00226 OpenMidEndingEval& operator=(const OpenMidEndingEval& src)
00227 {
00228 if (this != &src)
00229 memcpy(this, &src, sizeof(OpenMidEndingEval));
00230 return *this;
00231 }
00232 void changeTurn() { }
00233 static bool initialized()
00234 {
00235 return initialized_flag;
00236 }
00237 static bool setUp(const char *filename);
00238 static bool setUp();
00239 static std::string defaultFilename();
00240 int progressIndependentValue() const
00241 {
00242 return progress_independent_value + recalculated_value + piece_pair_value
00243 + piece_pair_king_value[BLACK] + piece_pair_king_value[WHITE];
00244 }
00245 void debug() const;
00246 MultiInt stageValue() const
00247 {
00248 return king_table_value + piece_stand_value +
00249 king25_effect_each[BLACK] + king25_effect_each[WHITE] +
00250 ptypex + ptypey + rook_mobility + bishop_mobility + lance_mobility +
00251 rook_effect + bishop_effect +
00252 piece_stand_combination + piece_stand_turn[turn] +
00253 rook_pawn + pawn_drop + piece_stand_y + knight_check +
00254 pawn_advance + pawn_ptypeo + promoted_minor_piece +
00255 nosupport +
00256 non_pawn_attacked[turn] + non_pawn_attacked_ptype[turn] +
00257 ptype_yy + king3pieces + bishop_head + knight_head
00258 + rook_promote_defense +
00259 ptype_count_value + lance_effect_piece + ptype_y_pawn_y +
00260 bishop_and_king + piece_fork_turn[turn] + rook_silver_knight + bishop_silver_knight +
00261 recalculated_stage_value;
00262 }
00263 int openingValue() const
00264 {
00265 return stageValue()[0];
00266 }
00267 int midgameValue() const
00268 {
00269 return stageValue()[1];
00270 }
00271 int midgame2Value() const
00272 {
00273 return stageValue()[2];
00274 }
00275 int endgameValue() const
00276 {
00277 return stageValue()[EndgameIndex];
00278 }
00279 void invalidateCache() { cache=INVALID; }
00280 static int progressIndependentValueAdjusted(int value, int progress,
00281 int progress_max)
00282 {
00283 if (value > ProgressIndependentValueLimit) {
00284 int diff = value - ProgressIndependentValueLimit;
00285 value = ProgressIndependentValueLimit
00286 + diff * progress/progress_max;
00287 }
00288 else if (value < -ProgressIndependentValueLimit) {
00289 int diff = value + ProgressIndependentValueLimit;
00290 value = -ProgressIndependentValueLimit
00291 + diff * progress/progress_max;
00292 }
00293 return value;
00294 }
00295 int composeOpenMidEndgame() const
00296 {
00297 const int progress_max = NewProgress::maxProgress(), c = progress_max/2;
00298 const int progress = this->progress.progress();
00299 int progress_independent = use_progress_independent_value_limit
00300 ? progressIndependentValueAdjusted
00301 (progressIndependentValue(), progress, progress_max)
00302 : progressIndependentValue();
00303 int sum = progress_independent * progress_max;
00304 if (progress < c)
00305 {
00306 sum += openingValue() * 2*(c - progress);
00307 sum += midgameValue() * 2*progress;
00308 }
00309 else
00310 {
00311 sum += midgameValue() * 2*(progress_max - progress);
00312 sum += endgameValue() * 2*(progress - c);
00313 }
00314 return sum;
00315 }
00316 #ifdef EVAL_QUAD
00317 int composeOpenMid2Endgame() const
00318 {
00319 const int progress_max = NewProgress::maxProgress();
00320 const int progress = this->progress.progress();
00321 const int c0 = progress_max/3, c1 = c0*2;
00322 #ifndef NDEBUG
00323 const int w2 = progress_max - c1;
00324 #endif
00325 assert(c0 == w2);
00326 int progress_independent = use_progress_independent_value_limit
00327 ? progressIndependentValueAdjusted
00328 (progressIndependentValue(), progress, progress_max)
00329 : progressIndependentValue();
00330 int sum = progress_independent * c0;
00331 const MultiInt stage_sum = stageValue();
00332 if (progress < c0)
00333 {
00334 sum += stage_sum[0] * (c0 - progress);
00335 sum += stage_sum[1] * progress;
00336 }
00337 else if (progress < c1)
00338 {
00339 sum += stage_sum[1] * (c1 - progress);
00340 sum += stage_sum[2] * (progress-c0);
00341 }
00342 else
00343 {
00344 sum += stage_sum[2] * (progress_max - progress);
00345 sum += stage_sum[3] * (progress - c1);
00346 }
00347 return sum;
00348 }
00349 #endif
00350 int value() const
00351 {
00352 if (cache==INVALID)
00353 {
00354 #ifdef EVAL_QUAD
00355 cache = roundUp(composeOpenMid2Endgame());
00356 #else
00357 cache = roundUp(composeOpenMidEndgame());
00358 #endif
00359 }
00360 return cache;
00361 }
00362 const Move suggestMove(const NumEffectState& state) const
00363 {
00364 assert(turn == state.turn());
00365 Move suggest;
00366 int best_value = 0;
00367 if (! rook_drop[turn].first.isPieceStand()) {
00368 assert(state.hasPieceOnStand(turn, ROOK));
00369 suggest = Move(rook_drop[turn].first, ROOK, turn);
00370 best_value = rook_drop[turn].second;
00371 }
00372 assert(best_value >= 0);
00373 if (bishop_drop[turn].second > best_value) {
00374 assert(! bishop_drop[turn].first.isPieceStand());
00375 assert(state.hasPieceOnStand(turn, BISHOP));
00376 suggest = Move(bishop_drop[turn].first, BISHOP, turn);
00377 best_value = bishop_drop[turn].second;
00378 }
00379 if (silver_drop[turn].second > best_value) {
00380 assert(! silver_drop[turn].first.isPieceStand());
00381 assert(state.hasPieceOnStand(turn, SILVER));
00382 suggest = Move(silver_drop[turn].first, SILVER, turn);
00383 best_value = silver_drop[turn].second;
00384 }
00385 if (knight_drop[turn].second > best_value
00386 && state.hasPieceOnStand(turn, KNIGHT)) {
00387 assert(! knight_drop[turn].first.isPieceStand());
00388 suggest = Move(knight_drop[turn].first, KNIGHT, turn);
00389 best_value = knight_drop[turn].second;
00390 }
00391 return suggest;
00392 }
00393 int expect(const NumEffectState &state, Move move) const;
00394 template<Player P>
00395 void updateSub(const NumEffectState &new_state, Move last_move);
00396 void update(const NumEffectState &new_state, Move last_move);
00397 const Progress32 progress32() const
00398 {
00399 return Progress32(progress.progress16(BLACK).value()
00400 + progress.progress16(WHITE).value());
00401 }
00402 const Progress16 progress16() const { return progress.progress16(); }
00403 int progressValue() const { return progress.progress(); }
00404 int progressMax() const { return progress.maxProgress(); }
00405 public:
00406 static int infty()
00407 {
00408 #ifdef EVAL_QUAD
00409 assert(NewProgress::maxProgress() % 3 == 0);
00410 return 57984 * (NewProgress::maxProgress()/3);
00411 #else
00412 return 57984 * NewProgress::maxProgress();
00413 #endif
00414 }
00415 static int captureValue(PtypeO ptypeO) {
00416 assert(isValidPtypeO(ptypeO));
00417 return roundUp((-PieceEval::value(ptypeO) +
00418 PieceEval::value(captured(ptypeO))) * seeScale());
00419 }
00420 static int seeScale() {
00421 #ifdef EVAL_QUAD
00422 assert(NewProgress::maxProgress() % 3 == 0);
00423 return (NewProgress::maxProgress()/3);
00424 #else
00425 return NewProgress::maxProgress();
00426 #endif
00427 }
00428
00429 OpenMidEndingEvalDebugInfo debugInfo(const NumEffectState &state);
00430 static void setRandom();
00431 static void resetWeights(const int *w, size_t length);
00432 static OpenMidEndingPtypeTable Piece_Value;
00433 bool progressIndependentValueLimit() const {
00434 return use_progress_independent_value_limit;
00435 }
00436 private:
00437 template <class Reader>
00438 static void doResetWeights(Reader& reader);
00439 };
00440 }
00441 using ml::OpenMidEndingEval;
00442 }
00443 using eval::OpenMidEndingEval;
00444 }
00445
00446 #endif // EVAL_ML_OPENMIDENDINGEVAL_H
00447
00448
00449
00450
00451