next if (!defined($pos));
if ($pos->fen() eq $pos_for_movelist->fen()) {
$pos->{'history'} = \@uci_movelist;
- $pos->{'pretty_history'} = \@pretty_movelist;
}
}
$getting_movelist = 0;
push @uci_moves, $uci_move;
}
$pos->{'history'} = \@uci_moves;
- $pos->{'pretty_history'} = $moves;
# Sometimes, PGNs lose a move or two for a short while,
# or people push out new ones non-atomically.
# single-PV only for now
$json->{'pv_uci'} = $info->{'pv'};
- $json->{'pv_pretty'} = [ prettyprint_pv($pos_calculating, @{$info->{'pv'}}) ];
my %refutation_lines = ();
my @refutation_lines = ();
score_sort_key => score_sort_key($info, $pos_calculating, $mpv, 0),
pretty_score => short_score($info, $pos_calculating, $mpv),
pretty_move => $pretty_move,
- pv_pretty => \@pretty_pv,
};
$refutation_lines{$pv->[0]}->{'pv_uci'} = $pv;
};
}
$json->{'refutation_lines'} = \%refutation_lines;
- open my $fh, ">", $remoteglotconf::json_output . ".tmp"
+ my $encoded = JSON::XS::encode_json($json);
+ atomic_set_contents($remoteglotconf::json_output, $encoded);
+
+ if (exists($pos_calculating->{'history'}) &&
+ defined($remoteglotconf::json_history_dir)) {
+ my $halfmove_num = scalar @{$pos_calculating->{'history'}};
+ (my $fen = $pos_calculating->fen()) =~ tr,/ ,-_,;
+ my $filename = $remoteglotconf::json_history_dir . "/move$halfmove_num-$fen.json";
+
+ # Overwrite old analysis (assuming it exists at all) if we're
+ # using a different engine, or if we've calculated deeper.
+ # nodes is used as a tiebreaker. Don't bother about Multi-PV
+ # data; it's not that important.
+ my ($old_engine, $old_depth, $old_nodes) = get_json_analysis_stats($filename);
+ my $new_depth = $json->{'depth'} // 0;
+ my $new_nodes = $json->{'nodes'} // 0;
+ if (!defined($old_engine) ||
+ $old_engine ne $json->{'id'}{'name'} ||
+ $new_depth > $old_depth ||
+ ($new_depth == $old_depth && $new_nodes >= $old_nodes)) {
+ atomic_set_contents($filename, $encoded);
+ }
+ }
+}
+
+sub atomic_set_contents {
+ my ($filename, $contents) = @_;
+
+ open my $fh, ">", $filename . ".tmp"
or return;
- print $fh JSON::XS::encode_json($json);
+ print $fh $contents;
+ close $fh;
+ rename($filename . ".tmp", $filename);
+}
+
+sub get_json_analysis_stats {
+ my $filename = shift;
+
+ my ($engine, $depth, $nodes);
+
+ open my $fh, "<", $filename
+ or return undef;
+ local $/ = undef;
+ eval {
+ my $json = JSON::XS::decode_json(<$fh>);
+ $engine = $json->{'id'}{'name'} // die;
+ $depth = $json->{'depth'} // 0;
+ $nodes = $json->{'nodes'} // 0;
+ };
close $fh;
- rename($remoteglotconf::json_output . ".tmp", $remoteglotconf::json_output);
+ if ($@) {
+ warn "Error in decoding $filename: $@";
+ return undef;
+ }
+ return ($engine, $depth, $nodes);
}
sub uciprint {