-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #159 from madcpf/board
Add Board class
- Loading branch information
Showing
2 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# Copyright 2023 The Unitary Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from typing import List | ||
import unitary.alpha as alpha | ||
from unitary.examples.quantum_chinese_chess.enums import ( | ||
SquareState, | ||
Color, | ||
Type, | ||
Language, | ||
) | ||
from unitary.examples.quantum_chinese_chess.piece import Piece | ||
|
||
|
||
# The default initial state of the game. | ||
_INITIAL_FEN = "RHEAKAEHR/9/1C5C1/P1P1P1P1P/9/9/p1p1p1p1p/1c5c1/9/rheakaehr w---1" | ||
|
||
|
||
class Board: | ||
"""Board holds the assemble of all pieces. Each piece could be either in classical or quantum state.""" | ||
|
||
def __init__( | ||
self, board: alpha.QuantumWorld, current_player: int, king_locations: List[str] | ||
): | ||
self.board = board | ||
self.current_player = current_player | ||
self.king_locations = king_locations | ||
self.lang = Language.EN # The default language is English. | ||
|
||
def set_language(self, lang: Language): | ||
self.lang = lang | ||
|
||
@classmethod | ||
def from_fen(cls, fen: str = _INITIAL_FEN) -> "Board": | ||
""" | ||
Translates FEN (Forsyth-Edwards Notation) symbols into the whole QuantumWorld board. | ||
FEN rule for Chinese Chess could be found at https://www.wxf-xiangqi.org/images/computer-xiangqi/fen-for-xiangqi-chinese-chess.pdf | ||
""" | ||
chess_board = {} | ||
row_index = 9 | ||
king_locations = [] | ||
pieces, turns = fen.split(" ", 1) | ||
for row in pieces.split("/"): | ||
col = ord("a") | ||
for char in row: | ||
# Add empty board pieces. | ||
if "1" <= char <= "9": | ||
for i in range(int(char)): | ||
name = f"{chr(col)}{row_index}" | ||
chess_board[name] = Piece( | ||
name, SquareState.EMPTY, Type.EMPTY, Color.NA | ||
) | ||
col += 1 | ||
# Add occupied board pieces. | ||
else: | ||
name = f"{chr(col)}{row_index}" | ||
piece_type = Type.type_of(char) | ||
if piece_type == Type.KING: | ||
king_locations.append(name) | ||
color = Color.RED if char.isupper() else Color.BLACK | ||
chess_board[name] = Piece( | ||
name, SquareState.OCCUPIED, piece_type, color | ||
) | ||
col += 1 | ||
row_index -= 1 | ||
board = alpha.QuantumWorld(chess_board.values()) | ||
# Here 0 means the player RED while 1 the player BLACK. | ||
current_player = 0 if "w" in turns else 1 | ||
return cls(board, current_player, king_locations) | ||
|
||
def __str__(self): | ||
num_rows = 10 | ||
board_string = ["\n "] | ||
# Print the top line of col letters. | ||
for col in "abcdefghi": | ||
board_string.append(f" {col}") | ||
board_string.append("\n") | ||
for row in range(num_rows): | ||
# Print the row index on the left. | ||
board_string.append(f"{row} ") | ||
for col in "abcdefghi": | ||
piece = self.board[f"{col}{row}"] | ||
board_string += piece.symbol(self.lang) | ||
if self.lang == Language.EN: | ||
board_string.append(" ") | ||
# Print the row index on the right. | ||
board_string.append(f" {row}\n") | ||
board_string.append(" ") | ||
# Print the bottom line of col letters. | ||
for col in "abcdefghi": | ||
board_string.append(f" {col}") | ||
board_string.append("\n") | ||
if self.lang == Language.EN: | ||
return "".join(board_string) | ||
# We need to turn letters into their full-width counterparts to align | ||
# a mix of letters + Chinese characters. | ||
chars = "".join(chr(c) for c in range(ord(" "), ord("z"))) | ||
full_width_chars = "\N{IDEOGRAPHIC SPACE}" + "".join( | ||
chr(c) | ||
for c in range( | ||
ord("\N{FULLWIDTH EXCLAMATION MARK}"), | ||
ord("\N{FULLWIDTH LATIN SMALL LETTER Z}"), | ||
) | ||
) | ||
translation = str.maketrans(chars, full_width_chars) | ||
return ( | ||
"".join(board_string) | ||
.replace(" ", "") | ||
.replace("abcdefghi", " abcdefghi") | ||
.translate(translation) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# Copyright 2023 The Unitary Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
from unitary.examples.quantum_chinese_chess.enums import Language | ||
from unitary.examples.quantum_chinese_chess.board import Board | ||
|
||
|
||
def test_init_with_default_fen(): | ||
board = Board.from_fen() | ||
assert ( | ||
board.__str__() | ||
== """ | ||
a b c d e f g h i | ||
0 r h e a k a e h r 0 | ||
1 . . . . . . . . . 1 | ||
2 . c . . . . . c . 2 | ||
3 p . p . p . p . p 3 | ||
4 . . . . . . . . . 4 | ||
5 . . . . . . . . . 5 | ||
6 P . P . P . P . P 6 | ||
7 . C . . . . . C . 7 | ||
8 . . . . . . . . . 8 | ||
9 R H E A K A E H R 9 | ||
a b c d e f g h i | ||
""" | ||
) | ||
|
||
board.set_language(Language.ZH) | ||
assert ( | ||
board.__str__() | ||
== """ | ||
abcdefghi | ||
0車馬相仕帥仕相馬車0 | ||
1.........1 | ||
2.砲.....砲.2 | ||
3卒.卒.卒.卒.卒3 | ||
4.........4 | ||
5.........5 | ||
6兵.兵.兵.兵.兵6 | ||
7.炮.....炮.7 | ||
8.........8 | ||
9车马象士将士象马车9 | ||
abcdefghi | ||
""" | ||
) | ||
|
||
assert board.king_locations == ["e9", "e0"] | ||
|
||
|
||
def test_init_with_specified_fen(): | ||
board = Board.from_fen("4kaR2/4a4/3hR4/7H1/9/9/9/9/4Ap1r1/3AK3c w---1 ") | ||
|
||
assert ( | ||
board.__str__() | ||
== """ | ||
a b c d e f g h i | ||
0 . . . A K . . . c 0 | ||
1 . . . . A p . r . 1 | ||
2 . . . . . . . . . 2 | ||
3 . . . . . . . . . 3 | ||
4 . . . . . . . . . 4 | ||
5 . . . . . . . . . 5 | ||
6 . . . . . . . H . 6 | ||
7 . . . h R . . . . 7 | ||
8 . . . . a . . . . 8 | ||
9 . . . . k a R . . 9 | ||
a b c d e f g h i | ||
""" | ||
) | ||
|
||
board.set_language(Language.ZH) | ||
assert ( | ||
board.__str__() | ||
== """ | ||
abcdefghi | ||
0...士将...砲0 | ||
1....士卒.車.1 | ||
2.........2 | ||
3.........3 | ||
4.........4 | ||
5.........5 | ||
6.......马.6 | ||
7...馬车....7 | ||
8....仕....8 | ||
9....帥仕车..9 | ||
abcdefghi | ||
""" | ||
) | ||
|
||
assert board.king_locations == ["e9", "e0"] |