00001
00021 #include "osl/search/quiescenceSearch2.h"
00022 #include "osl/search/quiescenceSearch2.tcc"
00023 #include "osl/search/simpleHashTable.h"
00024 #include "osl/checkmate/dualDfpn.h"
00025 #include "osl/state/numEffectState.h"
00026 #include "osl/record/csaString.h"
00027 #include "osl/record/csaRecord.h"
00028 #include "osl/eval/progressEval.h"
00029 #include "osl/apply_move/applyMove.h"
00030 #include "osl/stat/average.h"
00031
00032 #include "osl/stl/slist.h"
00033 #include <iostream>
00034 #include <cstdio>
00035 #include <fstream>
00036 #include <cstdlib>
00037
00038 using namespace osl;
00039 using namespace osl::search;
00040 using namespace osl::misc;
00041
00042 void qsearch(const char *filename);
00043
00044 void usage(const char *program_name)
00045 {
00046 std::cerr << program_name << " [-d depth] [-s skip] [-v] csafiles\n";
00047 exit(1);
00048 }
00049
00050 int record_depth = -6;
00051 bool verbose = false;
00052 size_t skip_first = 0;
00053 int center = 0;
00054
00055 int main(int argc, char **argv)
00056 {
00057 const char *program_name = argv[0];
00058 bool error_flag = false;
00059
00060 extern char *optarg;
00061 extern int optind;
00062 char c;
00063 while ((c = getopt(argc, argv, "c:d:s:vh")) != EOF)
00064 {
00065 switch(c)
00066 {
00067 case 'c': center = atoi(optarg);
00068 break;
00069 case 'd': record_depth = atoi(optarg);
00070 break;
00071 case 's': skip_first = atoi(optarg);
00072 break;
00073 case 'v': verbose = true;
00074 break;
00075 default: error_flag = true;
00076 }
00077 }
00078 argc -= optind;
00079 argv += optind;
00080
00081 if (error_flag || (argc < 1))
00082 usage(program_name);
00083
00084 std::cerr << "using table record depth " << record_depth << "\n";
00085 try
00086 {
00087 for (int i=0; i<argc; ++i)
00088 {
00089 qsearch(argv[i]);
00090 }
00091 }
00092 catch (std::exception& e)
00093 {
00094 std::cerr << e.what() << "\n";
00095 return 1;
00096 }
00097 catch (...)
00098 {
00099 throw;
00100 }
00101 }
00102
00103 typedef SearchState2Core::checkmate_t checkmate_t;
00104 typedef QuiescenceSearch2<eval::ProgressEval> qsearch_t;
00105 typedef qsearch_t::eval_t eval_t;
00106
00107 class Searcher
00108 {
00109 protected:
00110 stat::Average width, nodes, diff, accuracy;
00111 qsearch_t **searcher;
00112 eval_t& eval;
00113 public:
00114 Searcher(qsearch_t **q, eval_t& e) : searcher(q), eval(e)
00115 {
00116 }
00117 virtual ~Searcher()
00118 {
00119 }
00120 virtual const std::string name() const=0;
00121 virtual const std::pair<int,int> alphaBeta(Player turn,
00122 int pawn_value, int real_value) const=0;
00126 virtual int search(Player turn, int pawn_value, int real_value,
00127 Move last_move)=0;
00128 protected:
00129 const std::pair<int,int>
00130 count(Player turn, int alpha, int beta, Move last_move)
00131 {
00132 width.add(abs(alpha-beta));
00133 alpha = eval::max(turn, alpha, FixedEval::winThreshold(alt(turn)));
00134 beta = eval::max(alt(turn), beta, FixedEval::winThreshold(turn));
00135 const int before = (*searcher)->nodeCount();
00136 int result;
00137 if (turn == BLACK)
00138 result = (*searcher)->search<BLACK>(alpha, beta, eval, last_move);
00139 else
00140 result = (*searcher)->search<WHITE>(alpha, beta, eval, last_move);
00141 const int after = (*searcher)->nodeCount();
00142 return std::make_pair(after - before, result);
00143 }
00144 public:
00145 void report() const
00146 {
00147 const std::string n = name();
00148 fprintf(stderr, "%s\t%8.3f\t%8.3f\t%10.3f\t%8.3f\n",
00149 n.c_str(), width.getAverage(), nodes.getAverage(),
00150 diff.getAverage(), accuracy.getAverage());
00151 };
00152 };
00153
00154 class NormalSearcher : public Searcher
00155 {
00156 public:
00157 NormalSearcher(qsearch_t **q, eval_t& e) : Searcher(q,e)
00158 {
00159 }
00163 int search(Player turn, int pawn_value, int real_value,
00164 Move last_move)
00165 {
00166 const std::pair<int,int> alpha_beta = alphaBeta(turn, pawn_value, real_value);
00167 const std::pair<int,int> node_result
00168 = count(turn, alpha_beta.first, alpha_beta.second, last_move);
00169
00170 nodes.add(node_result.first);
00171 diff.add(abs(real_value - node_result.second));
00172 accuracy.add(real_value == node_result.second);
00173 return node_result.second;
00174 }
00175 };
00176
00177 class FullWidth : public NormalSearcher
00178 {
00179 public:
00180 FullWidth(qsearch_t **q, eval_t& e) : NormalSearcher(q, e)
00181 {
00182 }
00183 const std::string name() const { return "full width"; }
00184 const std::pair<int,int> alphaBeta(Player turn, int , int ) const
00185 {
00186 const int alpha = FixedEval::winThreshold(alt(turn));
00187 const int beta = FixedEval::winThreshold(turn);
00188 return std::make_pair(alpha, beta);
00189 }
00190 };
00191
00195 class FixedRange : public NormalSearcher
00196 {
00197 protected:
00198 int divider;
00199 public:
00200 FixedRange(qsearch_t **q, eval_t& e, int d) : NormalSearcher(q,e), divider(d)
00201 {
00202 }
00203 virtual int center(int real_value) const=0;
00204 int halfRange(int pawn_value) const
00205 {
00206 return pawn_value/divider;
00207 }
00208 const std::pair<int,int> alphaBeta(Player turn, int pawn_value, int real_value) const
00209 {
00210 const int center=this->center(real_value);
00211 const int half_range=halfRange(pawn_value);
00212 const int alpha = center - half_range + eval::delta(turn);
00213 const int beta = center + half_range - eval::delta(turn);
00214 return std::make_pair(alpha, beta);
00215 }
00216 };
00217
00218 const std::string tos(int val)
00219 {
00220 assert(val < 100);
00221 assert(val >= 0);
00222 std::string result = "00";
00223 sprintf(&result[0], "%d", val);
00224 return result;
00225 }
00226
00227 class FixedCenter : public FixedRange
00228 {
00229 protected:
00230 const int center_value;
00231 public:
00232 FixedCenter(qsearch_t **q, eval_t& e, int d, int c)
00233 : FixedRange(q, e, d), center_value(c)
00234 {
00235 }
00236 int center(int ) const
00237 {
00238 return center_value;
00239 }
00240 const std::string name() const {
00241 return "fixedcenter" + tos(center_value) +"/"+ tos(divider);
00242 }
00243 };
00244
00245 class AccurateCenter : public FixedRange
00246 {
00247 public:
00248 AccurateCenter(qsearch_t **q, eval_t& e, int d)
00249 : FixedRange(q, e, d)
00250 {
00251 }
00252 int center(int real_value) const { return real_value; }
00253 const std::string name() const {
00254 return "acc_center" + tos(divider);
00255 }
00256 };
00257
00258 class RootCenter : public FixedRange
00259 {
00260 public:
00261 RootCenter(qsearch_t **q, eval_t& e, int d)
00262 : FixedRange(q, e, d)
00263 {
00264 }
00265 int center(int ) const { return eval.value(); }
00266 const std::string name() const {
00267 return "root_center" + tos(divider);
00268 }
00269 };
00270
00274 class ExtendToCenter : public FixedCenter
00275 {
00276 const int extend_multiplier;
00277 public:
00278 ExtendToCenter(qsearch_t **q, eval_t& e, int range_d, int c,
00279 int extend_m)
00280 : FixedCenter(q, e, range_d, c), extend_multiplier(extend_m)
00281 {
00282 }
00283 const std::string name() const {
00284 return "extend2c" + tos(divider) + tos(extend_multiplier);
00285 }
00286 const std::pair<int,int> alphaBeta(Player turn, int pawn_value, int real_value) const
00287 {
00288 const int root_value = eval.value();
00289 const int extend_range = pawn_value * extend_multiplier;
00290 const std::pair<int,int> alpha_beta
00291 = FixedCenter::alphaBeta(turn, pawn_value, real_value);
00292 const int delta = eval::delta(turn);
00293 int alpha = alpha_beta.first;
00294 int beta = alpha_beta.second;
00295
00296 if (eval::betterThan(turn, center(real_value), root_value))
00297 {
00298 alpha = eval::min(turn, root_value+extend_range-delta, alpha);
00299 }
00300 else
00301 {
00302 beta = eval::max(turn, root_value-extend_range+delta, beta);
00303 }
00304 return std::make_pair(alpha, beta);
00305 }
00306 };
00307
00312 class ExtendToCenterModest : public FixedCenter
00313 {
00314 const int extend_multiplier;
00315 public:
00316 ExtendToCenterModest(qsearch_t **q, eval_t& e, int range_d, int c,
00317 int extend_m)
00318 : FixedCenter(q, e, range_d, c), extend_multiplier(extend_m)
00319 {
00320 }
00321 const std::string name() const {
00322 return "extend2cm" + tos(divider) + tos(extend_multiplier);
00323 }
00324 const std::pair<int,int> alphaBeta(Player turn, int pawn_value, int real_value) const
00325 {
00326 const int root_value = eval.value();
00327 const int extend_range = pawn_value * extend_multiplier;
00328 const int center=this->center(real_value);
00329 const int half_range=halfRange(pawn_value);
00330 const int delta = eval::delta(turn);
00331
00332 int alpha = center - half_range - delta;
00333 int beta = center + half_range + delta;
00334 if (eval::betterThan(turn, center, root_value))
00335 {
00336 alpha = eval::min(turn, root_value+extend_range-delta,
00337 center - half_range/2 - delta);
00338 }
00339 else
00340 {
00341 beta = eval::max(turn, root_value-extend_range+delta,
00342 center + half_range/2 + delta);
00343 }
00344 return std::make_pair(alpha, beta);
00345 }
00346 };
00347
00351 class ExtendToOther : public FixedCenter
00352 {
00353 static const int extend_multiplier=2;
00354 public:
00355 ExtendToOther(qsearch_t **q, eval_t& e, int range_d, int c)
00356 : FixedCenter(q, e, range_d, c)
00357 {
00358 }
00359 const std::string name() const {
00360 return "extend2o" + tos(divider) + tos(extend_multiplier);
00361 }
00362 const std::pair<int,int> alphaBeta(Player turn, int pawn_value, int real_value) const
00363 {
00364 const int root_value = eval.value();
00365 const int center=this->center(real_value);
00366 const int half_range=halfRange(pawn_value);
00367
00368 int alpha = center - half_range - eval::delta(turn);
00369 int beta = center + half_range + eval::delta(turn);
00370 if (eval::betterThan(turn, center, root_value))
00371 {
00372 beta = center + half_range*extend_multiplier + eval::delta(turn);
00373 }
00374 else
00375 {
00376 alpha = center - half_range*extend_multiplier - eval::delta(turn);
00377 }
00378 return std::make_pair(alpha, beta);
00379 }
00380 };
00381
00382 class Analyzer
00383 {
00384 size_t records;
00385 NumEffectState state;
00386 eval_t ev;
00387 checkmate_t checkmate;
00388 SimpleHashTable table;
00389 qsearch_t *qs;
00390 FullWidth full_searcher;
00391 typedef slist<Searcher*> list_t;
00392 list_t searchers;
00393 public:
00394 Analyzer() : records(0), state(SimpleState(HIRATE)), ev(state),
00395 table(100000,record_depth,verbose),
00396 full_searcher(&qs, ev)
00397 {
00398 searchers.push_front(new AccurateCenter(&qs, ev, 2));
00399 searchers.push_front(new AccurateCenter(&qs, ev, 4));
00400 searchers.push_front(new RootCenter(&qs, ev, 2));
00401 searchers.push_front(new RootCenter(&qs, ev, 4));
00402 searchers.push_front(new RootCenter(&qs, ev, 8));
00403 searchers.push_front(new RootCenter(&qs, ev, 16));
00404
00405 searchers.push_front(new FixedCenter(&qs, ev, 2, center));
00406 #if 0
00407 searchers.push_front(new ExtendToCenter(&qs, ev, 2, center, 4));
00408 searchers.push_front(new ExtendToCenterModest(&qs, ev, 2, center, 4));
00409 searchers.push_front(new ExtendToCenter(&qs, ev, 2, center, 8));
00410 searchers.push_front(new ExtendToCenterModest(&qs, ev, 2, center, 8));
00411 searchers.push_front(new ExtendToOther(&qs, ev, 2, center));
00412 #endif
00413 searchers.push_front(new FixedCenter(&qs, ev, 4, center));
00414 #if 0
00415 searchers.push_front(new ExtendToCenter(&qs, ev, 4, center, 4));
00416 searchers.push_front(new ExtendToCenterModest(&qs, ev, 4, center, 4));
00417 #endif
00418 searchers.push_front(new ExtendToCenter(&qs, ev, 4, center, 6));
00419 searchers.push_front(new ExtendToCenterModest(&qs, ev, 4, center, 6));
00420 #if 0
00421 searchers.push_front(new ExtendToCenter(&qs, ev, 4, center, 8));
00422 searchers.push_front(new ExtendToCenterModest(&qs, ev, 4, center, 8));
00423 searchers.push_front(new ExtendToOther(&qs, ev, 4, center));
00424 #endif
00425 searchers.push_front(new FixedCenter(&qs, ev, 8, center));
00426 searchers.push_front(new ExtendToCenter(&qs, ev, 8, center, 4));
00427 searchers.push_front(new ExtendToCenterModest(&qs, ev, 8, center, 4));
00428 #if 0
00429 searchers.push_front(new ExtendToCenter(&qs, ev, 8, center, 6));
00430 searchers.push_front(new ExtendToCenterModest(&qs, ev, 8, center, 6));
00431 searchers.push_front(new ExtendToCenter(&qs, ev, 8, center, 8));
00432 searchers.push_front(new ExtendToCenterModest(&qs, ev, 8, center, 8));
00433 searchers.push_front(new ExtendToOther(&qs, ev, 8, center));
00434 #endif
00435 searchers.reverse();
00436 }
00437 void report() const
00438 {
00439 std::cerr << "\nrecords " << records << "\n";
00440 full_searcher.report();
00441 for (list_t::const_iterator p=searchers.begin(); p!=searchers.end(); ++p)
00442 {
00443 (*p)->report();
00444 }
00445 }
00446 void search(size_t i, Move last_move)
00447 {
00448 SearchState2Core core(state, checkmate);
00449 qsearch_t searcher(core, table);
00450 qs = &searcher;
00451 const Player turn = state.getTurn();
00452 const int pawn_value
00453 = qsearch_t::eval_t::captureValue(newPtypeO(alt(turn),PAWN));
00454 if (verbose)
00455 std::cerr << i << " " << record::csa::show(last_move) << "\n";
00456
00457 table.clear();
00458 const int real_value_dummy = 0;
00459 const int real_value
00460 = full_searcher.search(turn, pawn_value, real_value_dummy, last_move);
00461
00462 for (list_t::iterator p=searchers.begin(); p!=searchers.end(); ++p)
00463 {
00464 table.clear();
00465 (*p)->search(turn, pawn_value, real_value, last_move);
00466 }
00467 }
00468 void search(const char *filename)
00469 {
00470 Record rec=CsaFile(filename).getRecord();
00471 state = NumEffectState(rec.getInitialState());
00472 ev = eval_t(state);
00473 const vector<osl::Move> moves=rec.getMoves();
00474 size_t i=0;
00475 while (true)
00476 {
00477 if (i >= skip_first)
00478 {
00479 const Move last_move
00480 = (i > 0) ? moves[i-1] : Move::PASS(alt(moves[0].player()));
00481 search(i, last_move);
00482 }
00483 if (i >= moves.size())
00484 break;
00485 const Move move = moves[i++];
00486 ApplyMoveOfTurn::doMove(state, move);
00487 ev.update(state, move);
00488 }
00489 ++records;
00490 report();
00491 }
00492 };
00493
00494 Analyzer analyzer;
00495
00496 void qsearch(const char *filename)
00497 {
00498 analyzer.search(filename);
00499 }
00500
00501
00502
00503
00504
00505