+sub schedule_tb_lookup {
+ return if (!defined($remoteglotconf::tb_serial_key));
+ my $pos = $pos_waiting // $pos_calculating;
+ return if (exists($tb_cache{$pos->fen()}));
+
+ # If there's more than seven pieces, there's not going to be an answer,
+ # so don't bother.
+ return if ($pos->num_pieces() > 7);
+
+ # Max one at a time. If it's still relevant when it returns,
+ # schedule_tb_lookup() will be called again.
+ return if ($tb_lookup_running);
+
+ $tb_lookup_running = 1;
+ my $url = 'http://158.250.18.203:6904/tasks/addtask?auth.login=' .
+ $remoteglotconf::tb_serial_key .
+ '&auth.password=aquarium&type=0&fen=' .
+ URI::Escape::uri_escape($pos->fen());
+ print TBLOG "Downloading $url...\n";
+ AnyEvent::HTTP::http_get($url, sub {
+ handle_tb_lookup_return(@_, $pos, $pos->fen());
+ });
+}
+
+sub handle_tb_lookup_return {
+ my ($body, $header, $pos, $fen) = @_;
+ print TBLOG "Response for [$fen]:\n";
+ print TBLOG $header . "\n\n";
+ print TBLOG $body . "\n\n";
+ eval {
+ my $response = JSON::XS::decode_json($body);
+ if ($response->{'ErrorCode'} != 0) {
+ die "Unknown tablebase server error: " . $response->{'ErrorDesc'};
+ }
+ my $state = $response->{'Response'}{'StateString'};
+ if ($state eq 'COMPLETE') {
+ my $pgn = Chess::PGN::Parse->new(undef, $response->{'Response'}{'Moves'});
+ if (!defined($pgn) || !$pgn->read_game()) {
+ warn "Error in parsing PGN\n";
+ } else {
+ $pgn->quick_parse_game;
+ my $pvpos = $pos;
+ my $moves = $pgn->moves;
+ my @uci_moves = ();
+ for my $move (@$moves) {
+ my $uci_move;
+ ($pvpos, $uci_move) = $pvpos->make_pretty_move($move);
+ push @uci_moves, $uci_move;
+ }
+ $tb_cache{$fen} = {
+ result => $pgn->result,
+ pv => \@uci_moves
+ };
+ output();
+ }
+ } elsif ($state =~ /QUEUED/ || $state =~ /PROCESSING/) {
+ # Try again in a second. Note that if we have changed
+ # position in the meantime, we might query a completely
+ # different position! But that's fine.
+ } else {
+ die "Unknown response state " . $state;
+ }
+
+ # Wait a second before we schedule another one.
+ $tb_retry_timer = AnyEvent->timer(after => 1.0, cb => sub {
+ $tb_lookup_running = 0;
+ schedule_tb_lookup();
+ });
+ };
+ if ($@) {
+ warn "Error in tablebase lookup: $@";
+
+ # Don't try this one again, but don't block new lookups either.
+ $tb_lookup_running = 0;
+ }
+}
+