My Project
kakinoki.cc
Go to the documentation of this file.
1/* kakinoki.cc
2 */
6#include "osl/misc/sjis2euc.h"
8#include "osl/simpleState.h"
9#include <boost/algorithm/string/split.hpp>
10#include <boost/algorithm/string/replace.hpp>
11#include <boost/algorithm/string/classification.hpp>
12#include <boost/date_time/gregorian/gregorian.hpp>
13#include <iostream>
14#include <fstream>
15#include <stdexcept>
16#include <cassert>
17#include <string>
18#include <sstream>
19
22 std::string s, CArray<bool,9>& board_parsed)
23{
24 static const KanjiMove& Kanji_Move = KanjiMove::instance();
25 static const CArray<std::string,11> n_str = {{
27 }};
28 // header
29 if (s[0] == '|') {
30 if (s.size() < 1+3*9+1+2)
31 throw KakinokiIOError("board too short in kakinokiParseLine "+s);
32 const int y = std::find(n_str.begin(), n_str.end(), s.substr(s.size()-2))
33 - n_str.begin();
34 if (! (1 <= y && y <= 9))
35 throw KakinokiIOError("unknown y in kakinokiParseLine "+s);
36 board_parsed[y-1] = true;
37 for (unsigned int x=9,i=1;i<s.length()&&x>0;i+=3,x--) {
38 std::pair<Player,Ptype> pp=kakinoki::strToPiece(s.substr(i,3));
39 if (! isPiece(pp.second))
40 continue;
41 state.setPiece(pp.first, Square(x,y), pp.second);
42 }
43 }
44 if (s.find(K_TESUU "--") == 0) {
45 // moves start
46 if (std::find(board_parsed.begin(), board_parsed.end(), true)
47 == board_parsed.end()) {
48 state.init(HIRATE);
49 board_parsed.fill(true);
50 }
51 if (*std::min_element(board_parsed.begin(), board_parsed.end()) == false)
52 throw KakinokiIOError("incomplete position description in kakinokiParseLine");
53 state.initPawnMask();
54 record.record.initial_state = NumEffectState(state);
55 return;
56 }
57 if (s.size() > 6)
58 {
59 if (s.find(K_BLACK K_COLON) == 0) {
60 record.player[BLACK] = s.substr(6);
61 return;
62 }
63 if (s.find(K_WHITE K_COLON) == 0) {
64 record.player[WHITE] = s.substr(6);
65 return;
66 }
67 if (s.find(K_KISEN K_COLON) == 0)
68 {
69 record.tournament_name = s.substr(6);
70 return;
71 }
72 if (s.find(K_KAISHI K_NICHIJI K_COLON) == 0) {
73 boost::gregorian::date date =
74 boost::gregorian::from_string(s.substr(strlen(K_KAISHI K_NICHIJI K_COLON),10));
75 record.start_date = date;
76 return;
77 }
78 if (s.find(K_MOCHIGOMA K_COLON) != s.npos
79 && s.find(K_NASHI) == s.npos) {
80 std::string piece_str = s.substr(s.find(K_COLON)+2);
81 boost::algorithm::replace_all(piece_str, K_SPACE, " ");
82 std::vector<std::string> pieces;
83 boost::algorithm::split(pieces, piece_str,
84 boost::algorithm::is_any_of(" "));
85 Player player;
86 if (s.find(K_BLACK) == 0) player = BLACK;
87 else if (s.find(K_WHITE) == 0) player = WHITE;
88 else throw KakinokiIOError("error in stand "+ s);
89
90 for (const auto& e: pieces) {
91 if (e.empty()) continue;
92 if (e.size() < 2) throw KakinokiIOError("error in stand "+ e);
93 const Ptype ptype = Kanji_Move.toPtype(e.substr(0,2));
94 int n = 1;
95 if (e.size() >= 4)
96 n = std::find(n_str.begin(),n_str.end(),e.substr(2,2))
97 - n_str.begin();
98 if (e.size() >= 6)
99 n = n * ((e.substr(2,2) == K_K10) ? 1 : 10)
100 + (std::find(n_str.begin(),n_str.end(),e.substr(4,2))
101 - n_str.begin());
102 for (int i=0; i<n; ++i)
103 state.setPiece(player, Square::STAND(), ptype);
104 }
105 }
106 }
107
108 // moves
109 if (s[0] == '*')
110 {
111 if (record.moves().empty())
112 Record::addWithNewLine(record.initial_comment, s.substr(1));
113 else
114 record.setMoveComment(s.substr(1));
115 return;
116 }
117 if (s[0] != ' ')
118 {
119 if (record.moves().empty())
120 Record::addWithNewLine(record.initial_comment, s);
121 return; // otherwise ignore
122 }
123 if (s.find(K_TORYO) != s.npos)
124 {
125 record.result = ((state.turn() == BLACK)
126 ? Record::WhiteWin : Record::BlackWin);
127 return;
128 }
129
130 {
131 // replace '(' and ')' with white space if exists
132 size_t p = s.find('(');
133 if (p != s.npos)
134 s.replace(p, 1, 1, ' ');
135 p = s.find(')');
136 if (p != s.npos)
137 s.replace(p, 1, 1, ' ');
138 }
139 Move last_move = record.lastMove();
140 const Move m = kakinoki::strToMove(s, state, last_move);
141 if (m.isNormal()) {
142 if (! state.isValidMove(m)) {
143 std::ostringstream ss;
144 ss << state << misc::eucToLang(s) << "\n" << m;
145 std::cerr << ss.str();
146 throw KakinokiIOError(ss.str());
147 }
148 record.record.moves.push_back(m);
149 NumEffectState copy(state);
150 copy.makeMove(m);
151 state = copy;
152 }
153}
154
155std::pair<osl::Player,osl::Ptype> osl::
156kakinoki::strToPiece(const std::string& s)
157{
158 static const KanjiMove& Kanji_Move = KanjiMove::instance();
159 if (s.size() != 3 || (s[0] != 'v' && s[0] != ' '))
160 throw KakinokiIOError("error in strToPiece " + s);
161 const Player pl = s[0] == ' ' ? BLACK : WHITE;
162 const Ptype ptype = Kanji_Move.toPtype(s.substr(1,2));
163 return std::make_pair(pl, ptype);
164}
165
167kakinoki::strToMove(const std::string& s, const SimpleState& state, Move last_move)
168{
169 static const KanjiMove& Kanji_Move = KanjiMove::instance();
170 std::istringstream is(s);
171 int move_number, from_number;
172 std::string move_string;
173 is >> move_number >> move_string;
174
175 Square to, from;
176 if (move_string.substr(0,2) == K_ONAZI)
177 to = last_move.to();
178 else
179 to = Kanji_Move.toSquare(move_string.substr(0,4));
180 if (to == Square()) // resign?
181 return Move();
182
183 Ptype ptype;
184 size_t cur = 4;
185 if (move_string.substr(cur,2) == K_NARU) // PLANCE, PKIGHT, PSILVER
186 {
187 assert(move_string.size() >= cur+4);
188 ptype = Kanji_Move.toPtype(move_string.substr(cur,4));
189 cur += 4;
190 }
191 else
192 {
193 ptype = Kanji_Move.toPtype(move_string.substr(cur,2));
194 cur += 2;
195 }
196 if (move_string.size() >= cur+2 && move_string.substr(cur,2)
197 == K_UTSU)
198 from = Square();
199 else
200 {
201 if (! (is >> from_number))
202 throw KakinokiIOError("error in move from");
203 from = Square(from_number / 10, from_number % 10);
204 }
205
206 bool is_promote = false;
207 if (move_string.size() >= cur+2 && move_string.substr(cur,2) == K_NARU)
208 is_promote = true;
209
210 if (from.isPieceStand())
211 return Move(to, ptype, state.turn());
212 Ptype captured = state.pieceOnBoard(to).ptype();
213 return Move(from, to, is_promote ? promote(ptype) : ptype,
214 captured, is_promote, state.turn());
215}
216
218KakinokiFile::KakinokiFile(const std::string& filename)
219{
220 std::ifstream is(filename);
221 if (! is)
222 {
223 const std::string msg = "KakinokiFile::KakinokiFile file cannot read ";
224 std::cerr << msg << filename << "\n";
225 throw KakinokiIOError(msg + filename);
226 }
227 SimpleState work;
228 work.init();
229 std::string line;
230 CArray<bool, 9> board_parsed = {{ false }};
231 while (std::getline(is, line))
232 {
233 // quick hack for \r
234 if ((! line.empty())
235 && (line[line.size()-1] == 13))
236 line.erase(line.size()-1);
237 if (line.length()==0)
238 continue;
239 // to euc
240 line = misc::sjis2euc(line);
241 // skip variations
242 if (line.find(K_HENKA) == 0)
243 break;
244 if (! line.empty() && line[0] == '#'
245 && line.find("separator") != line.npos)
246 break; // tanase shogi
247 parseLine(work, record, line, board_parsed);
248 }
249 assert(work.isConsistent());
250}
251
256
258KakinokiFile::isKakinokiFile(const std::string& filename)
259{
260 std::ifstream is(filename.c_str());
261 std::string line;
262 if (! is || ! getline(is, line))
263 return false;
264 line = misc::sjis2euc(line);
265 return line.find("Kifu for Windows") != line.npos
266 || line.find("KIFU") != line.npos
267 || line.find(K_SENKEI) == 0
268 || line.find(K_TEAIWARI) == 0
269 || (line.find("#") == 0 && line.find(K_KIFU) != line.npos);
270}
271
272// ;;; Local Variables:
273// ;;; mode:c++
274// ;;; c-basic-offset:2
275// ;;; End:
void fill(const T_simple &value=T_simple())
Definition container.h:67
iterator end()
Definition container.h:65
iterator begin()
Definition container.h:64
圧縮していない moveの表現 .
bool isNormal() const
INVALID でも PASS でもない.
const Square to() const
利きを持つ局面
void makeMove(Move move)
Ptype ptype() const
Definition basic_type.h:821
const Piece pieceOnBoard(Square sq) const
bool isValidMove(Move move, bool show_error=true) const
合法手かどうかを検査する. isValidMoveByRule, isAlmostValidMove をおこなう. 玉の素抜きや王手を防いでいるか, 千日手,打歩詰かどうかは検査しない.
void init()
盤面が空の状態に初期化
Player turn() const
bool isConsistent(bool show_error=true) const
void setPiece(Player player, Square sq, Ptype ptype)
bool isPieceStand() const
Definition basic_type.h:576
static bool isKakinokiFile(const std::string &filename)
Definition kakinoki.cc:258
KakinokiFile(const std::string &filename)
Definition kakinoki.cc:218
static void parseLine(SimpleState &state, Record &record, std::string s, CArray< bool, 9 > &board_parsed)
Definition kakinoki.cc:21
Parse kanji records such as "7六歩", the style of which is generally used to write Shogi records in Jap...
Definition kanjiMove.h:20
Square toSquare(const std::string &) const
Definition kanjiMove.cc:260
Ptype toPtype(const std::string &) const
Definition kanjiMove.cc:269
#define K_KAISHI
Definition kanjiCode.h:106
#define K_NARU
Definition kanjiCode.h:54
#define K_HENKA
Definition kanjiCode.h:101
#define K_K3
Definition kanjiCode.h:29
#define K_K7
Definition kanjiCode.h:33
#define K_SPACE
Definition kanjiCode.h:15
#define K_TEAIWARI
Definition kanjiCode.h:97
#define K_K8
Definition kanjiCode.h:34
#define K_NASHI
Definition kanjiCode.h:109
#define K_K9
Definition kanjiCode.h:35
#define K_ONAZI
Definition kanjiCode.h:53
#define K_K4
Definition kanjiCode.h:30
#define K_UTSU
Definition kanjiCode.h:56
#define K_BLACK
Definition kanjiCode.h:92
#define K_MOCHIGOMA
Definition kanjiCode.h:94
#define K_K5
Definition kanjiCode.h:31
#define K_K1
Definition kanjiCode.h:27
#define K_TESUU
Definition kanjiCode.h:108
#define K_K10
Definition kanjiCode.h:36
#define K_KIFU
Definition kanjiCode.h:104
#define K_NICHIJI
Definition kanjiCode.h:107
#define K_WHITE
Definition kanjiCode.h:93
#define K_COLON
Definition kanjiCode.h:17
#define K_K2
Definition kanjiCode.h:28
#define K_TORYO
Definition kanjiCode.h:100
#define K_K6
Definition kanjiCode.h:32
#define K_KISEN
Definition kanjiCode.h:103
#define K_SENKEI
Definition kanjiCode.h:99
Move strToMove(const std::string &, const SimpleState &, Move last_move=Move())
Definition kakinoki.cc:167
std::pair< Player, Ptype > strToPiece(const std::string &)
Definition kakinoki.cc:156
Ptype
駒の種類を4ビットでコード化する
Definition basic_type.h:84
Player
Definition basic_type.h:8
@ WHITE
Definition basic_type.h:10
@ BLACK
Definition basic_type.h:9
constexpr bool isPiece(Ptype ptype)
ptypeが空白やEDGEでないかのチェック
Definition basic_type.h:120
@ HIRATE
Definition simpleState.h:21
Ptype promote(Ptype ptype)
promote可能なptypeに対して,promote後の型を返す promote不可のptypeを与えてはいけない.
Definition basic_type.h:173
PtypeO captured(PtypeO ptypeO)
unpromoteすると共に,ownerを反転する.
Definition basic_type.h:264
NumEffectState initial_state
Definition csa.h:44
std::vector< Move > moves
Definition csa.h:45
std::string tournament_name
Definition record.h:28
RecordMinimal record
Definition record.h:16
ResultType result
Definition record.h:30
Move lastMove() const
Definition record.h:47
std::string initial_comment
Definition record.h:28
std::vector< Move > moves() const
Definition record.h:41
void setMoveComment(const std::string &)
Definition record.cc:17
CArray< std::string, 2 > player
Definition record.h:29
boost::gregorian::date start_date
Definition record.h:31