def __init__(self, *args, **kws): super().__init__(*args, **kws) self.setMouseTracking(True) # we want to receive mouseMoveEvents self.hive = Hive() self.level = self.hive.level self.hexgrid = hexutil.HexGrid(24) # initialize GUI objects needed for painting self.font = QtGui.QFont("Helvetica", 20) self.font.setStyleHint(QtGui.QFont.SansSerif) self.pen = QtGui.QPen() self.pen.setWidth(2) self.select_brush = QtGui.QBrush(QtGui.QColor(127, 127, 255, 127)) self.unseen_brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 127)) # set center position self.center = QtCore.QPoint(0, 0) # Related to mouse events self.last_pos = QtCore.QPoint() self.is_mouse_pressed = False # mouse timer helps to distinguish click from press-and-hold self.mouse_timer = QtCore.QTimer() self.mouse_timer.setInterval(250) self.mouse_timer.setSingleShot(True)
def setUp(self) -> None: self.sh = logging.StreamHandler(sys.stdout) logger.addHandler(self.sh) self.hive = Hive() self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wS1"), hexutil.Hex(0, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bS1"), hexutil.Hex(2, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wQ1"), hexutil.Hex(-1, -1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bQ1"), hexutil.Hex(3, -1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wS2"), hexutil.Hex(-1, 1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bG1"), hexutil.Hex(4, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wB1"), hexutil.Hex(-3, 1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bA1"), hexutil.Hex(2, -2)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wG1"), hexutil.Hex(-4, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bB1"), hexutil.Hex(3, 1)) self.hive.level.current_player = Player.BLACK
def step(self, hive: 'Hive'): #logging.debug("alpha player steps") #logging.debug("\n{}".format(environment.hive)) if hive.current_player == PlayerColor.BLACK: flipped_hive = Hive() for hex, p_list in hive.level.tiles.items(): flipped_hive.level.tiles[hex] = [p._replace(color=PlayerColor.WHITE if p.color == PlayerColor.BLACK else PlayerColor.BLACK) for p in p_list] flipped_hive.level.current_player = PlayerColor.WHITE board = represent.two_dim_representation(represent.get_adjacency_state(flipped_hive)) pis = self.mcts.getActionProb(board) valids = ai_environment.getValidMoves(board, 1) pis = pis * np.array(valids) # mask invalid moves #pis = self.mcts.getActionProb(board, temp=0) action_number = np.argmax(pis) #logging.debug("Flipped hive:\n{}".format(flipped_hive)) (piece, end_cell) = flipped_hive.action_from_vector(action_number) #logging.debug("Flipped decision: ({}, {})".format(piece, end_cell)) piece = piece._replace(color=PlayerColor.BLACK) else: board = represent.two_dim_representation(represent.get_adjacency_state(hive)) # board = environment.getCanonicalForm(board, player_num) pis = self.mcts.getActionProb(board) valids = ai_environment.getValidMoves(board, 1) pis = pis * np.array(valids) # mask invalid moves # pis = self.mcts.getActionProb(board, temp=0) action_number = np.argmax(pis) (piece, end_cell) = hive.action_from_vector(action_number) #logging.debug("Decision: ({}, {})".format(piece, end_cell)) return (piece, end_cell)
class TestImportExport(TestCase): """ Verify logic related to importing and exporting Hive state. """ def setUp(self) -> None: self.sh = logging.StreamHandler(sys.stdout) logger.addHandler(self.sh) self.hive = Hive() self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wS1"), hexutil.Hex(0, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bS1"), hexutil.Hex(2, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wQ1"), hexutil.Hex(-1, -1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bQ1"), hexutil.Hex(3, -1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wS2"), hexutil.Hex(-1, 1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bG1"), hexutil.Hex(4, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wB1"), hexutil.Hex(-3, 1)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bA1"), hexutil.Hex(2, -2)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("wG1"), hexutil.Hex(-4, 0)) self.hive.level.move_or_append_to(self.hive.get_piece_by_name("bB1"), hexutil.Hex(3, 1)) self.hive.level.current_player = Player.BLACK def tearDown(self) -> None: logger.removeHandler(self.sh) def test_export_hive(self): importexport.export_hive( self.hive, importexport.saved_game_path("test_export.json")) exported_data = json.load( open(importexport.saved_game_path('test_export.json'), 'r')) test_data = json.load( open( os.path.join(os.path.dirname(__file__), "import_export_data.json"), 'r')) self.assertEqual(exported_data, test_data) def test_import_hive(self): file_path = os.path.join(os.path.dirname(__file__), "import_export_data.json") imported_hive = importexport.import_hive(file_path) # Current player is the same self.assertEqual(imported_hive.current_player, self.hive.current_player) # Check if board is the same for hexagon, pieces in imported_hive.level.tiles.items(): self.assertEqual(pieces, self.hive.level.get_tile_content(hexagon))
def test_action_numbers(self): self.hive = Hive() self.hive.place_piece_without_action("wB2") self.hive.level.current_player = Player.BLACK self.hive.place_piece_without_action("bB1", "wB2", Direction.HX_W) self.hive.level.current_player = Player.WHITE self.hive.place_piece_without_action("wA2", "wB2", Direction.HX_SE) self.hive.level.current_player = Player.BLACK self.hive.place_piece_without_action("bS2", "bB1", Direction.HX_W) self.hive.level.current_player = Player.WHITE self.assertEqual(represent.get_all_action_vector(self.hive)[90], 0) self.assertRaises(HiveException, self.hive.action_from_vector, 90)
def import_hive(file: str) -> Hive: data = json.load(open(file, 'r')) current_player = data["player"] if current_player.lower() != "w" and current_player.lower() != "b": logging.error("Wrong format: cannot decode current player") raise RuntimeError() game = data["game"] if not game: logging.error("Could not open hive data") raise RuntimeError() if not isinstance(data, dict): logging.error("Wrong format, expected dict") raise RuntimeError() hive = Hive() hive.level.current_player = current_player.lower() for hex_str_tuple, v in game.items(): hex_tuple = ast.literal_eval(hex_str_tuple) if not isinstance(hex_tuple, tuple): logging.error("Wrong format while deparsing hex tuple") raise RuntimeError() hexagon = Hex(*hex_tuple) if not isinstance(v, list): logging.error("Wrong format, expected list") raise RuntimeError() for piece_str in v: hive.level.append_to(piecefact.name_to_piece(piece_str), hexagon) return hive
def test_action_vector(self): self.hive = Hive.load_state_with_player(self._list_repr, Player.WHITE) __location__ = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__))) with open(os.path.join(__location__, 'repr_data.json')) as f: print(self.hive) d = json.load(f) res = represent.get_all_action_vector(self.hive) print(res) assert all([a == b for a,b in zip(res, d["test_action_vector"])])
def test_actions_from_vector(self): self.hive = Hive.load_state_with_player(self._list_repr, Player.WHITE) all_actions = represent.get_all_action_vector(self.hive) indices = [i for i, v in enumerate(all_actions) if v > 0] for action_number in indices: self.hive.action_from_vector(action_number) # test other player's turn self.hive._toggle_player(self.hive.current_player) all_actions = represent.get_all_action_vector(self.hive) indices = [i for i, v in enumerate(all_actions) if v > 0] for action_number in indices: self.hive.action_from_vector(action_number)
def main(): hive = Hive() hive.level.move_or_append_to(hive.get_piece_by_name("wS1"), hexutil.Hex(0, 0)) hive.level.move_or_append_to(hive.get_piece_by_name("bS1"), hexutil.Hex(2, 0)) hive.level.move_or_append_to(hive.get_piece_by_name("wQ1"), hexutil.Hex(-1, -1)) hive.level.move_or_append_to(hive.get_piece_by_name("bQ1"), hexutil.Hex(3, -1)) hive.level.move_or_append_to(hive.get_piece_by_name("wS2"), hexutil.Hex(-1, 1)) hive.level.move_or_append_to(hive.get_piece_by_name("bG1"), hexutil.Hex(4, 0)) hive.level.move_or_append_to(hive.get_piece_by_name("wB1"), hexutil.Hex(-3, 1)) hive.level.move_or_append_to(hive.get_piece_by_name("bA1"), hexutil.Hex(2, -2)) hive.level.move_or_append_to(hive.get_piece_by_name("wG1"), hexutil.Hex(-4, 0)) hive.level.move_or_append_to(hive.get_piece_by_name("bB1"), hexutil.Hex(1, 1)) view = HiveView(hive.level) print(view.to_string())
def test_load_state_from_list(self): """Verify canonical adjacency state loading""" input_list = self._list_repr self.hive = Hive.load_state_with_player(input_list, Player.WHITE) # ['wS2', 'wB1', 'wS1', 'wG1', 'bS1', 'bB1', 'bQ1', 'wQ1', 'bG1', 'bA1'] self.assertEqual(len(self.hive.level.get_played_pieces()), 10) self.assertEqual(len(self.hive.level.get_unplayed_pieces(Player.WHITE)), 6) self.assertEqual(len(self.hive.level.get_unplayed_pieces(Player.BLACK)), 6) names = [str(p) for p in self.hive.level.get_played_pieces()] self.assertTrue("wS2" in names) self.assertTrue("wB1" in names) self.assertTrue("wS1" in names) self.assertTrue("wG1" in names) self.assertTrue("bS1" in names) self.assertTrue("bB1" in names) self.assertTrue("bQ1" in names) self.assertTrue("wQ1" in names) self.assertTrue("bG1" in names) self.assertTrue("bA1" in names) wB1_pos = self.hive.level.goto_direction(self.hive.locate("wG1"), Direction.HX_NE) self.assertEqual(self.hive.locate("wB1"), wB1_pos) # Verify everything around bS1 bS1_pos = self.hive.locate("bS1") self.assertEqual(self.hive.locate("wS1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_W)) self.assertEqual(self.hive.locate("bB1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_NE)) self.assertEqual(self.hive.locate("bG1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_E)) self.assertEqual(self.hive.locate("bQ1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_SE)) self.assertFalse(self.hive.level.get_tile_content(self.hive.level.goto_direction(bS1_pos, Direction.HX_NW))) self.assertFalse(self.hive.level.get_tile_content(self.hive.level.goto_direction(bS1_pos, Direction.HX_SW))) # Test transforming it back to the list representation result = represent.two_dim_representation(represent.get_adjacency_state(self.hive)) np.testing.assert_equal(result, input_list)
def getInitBoard(): hive = Hive() return represent.two_dim_representation( represent.get_adjacency_state(hive))
def main(): hive = Hive() hive.setup() DEPTH = 5 number_of_nodes = perft(hive, DEPTH) print("Number of nodes on level {} is: {}".format(DEPTH, number_of_nodes))
def setUp(self) -> None: self.sh = logging.StreamHandler(sys.stdout) logger.addHandler(self.sh) self.hive = Hive()
class GameWidget(QtWidgets.QWidget): """The Qt Widget which shows the game.""" _kind_to_text = { "A": "Ant", "B": "Beetle", "G": "Grasshopper", "S": "Spider", "Q": "Queen" } _text_to_piece = { "Ant": "A", "Beetle": "B", "Grasshopper": "G", "Spider": "S", "Queen": "Q" } hexagon_under_cursor = None selected_hexagon = None def set_state(self, level: GameState) -> None: self.level = level self.hive.level = level self.repaint() def __init__(self, *args, **kws): super().__init__(*args, **kws) self.setMouseTracking(True) # we want to receive mouseMoveEvents self.hive = Hive() self.level = self.hive.level self.hexgrid = hexutil.HexGrid(24) # initialize GUI objects needed for painting self.font = QtGui.QFont("Helvetica", 20) self.font.setStyleHint(QtGui.QFont.SansSerif) self.pen = QtGui.QPen() self.pen.setWidth(2) self.select_brush = QtGui.QBrush(QtGui.QColor(127, 127, 255, 127)) self.unseen_brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 127)) # set center position self.center = QtCore.QPoint(0, 0) # Related to mouse events self.last_pos = QtCore.QPoint() self.is_mouse_pressed = False # mouse timer helps to distinguish click from press-and-hold self.mouse_timer = QtCore.QTimer() self.mouse_timer.setInterval(250) self.mouse_timer.setSingleShot(True) def hexagon_of_pos(self, pos): """Compute the hexagon at the screen position.""" size = self.size() xc = size.width() // 2 yc = size.height() // 2 return self.hexgrid.hex_at_coordinate(pos.x() - xc, pos.y() - yc) def mousePressEvent(self, event): if event.button() == QtCore.Qt.RightButton: # Check if it is a border hex game_pos = event.pos() + self.center hexagon = self.hexagon_of_pos(game_pos) if hexagon not in self.level.get_border_tiles(): return # Show dropdown menu menu = QtWidgets.QMenu() available_kinds = self.level.available_kinds_to_place( self.level.current_player) for kind in available_kinds: action_to_add = menu.addAction(self._kind_to_text.get(kind)) # select executed item action = menu.exec_(self.mapToGlobal(event.pos())) if not action: return # user clicked elsewhere, or no more pieces available try: # TODO clean up text to kind self.hive.action_piece_to( piece_factory.create_piece( self.level.current_player, self._text_to_piece[action.text()], available_kinds[action.text()[0]]), hexagon) except: # TODO deal with user error pass self.selected_hexagon = None self.repaint() return elif event.button() == QtCore.Qt.LeftButton: self.is_mouse_pressed = True self.last_pos = event.pos() if not self.mouse_timer.isActive(): self.mouse_timer.start() return def mouseReleaseEvent(self, event): self.is_mouse_pressed = False if self.mouse_timer.isActive(): self.mouse_timer.stop() # perform selection game_pos = event.pos() + self.center hexagon = self.hexagon_of_pos(game_pos) # perform movement if self.selected_hexagon: try: self.hive.action_piece_to( self.level.get_tile_content(self.selected_hexagon)[-1], hexagon) except: # TODO deal with user error pass finally: self.selected_hexagon = None else: # perform selection if self.level.get_tile_content( hexagon) and self.level.get_tile_content( hexagon)[-1].color == self.level.current_player: self.selected_hexagon = hexagon self.repaint() def mouseMoveEvent(self, event): if self.is_mouse_pressed and not self.mouse_timer.isActive(): pos_change = event.pos() - self.last_pos self.center -= pos_change self.last_pos = event.pos() self.select_hexagon(event.pos()) def select_hexagon(self, pos): """Select hexagon and path to hexagon at position.""" game_pos = pos + self.center hexagon = self.hexagon_of_pos(game_pos) self.hexagon_under_cursor = hexagon self.repaint() def paintEvent(self, event): # compute center of window size = self.size() xc = size.width() // 2 yc = size.height() // 2 # bounding box when we translate the origin to be at the center bbox = hexutil.Rectangle(self.center.x() - xc, self.center.y() - yc, size.width(), size.height()) hexgrid = self.hexgrid painter = QtGui.QPainter() painter.begin(self) try: # paint background black painter.save() painter.setPen(QtCore.Qt.NoPen) painter.setBrush(QtGui.QColor()) painter.drawRect(0, 0, size.width(), size.height()) painter.restore() # set up drawing state painter.setPen(self.pen) painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.setRenderHint(QtGui.QPainter.TextAntialiasing) painter.setFont(self.font) painter.translate(xc, yc) # draw each hexagon which is in the window for hexagon in hexgrid.hexes_in_rectangle(bbox): selectable = False polygon = QtGui.QPolygon([ QtCore.QPoint(*corner) - self.center for corner in hexgrid.corners(hexagon) ]) # if it is a placed hexagon if self.level.get_tile_content(hexagon): selectable = True if hexagon == self.selected_hexagon: painter.setBrush(QtGui.QColor("yellow")) else: if self.level.get_tile_content( hexagon)[-1].color == Player.WHITE: painter.setBrush(QtGui.QColor("lightGray")) else: painter.setBrush(QtGui.QColor("red")) painter.drawPolygon(polygon) # draw bug (which is currently represented with a letter) rect = hexgrid.bounding_box(hexagon) relative_rect = hexutil.Rectangle( x=rect.x - self.center.x(), y=rect.y - self.center.y(), width=rect.width, height=rect.height) relative_rect = QtCore.QRectF( *relative_rect ) # convert to Qt RectF and add relative position painter.drawText( relative_rect, QtCore.Qt.AlignCenter, self.level.get_tile_content(hexagon)[-1].kind) # if it is a border hexagon elif self.level.is_border(hexagon): selectable = True painter.setBrush(QtGui.QColor(10, 20, 20)) painter.drawPolygon(polygon) # highlight hex under cursor if selectable: if hexagon == self.hexagon_under_cursor: painter.setBrush(QtGui.QColor(255, 255, 0, 150)) painter.drawPolygon(polygon) finally: painter.end()
def getBoardSize(): hive = Hive() return represent.two_dim_representation( represent.canonical_adjacency_state(hive)).shape
def getActionSize(): """ :return: Number of possible actions in the given state """ hive = Hive() return len(represent.get_all_action_vector(hive))
class TestRepresentation(TestCase): """ Verify logic related to various outputs and inputs of the Hive engine. """ @property def _list_repr(self): # / \ / \ / \ / \ / \ # |wB1|wS2| |bB1| | # / \ / \ / \ / \ / \ / # |wG1| |wS1|bS1|bG1| # \ / \ / \ / \ / \ / \ # | |wQ1| |bQ1| | # / \ / \ / \ / \ / \ / # | | | |bA1| | # \ / \ / \ / \ / \ / __location__ = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__))) with open(os.path.join(__location__, 'repr_data.json')) as f: d = json.load(f) return np.array(d["repr_list"]) def setUp(self) -> None: self.sh = logging.StreamHandler(sys.stdout) logger.addHandler(self.sh) self.hive = Hive() def tearDown(self) -> None: logger.removeHandler(self.sh) def test_empty_adjacency_state(self): adj = represent.get_adjacency_state(self.hive) self.assertEqual(len(adj), BUG_C) self.assertEqual(len(adj.get(list(adj.keys())[0])), BUG_C - 1) list_repr = represent.list_representation(adj) self.assertEqual(len(list_repr), BUG_C*(BUG_C - 1)) self.assertTrue(all(v == 0 for v in list_repr)) def test_load_state_from_list(self): """Verify canonical adjacency state loading""" input_list = self._list_repr self.hive = Hive.load_state_with_player(input_list, Player.WHITE) # ['wS2', 'wB1', 'wS1', 'wG1', 'bS1', 'bB1', 'bQ1', 'wQ1', 'bG1', 'bA1'] self.assertEqual(len(self.hive.level.get_played_pieces()), 10) self.assertEqual(len(self.hive.level.get_unplayed_pieces(Player.WHITE)), 6) self.assertEqual(len(self.hive.level.get_unplayed_pieces(Player.BLACK)), 6) names = [str(p) for p in self.hive.level.get_played_pieces()] self.assertTrue("wS2" in names) self.assertTrue("wB1" in names) self.assertTrue("wS1" in names) self.assertTrue("wG1" in names) self.assertTrue("bS1" in names) self.assertTrue("bB1" in names) self.assertTrue("bQ1" in names) self.assertTrue("wQ1" in names) self.assertTrue("bG1" in names) self.assertTrue("bA1" in names) wB1_pos = self.hive.level.goto_direction(self.hive.locate("wG1"), Direction.HX_NE) self.assertEqual(self.hive.locate("wB1"), wB1_pos) # Verify everything around bS1 bS1_pos = self.hive.locate("bS1") self.assertEqual(self.hive.locate("wS1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_W)) self.assertEqual(self.hive.locate("bB1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_NE)) self.assertEqual(self.hive.locate("bG1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_E)) self.assertEqual(self.hive.locate("bQ1"), self.hive.level.goto_direction(bS1_pos, Direction.HX_SE)) self.assertFalse(self.hive.level.get_tile_content(self.hive.level.goto_direction(bS1_pos, Direction.HX_NW))) self.assertFalse(self.hive.level.get_tile_content(self.hive.level.goto_direction(bS1_pos, Direction.HX_SW))) # Test transforming it back to the list representation result = represent.two_dim_representation(represent.get_adjacency_state(self.hive)) np.testing.assert_equal(result, input_list) def test_action_vector(self): self.hive = Hive.load_state_with_player(self._list_repr, Player.WHITE) __location__ = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__))) with open(os.path.join(__location__, 'repr_data.json')) as f: print(self.hive) d = json.load(f) res = represent.get_all_action_vector(self.hive) print(res) assert all([a == b for a,b in zip(res, d["test_action_vector"])]) def test_actions_from_vector(self): self.hive = Hive.load_state_with_player(self._list_repr, Player.WHITE) all_actions = represent.get_all_action_vector(self.hive) indices = [i for i, v in enumerate(all_actions) if v > 0] for action_number in indices: self.hive.action_from_vector(action_number) # test other player's turn self.hive._toggle_player(self.hive.current_player) all_actions = represent.get_all_action_vector(self.hive) indices = [i for i, v in enumerate(all_actions) if v > 0] for action_number in indices: self.hive.action_from_vector(action_number) def test_action_numbers(self): self.hive = Hive() self.hive.place_piece_without_action("wB2") self.hive.level.current_player = Player.BLACK self.hive.place_piece_without_action("bB1", "wB2", Direction.HX_W) self.hive.level.current_player = Player.WHITE self.hive.place_piece_without_action("wA2", "wB2", Direction.HX_SE) self.hive.level.current_player = Player.BLACK self.hive.place_piece_without_action("bS2", "bB1", Direction.HX_W) self.hive.level.current_player = Player.WHITE self.assertEqual(represent.get_all_action_vector(self.hive)[90], 0) self.assertRaises(HiveException, self.hive.action_from_vector, 90)