def _to_san(self): if self.is_oo: san = 'O-O' elif self.is_ooo: san = 'O-O-O' elif self.pc in ['P', 'p']: san = '' if self.is_capture or self.is_ep: san += 'abcdefgh'[file_(self.fr)] + 'x' san += sq_to_str(self.to) if self.prom: san += '=' + self.prom.upper() else: assert (not self.is_ep) san = self.pc.upper() ambigs = self.pos.get_from_sqs(self.pc, self.to) assert (len(ambigs) >= 1) if len(ambigs) > 1: r = rank(self.fr) f = file_(self.fr) # try disambiguating with file if len(filter(lambda sq: file_(sq) == f, ambigs)) == 1: san += 'abcdefgh'[f] elif len(filter(lambda sq: rank(sq) == r, ambigs)) == 1: san += '12345678'[r] else: san += sq_to_str(self.fr) if self.is_capture: san += 'x' san += sq_to_str(self.to) return san
def detect_check(self): """detect whether the player to move is out of material (has committed suicide) or stalemated, or if the game is drawn by opposite color bishops""" self.is_suicide = not any(pc != '-' and ( piece_is_white(pc) if self.wtm else not piece_is_white(pc)) for (sq, pc) in self) self.is_stalemate = not self._any_legal_moves() if self.is_stalemate: white_material = sum(piece_material[pc.lower()] for (sq, pc) in self if pc != '-' and piece_is_white(pc)) black_material = sum(piece_material[pc.lower()] for (sq, pc) in self if pc != '-' and not piece_is_white(pc)) self.is_stalemate_white = white_material < black_material self.is_stalemate_black = white_material > black_material self.is_draw_bishops = False for (sq, pc) in self: if pc == 'B': if (rank(sq) ^ file_(sq)) & 1 != 0: break elif pc == 'b': if (rank(sq) ^ file_(sq)) & 1 == 0: break elif pc != '-': break else: self.is_draw_bishops = True return for (sq, pc) in self: if pc == 'B': if (rank(sq) ^ file_(sq)) & 1 == 0: break elif pc == 'b': if (rank(sq) ^ file_(sq)) & 1 != 0: break elif pc != '-': break else: self.is_draw_bishops = True
def move_from_san(self, s): s = self.decorator_re.sub('', s) mv = None # examples: e4 e8=Q m = self.san_pawn_push_re.match(s) if m: to = str_to_sq(m.group(1)) if self.board[to] != '-': raise IllegalMoveError('pawn push blocked') prom = m.group(2) if prom: if self.wtm: prom = m.group(2) assert (prom == prom.upper()) else: prom = m.group(2).lower() new_ep = None if self.wtm: fr = to - 0x10 if rank(to) == 3 and self.board[fr] == '-': new_ep = fr fr = to - 0x20 if self.board[fr] != 'P': raise IllegalMoveError('illegal white pawn move') if prom: if rank(to) == 7: mv = Move(self, fr, to, prom=prom) else: raise IllegalMoveError('illegal promotion') else: mv = Move(self, fr, to, new_ep=new_ep) else: fr = to + 0x10 if rank(to) == 4 and self.board[fr] == '-': new_ep = fr fr = to + 0x20 if self.board[fr] != 'p': raise IllegalMoveError('illegal black pawn move') if prom: if rank(to) == 0: mv = Move(self, fr, to, prom=prom) else: raise IllegalMoveError('illegal promotion') else: mv = Move(self, fr, to, new_ep=new_ep) # examples: dxe4 dxe8=Q m = None if not mv: m = self.san_pawn_capture_re.match(s) if m: to = str_to_sq(m.group(2)) prom = m.group(3) if prom: if self.wtm: assert (prom == prom.upper()) else: prom = prom.lower() is_ep = to == self.ep if is_ep: assert (self.board[to] == '-') else: topc = self.board[to] if topc == '-' or piece_is_white(topc) == self.wtm: raise IllegalMoveError('bad pawn capture') f = 'abcdefgh'.index(m.group(1)) if f == file_(to) - 1: if self.wtm: fr = to - 0x11 if self.board[fr] != 'P': raise IllegalMoveError('bad pawn capture') else: fr = to + 0xf if self.board[fr] != 'p': raise IllegalMoveError('bad pawn capture') elif f == file_(to) + 1: if self.wtm: fr = to - 0xf if self.board[fr] != 'P': raise IllegalMoveError('bad pawn capture') else: fr = to + 0x11 if self.board[fr] != 'p': raise IllegalMoveError('bad pawn capture') else: raise IllegalMoveError('bad pawn capture file') mv = Move(self, fr, to, prom=prom, is_ep=is_ep) # examples: Nf3 Nxf3 Ng1xf3 m = None if not mv: m = self.san_piece_re.match(s) if m: to = str_to_sq(m.group(5)) if m.group(4): # capture if self.board[to] == '-': raise IllegalMoveError('capture on blank square') if piece_is_white(self.board[to]) == self.wtm: raise IllegalMoveError('capture own piece') else: if self.board[to] != '-': raise IllegalMoveError('missing "x" to indicate capture') pc = m.group(1) if self.wtm else m.group(1).lower() # TODO: it would be faster to disambiguate first, so we # do not check whether moves are legal unnecessarily froms = self.get_from_sqs(pc, to) if m.group(2): if len(froms) <= 1: raise IllegalMoveError('unnecessary disambiguation') f = 'abcdefgh'.index(m.group(2)) froms = filter(lambda sq: file_(sq) == f, froms) if m.group(3): r = '12345678'.index(m.group(3)) if len(froms) <= 1: raise IllegalMoveError('unnecessary disambiguation') froms = filter(lambda sq: rank(sq) == r, froms) if len(froms) != 1: raise IllegalMoveError( 'illegal or ambiguous move %s: %d interpretations' % (s, len(froms))) mv = Move(self, froms[0], to) # Legality checking is implicitly done above, so we don't need # to check it here. '''if mv: try: mv.check_pseudo_legal() except IllegalMoveError: raise RuntimeError('san inconsistency') mv.check_legal()''' return mv
def sq_to_str(sq): return 'abcdefgh'[file_(sq)] + '12345678'[rank(sq)]
def ep_hash(self, ep): return self._ep[file_(ep)]
def to_style12(self, user): """ returns a style12 string for a given user """ # <12> rnbqkbnr pppppppp -------- -------- -------- -------- PPPPPPPP RNBQKBNR W -1 1 1 1 1 0 473 GuestPPMD GuestCWVQ -1 1 0 39 39 60000 60000 1 none (0:00.000) none 1 0 0 board_str = '' for r in range(7, -1, -1): board_str += ' ' for f in range(8): board_str += self.pos.board[0x10 * r + f] side_str = 'W' if self.pos.wtm else 'B' ep = -1 if not self.pos.ep else file_(self.pos.ep) w_oo = int(self.pos.check_castle_flags(True, True)) w_ooo = int(self.pos.check_castle_flags(True, False)) b_oo = int(self.pos.check_castle_flags(False, True)) b_ooo = int(self.pos.check_castle_flags(False, False)) if self.game.gtype == EXAMINED: flip = 0 if user in self.game.players: relation = 2 elif user in self.game.observers: relation = -2 else: relation = -3 white_clock = 0 black_clock = 0 white_name = list(self.game.players)[0].name black_name = list(self.game.players)[0].name clock_is_ticking = 0 elif self.game.gtype == PLAYED: if self.game.white == user: relation = 1 if self.pos.wtm else -1 flip = 0 elif self.game.black == user: relation = 1 if not self.pos.wtm else -1 flip = 1 elif user in self.game.observers: relation = 0 flip = 0 else: relation = -3 flip = 0 if user.session.ivars['ms']: white_clock = int( round(1000 * self.game.clock.get_white_time())) black_clock = int( round(1000 * self.game.clock.get_black_time())) else: white_clock = int(round(self.game.clock.get_white_time())) black_clock = int(round(self.game.clock.get_black_time())) white_name = self.game.white.name black_name = self.game.black.name clock_is_ticking = int(self.game.clock.is_ticking) else: assert (False) if user.vars_['flip']: flip = 0 if flip else 1 full_moves = self.pos.ply // 2 + 1 last_mv = self.pos.get_last_move() if last_mv is None: last_move_time_str = time_format.hms(0.0, user) last_move_san = 'none' last_move_verbose = 'none' last_move_lag = 0 else: assert (last_mv.time is not None) last_move_time_str = time_format.hms(last_mv.time, user) last_move_san = last_mv.to_san() last_move_verbose = last_mv.to_verbose_alg() last_move_lag = last_mv.lag # board_str begins with a space s = '\n<12>%s %s %d %d %d %d %d %d %d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d %d\n' % ( board_str, side_str, ep, w_oo, w_ooo, b_oo, b_ooo, self.pos.fifty_count, self.game.number, white_name, black_name, relation, self.game.white_time, self.game.inc, self.pos.material[1], self.pos.material[0], white_clock, black_clock, full_moves, last_move_verbose, last_move_time_str, last_move_san, flip, clock_is_ticking, last_move_lag) if self.name in ['crazyhouse', 'bughouse']: # print <b1> lines s += self.get_b1() return s