Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Pengfei Chen committed Jan 31, 2024
1 parent 0c33743 commit ff0b842
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 74 deletions.
141 changes: 78 additions & 63 deletions unitary/examples/quantum_chinese_chess/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,20 @@

# The default initial state of the game.
_INITIAL_FEN = "RHEAKAEHR/9/1C5C1/P1P1P1P1P/9/9/p1p1p1p1p/1c5c1/9/rheakaehr w---1"
reset = "\033[0m"
bold = "\033[01m"
dim = "\033[02m"

# Constants for printing board
_RESET = "\033[0m"
_BOLD = "\033[01m"
# background
grey = "\033[47m"
_BG_GREY = "\033[47m"
# foreground
black = "\033[30m"
red = "\033[31m"
lightred = "\033[91m"
lightgrey = "\033[37m"
_FG_BLACK = "\033[30m"
_FG_RED = "\033[31m"
_FG_LIGHT_RED = "\033[91m"
_FG_LIGHT_GREY = "\033[37m"
# full width chars
_FULL_SPACE = "\N{IDEOGRAPHIC SPACE}"
_FULL_A = ord("\N{FULLWIDTH LATIN SMALL LETTER A}")


class Board:
Expand Down Expand Up @@ -94,36 +98,38 @@ def from_fen(cls, fen: str = _INITIAL_FEN) -> "Board":
return cls(board, current_player, king_locations)

