kisen.cc Source File

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
kisen.cc
Go to the documentation of this file.
1 #include "osl/record/kisen.h"
2 #include "osl/record/csaIOError.h"
3 #include "osl/pieceStand.h"
4 #include "osl/misc/filePath.h"
5 #include "osl/misc/iconvConvert.h"
6 #include "osl/misc/sjis2euc.h"
7 #include <boost/filesystem/convenience.hpp>
8 #include <boost/foreach.hpp>
9 #include <iostream>
10
11 namespace osl
12 {
13 namespace record
14 {
15 Square KisenUtils::convertSquare( int pos ){
16 assert(1<=pos && pos<=0x51);
17 int y=((pos-1)/9)+1, x=((pos-1)%9)+1;
18 return Square(x,y);
19 }
20 int KisenUtils::convertSquare(Square pos)
21 {
22 return ((pos.y() - 1) * 9 + 1) + pos.x() - 1;
23 }
24
25 Move KisenUtils::convertMove(SimpleState const& state,int c0,int c1){
26 Move move;
27
28 if(1<=c1 && c1<=0x51){
29 Square from=convertSquare(c1),to;
30 Piece fromPiece=state.pieceOnBoard(from);
31 if (! fromPiece.isPiece())
32 throw CsaIOError("Square error");
33 assert(fromPiece.isPiece());
34 assert(fromPiece.owner()==state.turn() ||
35 (std::cerr << c1 << "," << from << "," << fromPiece << std::endl,0)
36 );
37 bool isPromote=false;
38 if(1<=c0 && c0<=0x51){
39 to=convertSquare(c0);
40 }
41 else if(0x65<=c0 && c0<=0xb5){
42 to=convertSquare(c0-0x64);
43 isPromote=true;
44 }
45 else{
46 throw CsaIOError("c0 range error");
47 }
48 Piece toPiece=state.pieceAt(to);
49 if (! toPiece.isEmpty() && toPiece.owner()!=alt(state.turn()))
50 throw CsaIOError("inconsintent move (to)");
51 Ptype ptype=fromPiece.ptype();
52 if(isPromote)ptype=promote(ptype);
53 const Ptype captured = toPiece.ptype();
54 if (captured == KING)
55 return Move::INVALID();
56 move=Move(from,to,ptype,captured,isPromote,state.turn());
57 }
58 else{
59 assert(0x65<=c1);
60 assert(1<=c0&&c0<=0x51);
61 Square to=convertSquare(c0);
62 Ptype ptype=PTYPE_EMPTY;
63 int piece_on_stand = c1;
64 const Ptype ptypes[]={ROOK,BISHOP,GOLD,SILVER,KNIGHT,LANCE,PAWN};
65 for(size_t i=0;i<sizeof(ptypes)/sizeof(Ptype);i++){
66 int count=state.countPiecesOnStand(state.turn(),ptypes[i]);
67 if(count>0){
68 if(piece_on_stand>0x64){
69 piece_on_stand-=count;
70 if(piece_on_stand<=0x64) ptype=ptypes[i];
71 }
72 }
73 }
74 assert(ptype!=PTYPE_EMPTY ||
75 (std::cerr << state << to << " " << c1
76 << " " << piece_on_stand << std::endl, false));
77 move=Move(to,ptype,state.turn());
78 }
79 if (! state.isValidMove(move,true)) {
80 std::cerr << "warning: bad move in kisen\n" << state << move << "\n";
81 return Move();
82 }
83 assert(state.isValidMove(move,true) ||
84 (std::cerr << state << move << std::endl, false));
85 return move;
86 }
87
88
89 KisenFile::KisenFile(const std::string& fileName)
90 :ifs(fileName.c_str()),initialState(HIRATE), fileName(fileName)
91 {
92 if (! ifs)
93 throw CsaIOError("KisenFile not found");
94 ifs.seekg(0,std::ios::end);
95 assert((ifs.tellg() % 512)==0);
96 numberOfGames=ifs.tellg()/512;
97 }
98
99 const vector<Move> KisenFile::getMoves(size_t index)
100 {
101 assert(index<size());
102 vector<Move> moves;
103 // std::cerr << "Game[" << index << "]" << std::endl;
104 ifs.seekg(index*512,std::ios::beg);
105 CArray<unsigned char, 512> cbuf;
106 ifs.read(reinterpret_cast<char *>(&cbuf[0]),512);
107 NumEffectState state;
108 //
109 Player turn=BLACK;
110 for(size_t turnCount=0;
111 (turnCount*2 < cbuf.size())
112 && cbuf[turnCount*2]!=0 && cbuf[turnCount*2+1]!=0;
113 turnCount++, turn=alt(turn)){
114 if(turnCount==KisenFile::maxMoves || cbuf[ turnCount *2 ] == 0 || cbuf[ turnCount * 2 + 1 ] == 0 ){ break; }
115 int c0=cbuf[turnCount*2], c1=cbuf[turnCount*2+1];
116 if (moves.empty() && c0 == 0xff && c1 == 0xff) // komaochi
117 break;
118 const Move move=KisenUtils::convertMove(state,c0,c1);
119 if (move.isInvalid())
120 break;
121 moves.push_back(move);
122 state.makeMove(move);
123 assert(state.isConsistent( true ) );
124 }
125 return moves;
126 }
127 #ifndef MINIMAL
128 const std::string KisenFile::ipxFileName(const std::string& filename)
129 {
130 namespace bf = boost::filesystem;
131 const bf::path ipxfilename = bf::change_extension(bf::path(filename), ".ipx");
132 return misc::file_string(ipxfilename);
133 }
134
135 KisenIpxFile::KisenIpxFile(const std::string& fileName)
136 :ifs(fileName.c_str()), file_name(fileName)
137 {
138 if (! ifs)
139 throw CsaIOError("KisenIpxFile not found");
140 ifs.seekg(0,std::ios::end);
141 assert((ifs.tellg() % 256)==0);
142 numberOfGames=ifs.tellg()/256;
143 }
144 const std::string KisenIpxFile::getPlayer(size_t index,Player pl)
145 {
146 assert(index<size());
147 vector<Move> moves;
148 ifs.seekg(index*256,std::ios::beg);
149 CArray<unsigned char, 256> cbuf;
150 ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
151 int startIndex=0;
152 if(pl==WHITE)startIndex=14;
153 CArray<char,15> buf;
154 buf[14]='\0';
155 strncpy(&buf[0],reinterpret_cast<char *>(&cbuf[startIndex]),14);
156 return misc::sjis2euc(std::string(&buf[0]));
157 }
158 unsigned int KisenIpxFile::getRating(size_t index,Player pl)
159 {
160 assert(index<size());
161 vector<Move> moves;
162 ifs.seekg(index*256,std::ios::beg);
163 CArray<unsigned char, 256> cbuf;
164 ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
165 int startIndex=0324;
166 if(pl==WHITE)startIndex=0326;
167 return cbuf[startIndex]+256*cbuf[startIndex+1];
168 }
169 unsigned int KisenIpxFile::getResult(size_t index)
170 {
171 assert(index<size());
172 ifs.seekg(index*256,std::ios::beg);
173 CArray<unsigned char, 256> cbuf;
174 ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
175 return cbuf[64+48+6];
176 }
177 const std::string KisenIpxFile::getTitle(size_t index,Player pl)
178 {
179 assert(index<size());
180 vector<Move> moves;
181 ifs.seekg(index*256,std::ios::beg);
182 CArray<unsigned char, 256> cbuf;
183 ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
184 int startIndex=28;
185 if(pl==WHITE)startIndex+=8;
186 CArray<char,9> buf;
187 buf[8]='\0';
188 strncpy(&buf[0],reinterpret_cast<const char*>(&cbuf[startIndex]),8);
189 return misc::sjis2euc(std::string(&buf[0]));
190 }
191 boost::gregorian::date KisenIpxFile::getStartDate(size_t index)
192 {
193 assert(index<size());
194 ifs.seekg(index*256,std::ios::beg);
195 CArray<unsigned char, 256> cbuf;
196 ifs.read(reinterpret_cast<char *>(&cbuf[0]),256);
197 const int startIndex=84;
198 const unsigned int year = cbuf[startIndex] + 256*cbuf[startIndex+1];
199 const unsigned int month = cbuf[startIndex+2];
200 const unsigned int day = cbuf[startIndex+3];
201 try {
202 const boost::gregorian::date d = boost::gregorian::date(year, month, day);
203 return d;
204 } catch (std::out_of_range& e) {
205 std::cerr << e.what() << ": ["
206 << index << "] " << year << "-" << month << "-" << day << "\n";
207 return boost::gregorian::date(boost::gregorian::not_a_date_time);
208 }
209 }
210
211 KisenPlusFile::KisenPlusFile(const std::string& fileName)
212 :ifs(fileName.c_str()),initialState(HIRATE)
213 {
214 if (! ifs)
215 throw CsaIOError("KisenPlusFile not found");
216 ifs.seekg(0,std::ios::end);
217 assert((ifs.tellg() % 2048)==0);
218 numberOfGames=ifs.tellg()/2048;
219 }
220
221 const vector<Move> KisenPlusFile::getMoves(size_t index)
222 {
223 vector<Move> moves;
224 vector<int> times;
225 getMoves(index, moves, times);
226 return moves;
227 }
228
229 void KisenPlusFile::getMoves(size_t index,
230 vector<Move>& moves, vector<int>& times)
231 {
232 assert(index<size());
233 // std::cerr << "Game[" << index << "]" << std::endl;
234 ifs.seekg(index*2048,std::ios::beg);
235 CArray<unsigned char, 2048> cbuf;
236 ifs.read(reinterpret_cast<char *>(&cbuf[0]),2048);
237 NumEffectState state;
238 for (size_t i = 0;
239 i < 2048 && cbuf[i]!=0 && cbuf[i+1]!=0;
240 i += 8)
241 {
242 int c0 = cbuf[i];
243 int c1 = cbuf[i + 1];
244 bool is_promote = false;
245 Move move;
246
247 if (c0 > 100)
248 {
249 is_promote = true;
250 c0 = 256 - c0;
251 }
252
253 Square to(c0 % 10, c0 / 10);
254
255 if (c1 < 10)
256 {
257 // drop
258 move = Move(to,
259 PieceStand::order[c1 - 1],
260 state.turn());
261 }
262 else
263 {
264 Square from(c1 % 10, c1 / 10);
265 Ptype type = state.pieceAt(from).ptype();
266 if (is_promote)
267 type = promote(type);
268 move = Move(from, to,
269 type, state.pieceAt(to).ptype(),
270 is_promote, state.turn());
271 }
272 moves.push_back(move);
273 times.push_back(cbuf[i + 7] * 60 + cbuf[i + 6]);
274 state.makeMove(move);
275 assert(state.isConsistent( true ) );
276 }
277 }
278 #endif
279 } // namespace record
280 } // namespace osl
281
282 osl::record::
283 KisenFile::~KisenFile()
284 {
285 }
286 #ifndef MINIMAL
287 osl::record::
288 KisenIpxFile::~KisenIpxFile()
289 {
290 }
291
292 void osl::record::
293 OKisenStream::save(const SimpleState& src, const vector<Move> &moves)
294 {
295 if (!(src == SimpleState(HIRATE)))
296 {
297 std::cerr << "Can not save non-HIRATE record" << std::endl;
298 return;
299 }
300 NumEffectState state;
301 const int max_length = std::min(256, static_cast<int>(moves.size()));
302 for (int i = 0; i < max_length; ++i)
303 {
304 const Move move = moves[i];
305 if (!move.isDrop())
306 {
307 int from = KisenUtils::convertSquare(move.from());
308 int to = KisenUtils::convertSquare(move.to());
309 if (move.isPromotion())
310 {
311 to += 100;
312 }
313 os << static_cast<char>(to) << static_cast<char>(from);
314 }
315 else
316 {
317 int to = KisenUtils::convertSquare(move.to());
318 int count = 1;
319 BOOST_FOREACH(Ptype ptype, PieceStand::order)
320 {
321 if (ptype == move.ptype())
322 {
323 break;
324 }
325 count += state.countPiecesOnStand(move.player(), ptype);
326 }
327 count += 100;
328 os << static_cast<char>(to) << static_cast<char>(count);
329 }
330 state.makeMove(moves[i]);
331 }
332 for (int i = max_length; i < 256; ++i)
333 {
334 os << '\0' << '\0';
335 }
336 }
337
338 void osl::record::
339 OKisenStream::save(Record *record)
340 {
341 vector<Move> moves;
342 vector<int> time;
343 record->getMoves(moves, time);
344 SimpleState state = record->getInitialState();
345 save(state, moves);
346 }
347
348 void osl::record::
349 KisenIpxWriter::writeString(const std::string &name, size_t length)
350 {
351 for (size_t i = 0; i < length; ++i)
352 {
353 if (i < name.length())
354 {
355 os << name[i];
356 }
357 else
358 {
359 os << '\0';
360 }
361 }
362 }
363
364 void osl::record::
365 KisenIpxWriter::writeRating(int rating)
366 {
367 int high = rating / 256;
368 int low = rating % 256;
369 os << static_cast<char>(low) << static_cast<char>(high);
370 }
371
372 void osl::record::
373 KisenIpxWriter::writeStartDate(int year, int month, int day, int hour, int min)
374 {
375 const int high_year = year / 256;
376 const int low_year = year % 256;
377 os << static_cast<char>(low_year)
378 << static_cast<char>(high_year)
379 << static_cast<char>(month)
380 << static_cast<char>(day)
381 << static_cast<char>(hour)
382 << static_cast<char>(min);
383 }
384
385 void osl::record::
386 KisenIpxWriter::save(const Record &record,
387 int black_rating, int white_rating,
388 const std::string &black_title,
389 const std::string &white_title)
390 {
391 // total 256 bytes
392 // Player name: 14 bytes each
393 #ifndef _WIN32
394 writeString(IconvConvert::convert("EUC-JP", "SJIS", record.getPlayer(BLACK)), 14);
395 writeString(IconvConvert::convert("EUC-JP", "SJIS", record.getPlayer(WHITE)), 14);
396 writeString(IconvConvert::convert("EUC-JP", "SJIS", black_title), 8);
397 writeString(IconvConvert::convert("EUC-JP", "SJIS", white_title), 8);
398 #else
399 writeString("", 14);
400 writeString("", 14);
401 writeString("", 8);
402 writeString("", 8);
403 #endif
404 for (int i = 44; i < 84; ++i)
405 {
406 os << '\0';
407 }
408 const boost::gregorian::date start_date = record.getDate();
409 if (!start_date.is_special()) {
410 // time is fixed with 9am
411 writeStartDate(start_date.year(), start_date.month(), start_date.day(), 9, 0);
412 } else {
413 for (int i = 84; i < 90; ++i)
414 {
415 os << '\0';
416 }
417 }
418 for (int i = 90; i < 118; ++i)
419 {
420 os << '\0';
421 }
422 vector<Move> moves;
423 vector<int> time;
424 record.getMoves(moves, time);
425 // TODO: sennichite, jishogi
426 if (moves.size() <= 256)
427 {
428 if (moves.size() % 2 == 0)
429 os << static_cast<char>(KisenIpxFile::WHITE_WIN);
430 else
431 os << static_cast<char>(KisenIpxFile::BLACK_WIN);
432 }
433 else
434 {
435 if (moves.size() % 2 == 0)
436 os << static_cast<char>(KisenIpxFile::WHITE_WIN_256);
437 else
438 os << static_cast<char>(KisenIpxFile::BLACK_WIN_256);
439 }
440 for (int i = 119; i < 212; ++i)
441 {
442 os << '\0';
443 }
444 writeRating(black_rating);
445 writeRating(white_rating);
446 for (int i = 216; i < 256; ++i)
447 {
448 os << '\0';
449 }
450 }
451 #endif
452 // ;;; Local Variables:
453 // ;;; mode:c++
454 // ;;; c-basic-offset:2
455 // ;;; End: