Ticket #8: kombilo05m.patch

File kombilo05m.patch, 25.5 kB (added by ug, 2 years ago)

Aloril's patch

  • board1.py

    diff -urN --exclude-from=kombilo05.exclude kombilo05.orig/board1.py kombilo05/board1.py
    old new  
    416416 
    417417        return (x,y)     
    418418 
    419     def placeMark(self, pos, color, outln='', size=''): 
     419    def placeInfluenceMark(self, pos, color, type): 
     420        if type=='territory': 
     421            self.placeMark(pos, color="", outln=color, size="small", type="rectangle") 
     422        elif type=='moyo': 
     423            self.placeMark(pos, color="", outln=color, size="small", type="triangle") 
     424        elif type=='area': 
     425            self.placeMark(pos, color="", outln=color, size="small", type="circle") 
     426         
     427 
     428    def placeMark(self, pos, color, outln='', size='', type='circle'): 
    420429        """ Place colored mark at pos. """ 
    421430        x1, x2, y1, y2 = self.getPixelCoord(pos, 1) 
    422431 
     
    426435        else: 
    427436            tmp1 = 2 
    428437            tmp2 = 2 
    429         self.create_oval(x1+tmp1, x2+tmp2, y1-tmp1, y2-tmp2, fill = color, 
    430                          outline = outln, tags=('marks', 'non-bg')) 
     438        if type=='circle': 
     439            self.create_oval(x1+tmp1, x2+tmp2, y1-tmp1, y2-tmp2, fill = color, 
     440                             outline = outln, tags=('marks', 'non-bg')) 
     441        elif type=='rectangle': 
     442            self.create_rectangle(x1+6, x2+6, y1-6, y2-6, fill = color, 
     443                                  outline = outln, tags=('marks','non-bg')) 
     444        elif type=='triangle': 
     445            self.create_polygon((x1+y1)/2, x2+5-5, x1+5, y2-5-5, y1-5, y2-5-5, 
     446                                fill = color, outline = outln, tags=('marks','non-bg')) 
    431447        self.marks[pos]=color 
    432448        self.onChange() 
    433449 
     
    565581        y = int(r*math.sin((degree-90)*radPerDeg) + r) 
    566582        return (x,y) 
    567583 
     584    def drawShadedStone(self, pos, color, stipple='gray50', size='normal'): 
     585        x1, x2, y1, y2 = self.getPixelCoord(pos, 1) 
     586        if size=='normal': 
     587            tmp1 = 0 
     588            tmp2 = 0 
     589        elif size=='medium': 
     590            tmp1 = 3 
     591            tmp2 = 3 
     592        elif size=='small': 
     593            tmp1 = 6 
     594            tmp2 = 6 
     595        elif size=='tiny': 
     596            tmp1 = 9 
     597            tmp2 = 9 
     598        self.create_oval(x1+tmp1, x2+tmp2, y1-tmp1, y2-tmp2, 
     599                         fill=color, stipple=stipple, 
     600                         outline='', tags=('shaded','non-bg'))  
     601 
    568602    def shadedStone(self, event): 
    569603        x, y = self.getBoardCoord((event.x, event.y), 1) 
    570604        if (x,y) == self.shadedStonePos: return     # nothing changed 
  • kombilo05

    diff -urN --exclude-from=kombilo05.exclude kombilo05.orig/gtp.py kombilo05/gtp.py
    old new  
     1#! /usr/bin/env python 
     2 
     3# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
     4# This program is distributed with GNU Go, a Go program.        # 
     5#                                                               # 
     6# Write gnugo@gnu.org or see http://www.gnu.org/software/gnugo/ # 
     7# for more information.                                         # 
     8#                                                               # 
     9# Copyright 1999, 2000, 2001, 2002, 2003 and 2004               # 
     10# by the Free Software Foundation.                              # 
     11#                                                               # 
     12# This program is free software; you can redistribute it and/or # 
     13# modify it under the terms of the GNU General Public License   # 
     14# as published by the Free Software Foundation - version 2.     # 
     15#                                                               # 
     16# This program is distributed in the hope that it will be       # 
     17# useful, but WITHOUT ANY WARRANTY; without even the implied    # 
     18# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR       # 
     19# PURPOSE.  See the GNU General Public License in file COPYING  # 
     20# for more details.                                             # 
     21#                                                               # 
     22# You should have received a copy of the GNU General Public     # 
     23# License along with this program; if not, write to the Free    # 
     24# Software Foundation, Inc., 59 Temple Place - Suite 330,       # 
     25# Boston, MA 02111, USA.                                        # 
     26# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
     27 
     28# some comments (like above) and 
     29# lots of code copied from twogtp.py from gnugo-3.6-pre4 
     30# additions/changes by Aloril 2004 
     31 
     32 
     33import popen2 
     34import sys 
     35import string 
     36import time 
     37import os 
     38 
     39debug = 1 
     40 
     41def coords_to_sgf(size, board_coords): 
     42    global debug 
     43     
     44    board_coords = string.lower(board_coords) 
     45    if board_coords == "pass": 
     46        return "" 
     47    if debug>1: 
     48        print "Coords: <" + board_coords + ">" 
     49    letter = board_coords[0] 
     50    digits = board_coords[1:] 
     51    if letter > "i": 
     52        sgffirst = chr(ord(letter) - 1) 
     53    else: 
     54        sgffirst = letter 
     55    sgfsecond = chr(ord("a") + int(size) - int(digits)) 
     56    return sgffirst + sgfsecond 
     57 
     58 
     59def sgf_to_coords(size, sgf_coords): 
     60    print sgf_coords 
     61    letter = string.upper(sgf_coords[0]) 
     62    if letter>="I": 
     63        letter = chr(ord(letter)+1) 
     64    digit = str(ord('a') + int(size) - ord(sgf_coords[1])) 
     65    return letter+digit 
     66 
     67 
     68class GTP_connection: 
     69 
     70    # 
     71    # Class members: 
     72    #   outfile         File to write to 
     73    #   infile          File to read from 
     74 
     75    def __init__(self, command): 
     76        try: 
     77            infile, outfile = popen2.popen2(command) 
     78        except: 
     79            print "popen2 failed" 
     80            sys.exit(1) 
     81        self.infile  = infile 
     82        self.outfile = outfile 
     83 
     84        for i in range(100): 
     85            log_name = "gtp%03i.log" % i 
     86            if not os.path.exists(log_name): 
     87                break 
     88        self.log_fp = open(log_name, "w") 
     89        self.log_fp.write(command+"\n") 
     90        self.log_fp.flush() 
     91         
     92    def exec_cmd(self, cmd): 
     93        global debug 
     94         
     95        if debug: 
     96            sys.stderr.write("GTP command: " + cmd + "\n") 
     97        self.outfile.write(cmd + "\n\n") 
     98        self.outfile.flush() 
     99        if self.log_fp: 
     100            self.log_fp.write("Time: %f\n" % time.time()) 
     101            self.log_fp.write(cmd + "\n\n") 
     102            self.log_fp.flush() 
     103        result = "" 
     104        line = self.infile.readline() 
     105        if self.log_fp: 
     106            self.log_fp.write(line) 
     107            self.log_fp.flush() 
     108        while line != "\n": 
     109            result = result + line 
     110            line = self.infile.readline() 
     111            if self.log_fp: 
     112                self.log_fp.write(line) 
     113                self.log_fp.flush() 
     114        if debug: 
     115            sys.stderr.write("Reply: " + result + "\n") 
     116 
     117        # Remove trailing newline from the result 
     118        if result[-1] == "\n": 
     119            result = result[:-1] 
     120 
     121        if len(result) == 0: 
     122            return "ERROR: len = 0" 
     123        if (result[0] == "?"): 
     124            return "ERROR: GTP Command failed: " + result[2:] 
     125        if (result[0] == "="): 
     126            return result[2:] 
     127        return "ERROR: Unrecognized answer: " + result 
     128         
     129 
     130 
     131class GTP_player: 
     132 
     133    # Class members: 
     134    #    connection     GTP_connection 
     135 
     136    def __init__(self, command): 
     137        self.connection = GTP_connection(command) 
     138        protocol_version = self.connection.exec_cmd("protocol_version") 
     139        if protocol_version[:5] != "ERROR": 
     140            self.protocol_version = protocol_version 
     141        else: 
     142            self.protocol_version = "1" 
     143 
     144    def is_known_command(self, command): 
     145        return self.connection.exec_cmd("known_command " + command) == "true" 
     146 
     147    def genmove(self, color): 
     148        if color[0] in ["b", "B"]: 
     149            command = "black" 
     150        elif color[0] in ["w", "W"]: 
     151            command = "white" 
     152        if self.protocol_version == "1": 
     153            command = "genmove_" + command 
     154        else: 
     155            command = "genmove " + command 
     156 
     157        return self.connection.exec_cmd(command) 
     158 
     159    def black(self, move): 
     160        if self.protocol_version == "1": 
     161            self.connection.exec_cmd("black " + move) 
     162        else: 
     163            self.connection.exec_cmd("play black " + move) 
     164 
     165    def white(self, move): 
     166        if self.protocol_version == "1": 
     167            self.connection.exec_cmd("white " + move) 
     168        else: 
     169            self.connection.exec_cmd("play white " + move) 
     170 
     171    def komi(self, komi): 
     172        self.connection.exec_cmd("komi " + komi) 
     173 
     174    def boardsize(self, size): 
     175        self.connection.exec_cmd("boardsize " + size) 
     176        if self.protocol_version != "1": 
     177            self.connection.exec_cmd("clear_board") 
     178 
     179    def handicap(self, handicap, handicap_type): 
     180        if handicap_type == "fixed": 
     181            result = self.connection.exec_cmd("fixed_handicap %d" % (handicap)) 
     182        else: 
     183            result = self.connection.exec_cmd("place_free_handicap %d" 
     184                                              % (handicap)) 
     185 
     186        return string.split(result, " ") 
     187 
     188    def loadsgf(self, endgamefile, move_number): 
     189        if self.connection.log_fp: 
     190            self.connection.log_fp.write(open(endgamefile).read()) 
     191            self.connection.log_fp.flush() 
     192        return self.connection.exec_cmd(string.join(["loadsgf", endgamefile, 
     193                                 str(move_number)])) 
     194 
     195    def list_stones(self, color): 
     196        return string.split(self.connection.exec_cmd("list_stones " + color), " ") 
     197 
     198    def quit(self): 
     199        return self.connection.exec_cmd("quit") 
     200     
     201    def showboard(self): 
     202        board = self.connection.exec_cmd("showboard") 
     203        if board and (board[0] == "\n"): 
     204            board = board[1:] 
     205        return board 
     206 
     207    def get_random_seed(self): 
     208        result = self.connection.exec_cmd("get_random_seed") 
     209        if result[:5] == "ERROR": 
     210            return "unknown" 
     211        return result 
     212 
     213    def set_random_seed(self, seed): 
     214        self.connection.exec_cmd("set_random_seed " + seed) 
     215 
     216    def get_program_name(self): 
     217        return self.connection.exec_cmd("name") + " " + \ 
     218               self.connection.exec_cmd("version") 
     219 
     220    def final_score(self): 
     221        return self.connection.exec_cmd("final_score") 
     222 
     223    def score(self): 
     224        return self.final_score(self) 
     225 
     226    def experimental_score(self, color): 
     227        self.showboard() 
     228        return self.connection.exec_cmd("experimental_score " + color) 
     229 
     230    def all_move_values(self): 
     231        moves = string.split(self.connection.exec_cmd("all_move_values")) 
     232        result = [] 
     233        for i in range(0, len(moves), 2): 
     234            result.append((moves[i], float(moves[i+1]))) 
     235        return result 
     236 
     237    def dragon_stones_and_status(self): 
     238        dragon_status = {} 
     239        for line in string.split(self.connection.exec_cmd("dragon_status"), "\n"): 
     240            lst = string.split(line) 
     241            stone = lst[0][:-1] 
     242            status = lst[1] 
     243            dragon_status[stone] = status 
     244        result = [] 
     245        for line in string.split(self.connection.exec_cmd("dragon_stones"), "\n"): 
     246            stone_lst = string.split(line) 
     247            for stone in stone_lst: 
     248                if dragon_status.has_key(stone): 
     249                    key_stone = stone 
     250                    break 
     251            else: 
     252                key_stone = "" 
     253            for stone in stone_lst: 
     254                status = dragon_status.get(key_stone, "unknown") 
     255                result.append((stone, status)) 
     256        return result 
     257 
     258    def influence_regions(self, color): 
     259        result = [] 
     260        data = self.connection.exec_cmd("initial_influence " + color + " influence_regions") 
     261        for line in string.split(data, "\n"): 
     262            result.append(map(int, string.split(line))) 
     263        return result 
     264             
     265 
     266    def set_board(self, black_stones, white_stones): 
     267        self.connection.exec_cmd("clear_board") 
     268        for color, stone_lst in (("black", black_stones), ("white", white_stones)): 
     269            for stone in stone_lst: 
     270                self.connection.exec_cmd("play " + color + " " + stone) 
     271        self.showboard() 
     272 
     273    def cputime(self): 
     274        if (self.is_known_command("cputime")): 
     275            return self.connection.exec_cmd("cputime") 
     276        else: 
     277            return "0" 
  • kombilo.py

    diff -urN --exclude-from=kombilo05.exclude kombilo05.orig/kombilo.py kombilo05/kombilo.py
    old new  
    6565 
    6666from board1 import * 
    6767import v 
     68from gtp import GTP_player 
     69 
     70analyze_engine_command = "/usr/local/src/gnugo-3.6/interface/gnugo --mode gtp --chinese-rules --never-resign" 
     71analyze_engine_command = "/usr/local/src/gnugo-3.6/interface/gnugo --mode gtp --chinese-rules --never-resign" 
     72#for i in range(100): 
     73#    engine_sgf_name = "engine%03i.sgf" % i 
     74#    if not os.path.exists(engine_sgf_name): 
     75#        break 
     76#play_engine_command = "/usr/local/src/gnugo-3.4/interface/gnugo --mode gtp --chinese-rules --never-resign -o " + engine_sgf_name 
     77play_engine_command = "/usr/local/src/gnugo-3.4/interface/gnugo --mode gtp --chinese-rules --never-resign" 
    6878 
    6979try: 
    7080    from sgfpars import Node, Cursor, SGFError, SGFescape 
     
    59795989        except IOError: 
    59805990            showwarning('IOError', 'Could not write kombilo.def') 
    59815991 
     5992        self.analyze_engine.quit() 
     5993        self.play_engine.quit() 
    59825994        self.master.quit() 
    59835995         
    59845996 
     
    67806792        self.currentSearchPattern = None 
    67816793        self.balloonHelp() 
    67826794 
     6795        self.analyze_engine = GTP_player(analyze_engine_command) 
     6796        print "Analyze:", self.analyze_engine.get_program_name() 
     6797        self.play_engine = GTP_player(play_engine_command) 
     6798        self.play_engine.get_random_seed() 
     6799        #self.play_engine.handicap(2, "fixed") 
     6800        print "Opponent:", self.play_engine.get_program_name() 
     6801 
    67836802 
    67846803# --------------------------------------------------------------------------------------- 
    67856804 
  • kombilo05

    diff -urN --exclude-from=kombilo05.exclude kombilo05.orig/v.py kombilo05/v.py
    old new  
    5050    from sgfparser import Node, Cursor, SGFError, SGFescape 
    5151from board1 import * 
    5252 
     53import gtp 
     54 
    5355# --------------------------------------------------------------------------------------- 
    5456 
    5557class BunchTkVar: 
     
    15231525            pass 
    15241526 
    15251527        return 0 
     1528 
     1529    def getCurrentPosAsSGFstring(self): 
     1530        n = self.cursor.currentN 
     1531        result = [] 
     1532        while n: 
     1533            result.append(n.SGFstring) 
     1534            n = n.previous 
     1535        result.reverse() 
     1536        return "(" + join(result, "") + ")\n" 
     1537 
     1538    def analyzePosition(self): 
     1539        class AnalyseInfo: pass 
     1540        pos_as_sgf = self.getCurrentPosAsSGFstring() 
     1541        if not hasattr(self, "analyze_cache"): self.analyze_cache = {} 
     1542        if self.analyze_cache.has_key(pos_as_sgf): 
     1543            print "Cached" 
     1544            print pos_as_sgf 
     1545            analyse_info = self.analyze_cache[pos_as_sgf] 
     1546            color = analyse_info.color 
     1547            move = analyse_info.move 
     1548            score = analyse_info.score 
     1549            moves = analyse_info.moves 
     1550            dragon_stone_status = analyse_info.dragon_stone_status 
     1551            influence = analyse_info.influence 
     1552        else: 
     1553            self.analyze_cache[pos_as_sgf] = analyse_info = AnalyseInfo() 
     1554            gtp_sgf = "gtp.sgf" 
     1555            fp = open(gtp_sgf, "w") 
     1556            fp.write(pos_as_sgf) 
     1557            fp.close() 
     1558            analyse_info.color = color = self.analyze_engine.loadsgf(gtp_sgf, "") 
     1559            self.analyze_engine.showboard() 
     1560            node_count0 = int(self.analyze_engine.connection.exec_cmd("get_trymove_counter")) 
     1561            analyse_info.move = move = self.analyze_engine.connection.exec_cmd("reg_genmove "+ color) 
     1562            print move 
     1563            score = self.analyze_engine.connection.exec_cmd("estimate_score " + color) 
     1564            #score1 = self.analyze_engine.experimental_score(color) 
     1565            #score = score0 + " | " + score1 
     1566            node_count1 = int(self.analyze_engine.connection.exec_cmd("get_trymove_counter")) 
     1567            tmp = node_count = node_count1-node_count0 
     1568            node_count_str = "" 
     1569            if not node_count: 
     1570                node_count_str = "0" 
     1571            else: 
     1572                while tmp: 
     1573                    tmp, tmp_rem = divmod(tmp, 1000) 
     1574                    if node_count_str: node_count_str = ","+node_count_str 
     1575                    if tmp: 
     1576                        node_count_str = ("%03i" % tmp_rem) + node_count_str 
     1577                    else: 
     1578                        node_count_str = str(tmp_rem) + node_count_str 
     1579            score += "  ("+node_count_str+" nodes)" 
     1580            print "!:", score 
     1581            analyse_info.score = score 
     1582 
     1583            #Moves candidates 
     1584            if move!="PASS": 
     1585                #moves = split(self.analyze_engine.connection.exec_cmd("top_moves")) 
     1586                analyse_info.moves = moves = self.analyze_engine.all_move_values() 
     1587            else: 
     1588                analyse_info.moves = moves = [] 
     1589 
     1590            #Dragons 
     1591            if self.analyze_engine.connection.exec_cmd("list_stones black") or \ 
     1592               self.analyze_engine.connection.exec_cmd("list_stones white"): 
     1593                #dragon_data = self.analyze_engine.connection.exec_cmd("dragon_data") 
     1594                analyse_info.dragon_stone_status = dragon_stone_status = \ 
     1595                                                   self.analyze_engine.dragon_stones_and_status() 
     1596            else: 
     1597                analyse_info.dragon_stone_status = dragon_stone_status = [] 
     1598 
     1599            #Influence 
     1600            analyse_info.influence = influence = self.analyze_engine.influence_regions(color) 
     1601 
     1602        #Display results 
     1603        self.scoreVar.set(score) 
     1604        #Move candidates 
     1605        for pos, value in moves: 
     1606            #print pos, move, pos==move 
     1607            if pos==move: postfix = "!" 
     1608            else: postfix = "" 
     1609            pos = self.convCoord(gtp.coords_to_sgf(self.board.boardSize, pos)) 
     1610            if value<1.0: 
     1611                value = "<1" 
     1612            else: 
     1613                value = str(int(value)) 
     1614            self.board.placeLabel(pos, "LB", value + postfix) 
     1615        #Dragon status 
     1616        for stone, status in dragon_stone_status: 
     1617            #print stone, status 
     1618            if status=="critical": 
     1619                label = "!" 
     1620            elif status=="dead": 
     1621                label = "x" 
     1622            else: 
     1623                label = "" 
     1624            if label: 
     1625                pos = self.convCoord(gtp.coords_to_sgf(self.board.boardSize, stone)) 
     1626                self.board.placeLabel(pos, "LB", label) 
     1627        #Influence 
     1628        for j in range(len(influence)): 
     1629            for i in range(len(influence[j])): 
     1630                inf = influence[j][i] 
     1631                pos = i+1, j+1 
     1632                if inf==3: 
     1633                    self.board.placeInfluenceMark(pos, "green", "territory") 
     1634                elif inf==2: 
     1635                    self.board.placeInfluenceMark(pos, "#00C000", "moyo") 
     1636                elif inf==1: 
     1637                    self.board.placeInfluenceMark(pos, "#007000", "area") 
     1638                elif inf==-3: 
     1639                    self.board.placeInfluenceMark(pos, "red", "territory") 
     1640                elif inf==-2: 
     1641                    self.board.placeInfluenceMark(pos, "#C00000", "moyo") 
     1642                elif inf==-1: 
     1643                    self.board.placeInfluenceMark(pos, "#700000", "area") 
     1644         
     1645 
     1646    def playCurrentMoveInEngine(self): 
     1647        n = self.cursor.currentNode() 
     1648        print n 
     1649        pos_as_sgf = self.getCurrentPosAsSGFstring() 
     1650        if len(n)==1: 
     1651            if hasattr(self, "lastEnginePos"): 
     1652                if self.lastEnginePos[:-2] + self.cursor.currentN.SGFstring + self.lastEnginePos[-2:]!=pos_as_sgf: 
     1653                    print "Position not ok!" 
     1654                    return 
     1655            gtp_move = gtp.sgf_to_coords(self.board.boardSize, n.values()[0][0]) 
     1656            print gtp_move 
     1657            if n.keys()[0]=="B": 
     1658                self.play_engine.black(gtp_move) 
     1659                next_color = "white" 
     1660            else: 
     1661                self.play_engine.white(gtp_move) 
     1662                next_color = "black" 
     1663            move = self.play_engine.genmove(next_color) 
     1664            print move 
     1665            pos = self.convCoord(gtp.coords_to_sgf(self.board.boardSize, move)) 
     1666            self.nextMove(pos) 
     1667            pos_as_sgf = self.getCurrentPosAsSGFstring() 
     1668            #x1,y1,x2,y2 = self.board.getPixelCoord(pos) 
     1669            #print pos, x1,y1,x2,y2 
     1670            #class Ev: pass 
     1671            #ev = Ev() 
     1672            #ev.x = (x1+x2)/2 
     1673            #ev.y = (y1+y2)/2 
     1674            #self.cursor.onButton1(ev) 
     1675            #self.board.play(self.convCoord(gtp.coords_to_sgf(self.board.boardSize, move))) 
     1676            #self.board.currentColor = self.board.invert(self.board.currentColor) 
     1677            self.play_engine.showboard() 
     1678        self.play_engine.connection.log_fp.write(pos_as_sgf) 
     1679        print pos_as_sgf 
     1680        self.lastEnginePos = pos_as_sgf 
    15261681         
    15271682 
    15281683    def gotoMove(self, event): 
     
    27392894            self.dataWindow.updateGameInfo(self.cursor) 
    27402895 
    27412896 
     2897    def showRestOfGame(self): 
     2898        n = self.cursor.currentN 
     2899        count = 0 
     2900        while n: 
     2901            n = n.next 
     2902            if not n: break 
     2903            count += 1 
     2904            if count<=2: 
     2905                stipple = 'gray75' 
     2906            elif count<=10: 
     2907                stipple = 'gray50' 
     2908            elif count<=30: 
     2909                stipple = 'gray25' 
     2910            else: 
     2911                stipple = 'gray12' 
     2912            if count<=50: 
     2913                size = 'normal' 
     2914            elif count<=100: 
     2915                size = 'medium' 
     2916            elif count<=150: 
     2917                size = 'small' 
     2918            else: 
     2919                size = 'tiny' 
     2920            d = n.getData() 
     2921            pos = None 
     2922            if d.has_key("B"): 
     2923                pos = self.convCoord(d["B"][0]) 
     2924                color = "black" 
     2925            if d.has_key("W"): 
     2926                pos = self.convCoord(d["W"][0]) 
     2927                color = "white" 
     2928            #self.board.placeLabel(pos, "LB", str(count), color) 
     2929            self.board.drawShadedStone(pos, color, stipple, size) 
     2930 
    27422931    def toggleDatawindow(self): 
    27432932        if self.options.datawindowVisible.get(): 
    27442933            self.dataWindow.window.deiconify() 
     
    28463035        self.options.datawindowVisible.set(1) 
    28473036        self.datawindowButton = Checkbutton(navFrame, text='DATA', variable = self.options.datawindowVisible, 
    28483037                                            command = self.toggleDatawindow, indicatoron=0) 
    2849          
     3038 
     3039        self.analyzeButton = Button(navFrame, text='Analyze', command = self.analyzePosition) 
     3040        self.boardFrame.bind('<a>', lambda e, s = self.analyzeButton: s.invoke()) 
     3041        self.playCurrentButton = Button(navFrame, text='Play', command = self.playCurrentMoveInEngine) 
     3042        #self.boardFrame.bind('<p>', lambda e, s = self.playCurrentButton: s.invoke()) 
     3043        self.showRestOfGameButton = Button(navFrame, text='Rest', command = self.showRestOfGame) 
     3044        self.boardFrame.bind('<r>', lambda e, s = self.showRestOfGameButton: s.invoke()) 
     3045 
    28503046        # try to load icons for navigation buttons 
    28513047 
    28523048        if sys.path[0].endswith('library.zip'): SYSPATH = os.path.split(sys.path[0])[0] 
     
    28783074        self.passButton.grid(row=0, column=10) 
    28793075        self.gameinfoButton.grid(row=0, column=11) 
    28803076        self.datawindowButton.grid(row=0, column=12) 
     3077        self.analyzeButton.grid(row=0, column=13) 
     3078        self.playCurrentButton.grid(row=0, column=14) 
     3079        self.showRestOfGameButton.grid(row=0, column=15) 
    28813080         
    28823081        self.modeVar = StringVar() 
    28833082        self.modeVar.set('blackwhite') 
     
    29363135        self.capLabel = Label(labelFrame, height=1, width=15, relief=SUNKEN, justify=LEFT, 
    29373136                              textvariable=self.capVar) 
    29383137 
     3138        self.scoreVar = StringVar() 
     3139        self.scoreLabel = Label(labelFrame, height=1, width=53, relief=SUNKEN, justify=LEFT, 
     3140                              textvariable=self.scoreVar) 
     3141 
    29393142        # pack everything 
    29403143 
    29413144        self.gameNameLabel.pack(expand=NO, fill=X, side=LEFT, padx = 5) 
    29423145        self.movenoLabel.pack(expand=NO, fill=X, side=LEFT, padx=5) 
    29433146        self.capLabel.pack(expand=NO, fill=X, side=LEFT, padx=5) 
     3147        self.scoreLabel.pack(expand=NO, fill=X, side=LEFT, padx=5) 
    29443148 
    29453149 
    29463150    def balloonHelp(self): 
     
    29543158        self.balloon.bind(self.passButton, 'Pass') 
    29553159        self.balloon.bind(self.gameinfoButton, 'Edit game info') 
    29563160        self.balloon.bind(self.datawindowButton, 'Open/withdraw data window') 
     3161        self.balloon.bind(self.analyzeButton, 'Analyze position with GnuGo') 
     3162        self.balloon.bind(self.playCurrentButton, 'Play current move on board against engine/something else using gtp') 
    29573163 
    29583164        self.balloon.bind(self.BWbutton, 'Play black/white stones') 
    29593165        self.balloon.bind(self.WBbutton, 'Play white/black stones')