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