10 static void out_CSA_header( const tree_t * restrict ptree, record_t *pr );
11 static int str2piece( const char *str );
12 static int skip_comment( record_t *pr );
13 static int read_char( record_t *pr );
14 static int read_CSA_line( record_t *pr, char *str );
15 static int in_CSA_header( tree_t * restrict ptree, record_t *pr, int flag );
16 static int read_board_rep2( const char *str_line, min_posi_t *pmin_posi );
17 static int read_board_rep3( const char *str_line, min_posi_t *pmin_posi );
20 read_record( tree_t * restrict ptree, const char *str_file,
21 unsigned int moves, int flag )
26 iret = record_open( &record, str_file, mode_read, NULL, NULL );
27 if ( iret < 0 ) { return iret; }
31 iret = in_CSA_header( ptree, &record, flag );
34 record_close( &record );
39 iret = in_CSA( ptree, &record, NULL, flag );
42 record_close( &record );
45 } while ( iret != record_next
47 && moves > record.moves );
49 return record_close( &record );
54 record_open( record_t *pr, const char *str_file, record_mode_t record_mode,
55 const char *str_name1, const char *str_name2 )
57 pr->games = pr->moves = pr->lines = 0;
58 pr->str_name1[0] = '\0';
59 pr->str_name2[0] = '\0';
63 strncpy( pr->str_name1, str_name1, SIZE_PLAYERNAME-1 );
64 pr->str_name1[SIZE_PLAYERNAME-1] = '\0';
69 strncpy( pr->str_name2, str_name2, SIZE_PLAYERNAME-1 );
70 pr->str_name2[SIZE_PLAYERNAME-1] = '\0';
73 if ( record_mode == mode_write )
75 pr->pf = file_open( str_file, "w" );
76 if ( pr->pf == NULL ) { return -2; }
78 else if ( record_mode == mode_read_write )
80 pr->pf = file_open( str_file, "wb+" );
81 if ( pr->pf == NULL ) { return -2; }
84 assert( record_mode == mode_read );
86 pr->pf = file_open( str_file, "rb" );
87 if ( pr->pf == NULL ) { return -2; }
95 record_close( record_t *pr )
97 int iret = file_close( pr->pf );
104 out_CSA( tree_t * restrict ptree, record_t *pr, unsigned int move )
106 const char *str_move;
110 if ( move == MOVE_RESIGN )
112 if ( ! pr->moves ) { out_CSA_header( ptree, pr ); }
113 fprintf( pr->pf, "%s\n", str_resign );
119 root_turn = Flip(root_turn);
120 UnMakeMove( root_turn, move, 1 );
121 out_CSA_header( ptree, pr );
122 MakeMove( root_turn, move, 1 );
123 root_turn = Flip(root_turn);
125 str_move = str_CSA_move( move );
126 fprintf( pr->pf, "%c%s\n", ach_turn[Flip(root_turn)], str_move );
132 sec = root_turn ? sec_b_total : sec_w_total;
134 fprintf( pr->pf, "T%-7u,'%03u:%02u \n", sec_elapsed, sec / 60U, sec % 60U );
137 /* print repetition or mate status */
138 if ( game_status & flag_mated )
140 fprintf( pr->pf, "%%TSUMI\n" );
143 else if ( game_status & flag_drawn )
145 fprintf( pr->pf, "%s\n", str_repetition );
154 record_wind( record_t *pr )
156 char str_line[ SIZE_CSALINE ];
160 iret = read_CSA_line( pr, str_line );
161 if ( iret < 0 ) { return iret; }
162 if ( ! iret ) { return record_eof; }
163 if ( ! strcmp( str_line, "/" ) ) { break; }
171 #if ! defined(MINIMUM)
173 record_rewind( record_t *pr )
175 pr->games = pr->moves = pr->lines = 0;
176 if ( fseek( pr->pf, 0, SEEK_SET ) ) { return -2; }
183 record_getpos( record_t *pr, rpos_t *prpos )
185 if ( fgetpos( pr->pf, &prpos->fpos ) )
187 str_error = "fgetpos() failed.";
190 prpos->games = pr->games;
191 prpos->moves = pr->moves;
192 prpos->lines = pr->lines;
199 record_setpos( record_t *pr, const rpos_t *prpos )
201 if ( fsetpos( pr->pf, &prpos->fpos ) )
203 str_error = "fsetpos() failed.";
206 pr->games = prpos->games;
207 pr->moves = prpos->moves;
208 pr->lines = prpos->lines;
212 #endif /* no MINIMUM */
216 in_CSA( tree_t * restrict ptree, record_t *pr, unsigned int *pmove, int flag )
218 char str_line[ SIZE_CSALINE ];
224 if ( pr->moves == 0 )
226 iret = in_CSA_header( ptree, pr, flag );
227 if ( iret < 0 ) { return iret; }
231 iret = read_CSA_line( pr, str_line );
232 if ( iret < 0 ) { return iret; }
233 if ( ! iret ) { return record_eof; }
234 if ( ! strcmp( str_line, str_resign ) )
236 game_status |= flag_resigned;
237 return record_resign;
239 if ( ! strcmp( str_line, str_repetition )
240 || ! strcmp( str_line, str_jishogi ) )
242 game_status |= flag_drawn;
245 if ( ! strcmp( str_line, str_record_error ) )
249 } while ( str_line[0] == 'T' || str_line[0] == '%' );
251 if ( ! strcmp( str_line, "/" ) )
258 if ( game_status & mask_game_end )
260 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
261 pr->lines, str_bad_record );
262 str_error = str_message;
266 iret = interpret_CSA_move( ptree, &move, str_line+1 );
269 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
270 pr->lines, str_error );
271 str_error = str_message;
274 if ( pmove != NULL ) { *pmove = move; }
277 if ( flag & flag_time )
279 iret = read_CSA_line( pr, str_line );
280 if ( iret < 0 ) { return iret; }
283 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
284 pr->lines, str_unexpect_eof );
285 str_error = str_message;
288 if ( str_line[0] != 'T' )
290 snprintf( str_message, SIZE_MESSAGE, str_fmt_line, pr->lines,
291 "Time spent is not available." );
292 str_error = str_message;
295 l = strtol( str_line+1, &ptr, 0 );
296 if ( ptr == str_line+1 || l == LONG_MAX || l < 0 )
298 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
299 pr->lines, str_bad_record );
300 str_error = str_message;
305 sec_elapsed = (unsigned int)l;
306 if ( root_turn ) { sec_w_total += (unsigned int)l; }
307 else { sec_b_total += (unsigned int)l; }
309 iret = make_move_root( ptree, move, flag & ~flag_time );
312 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
313 pr->lines, str_error );
314 str_error = str_message;
325 interpret_CSA_move( tree_t * restrict ptree, unsigned int *pmove,
328 int ifrom_file, ifrom_rank, ito_file, ito_rank, ipiece;
331 unsigned int *pmove_last;
334 ifrom_file = str[0]-'0';
335 ifrom_rank = str[1]-'0';
336 ito_file = str[2]-'0';
337 ito_rank = str[3]-'0';
339 ito_file = 9 - ito_file;
340 ito_rank = ito_rank - 1;
341 ito = ito_rank * 9 + ito_file;
342 ipiece = str2piece( str+4 );
345 str_error = str_illegal_move;
349 if ( ! ifrom_file && ! ifrom_rank )
351 move = To2Move(ito) | Drop2Move(ipiece);
355 ifrom_file = 9 - ifrom_file;
356 ifrom_rank = ifrom_rank - 1;
357 ifrom = ifrom_rank * 9 + ifrom_file;
358 if ( abs(BOARD[ifrom]) + promote == ipiece )
365 move |= ( To2Move(ito) | From2Move(ifrom) | Cap2Move(abs(BOARD[ito]))
366 | Piece2Move(ipiece) );
370 pmove_last = ptree->amove;
371 pmove_last = GenCaptures(root_turn, pmove_last );
372 pmove_last = GenNoCaptures(root_turn, pmove_last );
373 pmove_last = GenCapNoProEx2(root_turn, pmove_last );
374 pmove_last = GenNoCapNoProEx2(root_turn, pmove_last );
375 pmove_last = GenDrop( root_turn, pmove_last );
376 for ( p = ptree->amove; p < pmove_last; p++ )
387 str_error = str_illegal_move;
391 && ( root_turn ? IsHandPawn(HAND_W) : IsHandPawn(HAND_B) ) )
397 u = BBToU( BB_WPAWN_ATK );
398 if ( u & (mask_file1>>ito_file) )
400 str_error = str_double_pawn;
402 else if ( BOARD[ito+nfile] == king )
404 str_error = str_mate_drppawn;
408 u = BBToU( BB_BPAWN_ATK );
409 if ( u & (mask_file1>>ito_file) ) { str_error = str_double_pawn; }
410 else if ( BOARD[ito-nfile] == -king )
412 str_error = str_mate_drppawn;
424 str_CSA_move_plus( tree_t * restrict ptree, unsigned int move, int ply,
427 static char str[ 13 ];
428 const unsigned int *pmove_last;
429 unsigned int amove[ MAX_LEGAL_EVASION ];
431 int is_promo, ipiece_cap, ipiece_move, ifrom, ito, turn_next;
433 is_promo = (int)I2IsPromote(move);
434 ipiece_move = (int)I2PieceMove(move);
435 ifrom = (int)I2From(move);
436 ito = (int)I2To(move);
437 ipiece_cap = (int)UToCap(move);
438 turn_next = Flip( turn );
440 if ( is_promo && ipiece_cap )
442 snprintf( str, 13, "%d%d%d%d%spx%s",
443 9-aifile[ifrom], airank[ifrom]+1,
444 9-aifile[ito], airank[ito] +1,
445 astr_table_piece[ ipiece_move + promote ],
446 astr_table_piece[ ipiece_cap ] );
449 else if ( ipiece_cap )
451 snprintf( str, 13, "%d%d%d%d%sx%s",
452 9-aifile[ifrom], airank[ifrom]+1,
453 9-aifile[ito], airank[ito] +1,
454 astr_table_piece[ ipiece_move ],
455 astr_table_piece[ ipiece_cap ] );
460 snprintf( str, 13, "%d%d%d%d%sp",
461 9-aifile[ifrom], airank[ifrom]+1,
462 9-aifile[ito], airank[ito] +1,
463 astr_table_piece[ ipiece_move + promote ] );
466 else if ( ifrom < nsquare )
468 snprintf( str, 13, "%d%d%d%d%s",
469 9-aifile[ifrom], airank[ifrom]+1,
470 9-aifile[ito], airank[ito] +1,
471 astr_table_piece[ ipiece_move ] );
475 snprintf( str, 13, "00%d%d%s", 9-aifile[ito], airank[ito]+1,
476 astr_table_piece[ From2Drop(ifrom) ] );
480 MakeMove( turn, move, ply );
481 if ( InCheck( turn_next ) )
483 pmove_last = GenEvasion( turn_next, amove );
484 if ( pmove_last == amove ) { *p++ = '#'; }
488 UnMakeMove( turn, move, ply );
495 str_CSA_move( unsigned int move )
498 int ifrom, ito, ipiece_move, is_promote;
500 is_promote = (int)I2IsPromote(move);
501 ipiece_move = (int)I2PieceMove(move);
502 ifrom = (int)I2From(move);
503 ito = (int)I2To(move);
507 snprintf( str, 7, "%d%d%d%d%s",
508 9-aifile[ifrom], airank[ifrom]+1,
509 9-aifile[ito], airank[ito] +1,
510 astr_table_piece[ ipiece_move + promote ] );
512 else if ( ifrom < nsquare )
514 snprintf( str, 7, "%d%d%d%d%s",
515 9-aifile[ifrom], airank[ifrom]+1,
516 9-aifile[ito], airank[ito] +1,
517 astr_table_piece[ ipiece_move ] );
520 snprintf( str, 7, "00%d%d%s",
521 9-aifile[ito], airank[ito]+1,
522 astr_table_piece[ From2Drop(ifrom) ] );
530 read_board_rep1( const char *str_line, min_posi_t *pmin_posi )
534 int piece, ifile, irank, isquare;
535 signed char board[nsquare];
537 memcpy( board, &min_posi_no_handicap.asquare, nsquare );
539 for ( p = str_line + 2; p[0] != '\0'; p += 4 )
541 if ( p[1] == '\0' || p[2] == '\0' || p[3] == '\0' )
543 str_error = str_bad_board;
549 piece = str2piece( str_piece );
554 isquare = irank * nfile + ifile;
555 if ( piece == -2 || ifile < file1 || ifile > file9 || irank < rank1
556 || irank > rank9 || abs(board[isquare]) != piece )
558 str_error = str_bad_board;
561 board[isquare] = empty;
564 for ( isquare = 0; isquare < nsquare; isquare++ ) if ( board[isquare] )
566 if ( pmin_posi->asquare[isquare] )
568 str_error = str_bad_board;
571 pmin_posi->asquare[isquare] = board[isquare];
579 out_CSA_header( const tree_t * restrict ptree, record_t *pr )
583 fprintf( pr->pf, "'Bonanza version " BNZ_VER "\n" );
585 if ( pr->str_name1[0] != '\0' )
587 fprintf( pr->pf, "N+%s\n", pr->str_name1 );
590 if ( pr->str_name2[0] != '\0' )
592 fprintf( pr->pf, "N-%s\n", pr->str_name2 );
596 if ( t == (time_t)-1 ) { out_warning( "%s time() faild." ); }
598 #if defined(_MSC_VER)
600 localtime_s( &tm, &t );
601 fprintf( pr->pf, "$START_TIME:%4d/%02d/%02d %02d:%02d:%02d\n",
602 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
603 tm.tm_hour, tm.tm_min, tm.tm_sec );
606 ptm = localtime( &t );
607 fprintf( pr->pf, "$START_TIME:%4d/%02d/%02d %02d:%02d:%02d\n",
608 ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
609 ptm->tm_hour, ptm->tm_min, ptm->tm_sec );
613 if ( ! memcmp( BOARD, min_posi_no_handicap.asquare, nsquare )
614 && min_posi_no_handicap.turn_to_move == root_turn
615 && min_posi_no_handicap.hand_black == HAND_B
616 && min_posi_no_handicap.hand_white == HAND_W )
618 fprintf( pr->pf, "PI\n" );
622 out_board( ptree, pr->pf, 0, 1 );
626 if ( root_turn ) { fprintf( pr->pf, "-\n" ); }
627 else { fprintf( pr->pf, "+\n" ); }
633 in_CSA_header( tree_t * restrict ptree, record_t *pr, int flag )
636 const char *str_name1, *str_name2;
637 char str_line[ SIZE_CSALINE ];
638 int iret, is_rep1_done, is_rep2_done, is_all_done, i, j;
640 for ( i = 0; i < MAX_ANSWER; i++ ) { pr->info.str_move[i][0] = '\0'; }
641 str_name1 = str_name2 = NULL;
643 /* version and info */
646 iret = read_CSA_line( pr, str_line );
647 if ( iret < 0 ) { return iret; }
649 if ( str_line[0] != 'N'
650 && str_line[0] != 'V'
651 && str_line[0] != '$' ) { break; }
653 if ( ! memcmp( str_line, "$ANSWER:", 8 ) )
655 for ( i = 0; i < MAX_ANSWER; i++ )
657 for ( j = 0; j < 8; j++ )
659 pr->info.str_move[i][j] = str_line[8+i*8+j];
661 pr->info.str_move[i][7] = '\0';
662 if ( str_line[8+i*8+7] == '\0' ) { break; }
664 if ( i == MAX_ANSWER )
666 snprintf( str_message, SIZE_MESSAGE, str_fmt_line, pr->lines,
667 "The number of answers reached MAX_ANSWER." );
668 str_error = str_message;
672 else if ( ! memcmp( str_line, "N+", 2 ) )
674 strncpy( pr->str_name1, str_line+2, SIZE_PLAYERNAME-1 );
675 pr->str_name1[SIZE_PLAYERNAME-1] = '\0';
676 str_name1 = pr->str_name1;
678 else if ( ! memcmp( str_line, "N-", 2 ) )
680 strncpy( pr->str_name2, str_line+2, SIZE_PLAYERNAME-1 );
681 pr->str_name2[SIZE_PLAYERNAME-1] = '\0';
682 str_name2 = pr->str_name2;
687 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
688 pr->lines, str_unexpect_eof );
689 str_error = str_message;
693 /* board representation */
694 memset( &min_posi.asquare, empty, nsquare );
695 min_posi.hand_black = min_posi.hand_white = 0;
696 is_rep1_done = is_rep2_done = is_all_done = 0;
697 while ( str_line[0] == 'P' )
699 if ( str_line[1] == 'I' && ! is_rep2_done && ! is_all_done )
702 iret = read_board_rep1( str_line, &min_posi );
704 else if ( isdigit( (int)str_line[1] ) && str_line[1] != '0'
705 && ! is_rep1_done && ! is_all_done )
708 iret = read_board_rep2( str_line, &min_posi );
710 else if ( str_line[1] == '+' || str_line[1] == '-' )
712 is_all_done = iret = read_board_rep3( str_line, &min_posi );
717 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
718 pr->lines, str_error );
719 str_error = str_message;
723 iret = read_CSA_line( pr, str_line );
724 if ( iret < 0 ) { return iret; }
727 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
728 pr->lines, str_unexpect_eof );
729 str_error = str_message;
735 if ( strcmp( str_line, "+" ) && strcmp( str_line, "-" ) )
737 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
738 pr->lines, str_bad_record );
739 str_error = str_message;
742 min_posi.turn_to_move = (char)( ( str_line[0] == '+' ) ? black : white );
744 return ini_game( ptree, &min_posi, flag, str_name1, str_name2 );
749 read_board_rep3( const char *str_line, min_posi_t *pmin_posi )
751 int is_all_done, irank, ifile, isquare, piece, n, color;
752 int npawn, nlance, nknight, nsilver, ngold, nbishop, nrook;
753 unsigned int handv, hand_white, hand_black;
759 color = str_line[1] == '+' ? black : white;
760 for ( n = 2; str_line[n] != '\0'; n += 4 ) {
761 if ( str_line[n+1] == '\0' || str_line[n+2] == '\0'
762 || str_line[n+3] == '\0' || is_all_done )
764 str_error = str_bad_board;
767 if ( str_line[n] == '0' && str_line[n+1] == '0'
768 && str_line[n+2] == 'A' && str_line[n+3] == 'L' ) {
769 hand_black = pmin_posi->hand_black;
770 hand_white = pmin_posi->hand_white;
771 npawn = (int)(I2HandPawn(hand_black) + I2HandPawn(hand_white));
772 nlance = (int)(I2HandLance(hand_black) + I2HandLance(hand_white));
773 nknight = (int)(I2HandKnight(hand_black) + I2HandKnight(hand_white));
774 nsilver = (int)(I2HandSilver(hand_black) + I2HandSilver(hand_white));
775 ngold = (int)(I2HandGold(hand_black) + I2HandGold(hand_white));
776 nbishop = (int)(I2HandBishop(hand_black) + I2HandBishop(hand_white));
777 nrook = (int)(I2HandRook(hand_black) + I2HandRook(hand_white));
778 for ( isquare = 0; isquare < nsquare; isquare++ )
779 switch ( abs( pmin_posi->asquare[isquare] ) )
781 case pawn: case pro_pawn: npawn++; break;
782 case lance: case pro_lance: nlance++; break;
783 case knight: case pro_knight: nknight++; break;
784 case silver: case pro_silver: nsilver++; break;
785 case gold: ngold++; break;
786 case bishop: case horse: nbishop++; break;
787 case rook: case dragon: nrook++; break;
789 assert( pmin_posi->asquare[isquare] == empty );
792 handv = flag_hand_pawn * ( npawn_max -npawn );
793 handv += flag_hand_lance * ( nlance_max -nlance );
794 handv += flag_hand_knight * ( nknight_max -nknight );
795 handv += flag_hand_silver * ( nsilver_max -nsilver );
796 handv += flag_hand_gold * ( ngold_max -ngold );
797 handv += flag_hand_bishop * ( nbishop_max -nbishop );
798 handv += flag_hand_rook * ( nrook_max -nrook );
799 if ( color ) { pmin_posi->hand_white += handv; }
800 else { pmin_posi->hand_black += handv; }
805 ifile = str_line[n+0]-'0';
806 irank = str_line[n+1]-'0';
807 str_piece[0] = str_line[n+2];
808 str_piece[1] = str_line[n+3];
809 piece = str2piece( str_piece );
812 if ( ifile == 0 && ifile == 0 )
816 case pawn: handv = flag_hand_pawn; break;
817 case lance: handv = flag_hand_lance; break;
818 case knight: handv = flag_hand_knight; break;
819 case silver: handv = flag_hand_silver; break;
820 case gold: handv = flag_hand_gold; break;
821 case bishop: handv = flag_hand_bishop; break;
822 case rook: handv = flag_hand_rook; break;
824 str_error = str_bad_board;
827 if ( color ) { pmin_posi->hand_white += handv; }
828 else { pmin_posi->hand_black += handv; }
834 isquare = irank * nfile + ifile;
835 if ( piece == -2 || ifile < file1 || ifile > file9
836 || irank < rank1 || irank > rank9 || pmin_posi->asquare[isquare] )
838 str_error = str_bad_board;
841 pmin_posi->asquare[isquare] = (signed char)( color ? -piece : piece );
850 read_board_rep2( const char * str_line, min_posi_t *pmin_posi )
852 int irank, ifile, piece;
857 irank = str_line[1] - '1';
859 for ( ifile = 0; ifile < nfile; ifile++ )
860 if ( str_line[2+ifile*3] == '+' || str_line[2+ifile*3] == '-' )
862 str_piece[0] = str_line[2+ifile*3+1];
863 str_piece[1] = str_line[2+ifile*3+2];
864 piece = str2piece( str_piece );
865 if ( piece < 0 || pmin_posi->asquare[ irank*nfile + ifile ] )
867 str_error = str_bad_board;
870 pmin_posi->asquare[ irank*nfile + ifile ]
871 = (signed char)( str_line[ 2 + ifile*3 ] == '-' ? -piece : piece );
873 else { pmin_posi->asquare[ irank*nfile + ifile ] = empty; }
880 str2piece( const char *str )
884 for ( i = 0; i < 16; i++ )
886 if ( ! strcmp( astr_table_piece[i], str ) ) { break; }
888 if ( i == 0 || i == piece_null || i == 16 ) { i = -2; }
894 /* reads a csa line in str, trancates trailing spases.
896 * 0 EOF, no line is read.
897 * 1 a csa line is read in str
901 read_CSA_line( record_t *pr, char *str )
907 c = skip_comment( pr );
908 if ( isgraph( c ) || c == EOF ) { break; }
910 if ( c == EOF ) { return 0; }
912 do_comma = ( c == 'N' || c == '$' ) ? 0 : 1;
914 for ( i = 0; i < SIZE_CSALINE-1; i++ )
916 if ( c == EOF || c == '\n' || ( do_comma && c == ',' ) ) { break; }
921 if ( i == SIZE_CSALINE-1 )
923 snprintf( str_message, SIZE_MESSAGE, str_fmt_line,
924 pr->lines, str_ovrflw_line );
929 while ( isascii( (int)str[i] ) && isspace( (int)str[i] ) ) { i--; }
937 skip_comment( record_t *pr )
944 if ( c != '\'' ) { break; }
948 if ( c == EOF || c == '\n' ) { break; }
957 read_char( record_t *pr )
962 if ( c == '\n' ) { pr->lines++; }