def test_bad_position(self): r = Rook() b = Board() failed_correctly = False try: b.place_piece(r, 'x42') except PositionError: failed_correctly = True assert failed_correctly
def test_knight_moves(self): k = Knight() b = Board() b.place_piece(k, 'a8') possible_moves = b.list_possible_moves(k) possible_moves.sort() assert possible_moves == ['b6', 'c7'], possible_moves b.clear_board() b.place_piece(k, 'h1') possible_moves = b.list_possible_moves(k) possible_moves.sort() assert possible_moves == ['f2', 'g3'], possible_moves
def __init__(self, player_agents): n = len(player_agents) if not 2 <= n <= 5: raise Exception( 'Unsupported number of players: {}'.format(player_agents)) cheques = { 2: CHEQUES_FOR_2[:], 3: CHEQUES_FOR_3[:], 4: CHEQUES_FOR_4[:], 5: CHEQUES_FOR_5[:] } players = [Player(p, cs) for p, cs in zip(player_agents, cheques[n])] self._players = players self._deck = Deck() self._board = Board(CHEQUE_STARTING) self._round = 1 self._round_end_policemen = ROUND_END_POLICEMEN if n > 2 else ROUND_END_POLICEMEN_TWOPLAYER self._end = False self._round_order_generator = TurnOrder( self._players, lambda x, y: x.player_agent == y.player_agent)
def test_rook_moves(self): r = Rook() b = Board() b.place_piece(r, 'd2') assert b.list_possible_moves(r) == [ 'a2', 'b2', 'c2', 'd1', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'e2', 'f2', 'g2', 'h2' ], b.list_possible_moves(r)
def test_queen_moves(self): q = Queen() b = Board() b.place_piece(q, 'd2') assert b.list_possible_moves(q) == [ 'a2', 'a5', 'b2', 'b4', 'c1', 'c2', 'c3', 'd1', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'e1', 'e2', 'e3', 'f2', 'f4', 'g2', 'g5', 'h2', 'h6' ], b.list_possible_moves(q)
SCREEN_HEIGHT = 512 FPS = 30 BLACK = (0, 0, 0) WHITE = (255, 255, 255) RED = (255, 0, 0) GREEN = (0, 255, 0) LIGHT_TILE = (255, 206, 158) DARK_TILE = (209, 139, 71) spritesheet = pygame.image.load("sprites.png") spritesheet = pygame.transform.scale(spritesheet, (384, 128)) pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) clock = pygame.time.Clock() board = Board(sys.argv) def renderPiece(piece): subimageY = 0 if piece[0] == 0: subimageY = 64 screen.blit(spritesheet, (piece[2] * 64, piece[3] * 64), ((6 - piece[1]) * 64, subimageY, 64, 64)) running = True #game loop while running: clock.tick(FPS)
import argparse from pieces import Board, create_piece parser = argparse.ArgumentParser() parser.add_argument('-piece', dest='piece', required=True, help='The piece to move') parser.add_argument('-position', dest='position', required=True, help='The starting position of the piece') args = parser.parse_args() position = args.position.lower() # Instantiate the piece's class from user input piece = create_piece(args.piece.lower()) board = Board() # The board has-a piece board.place_piece(piece, position) # The board tells us the possible moves possible_moves = board.list_possible_moves(piece) print("Moves for {} at {}:".format(piece.name, position)) print(", ".join(possible_moves))
class Game: def __init__(self, player_agents): n = len(player_agents) if not 2 <= n <= 5: raise Exception( 'Unsupported number of players: {}'.format(player_agents)) cheques = { 2: CHEQUES_FOR_2[:], 3: CHEQUES_FOR_3[:], 4: CHEQUES_FOR_4[:], 5: CHEQUES_FOR_5[:] } players = [Player(p, cs) for p, cs in zip(player_agents, cheques[n])] self._players = players self._deck = Deck() self._board = Board(CHEQUE_STARTING) self._round = 1 self._round_end_policemen = ROUND_END_POLICEMEN if n > 2 else ROUND_END_POLICEMEN_TWOPLAYER self._end = False self._round_order_generator = TurnOrder( self._players, lambda x, y: x.player_agent == y.player_agent) def _execute_winning_bid(self, bidder, bid_cheque, board): cheque_ordinal = bidder.num_unavailable_cheques + 1 new_cards = board.take_all_booty_cards() bidder.gain_cards(new_cards, self._round, bid_cheque, cheque_ordinal) gained_cheque = board.cheque bidder.remove_available_cheque(bid_cheque) bidder.add_unavailable_cheque(gained_cheque) board.replace_cheque(bid_cheque) logging.debug(' {} wins the auction:'.format(bidder.player_agent)) logging.debug(' loses cheque {}'.format(bid_cheque)) logging.debug( ' gains cheque {} (as unavailable)'.format(gained_cheque)) logging.debug(' gains cards: {}'.format(', '.join( c.name for c in new_cards))) def _execute_auction(self, auction_mode, initiator, board): auction = Auction(auction_mode, initiator, board.get_cards(), board.cheque) for player in self._round_order_generator.one_circle_from_next( auction.initiator): top = auction.highest_bid agent = player.player_agent if player.round_is_over: logging.debug( ' {} PASSes bid because no cheques are available.'.format( agent)) continue avail_cheques_str = ','.join( str(c) for c in player.available_cheques()) if top and player.highest_cheque < top: logging.debug( ' {} PASSes bid because cannot outbid (had {} available).' .format(agent, avail_cheques_str)) continue is_mandated = auction.auction_mode == AuctionMode.ByPlayer and player == auction.initiator game_view = GameView(self, player, self._players, self._board) auction_view = AuctionView(auction) player_view = PlayerView(player) bidded_cheque = player.player_agent.bid(game_view, auction_view, player_view, is_mandated) if bidded_cheque: logging.debug( ' {} BIDs with cheque {} (had {} available).'.format( agent, bidded_cheque, avail_cheques_str)) auction.set_highest_bid(bidded_cheque, player) elif is_mandated: raise Exception('Missing mandated bid.') else: logging.debug( ' {} PASSes bid deliberately (had {} available).'.format( agent, avail_cheques_str)) if auction.highest_bid: self._execute_winning_bid(auction.highest_bidder, auction.highest_bid, board) if not auction.highest_bidder.num_available_cheques: logging.debug(' is out of cheques and out of round') else: logging.debug(' No bids in this auction.') def _execute_auction_by_full_board(self, initiator): logging.debug('Starting an Auction (by full board)') highest_bidder = self._execute_auction(AuctionMode.ByFullBoard, initiator, self._board) if not highest_bidder: self._board.discard_booty_cards() def _execute_auction_by_player(self, initiator): pass # FIXME: implement this action def _execute_auction_by_policeman(self, initiator): logging.debug('Starting an Auction (by Policeman)') self._execute_auction(AuctionMode.ByPoliceman, initiator, self._board) def _execute_draw(self, initiator): card = self._deck.draw() logging.debug('Player agent {} DRAWs a card: {}'.format( initiator.player_agent, card)) if card == Card.Policeman: self._board.add_policeman() logging.debug('added policeman (total {})'.format( self._board.num_policemen)) is_instant_round_end = self._board.num_policemen == self._round_end_policemen if is_instant_round_end: logging.debug('Policemen limit reached.') discarded_str = ', '.join( str(c) for c in self._board.get_cards()) logging.debug('Discarding {} cards from board: {}'.format( self._board.num_cards, discarded_str)) if not self.last_round: logging.debug( 'Round ends with {} cards in deck remaining.'.format( self._deck.size())) self._board.discard_booty_cards() self._board.discard_policemen() return Trigger.Round else: self._execute_auction_by_policeman(initiator) return Trigger.Turn else: self._board.add_card(card) board_is_full = self._board.num_cards == AUTOMATIC_AUCTION_NUM_CARDS if board_is_full: self._execute_auction_by_full_board(initiator) return Trigger.Turn def _execute_thieves(self, initiator): num_thieves = initiator.num_thieves if not num_thieves or not self._board.num_cards: raise Exception( 'Cannot execute Thief action: player has no thieves or no cards on board.' ) cards_to_steal = initiator.player_agent.steal( GameView(self, initiator, self._players, self._board)) stolen_str = ', '.join([sc.name for sc in cards_to_steal]) logging.debug('Player agent {} STEALs cards with thieves: {}'.format( initiator.player_agent, stolen_str)) num_steal = len(cards_to_steal) if num_thieves < num_steal: raise Exception('Cannot steal {} cards with {} thieves.'.format( num_steal, num_thieves)) initiator.remove_cards(num_steal * [Card.Thief]) self._board.take_booty_cards(cards_to_steal) initiator.gain_cards(cards_to_steal, self.round, Card.Thief, Card.Thief) # Thief used instead of a cheque. return Trigger.Turn # 1. Check that initiator has thieves and there are cards on board. # 2. Call thief action (player agent decides how may thieves to use and what cards to pick.) # 3. Remove a number of thieves from player. # 4. Remove picked-up cards from board # 5. Let player gain the cards. # 6. Trigger Turn def _advance_round(self): self._round += 1 def _determine_starting_player(self): return max([p for p in self._players], key=lambda x: x.highest_cheque) def _play_one_turn(self, player): action = player.player_agent.act( GameView(self, player, self._players, self._board)) logging.debug('{} chooses {}'.format(player.player_agent, action)) if action == ActionType.Thief: return self._execute_thieves(player) elif action == ActionType.Draw: return self._execute_draw(player) elif action == ActionType.AuctionByPlayer: return self._execute_auction_by_player(player) else: raise Exception('Unexpected action: {}'.format(action)) def _score_round(self): nums_bodyguards = [player.num_bodyguards for player in self._players] for player in self._players: player.do_round_scoring(min(nums_bodyguards), max(nums_bodyguards)) def _play_round(self, round_number): logging.debug('-------') logging.debug('Round {}'.format(round_number)) logging.debug('-------') for player in self._players: player.refresh_cheques() starting_player = self._determine_starting_player() logging.debug( 'Starting player: {} has highest cheque ({}) and starts the Round.' .format(starting_player.player_agent, max(starting_player.available_cheques()))) consecutive_passes = 0 for player in self._round_order_generator.circling_from( starting_player): if player.round_is_over: logging.debug('Player agent {} passed (out of Round).'.format( player.player_agent)) consecutive_passes += 1 if consecutive_passes < self.num_players: continue else: logging.debug('All cheques have been used.') break consecutive_passes = 0 trigger = self._play_one_turn(player) #logging.debug(player) #logging.debug(self._board) if trigger == Trigger.Round: break def _is_game_end_valid(self): expected_cards = sum([c.how_many for c in Card]) deck_cards = self._deck.size() policemen = self._board.num_policemen discarded_booty_cards = len(self._board._discarded_booty) discarded_policemen = self._board._num_discarded_policemen player_cards = sum([len(p._scards) for p in self._players ]) # TODO: avoid accessing internals player_scored_cards = sum([ len(p._scored_scards) for p in self._players ]) # TODO: avoid accessing internals player_removed_cards = sum([ len(p._removed_scards) for p in self._players ]) # TODO: avoid accessing internals num_cards = deck_cards + discarded_booty_cards + policemen + discarded_policemen + player_cards + player_scored_cards + player_removed_cards if num_cards != expected_cards: raise Exception( 'Unexpected number of cards at game end: expected {}, but had {}.' .format(expected_cards, num_cards)) counted_player_cards = sum(v for p in self._players for k, v in p._counts.items()) counted_cards = deck_cards + discarded_booty_cards + policemen + discarded_policemen + counted_player_cards + player_scored_cards + player_removed_cards if counted_cards != expected_cards: raise Exception( 'Unexpected card counts at game end: expected {}, but had {}.'. format(expected_cards, counted_cards)) def _score_game_end(self): cheque_totals = [player.cheque_total for player in self._players] for player in self._players: player.do_game_end_scoring(min(cheque_totals), max(cheque_totals)) def _get_player_scorings(self): return { player.player_agent: player.get_final_scoring() for player in self._players } def play_game(self): if self._end: raise Exception('Game has already ended.') logging.debug('===============================') logging.debug('Starting Razzia! with {} players'.format( self.num_players)) logging.debug('===============================') for r in range(1, GAME_ROUNDS + 1): self._play_round(r) self._score_round() self._advance_round() self._end = True self._score_game_end() logging.debug('Game ends with {} cards in deck remaining.'.format( self._deck.size())) logging.debug('==============') logging.debug('Game has ended') logging.debug('==============') self._is_game_end_valid() scorings = self._get_player_scorings() return scorings def auctioned_cards(self): return len(self._board.get_cards()) @property def num_players(self): return len(self._players) @property def round(self): return self._round @property def rounds_remaining(self): return GAME_ROUNDS - self._round @property def last_round(self): return self._round == GAME_ROUNDS @property def end(self): return self._end
def test_constructors(self): b = Board() r = Rook() q = Queen() k = Knight()
def test_placing_piece(self): r = Rook() b = Board() b.place_piece(r, 'd2') assert b.squares[b.chessboard[6][3]] == [(6, 3), r], \ b.squares[b.chessboard[6][3]]
def test_chessboard(self): b = Board() assert b.chessboard[0][0] == 'a8', b.chessboard[0][0] assert b.chessboard[7][7] == 'h1', b.chessboard[7][7]
from pieces import Board from minmax import evaluate board = Board() print(evaluate(board, 0))