00001 #include "osl/checkmate/dfpn.h"
00002 #include "osl/checkmate/dfpnParallel.h"
00003 #include "osl/record/csaString.h"
00004 #include "osl/record/csaRecord.h"
00005 #include "osl/record/csaIOError.h"
00006 #include "osl/state/numEffectState.h"
00007 #include "osl/misc/perfmon.h"
00008 #include "osl/misc/milliSeconds.h"
00009
00010 #include "osl/move_generator/legalMoves.h"
00011 #include "osl/checkmate/dfpnRecord.h"
00012 #include "osl/hash/hashRandomPair.h"
00013 #include "osl/oslConfig.h"
00014
00015 #include <boost/scoped_ptr.hpp>
00016 #include <boost/foreach.hpp>
00017 #include <string>
00018 #include <iostream>
00019 #include <iomanip>
00020 #include <fstream>
00021 #include <cstdlib>
00022 #include <unistd.h>
00023
00024 #include <bitset>
00025
00026 using namespace osl;
00027 using namespace osl::checkmate;
00028 using namespace osl::misc;
00029
00030 unsigned int dovetailing_seed = 0;
00031 unsigned int dovetailing_prob = 0;
00032
00033 bool verbose=false;
00034 unsigned long long total_cycles=0;
00035 bool show_escape_filename = false;
00036 bool force_attack = false;
00037 int num_checkmate=0, num_nocheckmate=0, num_escape=0, num_unkown=0;
00038 double total_nodes=0, total_tables=0;
00039 int limit = 100000;
00040 bool blocking_verify = true;
00041 size_t table_growth_limit = 8000000;
00042 bool debug = false;
00043 int forward_moves = 0;
00044
00045 template<class DfpnSearch>
00046 void search(DfpnSearch&, const char *filename);
00047 void usage(const char *program_name)
00048 {
00049 std::cerr << "usage: " << program_name << " [-d] [-v] [-f] [-l limit] [-N] csa-files\n";
00050 }
00051 int main(int argc, char **argv)
00052 {
00053 const char *program_name = argv[0];
00054 bool error_flag = false;
00055 int parallel = 0;
00056 extern char *optarg;
00057 extern int optind;
00058
00059 char c;
00060 while ((c = getopt(argc, argv, "dfl:N:F:s:p:t:vh")) != EOF)
00061 {
00062 switch(c)
00063 {
00064 case 's': dovetailing_seed = static_cast<unsigned int>(atoi(optarg));
00065 break;
00066 case 'p': dovetailing_prob = static_cast<unsigned int>(atoi(optarg));
00067 break;
00068 case 'd': debug = true;
00069 break;
00070 case 'f': force_attack = true;
00071 break;
00072 case 'F': forward_moves = atoi(optarg);
00073 break;
00074 case 'l': limit = atoi(optarg);
00075 break;
00076 case 'N': parallel = atoi(optarg);
00077 break;
00078 case 't': table_growth_limit = atoi(optarg);
00079 break;
00080 #if 0
00081 case 'V': blocking_verify = false;
00082 break;
00083 #endif
00084 case 'v': verbose = true;
00085 break;
00086 default: error_flag = true;
00087 }
00088 }
00089 argc -= optind;
00090 argv += optind;
00091
00092 if (error_flag || (argc < 1)) {
00093 usage(program_name);
00094 return 1;
00095 }
00096 OslConfig::setDfpnMaxDepth(1600);
00097 if (dovetailing_prob > 0)
00098 HashRandomPair::setUp(dovetailing_seed, dovetailing_prob);
00099 try
00100 {
00101 for (int i=0; i<argc; ++i)
00102 {
00103 if (parallel)
00104 {
00105 #ifdef OSL_DFPN_SMP
00106 DfpnParallel dfpn(parallel);
00107 search(dfpn, argv[i]);
00108 #else
00109 std::cerr << "to use parallel dfpn, try compile with -DOSL_SMP or -DOSL_DFPN_SMP\n";
00110 return 1;
00111 #endif
00112 }
00113 else
00114 {
00115 Dfpn dfpn;
00116 search(dfpn, argv[i]);
00117 }
00118 total_cycles = 0;
00119 }
00120 std::cerr << "check " << num_checkmate << " nocheckmate " << num_nocheckmate << " escape " << num_escape
00121 << " unknown " << num_unkown << "\n";
00122 std::cerr << "total nodes " << total_nodes
00123 << " tables " << total_tables << "\n";
00124 }
00125 catch (std::exception& e)
00126 {
00127 std::cerr << e.what() << "\n";
00128 return 1;
00129 }
00130 }
00131
00132 double real_seconds = 0.0;
00133
00134 template <class DfpnSearch>
00135 void analyzeCheckmate(DfpnSearch& searcher, const NumEffectState& state, Move checkmate_move)
00136 {
00137 NumEffectState new_state = state;
00138 std::cerr << state << " " << checkmate_move << "\n";
00139 new_state.makeMove(checkmate_move);
00140 HashKey key(new_state);
00141 const DfpnTable& table = searcher.currentTable();
00142 DfpnRecordBase record = table.probe(key, PieceStand(WHITE, new_state));
00143 std::cerr << record.proof_disproof << " " << std::bitset<64>(record.solved) << "\n";
00144
00145 MoveVector moves;
00146 LegalMoves::generate(new_state, moves);
00147 for (size_t i=0; i<moves.size(); ++i) {
00148 NumEffectState tmp = new_state;
00149 tmp.makeMove(moves[i]);
00150 DfpnRecordBase record = table.probe(key.newHashWithMove(moves[i]), PieceStand(WHITE, tmp));
00151 std::cerr << moves[i] << " " << record.proof_disproof << " " << record.best_move << "\n";
00152 }
00153
00154 {
00155 Dfpn::DfpnMoveVector moves;
00156 if (state.turn() == BLACK)
00157 Dfpn::generateEscape<BLACK>(new_state, false, Square(), moves);
00158 else
00159 Dfpn::generateEscape<WHITE>(new_state, false, Square(), moves);
00160 std::cerr << "Escape " << moves.size()<< "\n";
00161 moves.clear();
00162 if (state.turn() == BLACK)
00163 Dfpn::generateEscape<BLACK>(new_state, true, Square(), moves);
00164 else
00165 Dfpn::generateEscape<BLACK>(new_state, true, Square(), moves);
00166 std::cerr << "Escape full " << moves.size() << "\n";
00167 }
00168 }
00169
00170 template <class DfpnSearch>
00171 void testWinOrLose(const char *filename,
00172 DfpnSearch& searcher,
00173 const SimpleState& sstate, int limit,
00174 ProofDisproof& result, Move& best_move,
00175 const vector<Move>& moves)
00176 {
00177 const Player P = sstate.turn();
00178 NumEffectState state(sstate);
00179 const PathEncoding path(state.turn());
00180 const Square my_king = state.kingSquare(P);
00181 if ((! force_attack)
00182 && ! my_king.isPieceStand() && state.inCheck(P))
00183 {
00184
00185 MilliSeconds timer = MilliSeconds::now();
00186 misc::PerfMon clock;
00187 result = searcher.hasEscapeMove(state, HashKey(state), path, limit, Move::PASS(alt(P)));
00188 total_cycles += clock.stop();
00189 real_seconds = timer.elapsedSeconds();
00190
00191 if (verbose)
00192 std::cerr << result << "\n";
00193 if (result.isCheckmateSuccess()) {
00194 ++num_checkmate;
00195 }
00196 else {
00197 if (result.isCheckmateFail())
00198 ++num_escape;
00199 else {
00200 assert(! result.isFinal());
00201 ++num_unkown;
00202 }
00203 }
00204 return;
00205 }
00206
00207 Move checkmate_move;
00208 vector<Move> pv;
00209 MilliSeconds timer = MilliSeconds::now();
00210 PerfMon clock;
00211 result = searcher.
00212 hasCheckmateMove(state, HashKey(state), path, limit, checkmate_move, Move(), &pv);
00213 total_cycles += clock.stop();
00214 real_seconds = timer.elapsedSeconds();
00215 if (verbose)
00216 std::cerr << result << "\n";
00217
00218 if (result.isCheckmateSuccess()) {
00219 ++num_checkmate;
00220 best_move = checkmate_move;
00221 if (verbose) {
00222 std::cerr << checkmate_move << "\n";
00223 for (size_t i=0; i<pv.size(); ++i) {
00224 std::cerr << std::setw(4) << std::setfill(' ') << i+1
00225 << ' ' << record::csa::show(pv[i]) << " ";
00226 if (i % 6 == 5)
00227 std::cerr << "\n";
00228 }
00229 if (pv.size() % 6 != 0)
00230 std::cerr << "\n";
00231 }
00232 if (debug) {
00233
00234 if (! moves.empty())
00235 searcher.analyze(path, state, moves);
00236 }
00237 }
00238 else {
00239 if (result.isFinal())
00240 ++num_nocheckmate;
00241 else
00242 ++num_unkown;
00243 if (debug)
00244 searcher.analyze(path, state, moves);
00245 }
00246 }
00247
00248 template <class DfpnSearch>
00249 void search(DfpnSearch& searcher, const char *filename)
00250 {
00251 NumEffectState state;
00252 vector<Move> moves;
00253 try {
00254 CsaFile file(filename);
00255 state = file.getInitialState();
00256 moves = file.getRecord().getMoves();
00257 int forward_here = std::min(forward_moves, (int)moves.size());
00258 for (int i=0; i<forward_here; ++i)
00259 state.makeMove(moves[i]);
00260 moves.erase(moves.begin(), moves.begin()+forward_here);
00261 }
00262 catch (CsaIOError&) {
00263 std::cerr << "\nskipping " << filename << "\n";
00264 return;
00265 }
00266 if (verbose)
00267 std::cerr << "\nsolving " << filename << "\n";
00268
00269
00270 const bool attack = force_attack
00271 || state.kingSquare(state.turn()).isPieceStand()
00272 || ! state.inCheck(state.turn());
00273 DfpnTable table(attack ? state.turn() : alt(state.turn()));
00274 table.setGrowthLimit(table_growth_limit);
00275 searcher.setTable(&table);
00276 ProofDisproof result;
00277 Move best_move;
00278 testWinOrLose(filename, searcher, state, limit, result, best_move, moves);
00279 const size_t table_used = searcher.currentTable().size();
00280 total_nodes += searcher.nodeCount();
00281 total_tables += table_used;
00282
00283 if (verbose) {
00284 PerfMon::message(total_cycles, "total ",
00285 searcher.nodeCount());
00286 PerfMon::message(total_cycles, "unique", table_used);
00287 std::cerr << "real " << real_seconds << " sec. nps " << searcher.nodeCount()/real_seconds << "\n";
00288 }
00289 std::cout << filename << "\t" << searcher.nodeCount()
00290 << "\t" << table_used << "\t" << real_seconds
00291 << " " << result;
00292 if (best_move.isNormal())
00293 std::cout << " " << record::csa::show(best_move);
00294 std::cout << "\n" << std::flush;
00295 }
00296
00297
00298
00299
00300
00301
00302
00303