@@ -8,14 +8,14 @@ use std::time::Instant;
88use ply:: fen:: { parse_fen, to_fen, FenError , STARTPOS_FEN } ;
99use ply:: movegen:: generate_legal_moves;
1010use ply:: perft:: { perft, perft_divide} ;
11- use ply:: pgn:: { parse_pgn_reader , reconstruct_game, PgnError , PgnReader } ;
12- use ply:: stats:: { AggregateStatsAccumulator , summarize_game } ;
11+ use ply:: pgn:: { reconstruct_game, PgnError , PgnReader } ;
12+ use ply:: stats:: { summarize_game , AggregateStatsAccumulator } ;
1313use thiserror:: Error ;
1414
1515use self :: commands:: { Cli , Commands } ;
1616use self :: render:: {
1717 render_fen, render_perft, render_stats, render_summaries, render_validate, FenOutput ,
18- PerftOutput , StatsOutput , SummariesOutput , SummaryEntry , ValidateOutput ,
18+ PerftOutput , StatsOutput , SummariesOutput , SummaryEntry , ValidateFailure , ValidateOutput ,
1919} ;
2020
2121#[ derive( Debug , Error ) ]
@@ -32,64 +32,78 @@ pub enum CliError {
3232
3333pub fn run ( cli : Cli ) -> Result < ( ) , CliError > {
3434 match cli. command {
35- Commands :: Validate { file } => print ! ( "{}" , render_validate( & cmd_validate( & file) ?) ) ,
35+ Commands :: Validate { file, verbose } => {
36+ print ! ( "{}" , render_validate( & cmd_validate( & file, verbose) ?) )
37+ }
3638 Commands :: Summarize { file } => print ! ( "{}" , render_summaries( & cmd_summarize( & file) ?) ) ,
3739 Commands :: Stats { file, json } => print ! ( "{}" , render_stats( & cmd_stats( & file, json) ?) ?) ,
38- Commands :: Fen { fen, legal_moves } => print ! ( "{}" , render_fen( & cmd_fen( & fen, legal_moves) ?) ) ,
40+ Commands :: Fen { fen, legal_moves } => {
41+ print ! ( "{}" , render_fen( & cmd_fen( & fen, legal_moves) ?) )
42+ }
3943 Commands :: Perft { fen, depth, divide } => {
4044 print ! ( "{}" , render_perft( & cmd_perft( fen. as_deref( ) , depth, divide) ?) )
4145 }
4246 }
4347 Ok ( ( ) )
4448}
4549
46- fn cmd_validate ( file : & std:: path:: Path ) -> Result < ValidateOutput , CliError > {
50+ fn cmd_validate ( file : & std:: path:: Path , verbose : bool ) -> Result < ValidateOutput , CliError > {
4751 let reader = BufReader :: new ( File :: open ( file) ?) ;
4852 let mut ok = 0usize ;
4953 let mut failed = 0usize ;
5054 let mut total = 0usize ;
51- for game in PgnReader :: new ( reader) {
55+ let mut failures = Vec :: new ( ) ;
56+ for ( idx, game) in PgnReader :: new ( reader) . enumerate ( ) {
5257 total += 1 ;
53- match reconstruct_game ( & game?) {
58+ let game = game?;
59+ match reconstruct_game ( & game) {
5460 Ok ( _) => ok += 1 ,
55- Err ( _) => failed += 1 ,
61+ Err ( err) => {
62+ failed += 1 ;
63+ if verbose {
64+ failures
65+ . push ( ValidateFailure { game_index : idx + 1 , message : err. to_string ( ) } ) ;
66+ }
67+ }
5668 }
5769 }
58- Ok ( ValidateOutput { validated_games : total, valid : ok, invalid : failed } )
70+ Ok ( ValidateOutput { validated_games : total, valid : ok, invalid : failed, failures } )
5971}
6072
6173fn cmd_summarize ( file : & std:: path:: Path ) -> Result < SummariesOutput , CliError > {
6274 let reader = BufReader :: new ( File :: open ( file) ?) ;
6375 let mut entries = Vec :: new ( ) ;
6476 for ( idx, game) in PgnReader :: new ( reader) . enumerate ( ) {
6577 match reconstruct_game ( & game?) {
66- Ok ( record) => entries. push ( SummaryEntry :: Valid { index : idx + 1 , summary : summarize_game ( & record) } ) ,
67- Err ( err) => entries. push ( SummaryEntry :: Invalid { index : idx + 1 , error : err. to_string ( ) } ) ,
78+ Ok ( record) => entries
79+ . push ( SummaryEntry :: Valid { index : idx + 1 , summary : summarize_game ( & record) } ) ,
80+ Err ( err) => {
81+ entries. push ( SummaryEntry :: Invalid { index : idx + 1 , error : err. to_string ( ) } )
82+ }
6883 }
6984 }
7085 Ok ( SummariesOutput { entries } )
7186}
7287
7388fn cmd_stats ( file : & std:: path:: Path , json : bool ) -> Result < StatsOutput , CliError > {
7489 let reader = BufReader :: new ( File :: open ( file) ?) ;
75- if json {
76- let games = parse_pgn_reader ( reader) ?;
77- let records = games. iter ( ) . filter_map ( |g| reconstruct_game ( g) . ok ( ) ) . collect :: < Vec < _ > > ( ) ;
78- let summaries = records. iter ( ) . map ( summarize_game) . collect :: < Vec < _ > > ( ) ;
79- let mut acc = AggregateStatsAccumulator :: default ( ) ;
80- for record in & records {
81- acc. push_record ( record) ;
82- }
83- return Ok ( StatsOutput { json : true , stats : acc. finish ( ) , summaries } ) ;
84- }
85-
8690 let mut acc = AggregateStatsAccumulator :: default ( ) ;
91+ let mut summaries = Vec :: new ( ) ;
92+
8793 for game in PgnReader :: new ( reader) {
88- if let Ok ( record) = reconstruct_game ( & game?) {
89- acc. push_record ( & record) ;
94+ let game = game?;
95+ if let Ok ( record) = reconstruct_game ( & game) {
96+ if json {
97+ let summary = summarize_game ( & record) ;
98+ acc. push_record_with_summary ( & record, & summary) ;
99+ summaries. push ( summary) ;
100+ } else {
101+ acc. push_record ( & record) ;
102+ }
90103 }
91104 }
92- Ok ( StatsOutput { json : false , stats : acc. finish ( ) , summaries : Vec :: new ( ) } )
105+
106+ Ok ( StatsOutput { json, stats : acc. finish ( ) , summaries } )
93107}
94108
95109fn cmd_fen ( fen : & str , legal_moves : bool ) -> Result < FenOutput , CliError > {
0 commit comments