+ $engine->{'readbuf'} .= $tmp;
+ }
+
+ # Blah.
+ my @lines = ();
+ while ($engine->{'readbuf'} =~ s/^([^\n]*)\n//) {
+ my $line = $1;
+ $line =~ tr/\r\n//d;
+ push @lines, $line;
+ }
+ return @lines;
+}
+
+# Find all possible legal moves.
+sub calculate_refutation_moves {
+ my $pos = shift;
+ my $board = $pos->{'board'};
+ my %refutation_moves = ();
+ for my $col (0..7) {
+ for my $row (0..7) {
+ my $piece = substr($board->[$row], $col, 1);
+
+ # Check that there's a piece of the right color on this square.
+ next if ($piece eq '-');
+ if ($pos->{'toplay'} eq 'W') {
+ next if ($piece ne uc($piece));
+ } else {
+ next if ($piece ne lc($piece));
+ }
+
+ for my $to_col (0..7) {
+ for my $to_row (0..7) {
+ next if ($col == $to_col && $row == $to_row);
+ next unless (can_reach($board, $piece, $row, $col, $to_row, $to_col));
+
+ my $promo = ""; # FIXME
+ my $nb = make_move($board, $row, $col, $to_row, $to_col, $promo);
+ my $check = in_check($nb);
+ next if ($check eq 'both');
+ if ($pos->{'toplay'} eq 'W') {
+ next if ($check eq 'white');
+ } else {
+ next if ($check eq 'black');
+ }
+ my $move = move_to_uci_notation($row, $col, $to_row, $to_col, $promo);
+ $refutation_moves{$move} = { depth => $second_engine_start_depth - 1, score_cp => 0, pv => '' };
+ }
+ }
+ }
+ }
+ return %refutation_moves;
+}
+
+sub give_new_move_to_second_engine {
+ my $pos = shift;
+
+ # Find the move that's been analyzed the shortest but is most promising.
+ # Tie-break on UCI move representation.
+ my $best_move = undef;
+ for my $move (sort keys %refutation_moves) {
+ if (!defined($best_move)) {
+ $best_move = $move;
+ next;
+ }
+ my $best = $refutation_moves{$best_move};
+ my $this = $refutation_moves{$move};
+
+ if ($this->{'depth'} < $best->{'depth'} ||
+ ($this->{'depth'} == $best->{'depth'} && $this->{'score_cp'} < $best->{'score_cp'})) {
+ $best_move = $move;
+ next;
+ }