def str2twixt(move): """ Converts one move string to a twixt backend class move. Handles both T1-style coordinates (e.g.: 'd5', 'f18'') as well as tsgf- style coordinates (e.g.: 'fg', 'bi') as well as special strings ('swap' and 'resign'). It can handle letter in upper as well as lowercase. Args: move: string with a move Returns: twixt.SWAP or twixt.RESIGN or twixt.Point Raises ValueError if the move_str can't be parsed in any valid format Examples: >>> str2twixt('b3') b3 >>> str2twixt('i18') i18 >>> str2twixt('fj') f10 >>> str2twixt('swap') 'swap' >>> str2twixt('resign') 'resign' >>> str2twixt('123') ValueError: Can't parse move: '123' >>> str2twixt('invalid') ValueError: Can't parse move: 'invalid' """ # Handle swap and resign if move.lower() == twixt.SWAP.lower(): return twixt.SWAP elif move.lower() == twixt.RESIGN.lower(): return twixt.RESIGN # Handle T1-style moves elif move[0] in string.ascii_letters and move[-1] in string.digits: return twixt.Point(move) # Handle tsgf-stype moves elif len(move) == 2 and all(c in string.ascii_letters for c in move): return twixt.Point(move[0] + str(ord(move[1].lower()) - ord('a') + 1)) # Can't handle move. Throw exception raise ValueError(f"Can't parse move: '{move}'")
def create_move_objects(self, game, index, visits=None): move = game.history[index] if not isinstance(move, twixt.Point): # swap case: flip first move if len(self.history) > 0: c1 = self.history.pop().objects[0] self.graph.delete_figure(c1) self.known_moves.clear() m1 = game.history[0] move = twixt.Point(m1.y, m1.x) # game.use_swap = True color = (index + 1) & 1 nho = TBWHistory(move) self.history.append(nho) highlight_last_move = visits is None and self.stgs.get( ct.K_HIGHLIGHT_LAST_MOVE[1]) and index == len(game.history) - 1 nho.objects.append( self._create_drawn_peg(move, color, highlight_last_move, visits)) self.known_moves.add(move) if visits is not None: nho.objects.append(self._create_visits_label(move, color, visits)) for dlink in game.DLINKS: other = move + dlink if other in self.known_moves: if game.safe_get_link(move, other, color): nho.objects.append( self._create_drawn_link(move, other, color, visits))
def policy_index_point(thing, index): if isinstance(thing, twixt.Game): color = thing.turn elif isinstance(thing, int): color = thing else: raise ValueError("Bad type for thing") assert color in (0, 1) major, minor = divmod(index, twixt.Game.SIZE) assert 0 <= major and major < twixt.Game.SIZE - 2 assert 0 <= minor and minor < twixt.Game.SIZE if color == twixt.Game.WHITE: return twixt.Point(major + 1, minor) else: return twixt.Point(minor, major + 1)
def points_and_locs(): cum = 0.0 locations = [0.0] points = [] for x in range(1, twixt.Game.SIZE - 1): for y in range(twixt.Game.SIZE): point = twixt.Point(x, y) score = _point_score(point) weight = math.exp(math.log(0.5) * abs(score - 0.5) / _halflife) cum += weight locations.append(cum) points.append(point) return points, locations
def valid_spot(self, move): p = self._move_to_point(move) if len(self.game.history) >= 2 and self.game.history[1] == twixt.SWAP: # game is swapped if p in self.game.history[2:]: # spot occupied after swap return False elif twixt.Point(p.y, p.x) == self.game.history[0]: # spot occupied on swap (flip) return False else: return True else: # game is not swapped if p in self.game.history: # spot occupied return False return True
def hflip(self): tmp = numpy.flip(self.naf, 0) S = twixt.Game.SIZE vix = twixt.Game.LINK_LONGY self.naf = numpy.zeros((S, S, 11), dtype=numpy.uint8) self.naf[:, :, 10] = tmp[:, :, 10] for color in range(2): self.naf[:, :, 8 + color] = tmp[:, :, 8 + color] for diffsign in range(2): dix = diffsign * twixt.Game.LINK_DIFFSIGN adix = (1 - diffsign) * twixt.Game.LINK_DIFFSIGN # non verticals are easy self.naf[:, :, color + dix] = tmp[:, :, color + adix] # verticals need to be shifted. self.naf[:-1, :, color + dix + vix] = tmp[1:, :, color + adix + vix] self.recents = [twixt.Point(twixt.Game.SIZE - 1 - p.x, p.y) for p in self.recents]
def _move_to_point(self, move): return twixt.Point(ord(move[0]) - ord('a'), int(move[1:]) - 1)
def first_move_report(): points, locations = points_and_locs() cum = locations[-1] for i, p in enumerate(points): if p.x >= twixt.Game.SIZE // 2 or p.y >= twixt.Game.SIZE // 2: continue pct = 4.0 * (locations[i + 1] - locations[i]) / cum logger.info("%3s %5.2f" % (str(p), pct * 100)) def choose_first_move(): points, locations = points_and_locs() cum = locations[-1] z = random.uniform(0, cum) i = bisect.bisect(locations, z) if i == len(locations): i -= 1 return points[i] if __name__ == "__main__": if len(sys.argv) == 1: logger.info(choose_first_move()) elif len(sys.argv) == 2 and sys.argv[1] == "all": first_move_report() elif len(sys.argv) == 2: p = twixt.Point(sys.argv[1]) logger.info(_point_score(p), want_swap(p))