1# 2# gnubg.py 3# 4# This file is read by GNU Backgammon during startup. 5# You can add your own user specified functions, if you wish. 6# Below are a few examples for inspiration. 7# 8# Exercise: write a shorter function for calculating pip count! 9# 10# by Joern Thyssen <jth@gnubg.org>, 2003 11# 12# This program is free software: you can redistribute it and/or modify 13# it under the terms of the GNU General Public License as published by 14# the Free Software Foundation, either version 3 of the License, or 15# (at your option) any later version. 16# 17# This program is distributed in the hope that it will be useful, 18# but WITHOUT ANY WARRANTY; without even the implied warranty of 19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20# GNU General Public License for more details. 21# 22# You should have received a copy of the GNU General Public License 23# along with this program. If not, see <http://www.gnu.org/licenses/>. 24# 25# $Id: gnubg.py,v 1.18 2017/11/13 21:07:43 plm Exp $ 26# 27 28# Add the scripts directory to the module path to allow 29# for modules from this directory to be imported 30import sys 31import os 32 33sys.path.insert(1, './scripts') 34if sys.platform == 'win32': 35 os.environ['TCL_LIBRARY']='PythonLib/lib/tcl8' 36 37if sys.version_info >= (3, 0): 38 import builtins as bi 39else: 40 import __builtin__ as bi 41 42 43def setinterpreterquit(): 44 class interpreterquit(object): 45 def __repr__(self): 46 self() 47 def __call__(self, code=None): 48 if not ('idlelib' in sys.stdin.__class__.__module__): 49 raise SystemExit(0) 50 else: 51 print('Press Ctrl-D to exit') 52 53 bi.quit = interpreterquit() 54 bi.exit = interpreterquit() 55 56setinterpreterquit() 57 58 59def gnubg_find_msvcrt(): 60 return 'msvcr100.dll' 61 62# This is a workaround for a pyreadline c runtime conflict 63# on Win32 platforms. Replace ctypes.util.find_msvcrt with 64# our own. Readline not properly supported on Win2000 or 65# WinXP with a Service Pack earlier than SP2 66 67supports_readline = True 68 69try: 70 from ctypes.util import find_msvcrt 71 import ctypes.util 72 ctypes.util.find_msvcrt = gnubg_find_msvcrt 73 import platform 74 winver = platform.win32_ver() 75 try: 76 sp_ver = int(winver[2][2]) 77 except: 78 sp_ver = 0 79 80 ver_split = winver[1].split('.') 81 major = int(ver_split[0]) 82 minor = int(ver_split[1]) 83 84 if ((major < 5) or (major == 5 and minor == 0) or (major == 5 and minor == 1 and sp_ver < 2)): 85 supports_readline = False 86except: 87 pass 88 89 90def gnubg_InteractivePyShell_tui(argv=[''], banner=None): 91 global supports_readline 92 import sys 93 import traceback 94 import code 95 96 try: 97 sys.argv = argv 98 99 # Check for IPython as it is generally the best cmdline interpreter 100 from IPython import version_info as ipy_version_info 101 if ipy_version_info[0] >= 1: 102 from IPython.terminal.embed import InteractiveShellEmbed 103 else: 104 from IPython.frontend.terminal.embed import InteractiveShellEmbed 105 106 from IPython import __version__ as ipyversion 107 if ipy_version_info[0] >= 4: 108 from traitlets.config.loader import Config 109 else: 110 from IPython.config.loader import Config 111 112 except: 113 # Otherwise use standard interpreter 114 if (banner == None): 115 banner = 'Python ' + sys.version 116 117 if (supports_readline): 118 try: 119 # See if we can use readline support 120 import readline 121 except: 122 # Might be Win32 so check for pyreadline 123 try: 124 import pyreadline as readline 125 except: 126 pass 127 try: 128 # See if we can add tab completion 129 import rlcompleter 130 readline.parse_and_bind('tab: complete') 131 except: 132 pass 133 134 try: 135 code.interact(banner=banner, local=globals()) 136 except SystemExit: 137 # Ignore calls to exit() and quit() 138 pass 139 140 return True 141 142 else: 143 # If we get this far we are on Win32 and too early 144 # a version to support the embedded interpreter so 145 # we simulate one 146 print(banner) 147 print('<Control-Z> and <Return> to exit') 148 while True: 149 print('>>> ',) 150 line = sys.stdin.readline() 151 if not line: 152 break 153 154 try: 155 exec(line) 156 except SystemExit: 157 # Ignore calls to exit() and quit() 158 break 159 160 return True 161 162 try: 163 # Launch IPython interpreter 164 if ipy_version_info[0] <= 4: 165 cfg = Config() 166 prompt_config = cfg.PromptManager 167 prompt_config.in_template = 'In <\\#> > ' 168 prompt_config.in2_template = ' .\\D. > ' 169 prompt_config.out_template = 'Out<\\#> > ' 170 cfg.InteractiveShell.confirm_exit = False 171 else: 172 # FIXME: 173 # As of IPython 5.0 `PromptManager` config will have no effect and 174 # has been replaced by TerminalInteractiveShell.prompts_class 175 cfg = None 176 177 if banner == None: 178 banner = 'IPython ' + ipyversion + ', Python ' + sys.version 179 180 # We want to execute in the name space of the CALLER of this function, 181 # not within the namespace of THIS function. 182 # This allows us to have changes made in the IPython environment 183 # visible to the CALLER of this function 184 185 # Go back one frame and get the locals. 186 call_frame = sys._getframe(0).f_back 187 calling_ns = call_frame.f_locals 188 189 ipshell = InteractiveShellEmbed( 190 config=cfg, user_ns=calling_ns, banner1=banner) 191 192 try: 193 ipshell() 194 except SystemExit: 195 # Ignore calls to exit() and quit() 196 pass 197 198 # Cleanup the sys environment (including exception handlers) 199 ipshell.restore_sys_module_state() 200 201 return True 202 203 except: 204 traceback.print_exc() 205 206 return False 207 208 209def gnubg_InteractivePyShell_gui(argv=['', '-n']): 210 import sys 211 sys.argv = argv 212 213 try: 214 import idlelib.PyShell 215 try: 216 idlelib.PyShell.main() 217 return True 218 except SystemExit: 219 # Ignore calls to exit() and quit() 220 return True 221 except: 222 traceback.print_exc() 223 224 except: 225 pass 226 227 return False 228 229 230def swapboard(board): 231 """Swap the board""" 232 233 return [board[1], board[0]] 234 235 236def pipcount(board): 237 """Calculate pip count""" 238 239 sum = [0, 0] 240 for i in range(2): 241 for j in range(25): 242 sum[i] += (j + 1) * board[i][j] 243 244 return sum 245 246 247# Following code is intended as an example on the usage of the match command. 248# It illustrates how to iterate over matches and do something useful with the 249# navigate command. 250import os.path 251 252 253def skillBad(s): 254 return s and (s == "very bad" or s == "bad" or s == "doubtful") 255 256 257def exportBad(baseName): 258 """ For current analyzed match, export all moves/cube decisions marked 259 doubtful or bad""" 260 261 # Get current match 262 m = gnubg.match() 263 264 # Go to match start 265 gnubg.navigate() 266 267 # Skill of previous action, to avoid exporting double actions twice 268 prevSkill = None 269 270 # Exported position number, used in file name 271 poscount = 0 272 273 for game in m["games"]: 274 for action in game["game"]: 275 276 analysis = action.get("analysis", None) 277 if analysis: 278 type = action["action"] 279 skill = analysis.get("skill", None) 280 bad = skillBad(skill) 281 282 if type == "move": 283 if skillBad(analysis.get("cube-skill", None)): 284 bad = True 285 elif type == "take" or type == "drop": 286 if skillBad(prevSkill): 287 # Already exported 288 bad = False 289 290 if bad: 291 exportfile = "%s__%d.html" % ( 292 os.path.splitext(baseName)[0], poscount) 293 gnubg.command( 294 "export position html " + "\"" + exportfile + "\"") 295 poscount += 1 296 297 # Advance to next record 298 gnubg.navigate(1) 299 300 # Advance to next game 301 gnubg.navigate(game=1) 302