def choose_board_layout(player): """ Board is stored as a list of lists. List is gv.CHESSBOARD[file_][rank]. Each square contains a single character, either ' ' or one of the characters representing a piece. Defender's pieces are upper-case, attackers are lower-case. """ global NRANKS, NFILES gv.prnt('{0}, choose the board layout.'.format(player)) gv.prnt('You must have 8 ranks.') gv.UI.clear_inv_choices() gv.UI.set_inv_choice({"Please enter a number": lambda x: not x.isdigit()}) gv.UI.set_inv_choice({ "You can only have whole numbers of files!": lambda x: math.fmod(float(x), 1) }) gv.UI.set_inv_choice( {"Can't have more than 8 files.": lambda x: int(x) > 8}) gv.UI.set_inv_choice( {"Can't have less than 2 files.": lambda x: int(x) < 2}) NFILES = int( gv.UI.user_input_check_choices( "How many files would you like (2 to 8)?", player=player, )) gv.CHESSBOARD = [] for i in xrange(NFILES): gv.CHESSBOARD += [[' '] * NRANKS] print_board('all', clear=True)
def process_build_turn(): gv.N_REINFORCE_ARMIES = count_army_allowance() while gv.N_REINFORCE_ARMIES > 0: save.checkpoint('during_build_turn') gv.prnt("You have " + str(gv.N_REINFORCE_ARMIES) + " armies to place.") gv.N_REINFORCE_ARMIES = reinforce_a_territory(gv.N_REINFORCE_ARMIES)
def manualsave(filename): """ Since we have a finite set of restore points, a manual save is just renaming the autosave such that it is kept. """ shutil.copy2(os.path.join('saves', 'autosave'), os.path.join('saves', filename)) gv.prnt('Game saved as %s.' % filename)
def choose_placement(player_type, player, pieces): unplaced_pieces = deepcopy(pieces) if player_type == 'attacker': gv.prnt('As the attacker, you start in the top half of the board:') board_part = 'top' valid_ranks = '[0-3]' elif player_type == 'defender': board_part = 'bottom' valid_ranks = '[4-7]' else: raise Exception('Invalid player_type.') while unplaced_pieces: gv.prnt('As the {}, you start in the {} half of the board:'.format( player_type, board_part), clear=True) print_board(board_part) gv.UI.clear_inv_choices() gv.UI.set_inv_choice({ "Choose from {0}.".format(unplaced_pieces): lambda x: x not in unplaced_pieces }) piece = gv.UI.user_input_check_choices( '{0}: choose a piece to place from:' '\n{1}\n'.format(player, unplaced_pieces), player=player) max_file = chr(NFILES + 96) gv.UI.clear_inv_choices() gv.UI.set_inv_choice({ "Invalid choice.\nPlease enter a string of the " "form XY with X in [A-{0}a-{1}] and Y in {2}.".format( max_file.upper(), max_file.lower(), valid_ranks): lambda x: not re.match( r'[a-{0}]{1}'.format(max_file.lower(), valid_ranks), x) }) pos = gv.UI.user_input_check_choices( 'Please choose square, example: "G3"', player=player) file_, rank = coords(pos) if gv.CHESSBOARD[file_][rank] != ' ': gv.prnt("There's already a piece there, try again") continue if player_type == 'attacker': piece_symbol = piece.lower() elif player_type == 'defender': piece_symbol = piece.upper() gv.CHESSBOARD[file_][rank] = piece_symbol unplaced_pieces.remove(piece) gv.prnt(('---------------YOUR FINAL LAYOUT---------------')) print_board(board_part) gv.prnt(('-----------------------------------------------'))
def process_attack_turn(): save.checkpoint('start_of_attack_turn') if not attackable_neighbours_exist() and not gv.RESTORING: gv.prnt("Not possible to attack! Build instead.") process_build_turn() while attackable_neighbours_exist() or gv.RESTORING: if not gv.RESTORING: gv.ATTACK_FROM = choose_attack_from() gv.ATTACK_TO = choose_attack_to() gv.N_ATTACK_ARMIES = choose_narmies_to_attack_with() gv.N_DEFEND_ARMIES = gv.TERRITORIES[gv.ATTACK_TO].narmies gv.DEFENDER = gv.TERRITORIES[gv.ATTACK_TO].owner else: gv.ATTACK_FROM = gv.SAVED_GLOBALS['ATTACK_FROM'] gv.ATTACK_TO = gv.SAVED_GLOBALS['ATTACK_TO'] gv.N_ATTACK_ARMIES = gv.SAVED_GLOBALS['N_ATTACK_ARMIES'] gv.N_DEFEND_ARMIES = gv.SAVED_GLOBALS['N_DEFEND_ARMIES'] gv.DEFENDER = gv.SAVED_GLOBALS['DEFENDER'] gv.CURR_PLAYER = gv.SAVED_GLOBALS['CURR_PLAYER'] gv.prnt.clear_output() gv.prnt('\n===================================\n' '{} is attacking {} at {} with {} armies from {}!\n' 'The defender has {} armies.\n' '===================================\n\n'.format( gv.CURR_PLAYER, gv.DEFENDER, gv.ATTACK_TO, gv.N_ATTACK_ARMIES, gv.ATTACK_FROM, gv.N_DEFEND_ARMIES, )) narmies_attacker, narmies_defender = chess.play_chess( gv.N_ATTACK_ARMIES, gv.N_DEFEND_ARMIES, gv.CURR_PLAYER, gv.DEFENDER) if narmies_defender == 0: gv.prnt("{0} defeated!".format(gv.TERRITORIES[gv.ATTACK_TO].owner)) gv.TERRITORIES[gv.ATTACK_FROM].narmies -= gv.N_ATTACK_ARMIES gv.TERRITORIES[gv.ATTACK_TO].narmies = narmies_attacker gv.TERRITORIES[gv.ATTACK_TO].reassign_owner(gv.CURR_PLAYER) else: gv.prnt("{0} repelled!".format(gv.CURR_PLAYER)) gv.TERRITORIES[gv.ATTACK_FROM].narmies -= \ gv.N_ATTACK_ARMIES - narmies_attacker gv.TERRITORIES[gv.ATTACK_TO].narmies = narmies_defender gv.UI.handle_user_input('<press enter>') save.checkpoint('after_battle') gv.BOARD.print_board() gv.prnt("Continue to attack, (y)es or (n)o?") attack_some_more = False while attack_some_more is False: response = gv.UI.handle_user_input('continue: ') if response in ['y', 'yes']: attack_some_more = True if response in ['n', 'no']: return 'Chickened out'
def attackable_neighbours_exist(): able_to_attack = False for unused_key, territory in gv.TERRITORIES.items(): if territory.owner == gv.CURR_PLAYER and territory.narmies > 1: for neighbour in territory.neighbours: if neighbour.owner != gv.CURR_PLAYER: able_to_attack = True if not able_to_attack: gv.prnt("No possiblities for attack!") return able_to_attack
def restore_saved_globals(): # Do some experimenting to ensure this works as expected - particularly with regards to scope. if gv.DEBUG: pprint(gv.SAVED_GLOBALS) restore_saved_globals_into_module(gv, gv.SAVED_GLOBALS) gv.BOARD.print_board() if gv.ATTACK_FROM and gv.ATTACK_TO: gv.prnt("{} is attacking from {} to {} with {} armies".format( gv.CURR_PLAYER, gv.ATTACK_FROM, gv.ATTACK_TO, gv.N_ATTACK_ARMIES))
def handle_user_input(self, message, cast_lower=True, clear=False, player=None): # By default, the player whose turn it is makes the input. # We need to know who is inputting, so we know which bot to run for AI. player = player or gv.CURR_PLAYER if gv.RESTORING: if gv.DEBUG: gv.prnt(message) user_input = fake_user_input_during_restore(message) elif gv.HEADLESS: gv.prnt(message, clear=clear) user_input = fake_user_input_from_http(message) else: if message != '': gv.prnt(message, clear=clear) user_input = None while user_input in [None]: gv.prnt('>>') curr_player = gv.PLAYERS.get(player) if gv.HEADLESS: input_func = sys.stdin.readline elif curr_player is not None and curr_player.is_ai: # If this is an AI player, dispatch to its turn processing methods # This returns a function that, when called, returns the desired string input_func = curr_player.ai_instance.dispatch_message( message, gv) else: input_func = raw_input # if cast_lower: # user_input = sys.stdin.readline() # else: # user_input = input_func() user_input = input_func() if cast_lower: user_input = user_input.lower() if curr_player is not None and curr_player.is_ai: gv.prnt(user_input, clear=False) if user_input in ['exit', 'x']: raise UserQuitException if user_input in ['s', 'save']: temp_inv_choices = self.inv_choices self.clear_inv_choices() handle_save_request() self.inv_choices = temp_inv_choices self.user_input_check_choices(message) if user_input in ['l', 'load']: raise LoadException return user_input
def eliminate_dead_players(): if gv.RESTORING: for player in gv.PLAYERS.keys(): if count_owned_territories(player) == 0: gv.prnt("{0} is out!".format(player)) # A hook that can get called if the player has lost. if (hasattr(gv.PLAYERS[player], 'lose') and callable(gv.PLAYERS[player].lose)): gv.PLAYERS[player].lose() del gv.PLAYERS[player] else: pass
def run_game(answer_queue, response_queue, worker=False, game_id=''): gv._AQ = answer_queue gv._RQ = response_queue gv.HEADLESS = worker gv.GAME_ID = game_id try: try: setup_game() main_loop() except utils.LoadException: restore_saved_game() except utils.UserQuitException: save.save('last_quit') gv.prnt("Byeeee!") sys.exit(0)
def choose_attack_to(): gv.prnt("Choose territory to attack, from the following list:") attack_to_list = [] for territory in gv.TERRITORIES[gv.ATTACK_FROM].neighbours: if territory.owner != gv.CURR_PLAYER: gv.prnt(territory.name) attack_to_list.append(territory.lname) gv.UI.clear_inv_choices() gv.UI.set_inv_choice({ "Can't attack there, choose again!": lambda x: x not in attack_to_list }) return gv.UI.user_input_check_choices('to: ')
def check_for_victory(): if gv.RESTORING: return False else: if len(gv.PLAYERS) == 1: winner = gv.PLAYERS.keys()[0] gv.prnt("{0} wins!".format(winner)) # A hook that can get called if the player has won. if (hasattr(gv.PLAYERS[winner], 'win') and callable(gv.PLAYERS[winner].win)): gv.PLAYERS[winner].win() return True else: return False
def risk_style(n_attack_armies, n_defend_armies, attacker, defender): continue_fight = True while continue_fight: attack_dice = [] defend_dice = [] for i in range(min(n_attack_armies, 3)): attack_dice.append(random.randint(1, 6)) for i in range(min(n_defend_armies, 2)): defend_dice.append(random.randint(1, 6)) gv.UI.handle_user_input("{0}, press enter to roll:".format(attacker), player=attacker) for attd in attack_dice: gv.UI.handle_user_input("{0}".format(attd), player=attacker) if gv.AI_PLAYERS_ARE_PLAYING: sleep(gv.AI_PRINT_DELAY) gv.UI.handle_user_input("{0}, press enter to roll:".format(defender)) for defd in defend_dice: gv.UI.handle_user_input("{0}".format(defd), player=defender) if gv.AI_PLAYERS_ARE_PLAYING: sleep(gv.AI_PRINT_DELAY) defend_dice.sort(reverse=True) attack_dice.sort(reverse=True) for dice in xrange(min(n_attack_armies, n_defend_armies, 2)): if attack_dice[dice] > defend_dice[dice]: n_defend_armies = max(n_defend_armies - 1, 0) else: n_attack_armies = max(n_attack_armies - 1, 0) gv.prnt("{0}: {1}".format(attacker, str(n_attack_armies))) gv.prnt("{0}: {1}".format(defender, str(n_defend_armies))) if n_attack_armies == 0 or n_defend_armies == 0: continue_fight = False if continue_fight: carry_on = gv.UI.handle_user_input( "Continue the battle, (y)es or (n)o?") if carry_on in ['y', 'yes']: continue_fight = True gv.prnt.clear_output() elif carry_on in ['n', 'no']: continue_fight = False return n_attack_armies, n_defend_armies
def choose_narmies_to_attack_with(): gv.prnt("There are " + str(gv.TERRITORIES[gv.ATTACK_FROM].narmies - 1) + " armies available for attack.") gv.UI.clear_inv_choices() gv.UI.set_inv_choice({"Please enter a number": lambda x: not x.isdigit()}) gv.UI.set_inv_choice({ "You can only have whole numbers of armies!": lambda x: math.fmod(float(x), 1) }) gv.UI.set_inv_choice({ "You must leave at least one army at home, try again!": lambda x: int(x) >= gv.TERRITORIES[gv.ATTACK_FROM].narmies }) return int( gv.UI.user_input_check_choices( "Choose number of armies to attack with:"))
def choose_attack_from(): gv.prnt("Choose territory to attack from, from the following list:") attack_from_list = [] for territory in gv.TERRITORIES.values(): if territory.owner == gv.CURR_PLAYER and territory.narmies > 1: for neighbour in territory.neighbours: if neighbour.owner != gv.CURR_PLAYER: gv.prnt(territory.name) attack_from_list.append(territory.lname) break gv.UI.clear_inv_choices() gv.UI.set_inv_choice({ "Can't attack from there, choose again!": lambda x: x not in attack_from_list }) return gv.UI.user_input_check_choices('from: ')
def print_board(self): w = 10. gv.prnt(' ' * int(float(self.ncols) * (w + 1.) / 2. - 8.) + "~~~ The World ~~~", clear=True) for row in xrange(self.nrows): subrows = [''] * 4 for col in xrange(self.ncols): mark = gv.PLAYERS[self.territory_array[row][col].owner].colour namelen = min(len(self.territory_array[row][col].name), int(w - 2.)) namestring = self.territory_array[row][col].name[0:namelen] ownerlen = min(len(self.territory_array[row][col].owner), int(w - 2.)) ownerstring = self.territory_array[row][col].owner[0:ownerlen] armystring = str( min(self.territory_array[row][col].narmies, 10**int(w - 2))) armylen = len(armystring) lpad = lambda x: mark * int( math.floor((w - float(x)) / 2.) - 1) rpad = lambda x: mark * int(math.ceil((w - float(x)) / 2.) - 1) subrows[0] += '+' + '-' * int(w) subrows[1] += '|' + lpad( namelen) + ' ' + namestring + ' ' + rpad(namelen) subrows[2] += '|' + lpad( armylen) + ' ' + armystring + ' ' + rpad(armylen) subrows[3] += '|' + lpad( ownerlen) + ' ' + ownerstring + ' ' + rpad(ownerlen) subrows[0] += '+' for isr in xrange(1, 4): subrows[isr] += '|' for subrow in subrows: gv.prnt(subrow) gv.prnt(('+' + '-' * int(w)) * self.ncols + '+') gv.prnt(' ' * int(float(self.ncols) * (w + 1.) / 2. - 8.) + "~~~~~~~~~~~~~~~~~") if gv.AI_PLAYERS_ARE_PLAYING: sleep(gv.AI_PRINT_DELAY)
def pre_round(): gv.ROUND_NUMBER += 1 save.checkpoint('round_start') gv.prnt("------------------------") gv.prnt("- Round: " + str(gv.ROUND_NUMBER) + "-") gv.prnt("------------------------") gv.BOARD.print_board()
def user_input_check_choices(self, message, clear=False, player=None): if gv.RESTORING: user_input = fake_user_input_during_restore(message) elif gv.HEADLESS: gv.prnt(message, clear=clear) user_input = fake_user_input_from_http(message) else: valid_choice = False while valid_choice == False: user_input = self.handle_user_input(message, clear=clear, player=player) valid_choice = True if user_input == '': valid_choice = False continue for warning, condition in self.inv_choices.items(): if gv.DEBUG: gv.prnt(warning, '*******', clear=False) if condition(user_input): gv.prnt(warning, clear=False) valid_choice = False break return user_input
def process_move(player_type, player, opponents_pieces): print_board('all', clear=True) if gv.CHECK[player_type]: gv.prnt('~~~ CHECK! ~~~') # If it's the attacker's turn, # give them the option to withdraw. if player_type == 'attacker': withdraw_string = " or 'w' to withdraw" elif player_type == 'defender': withdraw_string = "" else: raise Exception('Invalid player type') # max_rank = chr(len(chessboard[0])+97) # Check whether there are any valid moves for this player if not all_valid_moves(player_type): gv.UI.clear_inv_choices() gv.UI.set_inv_choice({ "Please enter either 'w' or 'd'": lambda x: x not in ['w', 'd', 'withdraw', 'do nothing'] }) pos = gv.UI.user_input_check_choices( "{0}, you have no valid moves available," "enter 'd' to do nothing{1}.".format(player, withdraw_string), player=player) if pos in ['w', 'withdraw']: return 'withdraw' else: return False valid_squares = get_coords_by_player_type(player_type) # Get the player's choice of piece to move & calculate valid moves valid_moves = None while not valid_moves: gv.UI.clear_inv_choices() if player_type == 'attacker': gv.UI.set_inv_choice({ "No piece at that position!": lambda x: coords(x) not in valid_squares and x not in ['w', 'withdraw'] }) else: gv.UI.set_inv_choice({ "No piece at that position!": lambda x: coords(x) not in valid_squares }) pos = gv.UI.user_input_check_choices( "{} ({}), choose a piece to move by " "entering its coordinates{}:".format(player, player_type, withdraw_string), player=player) if pos in ['w', 'withdraw']: return 'withdraw' file_, rank = coords(pos) piece = gv.CHESSBOARD[file_][rank] valid_moves = valid_moves_one_piece(player_type, file_, rank, piece) if not valid_moves: gv.prnt("No valid moves for that piece, try again!") # Get the player's choice of move gv.UI.clear_inv_choices() gv.UI.set_inv_choice({ "Illegal move, choose properly.": lambda x: coords(x) not in valid_moves }) move_to = gv.UI.user_input_check_choices('Move to which square?', player=player) file_to, rank_to = coords(move_to) # Move the piece and capture any current occupant if gv.CHESSBOARD[file_to][rank_to] != ' ': captured_piece = gv.CHESSBOARD[file_to][rank_to] gv.UI.handle_user_input('{0} captured!'.format(captured_piece), player=player) opponents_pieces.remove(captured_piece.lower()) gv.CHESSBOARD[file_to][rank_to] = piece gv.CHESSBOARD[file_][rank] = ' ' if check_or_mate(player_type): gv.prnt('CHECKMATE!') return 'checkmate' if piece.lower() == 'p': promote_pawn(player_type, file_to, rank_to, player) # We return False because by this point, # withdraw has not been selected. return False
def setup_board(): gv.prnt("Setting up the risk board.") gv.prnt("In this version, territories are set up randomly.") gv.prnt("In this version, initial army placement is randomised.") gv.BOARD = Board()
def choose_pieces(player, n_armies): gv.prnt('{0}, choose your pieces!'.format(player)) gv.prnt('Values of pieces: ') gv.prnt('---------------------') gv.prnt('Pawn: {0}'.format(gv.CHESSMEN_VALUES['p'])) gv.prnt('Knight: {0}'.format(gv.CHESSMEN_VALUES['k'])) gv.prnt('Bishop: {0}'.format(gv.CHESSMEN_VALUES['b'])) gv.prnt('Rook: {0}'.format(gv.CHESSMEN_VALUES['r'])) gv.prnt('Queen: {0}'.format(gv.CHESSMEN_VALUES['q'])) gv.prnt('---------------------') gv.prnt('You always start with one kin(g).') gv.prnt('Choose from (p)awn, (k)night, (b)ishop, (r)ook, (q)ueen:') gv.UI.clear_inv_choices() gv.UI.set_inv_choice({ "Please enter p, k, b, r or q.": lambda x: x not in ['p', 'k', 'b', 'r', 'q'] }) gv.UI.set_inv_choice({ "Not enough armies for that piece!": lambda x: gv.CHESSMEN_VALUES[x] > n_armies }) pieces = ['g'] while n_armies > 0: pieces.append( gv.UI.user_input_check_choices('{0} armies left.'.format(n_armies), player=player)) n_armies -= gv.CHESSMEN_VALUES[pieces[-1]] gv.prnt("Your forces: {0}".format(pieces)) return pieces
def print_board(part, clear=False): """ gv.CHESSBOARD[file_][rank] ranks are numbers 0-8 ranks are up-down files are letters A- files are side-side """ if clear: gv.prnt.clear_output() if part == 'all': prt = (0, 7) elif part == 'top': prt = (0, 3) elif part == 'bottom': prt = (4, 7) else: raise Exception('Unexpected part of the board!') for irank in xrange(prt[0], prt[1] + 1): if irank % 2: colour = ' ' else: colour = '#' creamy_filling = {'top': '', 'mid': '', 'bot': ''} for ifile_ in xrange(NFILES): square = gv.CHESSBOARD[ifile_][irank] if colour == '#': colour = ' ' elif colour == ' ': colour = '#' else: raise Exception('Unexpected colour!') creamy_filling['top'] += '|{0} {0}'.format(colour) creamy_filling['mid'] += '| {1} '.format(colour, square) creamy_filling['bot'] += '|{0} {0}'.format(colour) gv.prnt(' ' + '+---' * (NFILES) + '+') gv.prnt(' ' + creamy_filling['top'] + '|') gv.prnt(str(irank) + creamy_filling['mid'] + '|') gv.prnt(' ' + creamy_filling['bot'] + '|') gv.prnt(' ' + '+---' * (NFILES) + '+') files_string = '' for ifile_ in xrange(NFILES): file_name = chr(97 + ifile_).upper() files_string += ' {0} '.format(file_name) gv.prnt(' {0} '.format(files_string)) if gv.AI_PLAYERS_ARE_PLAYING: sleep(gv.AI_PRINT_DELAY)
def stalemate(att_pieces, def_pieces): if att_pieces == ['g'] and def_pieces == ['g']: gv.prnt('STALEMATE!') return True return False