My Project
kakinoki.cc
Go to the documentation of this file.
1 /* kakinoki.cc
2  */
3 #include "osl/record/kakinoki.h"
4 #include "osl/record/kanjiMove.h"
5 #include "osl/record/kanjiCode.h"
6 #include "osl/misc/sjis2euc.h"
7 #include "osl/misc/eucToLang.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 = {{
26  "", K_K1, K_K2, K_K3, K_K4, K_K5, K_K6, K_K7, K_K8, K_K9, K_K10
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 
155 std::pair<osl::Player,osl::Ptype> osl::
156 kakinoki::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 
167 kakinoki::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 
218 KakinokiFile::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 
254 {
255 }
256 
258 KakinokiFile::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の表現 .
Definition: basic_type.h:1052
bool isNormal() const
INVALID でも PASS でもない.
Definition: basic_type.h:1088
const Square to() const
Definition: basic_type.h:1132
利きを持つ局面
void makeMove(Move move)
Ptype ptype() const
Definition: basic_type.h:821
const Piece pieceOnBoard(Square sq) const
Definition: simpleState.h:170
bool isValidMove(Move move, bool show_error=true) const
合法手かどうかを検査する. isValidMoveByRule, isAlmostValidMove をおこなう. 玉の素抜きや王手を防いでいるか, 千日手,打歩詰かどうかは検査しない.
Definition: simpleState.cc:435
void init()
盤面が空の状態に初期化
Definition: simpleState.cc:44
Player turn() const
Definition: simpleState.h:220
bool isConsistent(bool show_error=true) const
Definition: simpleState.cc:157
void setPiece(Player player, Square sq, Ptype ptype)
Definition: simpleState.cc:114
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
const Move strToMove(const std::string &s, const SimpleState &st)
Definition: csa.cc:48
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
std::string sjis2euc(const std::string &str)
Convert character encoding from Shift_JIS to EUC-JP.
Definition: sjis2euc.cc:9
std::string eucToLang(const std::string &src)
Definition: eucToLang.cc:14
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