00001 #include "osl/container/moveVector.h"
00002 #include "osl/hash/hashKey.h"
00003 #include "osl/state/numEffectState.h"
00004 #include "osl/state/historyState.h"
00005 #include "osl/record/kisen.h"
00006 #include "osl/record/csaRecord.h"
00007 #include "osl/checkmate/dualDfpn.h"
00008 #include "osl/eval/see.h"
00009 #include "osl/misc/filePath.h"
00010
00011 #include <boost/accumulators/accumulators.hpp>
00012 #include <boost/accumulators/statistics/mean.hpp>
00013 #include <boost/accumulators/statistics/max.hpp>
00014 #include <boost/scoped_ptr.hpp>
00015 #include <boost/program_options.hpp>
00016 #include <boost/filesystem/convenience.hpp>
00017 #include <boost/foreach.hpp>
00018 #include <boost/format.hpp>
00019 #include <iostream>
00020 #include <fstream>
00021
00022 static void
00023 convert_from_first(const osl::NumEffectState& initial,
00024 const osl::vector<osl::Move> &in,
00025 osl::vector<osl::Move> &out, size_t checkmate_limit)
00026 {
00027 osl::DualDfpn dfpn;
00028 osl::NumEffectState state(initial);
00029 BOOST_FOREACH(osl::Move move, in)
00030 {
00031 const int see = osl::See::see
00032 (state, move, state.pin(state.turn()), state.pin(alt(state.turn())));
00033 out.push_back(move);
00034 state.makeMove(move);
00035 if (state.inCheck() && see < 0
00036 && dfpn.isLosingState(checkmate_limit, state,
00037 osl::HashKey(state), osl::PathEncoding(state.turn())))
00038 break;
00039 }
00040 }
00041
00042 static void
00043 trim_last(const osl::NumEffectState& initial,
00044 const osl::vector<osl::Move> &in,
00045 osl::vector<osl::Move> &out, size_t checkmate_limit)
00046 {
00047 if (in.empty())
00048 return;
00049 osl::DualDfpn dfpn;
00050 osl::HistoryState history(initial);
00051 BOOST_FOREACH(osl::Move move, in)
00052 history.makeMove(move);
00053 const osl::Player last_played = in.back().player();
00054 int length = in.size();
00055 for (; length > 0; length -= 2)
00056 {
00057 osl::NumEffectState current = history.state();
00058 assert(current.turn() == alt(last_played));
00059 if (! current.inCheck())
00060 break;
00061 if (! dfpn.isLosingState(checkmate_limit, current,
00062 osl::HashKey(current), osl::PathEncoding(last_played)))
00063 break;
00064 history.unmakeMove();
00065 history.unmakeMove();
00066 }
00067 out = in;
00068 out.resize(length);
00069 }
00070
00071 static void convert(const std::vector<std::string> &input_filename,
00072 const std::string &output_kisen_filename,
00073 size_t checkmate_limit, bool output_ipx, bool trim)
00074 {
00075 namespace acc = boost::accumulators;
00076 acc::accumulator_set<double, acc::features<acc::tag::max, acc::tag::mean> > accumulator;
00077 std::ofstream ofs(output_kisen_filename.c_str());
00078 osl::record::OKisenStream ks(ofs);
00079
00080 boost::scoped_ptr<osl::record::KisenIpxWriter> ipx_writer;
00081 boost::scoped_ptr<std::ofstream> ipx_ofs;
00082 if (output_ipx)
00083 {
00084 const boost::filesystem::path ipx_path =
00085 boost::filesystem::change_extension(boost::filesystem::path(output_kisen_filename), ".ipx");
00086 const std::string ipx = osl::misc::file_string(ipx_path);
00087 ipx_ofs.reset(new std::ofstream(ipx.c_str()));
00088 ipx_writer.reset(new osl::record::KisenIpxWriter(*ipx_ofs));
00089 }
00090
00091 for (size_t i = 0; i < input_filename.size(); ++i)
00092 {
00093 osl::KisenFile kisen(input_filename[i]);
00094 osl::KisenIpxFile ipx(kisen.ipxFileName());
00095 for (size_t j=0; j<kisen.size(); ++j)
00096 {
00097 osl::NumEffectState state = kisen.getInitialState();
00098 osl::vector<osl::Move> moves = kisen.getMoves(j);
00099 osl::vector<osl::Move> new_moves;
00100 if (trim)
00101 trim_last(state, moves, new_moves, checkmate_limit);
00102 else
00103 convert_from_first(state, moves, new_moves, checkmate_limit);
00104
00105 osl::record::Record new_record;
00106 new_record.setPlayer(osl::BLACK, ipx.getPlayer(j, osl::BLACK));
00107 new_record.setPlayer(osl::WHITE, ipx.getPlayer(j, osl::WHITE));
00108 new_record.setDate(ipx.getStartDate(j));
00109 osl::SimpleState record_state = state;
00110 osl::record::RecordVisitor visitor;
00111 visitor.setState(&record_state);
00112 visitor.setRecord(&new_record);
00113 for (size_t k=0; k<new_moves.size(); ++k)
00114 {
00115 visitor.addMoveAndAdvance(new_moves[k]);
00116 state.makeMove(new_moves[k]);
00117 }
00118 new_record.setResult(state.turn() == osl::BLACK
00119 ? osl::Record::WHITE_WIN : osl::Record::BLACK_WIN);
00120 accumulator(moves.size() - new_moves.size());
00121 if (new_moves.size() >= 256)
00122 std::cerr << "long record " << j << ' ' << new_moves.size() << "\n";
00123 ks.save(&new_record);
00124 if (output_ipx)
00125 {
00126 ipx_writer->save(new_record,
00127 ipx.getRating(j, osl::BLACK),ipx.getRating(j, osl::WHITE),
00128 ipx.getTitle(j, osl::BLACK), ipx.getTitle(j, osl::WHITE));
00129 }
00130 if ((j % 1000) == 999)
00131 std::cerr << input_filename[i] << " " << j
00132 << " max " << acc::max(accumulator)
00133 << " mean " << acc::mean(accumulator) << "\n";
00134 }
00135 std::cerr << input_filename[i]
00136 << " max " << acc::max(accumulator)
00137 << " mean " << acc::mean(accumulator) << "\n";
00138 }
00139 }
00140
00141 int main(int argc, char **argv)
00142 {
00143 bool output_ipx, trim;
00144 std::string kisen_filename;
00145 size_t checkmate_limit;
00146 boost::program_options::options_description command_line_options;
00147 command_line_options.add_options()
00148 ("trim-from-last",
00149 boost::program_options::value<bool>(&trim)->default_value(true),
00150 "trim last checkmate sequence")
00151 ("output-ipx",
00152 boost::program_options::value<bool>(&output_ipx)->default_value(true),
00153 "Whether output IPX file in addition to KIF file")
00154 ("output-kisen-filename,o",
00155 boost::program_options::value<std::string>(&kisen_filename)->
00156 default_value("test.kif"),
00157 "Output filename of Kisen file")
00158 ("checkmate-limit,l",
00159 boost::program_options::value<size_t>(&checkmate_limit)->default_value(1000),
00160 "Whether output IPX file in addition to KIF file")
00161 ("input-file", boost::program_options::value< std::vector<std::string> >(),
00162 "input files in kisen format")
00163 ("help", "Show help message");
00164 boost::program_options::variables_map vm;
00165 boost::program_options::positional_options_description p;
00166 p.add("input-file", -1);
00167
00168 try
00169 {
00170 boost::program_options::store(
00171 boost::program_options::command_line_parser(
00172 argc, argv).options(command_line_options).positional(p).run(), vm);
00173 boost::program_options::notify(vm);
00174 if (vm.count("help"))
00175 {
00176 std::cerr << "Usage: " << argv[0] << " [options] kisen-files\n";
00177 std::cerr << " " << argv[0] << " [options]\n";
00178 std::cout << command_line_options << std::endl;
00179 return 0;
00180 }
00181 }
00182 catch (std::exception &e)
00183 {
00184 std::cerr << "error in parsing options" << std::endl
00185 << e.what() << std::endl;
00186 std::cerr << "Usage: " << argv[0] << " [options] kisen-files\n";
00187 std::cerr << " " << argv[0] << " [options]\n";
00188 std::cerr << command_line_options << std::endl;
00189 return 1;
00190 }
00191
00192 std::vector<std::string> files;
00193 if (vm.count("input-file"))
00194 files = vm["input-file"].as<std::vector<std::string> >();
00195
00196 convert(files, kisen_filename, checkmate_limit, output_ipx, trim);
00197 return 0;
00198 }
00199
00200
00201
00202