# TODO(): print players' names in their corresponding side of the board.
# To run the game on sublime terminus, set the following sublime_terminus=True
# for proer printing.
# TODO(): check if there is better way to automatic determine the current terminal
# type, e.g. sublime terminus vs glinux / mac terminal.
# TODO(): right now all possibilities are printed in black, maybe update to print
# in the same color as the corresponding pieces.
def to_str(
self,
probabilities: List[float] = None,
print_probabilities=True,
peek_result: List[int] = None,
sublime_terminus=False,
sublime_terminus: bool = True,
):
def add_piece_symbol(
board_string: str,
piece: Piece,
peek_result: List[int] = None,
index: int = 0,
sublime_terminus=False,
peek_result: List[int],
index: int,
sublime_terminus: bool,
):
if peek_result is None and piece.is_entangled:
# dim works on mac terminal and gLinux terminal,
# but not on sublime terminus
# if not sublime_terminus:
# board_string += dim
if piece.color == Color.RED:
board_string += lightred
board_string += _FG_LIGHT_RED
else:
board_string += lightgrey
board_string += _FG_LIGHT_GREY
else:
# bold works on mac terminal and gLinux terminal,
# but not on sublime terminus
if not sublime_terminus:
board_string += bold
board_string += _BOLD
if piece.color == Color.RED:
board_string += red
board_string += _FG_RED
else:
pass
if (
Expand All @@ -132,9 +138,10 @@ def add_piece_symbol(
or peek_result[index] == 1
):
board_string += piece.symbol(self.lang)
# If an entangled piece is peeked to be empty, we print empty.
elif piece.is_entangled and peek_result[index] == 0:
board_string += Type.symbol(Type.EMPTY, Color.NA, self.lang)
board_string += reset
board_string += _RESET

num_rows = 10
if print_probabilities and probabilities is None:
Expand All @@ -143,95 +150,103 @@ def add_piece_symbol(
if self.lang == Language.EN:
board_string = ["\n "]
# Print the top line of col letters.
board_string += grey
board_string += black
board_string += _BG_GREY
board_string += _FG_BLACK
for col in "abcdefghi":
board_string.append(f" {col} ")
board_string += "\b" + reset + " \n"
board_string += "\b" + _RESET + " \n"
index = 0
for row in range(num_rows):
# Print the row index on the left.
board_string.append(f"{row} ")
# Print each piece of this row, including empty piece.
for col in "abcdefghi":
piece = self.board[f"{col}{row}"]
add_piece_symbol(
board_string, piece, peek_result, index, sublime_terminus
)
if col != "i":
board_string.append(" ")
board_string += reset
board_string += _RESET
index += 1
# Print the row index on the right.
board_string += f" {row}" + reset + "\n"
board_string += f" {row}" + _RESET + "\n"
# Print the sampled prob. of the pieces in the above row.
if print_probabilities:
board_string += " "
board_string += grey
board_string += black
board_string += _BG_GREY
board_string += _FG_BLACK
for i in range(row * 9, (row + 1) * 9):
if probabilities[i] > 0.01 and probabilities[i] < 0.99:
# We only print non-zero probabilities
if probabilities[i] >= 1e-3:
board_string.append("{:.1f} ".format(probabilities[i]))
else:
board_string.append(" ")
board_string += "\b" + reset + " \n"
board_string += "\b" + _RESET + " \n"
board_string.append(" ")
# Print the bottom line of col letters.
board_string += grey
board_string += black
board_string += _BG_GREY
board_string += _FG_BLACK
for col in "abcdefghi":
board_string.append(f" {col} ")
board_string += "\b" + reset + " \n"
board_string += "\b" + _RESET + " \n"
return "".join(board_string)
else:
f_space = "\N{IDEOGRAPHIC SPACE}"
f_a = ord("\N{FULLWIDTH LATIN SMALL LETTER A}")
board_string = ["\n" + f_space + " "]
else: # Print Chinese + full width characters
board_string = ["\n" + _FULL_SPACE + " "]
# Print the top line of col letters.
board_string += grey
board_string += black
for col in range(f_a, f_a + 9):
board_string += _BG_GREY
board_string += _FG_BLACK
for col in range(_FULL_A, _FULL_A + 9):
board_string.append(f"{chr(col)}")
if col != f_a + 8:
board_string += f_space * 2
board_string += " \n" + reset
if col != _FULL_A + 8:
board_string += _FULL_SPACE * 2
board_string += " \n" + _RESET
index = 0
for row in range(num_rows):
# Print the row index on the left.
board_string.append(f"{row}" + f_space)
board_string.append(f"{row}" + _FULL_SPACE)
# Print each piece of this row, including empty piece.
for col in "abcdefghi":
piece = self.board[f"{col}{row}"]
add_piece_symbol(
board_string, piece, peek_result, index, sublime_terminus
)
if col != "i":
board_string.append(f_space * 2)
board_string.append(_FULL_SPACE * 2)
index += 1
# Print the row index on the right.
board_string += f_space * 2 + f"{row}\n"
board_string += _FULL_SPACE * 2 + f"{row}\n"
# Print the sampled prob. of the pieces in the above row.
if print_probabilities:
board_string += f_space + " "
board_string += grey
board_string += black
board_string += _FULL_SPACE + " "
board_string += _BG_GREY
board_string += _FG_BLACK
for i in range(row * 9, (row + 1) * 9):
# We only print non-zero probabilities
if not sublime_terminus:
# space + f_space works for mac terminal and gLinux terminal.
board_string.append(
"{:.1f} ".format(probabilities[i]) + f_space
)
# space + _FULL_SPACE works for mac terminal and gLinux terminal.
if probabilities[i] >= 1e-3:
board_string.append(
"{:.1f} ".format(probabilities[i]) + _FULL_SPACE
)
else:
board_string.append(" " + _FULL_SPACE)
else:
# space + space works for sublime terminus.
board_string.append("{:.1f} ".format(probabilities[i]))
board_string += "\b" + reset + f_space + "\n"
if probabilities[i] >= 1e-3:
# space + space works for sublime terminus.
board_string.append("{:.1f} ".format(probabilities[i]))
else:
board_string.append(" ")
board_string += "\b" + _RESET + _FULL_SPACE + "\n"
# Print the bottom line of col letters.
board_string.append(f_space + " ")
board_string += grey
board_string += black
for col in range(f_a, f_a + 9):
board_string.append(_FULL_SPACE + " ")
board_string += _BG_GREY
board_string += _FG_BLACK
for col in range(_FULL_A, _FULL_A + 9):
board_string.append(f"{chr(col)}")
if col != f_a + 8:
board_string += f_space * 2
board_string += " " + reset
if col != _FULL_A + 8:
board_string += _FULL_SPACE * 2
board_string += " " + _RESET + "\n"
return "".join(board_string)

def path_pieces(self, source: str, target: str) -> Tuple[List[str], List[str]]:
Expand Down
45 changes: 45 additions & 0 deletions unitary/examples/quantum_chinese_chess/board_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

def test_init_with_default_fen():
board = Board.from_fen()

# test English print
assert (
re.sub("\\033\[\d{1,2}m", "", board.to_str(None, False)).replace("\b", "")
== """
Expand All @@ -51,12 +53,34 @@ def test_init_with_default_fen():
"""
)

# test Chinese print
board.set_language(Language.ZH)
assert (
re.sub("\\033\[\d{1,2}m", "", board.to_str(None, False)).replace("\b", "")
== """
  a  b  c  d  e  f  g  h  i
0 车  马  象  士  将  士  象  马  车  0
1 ・  ・  ・  ・  ・  ・  ・  ・  ・  1
2 ・  炮  ・  ・  ・  ・  ・  炮  ・  2
3 兵  ・  兵  ・  兵  ・  兵  ・  兵  3
4 ・  ・  ・  ・  ・  ・  ・  ・  ・  4
5 ・  ・  ・  ・  ・  ・  ・  ・  ・  5
6 卒  ・  卒  ・  卒  ・  卒  ・  卒  6
7 ・  砲  ・  ・  ・  ・  ・  砲  ・  7
8 ・  ・  ・  ・  ・  ・  ・  ・  ・  8
9 車  馬  相  仕  帥  仕  相  馬  車  9
  a  b  c  d  e  f  g  h  i
"""
)

# check locations of KINGs
assert board.king_locations == ["e0", "e9"]


def test_init_with_specified_fen():
board = Board.from_fen("4kaR2/4a4/3hR4/7H1/9/9/9/9/4Ap1r1/3AK3c w---1 ")

# test English print
assert (
re.sub("\\033\[\d{1,2}m", "", board.to_str(None, False)).replace("\b", "")
== """
Expand All @@ -75,6 +99,27 @@ def test_init_with_specified_fen():
"""
)

# test Chinese print
board.set_language(Language.ZH)
assert (
re.sub("\\033\[\d{1,2}m", "", board.to_str(None, False)).replace("\b", "")
== """
  a  b  c  d  e  f  g  h  i
0 ・  ・  ・  ・  帥  仕  车  ・  ・  0
1 ・  ・  ・  ・  仕  ・  ・  ・  ・  1
2 ・  ・  ・  馬  车  ・  ・  ・  ・  2
3 ・  ・  ・  ・  ・  ・  ・  马  ・  3
4 ・  ・  ・  ・  ・  ・  ・  ・  ・  4
5 ・  ・  ・  ・  ・  ・  ・  ・  ・  5
6 ・  ・  ・  ・  ・  ・  ・  ・  ・  6
7 ・  ・  ・  ・  ・  ・  ・  ・  ・  7
8 ・  ・  ・  ・  士  卒  ・  車  ・  8
9 ・  ・  ・  士  将  ・  ・  ・  砲  9
  a  b  c  d  e  f  g  h  i
"""
)

# check locations of KINGs
assert board.king_locations == ["e0", "e9"]


Expand Down
15 changes: 7 additions & 8 deletions unitary/examples/quantum_chinese_chess/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,20 @@ class Type(enum.Enum):
- Chinese black
"""

EMPTY = (
"\u00B7",
"\u00B7",
"\u30FB",
"\u30FB",
) # \u00B7 is a half width mid dot, and \u30FB is full width
PAWN = ("P", "p", "兵", "卒")
CANNON = ("C", "c", "炮", "砲")
ROOK = ("R", "r", "车", "車")
HORSE = ("H", "h", "马", "馬")
ELEPHANT = ("E", "e", "象", "相")
ADVISOR = ("A", "a", "士", "仕")
KING = ("K", "k", "将", "帥")
# \u00B7 is a half width mid dot, and \u30FB is full width
EMPTY = (
"\u00B7",
"\u00B7",
"\u30FB",
"\u30FB",
)

@staticmethod
def type_of(c: str) -> Optional["Type"]:
Expand All @@ -115,8 +116,6 @@ def type_of(c: str) -> Optional["Type"]:
@staticmethod
def symbol(type_: "Type", color: Color, lang: Language = Language.EN) -> str:
"""Returns symbol of the given piece according to its color and desired language."""
if type_ == Type.EMPTY:
return type_.value[0]
if lang == Language.EN: # Return English symbols
if color == Color.RED:
return type_.value[0]
Expand Down
4 changes: 2 additions & 2 deletions unitary/examples/quantum_chinese_chess/enums_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ def test_symbol():

assert Type.symbol(Type.EMPTY, Color.RED) == "·"
assert Type.symbol(Type.EMPTY, Color.BLACK) == "·"
assert Type.symbol(Type.EMPTY, Color.RED, Language.ZH) == "·"
assert Type.symbol(Type.EMPTY, Color.BLACK, Language.ZH) == "·"
assert Type.symbol(Type.EMPTY, Color.RED, Language.ZH) == ""
assert Type.symbol(Type.EMPTY, Color.BLACK, Language.ZH) == ""
2 changes: 1 addition & 1 deletion unitary/examples/quantum_chinese_chess/piece_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def test_symbol():
p2 = Piece("c2", SquareState.EMPTY, Type.EMPTY, Color.NA)
assert p2.symbol() == "·"
assert p2.__str__() == "·"
assert p2.symbol(Language.ZH) == "·"
assert p2.symbol(Language.ZH) == ""


def test_enum():
Expand Down

0 comments on commit ff0b842

Please sign in to comment.