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