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