#! perl -w use lib "/afs/sipb.mit.edu/user/kenta/chess-rep-0.4/share/perl/5.8.8"; use Chess::Rep; use Expect; use strict; $::command = "./glaurung"; $::killswitch = "killswitch"; $::matemult=100000; #die unless $ARGV[0] =~ /^\d+$/; $::timethink=$ARGV[0]; shift @ARGV; &start_engine; &main; $::exp->send("quit\n"); $::exp->soft_close(); sub main { #@moves_so_far=qw/c2c4 g8f6 c4c5 f6g8 c5c6 g8f6 c6b7 f6g8/; print << 'EOF'; Glaurung analysis EOF #my @moves_so_far=qw/f3 e5 h3/; my @moves_so_far; open FI,$ARGV[0] or die "cannot open file $ARGV[0]"; while(){ next if /^#/; my @G=split; for(@G){ next if /^\d+\.$/; s/^\d+\.//; push @moves_so_far,$_; } } print "

$ARGV[1], Pondering move ",(2+scalar@moves_so_far)/2, ", Glaurung $::timethink

\n
\n";
    my $rep=Chess::Rep->new;
    my $canon="";
    my $parity=1;
    for(@moves_so_far){
	$canon.=" ".canonicalmove($rep,$_);
        $parity=not$parity;
    }
    $canon.=" ";
    my $current_fen=$rep->get_fen();
    my @themoves=basic_algebraic_moves(@{$rep->status->{moves}});
    
    print STDERR "$canon\n";
    my $total=@themoves;
    my %continuation_score;
    my $count=1;
    for(@themoves){
	if (-e $::killswitch) {
	    unlink $::killswitch;
	    die "killswitch";
	}
	my($computer,$score,$pv,$depth,$nps)=
	    &engine($canon.$_,$::timethink);
	print STDERR " $count/$total is $_ -> $computer $score/$depth $nps $pv \n";
	$count++;
	my@sans=san_sequence($current_fen,$_,split /\s+/,$pv);
	my$line=&concat_san(@sans)." depth $depth nps $nps";
	$continuation_score{$line}=$score;
    }
    my@sorted_keys=(sort {score_compare($continuation_score{$a},$continuation_score{$b})} (keys %continuation_score));
    
    $count=1;
    for (@sorted_keys){
        my $i;
        if ($parity){
            $i=invert_score($continuation_score{$_});
        }else{
            $i=$continuation_score{$_};
        }
	print "$count. $i: $_\n";
	$count++;
    }
    print "
\n

Moves:\n",&concat_san(@moves_so_far); print"

\n\n

FEN $current_fen

\n"; print << 'EOF';

See the RCS file for previous moves. Here is the script used to generate this analysis.

"cp" = centi-pawn

EOF } sub engine { my $movelist1=shift; my $timethink=shift; #print "movelist1 $movelist1\n"; $::exp->send( << "EOF" ucinewgame position startpos moves $movelist1 go $timethink EOF #go wtime $two btime $two winc $hour binc $hour ); my($depth,$score,$pv,$nps); for(;;){ if (-e $::killswitch) { unlink $::killswitch; die "killswitch internal"; } #($matched_pattern_position, $error, $successfully_matching_string, $before_match, $after_match); my@expect_result=$::exp->expect(undef,("-re",'bestmove.*\r',"-re",'info depth.*score.*\r')) or die; my$successfully_matching_string=$expect_result[2]; #print STDERR "gotsms $successfully_matching_string\n"; if ($successfully_matching_string =~ /info depth .* score.*/){ die unless ($depth,$score,$nps,$pv)=($successfully_matching_string =~ /info depth (\d+) score (.*) time .* nodes .* nps (.*) pv (.*)/); } last if $successfully_matching_string =~ /bestmove/; } my$gotmatch=$::exp->match; die $_ unless $gotmatch=~/bestmove (\S+)/; my $computermove=$1; #print "$computermove: score $score, pv $pv\n"; ($computermove,$score,$pv,$depth,$nps) } sub basic_algebraic_moves { my @yesmoves; for(@_){ #printf("%02x ",$$_{piece}); my$go=lc(Chess::Rep::get_field_id($$_{from}) .Chess::Rep::get_field_id($$_{to})); if (($$_{piece}==0x81 and (Chess::Rep::get_row_col($$_{to}))[0] == 7) or ($$_{piece}==0x01 and (Chess::Rep::get_row_col($$_{to}))[0] == 0)) { for my $p (qw/n b r q/){ push @yesmoves,"$go$p" } } else { push @yesmoves,$go; } } @yesmoves; } sub canonicalmove { my($rep,$usermove)=@_; die if $rep->status->{mate}; die if $rep->status->{stalemate}; my %rh=%{${$rep->status}{hash_moves}}; my $r; eval {$r=$rep->go_move($usermove);}; if ($@){ print "Died $@\n"; die; } unless ($rh{"$$r{from_index}-$$r{to_index}"}) { print "bad\n"; die; } if ($$r{piece} eq 'P' and $$r{to_row}==7 and not $$r{promote}) { die "need promotion"; } my $gomove="$$r{from}$$r{to}"; $gomove .= $$r{promote} if ($$r{promote}); $gomove=lc$gomove; } sub san_sequence { my $current_fen=shift; my $rep=Chess::Rep->new($current_fen); my @sans; for(@_){ #print "doing $_\n"; my $result=$rep->go_move($_); push @sans,$$result{san} } @sans; } sub mate_convert { my $rawmoves=shift; if ($rawmoves<0){ -($::matemult+$rawmoves); } elsif ($rawmoves>0){ $::matemult-$rawmoves; } else { die "cannot convert $rawmoves" ; } } sub string_convert { if ($_[0] =~ /cp\s+(\S+)/) { $1; } elsif ($_[0] =~ /mate\s+(\S*)/){ &mate_convert($1); } else { die "cant convert $_[0]"; } } sub score_compare { (&string_convert($_[0])<=>(&string_convert($_[1]))); } sub concat_san { my $o=""; for(@_){ $o.=" $_"; } $o; } sub invert_score { my $answer; for($_[0]){ die "$_" unless /(.*)\s+(-?\d+)/; $answer=$1." ".(0-$2); } $answer; } sub start_engine { $::exp = Expect->spawn($::command) or die; $::exp->log_stdout(0); $::exp->log_file("/tmp/glauxz12.log"); $::exp->expect(15, ("Tord Romstad.\r")) or die; $::exp->send("uci\n"); $::exp->expect(5,("uciok\r")) or die; $::exp->send("isready\n"); $::exp->expect(5,"readyok\r") or die; }