Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Docs and properties for Square.

  • Loading branch information...
commit f106f94ef308645c880fc1f6ce94737fda84d92a 1 parent 4e96018
@niklasf authored
View
2  chess/move.py
@@ -45,7 +45,7 @@ def get_uci(self):
promotion = ""
if self._promotion:
promotion = self._promotion
- return self._source.get_name() + self._target.get_name() + promotion
+ return self._source.name + self._target.name + promotion
def get_source(self):
"""Gets the source square.
View
4 chess/piece.py
@@ -28,8 +28,6 @@ class Piece(object):
>>> import chess
>>> chess.Piece("Q") == chess.Piece.from_color_and_type("w", "q")
True
-
- :raise ValueError: If the piece symbol is not valid.
"""
def __init__(self, symbol):
if not symbol.lower() in ["p", "b", "n", "r", "k", "q"]:
@@ -112,8 +110,6 @@ def from_color_and_type(cls, color, type):
Piece('P')
>>> chess.Piece.from_color_and_type("black", "q")
Piece('q')
-
- :raise ValueError: If color or type are invalid.
"""
if type in ["p", "pawn"]:
symbol = "p"
View
84 chess/position.py
@@ -46,7 +46,7 @@ def get(self, square):
A piece object for the piece that is on that square or None if
there is no piece on the square.
"""
- return self._board[square.get_0x88_index()]
+ return self._board[square.x88]
def set(self, square, piece):
"""Sets a piece on the given square.
@@ -55,7 +55,7 @@ def set(self, square, piece):
square: The square to set the piece on.
piece: The piece to set. None to clear the square.
"""
- self._board[square.get_0x88_index()] = piece
+ self._board[square.x88] = piece
def clear_board(self):
"""Removes all pieces from the board."""
@@ -78,21 +78,21 @@ def _get_disambiguator(self, move):
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().get_rank() == m.get_source().get_rank():
+ if move.get_source().rank == m.get_source().rank:
same_rank = True
- if move.get_source().get_file() == m.get_source().get_file():
+ if move.get_source().file == m.get_source().file:
same_file = True
if same_rank and same_file:
break
if same_rank and same_file:
- return move.get_source().get_name()
+ return move.get_source().name
elif same_file:
- return str(move.get_source().get_rank())
+ return str(move.get_source().rank)
elif same_rank:
- return move.get_source().get_file()
+ return move.get_source().file
else:
return ""
@@ -124,9 +124,9 @@ def get_move_from_san(self, san):
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().get_file():
+ if matches.group(2) and matches.group(2) != m.get_source().file:
continue
- if matches.group(3) and matches.group(3) != str(m.get_source().get_rank()):
+ if matches.group(3) and matches.group(3) != str(m.get_source().rank):
continue
# Move matches. Assert it is not ambigoous.
assert not source
@@ -154,13 +154,13 @@ def get_move_info(self, move):
enpassant = False
if piece.type == "p":
# En-passant.
- if move.get_target().get_file() != move.get_source().get_file() and not capture:
+ if move.get_target().file != move.get_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().get_x() - move.get_source().get_x() == 2
- is_queen_side_castle = piece.type == 'k' and move.get_target().get_x() - move.get_source().get_x() == -2
+ 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
# Checks.
is_check = resulting_position.is_check()
@@ -180,9 +180,9 @@ def get_move_info(self, move):
if capture:
if piece.type == 'p':
- san += move.get_source().get_file()
+ san += move.get_source().file
san += "x"
- san += move.get_target().get_name()
+ san += move.get_target().name
if move.get_promotion():
san += "="
@@ -227,16 +227,16 @@ def make_move(self, move, validate=True):
# Pawn moves.
if self.get(move.get_target()).type == 'p':
# En-passant.
- if move.get_target().get_file() != move.get_source().get_file() and not capture:
+ if move.get_target().file != move.get_source().file and not capture:
if self.get_turn() == "b":
- self._board[move.get_target().get_0x88_index() - 16] = None
+ self._board[move.get_target().x88 - 16] = None
else:
- self._board[move.get_target().get_0x88_index() + 16] = None
+ self._board[move.get_target().x88 + 16] = None
capture = True
# If big pawn move, set the en-passant file.
- if abs(move.get_target().get_rank() - move.get_source().get_rank()) == 2:
- if self.get_theoretical_ep_right(move.get_target().get_file()):
- self._ep_file = move.get_target().get_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
else:
self._ep_file = None
else:
@@ -250,16 +250,16 @@ def make_move(self, move, validate=True):
# Potential castling.
if self.get(move.get_target()).type == 'k':
- steps = move.get_target().get_x() - move.get_source().get_x()
+ steps = move.get_target().x - move.get_source().x
if abs(steps) == 2:
# Queen-side castling.
if steps == -2:
- rook_target = move.get_target().get_0x88_index() + 1
- rook_source = move.get_target().get_0x88_index() - 2
+ rook_target = move.get_target().x88 + 1
+ rook_source = move.get_target().x88 - 2
# King-side castling.
else:
- rook_target = move.get_target().get_0x88_index() - 1
- rook_source = move.get_target().get_0x88_index() + 1
+ rook_target = move.get_target().x88 - 1
+ rook_source = move.get_target().x88 + 1
self._board[rook_target] = self._board[rook_source]
self._board[rook_source] = None
@@ -693,7 +693,7 @@ def get_pseudo_legal_moves(self):
# Pawn moves.
if piece.type == "p":
# Single square ahead. Do not capture.
- target = chess.Square.from_0x88_index(square.get_0x88_index() + PAWN_OFFSETS[self.get_turn()][0])
+ target = chess.Square.from_x88(square.x88 + PAWN_OFFSETS[self.get_turn()][0])
if not self.get(target):
# Promotion.
if target.is_backrank():
@@ -703,16 +703,16 @@ def get_pseudo_legal_moves(self):
yield chess.Move(square, target)
# Two squares ahead. Do not capture.
- target = chess.Square.from_0x88_index(square.get_0x88_index() + PAWN_OFFSETS[self.get_turn()][1])
- if (self.get_turn() == "w" and square.get_rank() == 2) or (self.get_turn() == "b" and square.get_rank() == 7) and not self.get(target):
+ target = chess.Square.from_x88(square.x88 + PAWN_OFFSETS[self.get_turn()][1])
+ if (self.get_turn() == "w" and square.rank == 2) or (self.get_turn() == "b" and square.rank == 7) and not self.get(target):
yield chess.Move(square, target)
# Pawn captures.
for j in [2, 3]:
- target_index = square.get_0x88_index() + PAWN_OFFSETS[self.get_turn()][j]
+ target_index = square.x88 + PAWN_OFFSETS[self.get_turn()][j]
if target_index & 0x88:
continue
- target = chess.Square.from_0x88_index(target_index)
+ target = chess.Square.from_x88(target_index)
if self.get(target) and self.get(target).color != self.get_turn():
# Promotion.
if target.is_backrank():
@@ -721,17 +721,17 @@ def get_pseudo_legal_moves(self):
else:
yield chess.Move(square, target)
# En-passant.
- elif not self.get(target) and target.get_file() == self._ep_file:
+ elif not self.get(target) and target.file == self._ep_file:
yield chess.Move(square, target)
# Other pieces.
else:
for offset in PIECE_OFFSETS[piece.type]:
- target_index = square.get_0x88_index()
+ target_index = square.x88
while True:
target_index += offset
if target_index & 0x88:
break
- target = chess.Square.from_0x88_index(target_index)
+ target = chess.Square.from_x88(target_index)
if not self.get(target):
yield chess.Move(square, target)
else:
@@ -750,19 +750,19 @@ def get_pseudo_legal_moves(self):
# King-side castling.
k = "k" if self.get_turn() == "b" else "K"
if self.get_castling_right(k):
- of = self.get_king(self.get_turn()).get_0x88_index()
+ of = self.get_king(self.get_turn()).x88
to = of + 2
- if not self._board[of + 1] and not self._board[to] and not self.is_check() and not self.is_attacked(opponent, chess.Square.from_0x88_index(of + 1)) and not self.is_attacked(opponent, chess.Square.from_0x88_index(to)):
- yield chess.Move(chess.Square.from_0x88_index(of), chess.Square.from_0x88_index(to))
+ if not self._board[of + 1] and not self._board[to] and not self.is_check() and not self.is_attacked(opponent, chess.Square.from_x88(of + 1)) and not self.is_attacked(opponent, chess.Square.from_x88(to)):
+ yield chess.Move(chess.Square.from_x88(of), chess.Square.from_x88(to))
# Queen-side castling
q = "q" if self.get_turn() == "b" else "Q"
if self.get_castling_right(q):
- of = self.get_king(self.get_turn()).get_0x88_index()
+ of = self.get_king(self.get_turn()).x88
to = of - 2
- if not self._board[of - 1] and not self._board[of - 2] and not self._board[of - 3] and not self.is_check() and not self.is_attacked(opponent, chess.Square.from_0x88_index(of - 1)) and not self.is_attacked(opponent, chess.Square.from_0x88_index(to)):
- yield chess.Move(chess.Square.from_0x88_index(of), chess.Square.from_0x88_index(to))
+ if not self._board[of - 1] and not self._board[of - 2] and not self._board[of - 3] and not self.is_check() and not self.is_attacked(opponent, chess.Square.from_x88(of - 1)) and not self.is_attacked(opponent, chess.Square.from_x88(to)):
+ yield chess.Move(chess.Square.from_x88(of), chess.Square.from_x88(to))
def get_legal_moves(self):
"""Gets legal moves in the current position.
@@ -837,7 +837,7 @@ def get_attackers(self, color, square):
if not piece or piece.color != color:
continue
- difference = source.get_0x88_index() - square.get_0x88_index()
+ difference = source.x88 - square.x88
index = difference + 119
if ATTACKS[index] & (1 << SHIFTS[piece.type]):
@@ -857,9 +857,9 @@ def get_attackers(self, color, square):
# Handle the others.
offset = RAYS[index]
- j = source.get_0x88_index() + offset
+ j = source.x88 + offset
blocked = False
- while j != square.get_0x88_index():
+ while j != square.x88:
if self._board[j]:
blocked = True
break
View
212 chess/square.py
@@ -16,152 +16,148 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-class Square(object):
- """Represents a square on the chess board."""
-
- def __init__(self, name):
- """Inits a square with via its name.
-
- Args:
- x: The x-coordinate, starting with 0 for the a-file.
- y: The y-coordinate, starting with 0 for the first rank.
- """
- assert len(name) == 2
- assert name[0] in ["a", "b", "c", "d", "e", "f", "g", "h"]
- assert name[1] in ["1", "2", "3", "4", "5", "6", "7", "8"]
- self._name = name
+import types
- def get_x(self):
- """Gets the x-coordinate, starting with 0 for the a-file.
+class Square(object):
+ """Represents a square on the chess board.
- Returns:
- An integer between 0 and 7.
- """
- return ord(self._name[0]) - ord("a")
+ :param name: The name of the square in algebraic notation.
- def get_y(self):
- """Gets the y-coordinate, starting with 0 for the first rank.
+ Square objects that represent the same square compare as equal.
- Returns:
- An integer between 0 and 7.
- """
- return ord(self._name[1]) - ord("1")
+ >>> import chess
+ >>> chess.Square("e4") == chess.Square("e4")
+ True
+ """
+ def __init__(self, name):
+ if type(name) is not types.StringType:
+ raise TypeError(
+ "Expected the square name as a string: %s." % repr(name))
+ if not len(name) == 2:
+ raise ValueError(
+ "Invalid length for a square name: %s." % repr(name))
+ if not name[0] in ["a", "b", "c", "d", "e", "f", "g", "h"]:
+ raise ValueError(
+ "File: Expected a, b, c, e, e, f, g or h: %s." % repr(name[0]))
+ if not name[1] in ["1", "2", "3", "4", "5", "6", "7", "8"]:
+ raise ValueError(
+ "Rank: Expected 1, 2, 3, 4, 5, 6, 7 or 8: %s." % repr(name[1]))
+
+ self.__name = name
+
+ @property
+ def x(self):
+ """The x-coordinate, starting with 0 for the a-file."""
+ return ord(self.__name[0]) - ord("a")
+
+ @property
+ def y(self):
+ """The y-coordinate, starting with 0 for the first rank."""
+ return ord(self.__name[1]) - ord("1")
+
+ @property
+ def rank(self):
+ """The rank as an integer between 1 and 8."""
+ return self.y + 1
+
+ @property
+ def file(self):
+ """The file as a letter between `"a"` and `"h"`."""
+ return self.__name[0]
+
+ @property
+ def name(self):
+ """The algebraic name of the square."""
+ return self.__name
+
+ @property
+ def x88(self):
+ """The `x88 <http://en.wikipedia.org/wiki/Board_representation_(chess)#0x88_method>`_
+ index of the square."""
+ return self.x + 16 * (7 - self.y)
def is_dark(self):
- """Checks the color of the square.
-
- Returns:
- A boolean indicating if the square is dark.
- """
- return (ord(self._name[0]) - ord(self._name[1])) % 2 == 0
+ """:return: Whether it is a dark square."""
+ return (ord(self.__name[0]) - ord(self.__name[1])) % 2 == 0
def is_light(self):
- """Checks the color of the square.
-
- Returns:
- A boolean indicating if the square is light.
- """
+ """:return: Whether it is a light square."""
return not self.is_dark()
- def get_rank(self):
- """Gets the rank.
-
- Returns:
- An integer between 1 and 8, where 1 is the first rank.
- """
- return self.get_y() + 1
-
- def get_file(self):
- """Gets the file.
-
- Returns:
- "a", "b", "c", "d", "e", "f", "g" or "h".
- """
- return self._name[0]
-
- def get_name(self):
- """Gets the algebraic name.
-
- Returns:
- An algebraic name like "a1".
- """
- return self._name
-
- def get_0x88_index(self):
- """Gets the index of the square in 0x88 board representation.
-
- Returns:
- An integer between 0 and 119.
- """
- return self.get_x() + 16 * (7 - self.get_y())
-
def is_backrank(self):
- """Checks whether the square is on the backrank of either side.
-
- Returns:
- A boolean indicating if it is a backrank square.
- """
- return self._name[1] in ["1", "8"]
+ """:return: Whether the square is on the backrank of either
+ side."""
+ return self.__name[1] in ["1", "8"]
def __str__(self):
- return self.get_name()
+ return self.__name
def __repr__(self):
- return "Square('%s')" % self.get_name()
+ return "Square('%s')" % self.__name
def __eq__(self, other):
- return self.get_x() == other.get_x() and self.get_y() == other.get_y()
+ return self.name == other.name
def __ne__(self, other):
- return self.get_x() != other.get_x() or self.get_y() != other.get_y()
+ return self.name != other.name
def __hash__(self):
- return self.get_0x88_index()
+ return self.x88
@classmethod
- def from_0x88_index(cls, index):
- """Gets a square from a 0x88 index.
+ def from_x88(cls, x88):
+ """Creates a square object from an `x88 <http://en.wikipedia.org/wiki/Board_representation_(chess)#0x88_method>`_
+ index.
- Args:
- index: An index of the 0x88 board representation.
-
- Returns:
- An object of the Square class.
+ :param x88:
+ The x88 index as integer between 0 and 128.
"""
- index = int(index)
- assert index >= 0 and index <= 128
- assert not index & 0x88 # On the board.
- return cls("abcdefgh"[index & 7] + "87654321"[index >> 4])
+ if type(x88) is not types.IntType:
+ raise TypeError(
+ "Expected the x88 index as an integer: %s." % repr(x88))
+ if x88 < 0 or x88 > 128:
+ raise ValueError("x88 index is out of range: %s." % repr(x88))
+ if x88 & 0x88:
+ raise ValueError(
+ "x88 index is on the second board: %s." % repr(x88))
+
+ return cls("abcdefgh"[x88 & 7] + "87654321"[x88 >> 4])
@classmethod
def from_rank_and_file(cls, rank, file):
- """Gets a square from rank and file.
+ """Creates a square object from rank and file.
- Args:
- rank: An integer between 1 and 8 for the rank.
- file: "a", "b", "c", "d", "e", "f", "g" or "h".
-
- Returns:
- An object of the Square class.
+ :param rank:
+ An integer between 1 and 8.
+ :param file:
+ The rank as a letter between `"a"` and `"h"`.
"""
- rank = int(rank)
- assert rank >= 1 and rank <= 8
- assert file in ["a", "b", "c", "d", "e", "f", "g", "h"]
+ if type(rank) is not types.IntType:
+ raise TypeError("Expected rank to be an integer: %s." % repr(rank))
+ if rank < 1 or rank > 8:
+ raise ValueError(
+ "Expected rank to be between 1 and 8: %s." % repr(rank))
+ if not file in ["a", "b", "c", "d", "e", "f", "g", "h"]:
+ raise ValueError(
+ "Expected the file to be a letter between 'a' and 'h': %s."
+ % repr(file))
+
return cls(file + str(rank))
@classmethod
def from_x_and_y(cls, x, y):
- assert x >= 0 and x <= 7
- assert y >= 0 and y <= 7
+ """Creates a square object from x and y coordinates.
+
+ :param x:
+ An integer between 0 and 7 where 0 is the a-file.
+ :param y:
+ An integer between 0 and 7 where 0 is the first rank.
+ """
return cls("abcdefgh"[x] + "12345678"[y])
@classmethod
def get_all(cls):
- """Gets all squares.
-
- Yields:
- All squares.
- """
+ """:yield: All squares."""
for x in range(0, 8):
for y in range(0, 8):
yield cls.from_x_and_y(x, y)
View
2  chess/zobrist_hasher.py
@@ -246,7 +246,7 @@ def hash_position(self, position):
piece = position.get(square)
if piece:
piece_index = "pPnNbBrRqQkK".index(piece.symbol)
- key ^= self._random_array[64 * piece_index + 8 * square.get_y() + square.get_x()]
+ key ^= self._random_array[64 * piece_index + 8 * square.y + square.x]
# Hash in the castling flags.
if position.get_castling_right("K"):
View
14 tests/test_square.py
@@ -41,18 +41,18 @@ def test_simple_properties(self):
f7 = chess.Square("f7")
self.assertFalse(f7.is_dark())
self.assertTrue(f7.is_light())
- self.assertEqual(f7.get_rank(), 7)
- self.assertEqual(f7.get_file(), 'f')
- self.assertEqual(f7.get_name(), 'f7')
- self.assertEqual(f7.get_0x88_index(), 21)
- self.assertEqual(f7.get_x(), 5)
- self.assertEqual(f7.get_y(), 6)
+ self.assertEqual(f7.rank, 7)
+ self.assertEqual(f7.file, 'f')
+ self.assertEqual(f7.name, 'f7')
+ self.assertEqual(f7.x88, 21)
+ self.assertEqual(f7.x, 5)
+ self.assertEqual(f7.y, 6)
self.assertFalse(f7.is_backrank())
def test_creation(self):
"""Tests creation of Square instances."""
self.assertEqual(chess.Square.from_x_and_y(3, 5), chess.Square("d6"))
- self.assertEqual(chess.Square.from_0x88_index(2), chess.Square("c8"))
+ self.assertEqual(chess.Square.from_x88(2), chess.Square("c8"))
self.assertEqual(chess.Square.from_rank_and_file(rank=2, file="g"), chess.Square("g2"))
def test_iteration(self):
Please sign in to comment.
Something went wrong with that request. Please try again.