+
+ $http_timer = AnyEvent->timer(after => 1.0, cb => sub {
+ fetch_pgn($url);
+ });
+}
+
+sub handle_position {
+ my ($pos) = @_;
+ find_clock_start($pos, $pos_calculating);
+
+ # If we're already chewing on this and there's nothing else in the queue,
+ # ignore it.
+ if (defined($pos_calculating) && $pos->fen() eq $pos_calculating->fen()) {
+ $pos_calculating->{'result'} = $pos->{'result'};
+ for my $key ('white_clock', 'black_clock', 'white_clock_target', 'black_clock_target') {
+ $pos_calculating->{$key} //= $pos->{$key};
+ }
+ return;
+ }
+
+ # If we're already thinking on something, stop and wait for the engine
+ # to approve.
+ if (defined($pos_calculating)) {
+ # Store the final data we have for this position in the history,
+ # with the precise clock information we just got from the new
+ # position. (Historic positions store the clock at the end of
+ # the position.)
+ #
+ # Do not output anything new to the main analysis; that's
+ # going to be obsolete really soon. (Exception: If we've never
+ # output anything for this move, ie., it didn't hit the 200ms
+ # limit, spit it out to the user anyway. It's probably a really
+ # fast blitz game or something, and it's good to show the moves
+ # as they come in even without great analysis.)
+ $pos_calculating->{'white_clock'} = $pos->{'white_clock'};
+ $pos_calculating->{'black_clock'} = $pos->{'black_clock'};
+ delete $pos_calculating->{'white_clock_target'};
+ delete $pos_calculating->{'black_clock_target'};
+
+ if (defined($pos_calculating_started)) {
+ output_json(0);
+ } else {
+ output_json(1);
+ }
+ $pos_calculating_started = [Time::HiRes::gettimeofday];
+ $pos_pv_started = undef;
+
+ # Ask the engine to stop; we will throw away its data until it
+ # sends us "bestmove", signaling the end of it.
+ $engine->{'stopping'} = 1;
+ uciprint($engine, "stop");
+ }
+
+ # It's wrong to just give the FEN (the move history is useful,
+ # and per the UCI spec, we should really have sent "ucinewgame"),
+ # but it's easier, and it works around a Stockfish repetition issue.
+ if ($engine->{'chess960'} != $pos->{'chess960'}) {
+ uciprint($engine, "setoption name UCI_Chess960 value " . ($pos->{'chess960'} ? 'true' : 'false'));
+ $engine->{'chess960'} = $pos->{'chess960'};
+ }
+ uciprint($engine, "position fen " . $pos->fen());
+ uciprint($engine, "go infinite");
+ $pos_calculating = $pos;
+ $pos_calculating_started = [Time::HiRes::gettimeofday];
+ $pos_pv_started = undef;
+
+ if (defined($engine2)) {
+ if (defined($pos_calculating_second_engine)) {
+ $engine2->{'stopping'} = 1;
+ uciprint($engine2, "stop");
+ }
+ if ($engine2->{'chess960'} != $pos->{'chess960'}) {
+ uciprint($engine2, "setoption name UCI_Chess960 value " . ($pos->{'chess960'} ? 'true' : 'false'));
+ $engine2->{'chess960'} = $pos->{'chess960'};
+ }
+ uciprint($engine2, "position fen " . $pos->fen());
+ uciprint($engine2, "go infinite");
+ $pos_calculating_second_engine = $pos;
+ $engine2->{'info'} = {};
+ }
+
+ $engine->{'info'} = {};
+ $last_move = time;
+
+ schedule_tb_lookup();
+
+ #
+ # Output a command every move to note that we're
+ # still paying attention -- this is a good tradeoff,
+ # since if no move has happened in the last half
+ # hour, the analysis/relay has most likely stopped
+ # and we should stop hogging server resources.
+ #
+ if (defined($t)) {
+ $t->cmd("date");
+ }