Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Docs and properties for Move.

  • Loading branch information...
commit 2b787369e8ff54986da46eb1c5b7abd57d0762f9 1 parent 48e6300
@niklasf authored
View
127 chess/move.py
@@ -19,83 +19,92 @@
import re
import chess
+uci_move_regex = re.compile("^([a-h][1-8])([a-h][1-8])([rnbq]?)$")
+
class Move(object):
+ """Represents a move.
+
+ :param source:
+ The source square.
+ :param target:
+ The target square.
+ :param promotion:
+ Optional. If given this indicates which piece a pawn has been
+ promoted to: `"r"`, `"n"`, `"b"` or `"q"`.
+
+ Identical moves compare as equal.
+
+ >>> import chess
+ >>> e4 = chess.Move(chess.Square("e2"), chess.Square("e4"))
+ >>> e4 == chess.Move.from_uci("e2e4")
+ True
+ """
def __init__(self, source, target, promotion = None):
- """Inits a move.
-
- Args:
- source: Source square.
- target: Target square.
- promotion: The piece type the pawn has been promoted to, if any.
- """
- self._source = source
- self._target = target
- self._promotion = promotion
-
- if promotion:
- assert target.is_backrank()
- assert promotion in "rnbq"
-
- def get_uci(self):
- """Gets an UCI move.
-
- Returns:
- A string like "a1a2" or "b7b8q".
- """
- promotion = ""
- if self._promotion:
- promotion = self._promotion
- return self._source.name + self._target.name + promotion
-
- def get_source(self):
- """Gets the source square.
-
- Returns:
- The source square.
- """
- return self._source
-
- def get_target(self):
- """Gets the target square.
+ if type(source) is not chess.Square:
+ raise TypeError(
+ "Expected source to be Square object: %s." % repr(source))
+ if type(target) is not chess.Square:
+ raise TypeError(
+ "Expected target to be Square object: %s." % repr(target))
+
+ if not promotion in ["r", "n", "b", "q", None]:
+ raise ValueError(
+ "Invalid promotion piece: %s.", repr(promotion))
+ if promotion is not None and not target.is_backrank():
+ raise ValueError(
+ "Promotion move even though target is no backrank square.")
+
+ self.__source = source
+ self.__target = target
+ self.__promotion = promotion
+
+ @property
+ def uci(self):
+ """The UCI move string like `"a1a2"` or `"b7b8q"`."""
+ if self.__promotion:
+ return self.__source.name + self.__target.name + self.__promotion
+ else:
+ return self.__source.name + self.__target.name
- Returns:
- The target square.
- """
- return self._target
+ @property
+ def source(self):
+ """The source square."""
+ return self.__source
- def get_promotion(self):
- """Gets the promotion type.
+ @property
+ def target(self):
+ """The target square."""
+ return self.__target
- Returns:
- None, "r", "n", "b" or "q".
- """
- if not self._promotion:
- return None
- else:
- return self._promotion
+ @property
+ def promotion(self):
+ """The promotion type as `None`, `"r"`, `"n"`, `"b"` or `"q"`."""
+ return self.__promotion
def __str__(self):
- return self.get_uci()
+ return self.uci
def __repr__(self):
- return "Move.from_uci('%s')" % self.get_uci()
+ return "Move.from_uci(%s)" % repr(self.uci)
def __eq__(self, other):
- return self.get_uci() == other.get_uci()
+ return self.uci == other.uci
def __ne__(self, other):
- return self.get_uci() != other.get_uci()
+ return self.uci != other.uci
def __hash__(self):
- return hash(self.get_uci())
+ return hash(self.uci)
@classmethod
def from_uci(cls, move):
- """Parses an UCI move like "a1a2" or "b7b8q
+ """Creates a move object from an UCI move string.
- Returns:
- A new move object.
+ :param move: An UCI move string like "a1a2" or "b7b8q".
"""
- uci_move_regex = re.compile("^([a-h][1-8])([a-h][1-8])([rnbq]?)$")
match = uci_move_regex.match(move)
- return cls(chess.Square(match.group(1)), chess.Square(match.group(2)), match.group(3))
+
+ return cls(
+ source=chess.Square(match.group(1)),
+ target=chess.Square(match.group(2)),
+ promotion=match.group(3) or None)
View
8 chess/polyglot_opening_book.py
@@ -106,13 +106,13 @@ def next(self):
promotion="nbrq"[promote + 1] if promote else None)
# Replace the non standard castling moves.
- if move.get_uci() == "e1h1":
+ if move.uci == "e1h1":
move = chess.Move.from_uci("e1g1")
- elif move.get_uci() == "e1a1":
+ elif move.uci == "e1a1":
move = chess.Move.from_uci("e1c1")
- elif move.get_uci() == "e8h8":
+ elif move.uci == "e8h8":
move = chess.Move.from_uci("e8g8")
- elif move.get_uci() == "e8a8":
+ elif move.uci == "e8a8":
move = chess.Move.from_uci("e8c8")
return {
View
80 chess/position.py
@@ -73,26 +73,26 @@ def _get_disambiguator(self, move):
"""
same_rank = False
same_file = False
- piece = self.get(move.get_source())
+ piece = self.get(move.source)
for m in self.get_legal_moves():
- ambig_piece = self.get(m.get_source())
- if piece == ambig_piece and move.get_source() != m.get_source() and move.get_target() == m.get_target():
- if move.get_source().rank == m.get_source().rank:
+ ambig_piece = self.get(m.source)
+ if piece == ambig_piece and move.source != m.source and move.target == m.target:
+ if move.source.rank == m.source.rank:
same_rank = True
- if move.get_source().file == m.get_source().file:
+ if move.source.file == m.source.file:
same_file = True
if same_rank and same_file:
break
if same_rank and same_file:
- return move.get_source().name
+ return move.source.name
elif same_file:
- return str(move.get_source().rank)
+ return str(move.source.rank)
elif same_rank:
- return move.get_source().file
+ return move.source.file
else:
return ""
@@ -123,14 +123,14 @@ def get_move_from_san(self, san):
target = chess.Square(matches.group(4))
source = None
for m in self.get_legal_moves():
- if self.get(m.get_source()) == piece and m.get_target() == target:
- if matches.group(2) and matches.group(2) != m.get_source().file:
+ if self.get(m.source) == piece and m.target == target:
+ if matches.group(2) and matches.group(2) != m.source.file:
continue
- if matches.group(3) and matches.group(3) != str(m.get_source().rank):
+ if matches.group(3) and matches.group(3) != str(m.source.rank):
continue
# Move matches. Assert it is not ambigoous.
assert not source
- source = m.get_source()
+ source = m.source
# Assert a possible source square was found.
assert source
@@ -147,20 +147,20 @@ def get_move_info(self, move):
resulting_position = self.copy()
resulting_position.make_move(move)
- capture = self.get(move.get_target())
- piece = self.get(move.get_source())
+ capture = self.get(move.target)
+ piece = self.get(move.source)
# Pawn moves.
enpassant = False
if piece.type == "p":
# En-passant.
- if move.get_target().file != move.get_source().file and not capture:
+ if move.target.file != move.source.file and not capture:
enpassant = True
capture = chess.Piece.from_color_and_type(resulting_position.get_turn(), 'p')
# Castling.
- is_king_side_castle = piece.type == 'k' and move.get_target().x - move.get_source().x == 2
- is_queen_side_castle = piece.type == 'k' and move.get_target().x - move.get_source().x == -2
+ is_king_side_castle = piece.type == 'k' and move.target.x - move.source.x == 2
+ is_queen_side_castle = piece.type == 'k' and move.target.x - move.source.x == -2
# Checks.
is_check = resulting_position.is_check()
@@ -180,13 +180,13 @@ def get_move_info(self, move):
if capture:
if piece.type == 'p':
- san += move.get_source().file
+ san += move.source.file
san += "x"
- san += move.get_target().name
+ san += move.target.name
- if move.get_promotion():
+ if move.promotion:
san += "="
- san += move.get_promotion().upper()
+ san += move.promotion.upper()
if is_checkmate:
san += "#"
@@ -215,28 +215,28 @@ def make_move(self, move, validate=True):
"""
assert not validate or move in self.get_legal_moves()
- capture = self.get(move.get_target())
+ capture = self.get(move.target)
# Move the piece.
- self.set(move.get_target(), self.get(move.get_source()))
- self.set(move.get_source(), None)
+ self.set(move.target, self.get(move.source))
+ self.set(move.source, None)
# It is the next players turn.
self.toggle_turn()
# Pawn moves.
- if self.get(move.get_target()).type == 'p':
+ if self.get(move.target).type == 'p':
# En-passant.
- if move.get_target().file != move.get_source().file and not capture:
+ if move.target.file != move.source.file and not capture:
if self.get_turn() == "b":
- self._board[move.get_target().x88 - 16] = None
+ self._board[move.target.x88 - 16] = None
else:
- self._board[move.get_target().x88 + 16] = None
+ self._board[move.target.x88 + 16] = None
capture = True
# If big pawn move, set the en-passant file.
- if abs(move.get_target().rank - move.get_source().rank) == 2:
- if self.get_theoretical_ep_right(move.get_target().file):
- self._ep_file = move.get_target().file
+ if abs(move.target.rank - move.source.rank) == 2:
+ if self.get_theoretical_ep_right(move.target.file):
+ self._ep_file = move.target.file
else:
self._ep_file = None
else:
@@ -245,26 +245,26 @@ def make_move(self, move, validate=True):
self._ep_file = None
# Promotion.
- if move.get_promotion():
- self.set(move.get_target(), chess.Piece.from_color_and_type(self.get(move.get_target()).color, move.get_promotion()))
+ if move.promotion:
+ self.set(move.target, chess.Piece.from_color_and_type(self.get(move.target).color, move.promotion))
# Potential castling.
- if self.get(move.get_target()).type == 'k':
- steps = move.get_target().x - move.get_source().x
+ if self.get(move.target).type == 'k':
+ steps = move.target.x - move.source.x
if abs(steps) == 2:
# Queen-side castling.
if steps == -2:
- rook_target = move.get_target().x88 + 1
- rook_source = move.get_target().x88 - 2
+ rook_target = move.target.x88 + 1
+ rook_source = move.target.x88 - 2
# King-side castling.
else:
- rook_target = move.get_target().x88 - 1
- rook_source = move.get_target().x88 + 1
+ rook_target = move.target.x88 - 1
+ rook_source = move.target.x88 + 1
self._board[rook_target] = self._board[rook_source]
self._board[rook_source] = None
# Increment the half move counter.
- if self.get(move.get_target()).type == 'p':
+ if self.get(move.target).type == 'p':
self._half_moves = 0
elif capture:
self._half_moves = 0
View
4 tests/test_move.py
@@ -38,5 +38,5 @@ def test_equality(self):
def test_uci_parsing(self):
"""Tests the UCI move parsing."""
- self.assertEqual(chess.Move.from_uci('b5c7').get_uci(), 'b5c7')
- self.assertEqual(chess.Move.from_uci('e7e8q').get_uci(), 'e7e8q')
+ self.assertEqual(chess.Move.from_uci('b5c7').uci, 'b5c7')
+ self.assertEqual(chess.Move.from_uci('e7e8q').uci, 'e7e8q')
Please sign in to comment.
Something went wrong with that request. Please try again.