def setup_pre_phase(G, player_setup_path='config/faction_setup.yml'): player_setup = load(player_setup_path) # place fixed units for name, config in player_setup.items(): if 'units' not in config.setup: continue for unit in config.setup.units: add_unit(G, unit) # prep temp info G.temp = tdict() for name, faction in player_setup.items(): out = tdict() out.player = name if 'cadres' in faction.setup: out.info = faction.setup.cadres out.msg = 'Choose this many cadres to place into each of these territories' else: out.msg = 'Wait while other players place their cadres'
def load_map(G, tiles='config/tiles.yml', borders='config/borders.yml'): tiles = load(tiles) borders = load(borders) for b in borders: n1, n2 = b.tile1, b.tile2 t = b.type if 'borders' not in tiles[n1]: tiles[n1].borders = tdict() tiles[n1].borders[n2] = t if 'borders' not in tiles[n2]: tiles[n2].borders = tdict() tiles[n2].borders[n1] = t G.tiles = tiles for name, tile in G.tiles.items(): tile.name = name tile.units = tset() if tile.type != 'Sea' and tile.type != 'Ocean': for neighbor in tile.borders.keys(): if G.tiles[neighbor].type == 'Sea' or G.tiles[ neighbor].type == 'Ocean': tile.type = 'Coast' break # add tile to game objects tile.obj_type = 'tile' G.objects.table[name] = tile
def load_game_info(G, seed=None, path='config/game_info.yml'): info = load(path) game = tdict() game.seed = seed G.random = random.Random(seed) # G.random = TestRandom(seed) game.year = info.first_year - 1 # zero based game.last_year = info.last_year num_rounds = game.last_year - game.year game.turn_order_options = info.turn_order_options game.sequence = ['Setup'] + num_rounds * info.year_order + ['Scoring'] game.index = 0 # start below 0, so after increment in next_phase() it starts at 0 #game.action_phases = tset(x for x in info.phases if info.phases[x]) # no need for action phases anymore (all action phases have a pre phase) game.peace_dividends = tlist( sum([[v] * n for v, n in info.peace_dividends.items()], [])) G.random.shuffle(game.peace_dividends) game.victory = info.victory G.game = game G.objects = tdict() G.objects.table = tdict()
def load_map(G, tiles='config/tiles.yml', borders='config/borders.yml'): tiles = load(tiles) borders = load(borders) for b in borders: n1, n2 = b.tile1, b.tile2 t = b.type if 'borders' not in tiles[n1]: tiles[n1].borders = tdict() tiles[n1].borders[n2] = t if 'borders' not in tiles[n2]: tiles[n2].borders = tdict() tiles[n2].borders[n1] = t G.tiles = tdict({name: idict(tile) for name, tile in tiles.items()}) for name, tile in G.tiles.items(): tile.__dict__['_id'] = name # tile.name = name tile.units = tset() if tile.type not in {'Sea', 'Ocean', 'Strait'}: for neighbor in tile.borders.keys(): if G.tiles[neighbor].type == 'Sea' or G.tiles[ neighbor].type == 'Ocean': tile.type = 'Coast' break # add tile to game objects tile.obj_type = 'tile' tile.visible = tset({'Axis', 'West', 'USSR'}) G.objects.table[name] = tile
def production_pre_phase(G): if 'temp' in G: del G.temp G.temp = tdict() G.temp.active_idx = 0 G.temp.prod = tdict() # TODO: update blockades for player, faction in G.players.items(): G.temp.prod[player] = tdict() G.temp.prod[player].production_remaining = compute_production_level( faction) G.temp.prod[player].upgraded_units = tset() G.temp.prod[player].action_cards_drawn = 0 G.temp.prod[player].invest_cards_drawn = 0 # remove all blockades (not unsupplied markers) active_player = G.game.turn_order[G.temp.active_idx] G.logger.write('{} may spend {} production points'.format( active_player, G.temp.prod[active_player].production_remaining)) return encode_production_actions(G)
def new_movement(G, player): G.temp.battles = tdict() # track new battles due to engaging G.temp.has_moved = tdict() # units can only move once per movement phase G.temp.threats = tset() G.temp.battle_groups = tdict() active = G.temp.order[G.temp.active_idx] G.logger.write('{} has {} command points for movement'.format( active, G.temp.commands[active].value))
def load_game_info(G, path='config/game_info.yml'): info = load(path) game = tdict() game.sequence = ['Setup'] + 10 * info.year_order game.index = -1 # start below 0, so after increment in next_phase() it starts at 0 #game.action_phases = tset(x for x in info.phases if info.phases[x]) # no need for action phases anymore (all action phases have a pre phase) G.game = game G.objects = tdict() G.objects.table = tdict()
def eval_movement(G, source, unit, dest): # usually done when a unit leaves a tile player = G.nations.designations[unit.nationality] new_battle, engaging, disengaging = False, False, False # update source enemies = get_enemies(G, player) source_powers = powers_present(G, source) if 'disputed' in source and len(enemies.intersection( source_powers)): # there were enemies in source disengaging = True if not conflict_present(G, source): make_undisputed(G, source) G.logger.write('{} is no longer disputed'.format(source._id)) elif player not in source_powers and player in source.aggressors: # player no longer present source.aggressors.remove(player) G.objects.updated[source._id] = source G.logger.write('{} has left {}'.format(player, source._id)) if 'owner' in source and source.owner not in source_powers: # owner no longer present new_owner = source.aggressors[0] switch_ownership(G, source, new_owner) dest_powers = powers_present(G, dest) if len(enemies.intersection( dest_powers)): # enemy in destination -> engaging engaging = True if 'disputed' not in dest: new_battle = True make_disputed(G, dest, player) elif player not in dest.aggressors: dest.aggressors.append(player) elif 'owner' in dest and dest.owner != player: # unoccupied enemy territory switch_ownership(G, dest, player) # TODO: interventions #track battle groups if isANS(G, unit) and engaging: #TODO: only if dest is a Sea tile!? sourceName = source._id destName = dest._id if not destName in G.temp.battle_groups: G.temp.battle_groups[destName] = tdict() G.temp.battle_groups[destName][unit._id] = sourceName # TODO: Sea Invasions -> unit can't fight in current battle # # TODO: Check for realizations of threats (violations) # Axis entering Canada -> USA becomes West satellite if player == 'Axis' and dest._id == 'Ottawa' and 'USA' not in G.player.West.members: USA_becomes_satellite(G, 'West') return new_battle, engaging, disengaging
def convert_from_saveable(data): if data is None: return None if isinstance(data, (str, int, float)): try: return int(data) except: pass return data if isinstance(data, dict): if len(data) == 1: key, val = next(iter(data.items())) if 'set' == key: return tset(convert_from_saveable(el) for el in val) if 'xset' == key: return xset(convert_from_saveable(el) for el in val) if 'tuple' == key: return tuple(convert_from_saveable(el) for el in val) if '_object_' == key[:8]: typ = eval(key[8:]) obj = typ() obj.load_state(val) return obj if '_id' in data: return idict({convert_from_saveable(k): convert_from_saveable(v) for k, v in data.items()}) return tdict({convert_from_saveable(k): convert_from_saveable(v) for k, v in data.items()}) if isinstance(data, list): return tlist(convert_from_saveable(el) for el in data) try: return data.save_state() except AttributeError: raise Exception('Cannot save data of type: {}'.format(type(data)))
def prepare_combat_structs(G, player): G.temp.combat = adict() c = G.temp.combat c.stages = [] #calc optional battles for player battles_to_select = tset() for tilename in G.temp.potential_battles: if tilename in G.temp.battles: continue is_relevant = player in powers_present(G, G.tiles[tilename]) if is_relevant: battles_to_select.add(tilename) c.battles_to_select = battles_to_select #calc battles that have to be fought and therefore are revealed battles_to_reveal = tdict() for tilename in G.temp.battles: if G.temp.battles[tilename] == player: battles_to_reveal[tilename] = player else: #print('RIESEN ERROR: new battle with another player!!!!',G.temp.battles[b]) pass c.battles_to_reveal = battles_to_reveal #add all bettles_to_reveal to c.battles c.battles = adict() c.battles_remaining = [] add_battles_to_reveal(G, player) assert len(c.battles_to_reveal.keys()) == 0, 'prepare_combat_structs: AFTER REVEALING STILL BATTLES_TO_REVEAL!'
def government_pre_phase(G): # prep influence if 'temp' in G: del G.temp G.temp = tdict() G.temp.diplomacy = tdict() G.temp.diplomacy_cards = tset() G.temp.intel = tdict() G.temp.past_upgrades = tdict() for player in G.players: G.temp.past_upgrades[player] = 0 G.temp.passes = 0 G.temp.active_idx = 0 return encode_government_actions(G)
def play_intel(G, player, card, target, *args): G.temp.hack = tdict() G.temp.hack.target = target G.temp.hack.card = card G.temp.hack.source = player G.temp.hack.args = args return encode_intel_response(G, card, player, target)
def load_card_decks(G, action_path='config/cards/action_cards.yml', investment_path='config/cards/investment_cards.yml', info_path='config/cards/card_info.yml'): cinfo = load(info_path) caction = load(action_path) cinvest = load(investment_path) action_cards = tdict() action_cards.deck = tlist() for ID, card in caction.items(): card = idict(card) card.obj_type = 'action_card' card.visible = tset() card.__dict__['_id'] = 'action_{}'.format(ID) action_cards.deck.append(card._id) G.objects.table[card._id] = card investment_cards = tdict() investment_cards.deck = tlist() for ID, card in cinvest.items(): card = idict(card) card.obj_type = 'investment_card' card.visible = tset() card.__dict__['_id'] = 'invest_{}'.format(ID) investment_cards.deck.append(card._id) G.objects.table[card._id] = card G.cards = tdict() G.cards.action = action_cards G.cards.action.discard_pile = tlist() G.cards.investment = investment_cards G.cards.investment.discard_pile = tlist() G.cards.info = cinfo shuffle(G.random, G.cards.investment) shuffle(G.random, G.cards.action)
def step(player, action): phase = PHASES[G.game.sequence[G.game.index]] G.objects.created = tdict() G.objects.updated = tdict() G.objects.removed = tdict() G.begin() global PHASE_DONE try: if PHASE_DONE: PHASE_DONE = False all_actions = next_phase() else: # validate action assert player in WAITING_ACTIONS, 'It is not {}\'s turn'.format( player) options = util.decode_actions(WAITING_ACTIONS[player]) assert action in options, 'Invalid action: {}'.format(action) try: all_actions = phase(G, player, action) except PhaseComplete: if DEBUG: PHASE_DONE = True all_actions = adict() else: all_actions = next_phase() except Exception as e: G.abort() return process_actions('error', sys.exc_info(), player) else: G.commit() return process_actions('actions', all_actions, player)
def step(player, action): G.objects.created = tdict() G.objects.updated = tdict() G.objects.removed = tdict() G.begin() global PHASE_DONE try: #print('step',player,action,'PHASE_DONE=',PHASE_DONE) if PHASE_DONE: PHASE_DONE = False all_actions = evaluate_action() else: # validate action assert player in WAITING_ACTIONS, 'It is not {}\'s turn'.format(player) options = util.decode_actions(WAITING_ACTIONS[player]) assert action in options, 'Invalid action: {}'.format(action) all_actions = evaluate_action(player, action) except GameEnds: print('GAME ENDS') pass except Exception as e: #print(e) G.abort() if DEBUG: raise e return process_actions('error', sys.exc_info(), player) else: G.commit() return process_actions('actions', all_actions, player)
def start_new_game(player='Axis', debug=False): global G, DEBUG DEBUG = debug G = setup.init_gamestate() G.logger = Logger(*G.players.keys(), stdout=True) G.objects.created = G.objects.table.copy() G.objects.updated = tdict() G.objects.removed = tdict() for name in G.players: WAITING_OBJS[name] = adict() WAITING_OBJS[name].created = adict() WAITING_OBJS[name].updated = adict() WAITING_OBJS[name].removed = adict() # start setup phase - no need for a transaction, since there is no user input yet, so the outcome is constant return process_actions('actions', next_phase(), player)
def pre_command_phase(G): if 'temp' in G: del G.temp G.temp = tdict() G.temp.season = G.game.sequence[G.game.index] G.temp.active_idx = 0 G.temp.active_players = G.game.turn_order.copy() if G.temp.season == 'Winter': G.temp.active_players = tlist(p for p in G.game.turn_order if G.players[p].stats.enable_Winter) G.temp.decision = tdict() G.temp.passes = 0 G.temp.borders = tdict({p: tdict() for p in G.players}) G.temp.battles = tdict() return encode_command_card_phase(G)
def init_gamestate(): G = tdict() load_game_info(G) load_map(G) load_players_and_minors(G) load_card_decks(G) load_unit_rules(G) return G
def setup_pre_phase(G, player_setup_path='config/faction_setup.yml'): player_setup = load(player_setup_path) # prep temp info - phase specific data temp = tdict() temp.setup = tdict() for name, faction in player_setup.items(): if 'units' in faction.setup: for unit in faction.setup.units: add_unit(G, unit) del faction.setup.units temp.setup[name] = faction.setup G.temp = temp # return action adict(faction: (action_keys, action_options)) return encode_setup_actions(G)
def start_new_game(player='Axis', debug=False, seed=None): global G, DEBUG DEBUG = debug G = setup.init_gamestate(seed=seed) G.logger = Logger(*G.players.keys(), stdout=True) if G.game.seed is not None: G.logger.write('Set seed {}'.format(G.game.seed)) G.objects.created = G.objects.table.copy() G.objects.updated = tdict() G.objects.removed = tdict() for name in G.players: WAITING_OBJS[name] = adict() WAITING_OBJS[name].created = adict() WAITING_OBJS[name].updated = adict() WAITING_OBJS[name].removed = adict() # start setup phase - no need for a transaction, since there is no user input yet, so the outcome is constant return process_actions('actions', evaluate_action(), player)
def setup_phase(G, action): # player, tilename, unit_type # place user chosen units # out: send message to all players to choose what tiles to place how many cadres on try: msg = io.get() assert msg.player in incomplete, 'Player {} is already done'.format( msg.player) reqs = player_setup[msg.player].setup.cadres placed = False for member, tiles in reqs.items(): if msg.tile in tiles: placed = True assert tiles[ msg. tile] > 0, 'No more cadres can be placed onto {}'.format( msg.tile) unit = tdict() unit.type = msg.type unit.tile = msg.tile unit.nationality = member unit.cv = 1 add_unit(G, unit) tiles[msg.tile] -= 1 if tiles[msg.tile] == 0: del tiles[msg.tile] assert placed, 'Tile {} not available for placement'.format(msg.tile) except (ActionError, AssertionError) as e: io.put({'error': 'Invalid Action', 'msg': str(e)}) # draw action cards for name, config in player_setup.items(): if 'action_cards' in config.setup: G.players[name].hand.extend( draw_cards(G.action_cards, config.setup.action_cards)) if 'investment_cards' in config.setup: G.players[name].hand.extend( draw_cards(G.investment_cards, config.setup.investment_cards))
def init_gamestate(seed=None): if seed is None: seed = random.getrandbits(64) G = tdict() load_game_info(G, seed=seed) load_map(G) load_players_and_minors(G) load_card_decks(G) load_unit_rules(G) return G
def planning_phase(G, player, action): if action is None: if 'temp' in G: del G.temp G.temp = tdict() G.temp.season = G.game.sequence[G.game.index] G.temp.active_idx = 0 G.temp.active_players = G.game.turn_order.copy() if G.temp.season == 'Winter': G.temp.active_players = tlist(p for p in G.game.turn_order if G.players[p].stats.enable_Winter) G.temp.decision = tdict() G.temp.passes = 0 G.temp.borders = tdict({p: tdict() for p in G.players}) return encode_command_card_phase(G) faction = G.players[player] head, *tail = action if head == 'pass': G.temp.passes += 1 G.temp.active_idx += 1 G.temp.active_idx %= len(G.temp.active_players) G.logger.write('{} passes'.format(player)) elif head in faction.hand: G.temp.passes = 0 card = G.objects.table[head] del card.owner G.objects.updated[head] = card G.temp.decision[player] = card faction.hand.remove(head) G.logger.write('{} plays a card'.format(player)) G.temp.active_players.remove(player) if len(G.temp.active_players): G.temp.active_idx %= len(G.temp.active_players) if len(G.temp.active_players) > G.temp.passes: return encode_command_card_phase(G) # evaluate card choices G.temp.commands = tdict() for p, card in G.temp.decision.items( ): # RULE OVERRULED: emergency priority tie breaks are automatic if 'season' in card: cmd = tdict() cmd.priority = card.priority cmd.moved = tset() if card.season == G.temp.season: val = card.value msg = ' {} command: {} {}'.format(card.season, card.priority, val) else: cmd.emergency = True val = G.players[p].stats.emergency_command msg = 'n emergency command: {} {}'.format(card.priority, val) cmd.value = val G.temp.commands[p] = cmd else: msg = ' bluff (investment card)' G.logger.write('{} has played a{}'.format(p, msg)) discard_cards(G, card._id) if len(G.temp.commands): ##someone played cmd card ##players put in order of cards: G.temp.order contains players G.temp.order = tlist( k for k, v in sorted([(k, v.priority + ('e' if 'emergency' in v else '')) for k, v in G.temp.commands.items()], key=lambda x: x[1])) G.logger.write('Play order is: {}'.format(', '.join(G.temp.order))) G.temp.active_idx = 0 add_next_phase(G, 'Movement') else: G.logger.write('No player played a command card during {}'.format( G.temp.season)) raise PhaseComplete
def governmnet_phase(G, player, action): # play cards if action is None: # prep influence G.logger.write('Beginning Government Phase') if 'temp' in G: del G.temp G.temp = tdict() G.temp.diplomacy = tdict() G.temp.diplomacy_cards = tset() G.temp.intel = tdict() G.temp.past_upgrades = tdict() for player in G.players: G.temp.past_upgrades[player] = 0 G.temp.passes = 0 G.temp.active_idx = 0 return encode_government_actions(G) if 'move_to_post' in G.temp: # after phase has ended and only clean up is necessary return government_post_phase(G, player, action) # TODO: make sure cards that should now be visible stay visible if player in G.temp.intel: # hide any temporarily visible objects from intel cards for ID, obj in G.temp.intel[player].items(): obj.visible.discard(player) G.objects.updated[ID] = obj del G.temp.intel[player] if 'hack' in G.temp: if player == G.temp.hack.source: raise NotImplementedError assert action == ( 'cancel', ), 'Misunderstood action: {}'.format(action) G.players[player].hand.add( G.temp.hack.card._id ) # make sure card is back in sources's ownership del G.temp.hack return encode_government_actions(G) else: actions = resolve_intel(G, player, action) if actions is not None: return actions elif 'mole' in G.temp: if action != ('accept', ): _, tech, _ = action G.logger.write('{} uses their mole to achieve {}'.format( player, tech), player=G.temp.mole) achieve_tech(G, player, *action) del G.temp.mole elif 'factory_upgrade' in G.temp: if action == ('cancel', ): G.logger.write('Cancelled factory upgrade', player=player) del G.temp.factory_upgrade return encode_government_actions(G) ID, = action val = G.objects.table[ID].value if ID in G.temp.factory_upgrade.selects: val = -val G.temp.factory_upgrade.selects.discard(ID) G.logger.write('Unselected {}'.format(ID), end='', player=player) else: G.temp.factory_upgrade.selects.add(ID) G.logger.write('Selected {}'.format(ID), end='', player=player) G.temp.factory_upgrade.value += val G.logger.write(' (value so far: {}/{})'.format( G.temp.factory_upgrade.value, G.players[player].stats.factory_cost), player=player) # print(G.temp.factory_upgrade.value) if G.temp.factory_upgrade.value < G.players[player].stats.factory_cost: return encode_factory_upgrade_actions(G) # factory upgrade complete G.players[player].tracks.IND += 1 G.temp.past_upgrades[player] += 1 G.players[player].hand -= G.temp.factory_upgrade.selects G.logger.write( '{} upgrades their IND to {} with factory card values of: {}'. format( player, G.players[player].tracks.IND, ', '.join( str(G.objects.table[ID].value) for ID in G.temp.factory_upgrade.selects))) discard_cards(G, *G.temp.factory_upgrade.selects) del G.temp.factory_upgrade G.temp.passes = 0 elif action == ('pass', ): G.logger.write('{} passes'.format(player)) G.temp.passes += 1 if G.temp.passes == len(G.players): G.logger.write( 'All players have passed consecutively - moving on to Government resolution' ) G.temp.move_to_post = tdict() # for handsize limit options for name, faction in G.players.items(): handsize = len(faction.hand) diff = handsize - faction.stats.handlimit if diff > 0: G.logger.write('{} must discard {} cards'.format( name, diff)) G.temp.move_to_post[name] = True return government_post_phase(G) else: # execute action head, *tail = action if head == 'factory_upgrade': G.temp.factory_upgrade = tdict() G.temp.factory_upgrade.value = 0 G.temp.factory_upgrade.selects = tset() G.logger.write('Select the cards to use for the factory upgrade', player=player) return encode_factory_upgrade_actions(G) elif head in G.players[ player].secret_vault: # reveal tech from secret vault reveal_tech(G, player, head) return encode_government_actions(G) elif head == 'remove': nation, = tail decrement_influence(G, nation) G.logger.write('{} removes one of their influence from {}'.format( player, nation)) return encode_government_actions(G) elif head in {'open', 'secret'}: G.temp.passes = 0 achieve_tech(G, player, head, *tail) else: G.temp.passes = 0 card = G.objects.table[head] if 'wildcard' in card: nation, = tail increment_influence(G, player, nation) extra = '' if card.wildcard == 'Foreign_Aid': # pay IND G.players[player].tracks.IND -= 1 extra = ' (decreasing IND to {})'.format( G.players[player].tracks.IND) G.logger.write( '{} plays {} adding/removing influence in {}{}'.format( player, card.wildcard, nation, extra)) discard_cards(G, head) elif 'intelligence' in card: discard_cards(G, head) return play_intel(G, player, card, *tail) else: nation, = tail play_diplomacy(G, player, nation) G.temp.diplomacy_cards.add(head) card.visible = xset(G.players.keys()) # visible to everyone G.players[card.owner].hand.discard(card._id) del card.owner G.objects.updated[head] = card # discard_cards(G, head) G.temp.active_idx += 1 G.temp.active_idx %= len(G.players) return encode_government_actions(G)
def load_players_and_minors(G): player_setup = load('config/faction_setup.yml') capitals = load('config/capitals.yml') G.nations = tdict() territories = tdict() designations = tdict() minor_designation = 'Minor' for tile in G.tiles.values(): if 'alligence' in tile: designations[tile.alligence] = minor_designation if tile.alligence not in territories: territories[tile.alligence] = tset() territories[tile.alligence].add(tile._id) designations['USA'] = 'Major' G.nations.designations = designations G.nations.territories = territories G.nations.capitals = capitals for nation, tilename in capitals.items(): G.tiles[tilename].capital = True G.nations.groups = tdict() # load factions/players players = tdict() groups = tset(player_setup.keys()) rivals = tdict() for g in groups: gps = groups.copy() gps.remove(g) rivals[g] = tset(gps) for name, config in player_setup.items(): faction = tdict() faction.stats = tdict() faction.stats.handlimit = config.Handlimit faction.stats.factory_all_costs = config.FactoryCost faction.stats.factory_idx = 0 faction.stats.factory_cost = faction.stats.factory_all_costs[ faction.stats.factory_idx] faction.stats.emergency_command = config.EmergencyCommand faction.stats.rivals = rivals[name] faction.stats.DoW = tdict({r: False for r in rivals[name]}) faction.stats.at_war_with = tdict({r: False for r in rivals[name]}) faction.stats.at_war = False faction.stats.aggressed = False faction.stats.peace_dividends = tlist() faction.stats.enable_USA = 'enable_USA' in config faction.stats.enable_Winter = 'enable_Winter' in config faction.cities = tdict() faction.cities.MainCapital = config.MainCapital faction.cities.SubCapitals = config.SubCapitals faction.members = tdict() for nation, info in config.members.items(): faction.members[nation] = tset([nation]) if info.type == 'Great_Power': faction.stats.great_power = nation if 'Colonies' in info: faction.members[nation].update(info.Colonies) full_cast = tset() for members in faction.members.values(): full_cast.update(members) for member in full_cast: G.nations.designations[member] = name faction.homeland = tdict( {member: tset() for member in faction.members.keys()}) faction.territory = tset() for tile_name, tile in G.tiles.items(): if 'alligence' not in tile: continue if tile.alligence in faction.members: # homeland faction.homeland[tile.alligence].add(tile_name) if tile.alligence in full_cast: faction.territory.add(tile_name) tile.owner = name faction.tracks = tdict() pop, res = compute_tracks(faction.territory, G.tiles) faction.tracks.POP = pop faction.tracks.RES = res faction.tracks.IND = config.initial_ind faction.units = tdict() faction.hand = tset() # for cards faction.technologies = tset() faction.secret_vault = tset() faction.influence = tset() faction.diplomacy = tdict() faction.diplomacy.associates = tset() faction.diplomacy.protectorates = tset() faction.diplomacy.satellites = tset() faction.diplomacy.violations = tset() players[name] = faction G.players = players # load minors/diplomacy minors = tdict() majors = tdict() status = tdict() for name, team in G.nations.designations.items(): if team not in G.nations.groups: G.nations.groups[team] = tset() G.nations.groups[team].add(name) if team in {minor_designation, 'Major'}: status[name] = tdict() status[name].is_armed = False status[name].units = tdict() if team == minor_designation: # only minors minor = tdict() minor.faction = None minor.value = 0 minors[name] = minor if team == 'Major': # only includes neutral majors major = tdict() major.faction = None major.value = 0 majors[name] = major G.diplomacy = tdict() G.diplomacy.minors = minors G.diplomacy.majors = majors G.diplomacy.neutrals = minors.copy() G.diplomacy.neutrals.update(majors) G.diplomacy.influence = tdict() G.nations.status = status
def setup_phase(G, player, action): # player, nationality, tilename, unit_type # place user chosen units if action is None: # pre phase player_setup = load(player_setup_path) # prep temp info - phase specific data temp = tdict() temp.setup = tdict() for name, faction in player_setup.items(): if 'units' in faction.setup: for unit in faction.setup.units: add_unit(G, unit) del faction.setup.units temp.setup[name] = faction.setup G.temp = temp # return action adict(faction: (action_keys, action_options)) return encode_setup_actions(G) nationality, tilename, unit_type = action unit = adict() unit.nationality = nationality unit.tile = tilename unit.type = unit_type add_unit(G, unit) G.temp.setup[player].cadres[nationality][tilename] -= 1 if G.temp.setup[player].cadres[nationality][tilename] == 0: del G.temp.setup[player].cadres[nationality][tilename] if len(G.temp.setup[player].cadres[nationality]) == 0: del G.temp.setup[player].cadres[nationality] if len(G.temp.setup[player].cadres) == 0: # all cadres are placed del G.temp.setup[player].cadres if 'action_cards' in G.temp.setup[player]: draw_cards(G, 'action', player, N=G.temp.setup[player].action_cards) del G.temp.setup[player].action_cards if 'investment_cards' in G.temp.setup[player]: draw_cards(G, 'action', player, N=G.temp.setup[player].action_cards) del G.temp.setup[player].investment_cards return encode_setup_actions(G)
def load_players_and_minors(G): player_setup = load('config/faction_setup.yml') nations = tdict() minor_designation = 'Minor' for tile in G.tiles.values(): if 'alligence' in tile: nations[tile.alligence] = minor_designation G.nations = nations # map nationality to faction/minor # load factions/players players = tdict() groups = tset(player_setup.keys()) rivals = tdict() for g in groups: gps = groups.copy() gps.remove(g) rivals[g] = list(gps) for name, config in player_setup.items(): faction = tdict() faction.stats = tdict() faction.stats.handlimit = config.Handlimit faction.stats.factory_all_costs = config.FactoryCost faction.stats.factory_idx = 0 faction.stats.factory_cost = faction.stats.factory_all_costs[ faction.stats.factory_idx] faction.stats.emergency_command = config.EmergencyCommand faction.stats.DoW = tdict() faction.stats.DoW[rivals[name][0]] = False faction.stats.DoW[rivals[name][1]] = False faction.stats.enable_USA = 'enable_USA' in config faction.stats.enable_Winter = 'enable_Winter' in config faction.cities = tdict() faction.cities.MainCapital = config.MainCapital faction.cities.SubCapitals = config.SubCapitals faction.members = tdict() for nation, info in config.members.items(): nations[nation] = name faction.members[nation] = tset([nation]) if 'Colonies' in info: faction.members[nation].update(info.Colonies) faction.homeland = tset() faction.territory = tset() full_cast = tset() for members in faction.members.values(): full_cast.update(members) for tile_name, tile in G.tiles.items(): if 'alligence' not in tile: continue if tile.alligence in faction.members: # homeland faction.homeland.add(tile_name) if tile.alligence in full_cast: faction.territory.add(tile_name) faction.tracks = tdict() pop, res = compute_tracks(faction.territory, G.tiles) faction.tracks.pop = pop faction.tracks.res = res faction.tracks.ind = config.initial_ind faction.units = tdict() faction.hand = tset() # for cards faction.influence = tdict() players[name] = faction G.players = players # load minors/diplomacy minors = tdict() for name, team in nations.items(): if team == minor_designation: minor = tdict() minor.units = tset() minor.is_armed = False minor.influence_faction = None minor.influence_value = 0 minors[name] = minor G.minors = minors
def resolve_intel(G, player, response): card = G.temp.hack.card assert player == G.temp.hack.target, 'Target should be responding' # G.logger.write('{} plays {} targeting {}'.format(G.temp.hack.source, G.temp.hack.card.intelligence, G.temp.hack.target)) if response != ('accept', ): # target plays Double Agent ID, *args = response # switch target and source, update args G.temp.hack.target = G.temp.hack.source G.temp.hack.source = player if len(args) > 1: args = (args[-1], ) G.temp.hack.args = args # discard double agent card discard_cards(G, ID) G.logger.write( 'However, {} uses their double agent to reverse the effects'. format(player)) target = G.temp.hack.target player = G.temp.hack.source args = G.temp.hack.args code = None if card.intelligence == 'Coup': nation, = args inf = G.diplomacy.influence[nation] assert inf.faction == target, 'Influence is owned by {} not the target ({})'.format( inf.faction, target) G.players[target].influence.remove(inf._id) del G.diplomacy.influence[nation] del G.objects.table[inf._id] G.objects.removed[inf._id] = inf G.logger.write('{} {} influence is removed from {}'.format( inf.value, target, nation)) elif card.intelligence == 'Agent': tilename, = args tile = G.tiles[tilename] G.temp.intel[player] = tdict() for uid in tile.units: unit = G.objects.table[uid] if unit.nationality in G.players[target].members: unit.visible.add(player) G.objects.updated[uid] = unit G.temp.intel[player][uid] = unit G.logger.write('{} may view all {}\'s units in {} for one turn'.format( player, target, tilename)) elif card.intelligence == 'Spy_Ring': cid = G.random.choice(list(G.players[target].hand)) G.players[target].hand.remove(cid) G.players[player].hand.add(cid) pick = G.objects.table[cid] pick.visible.clear() pick.visible.add(player) pick.owner = player G.objects.updated[cid] = pick G.logger.write('{} steals one card from {}\'s hand'.format( player, target)) elif card.intelligence == 'Sabotage': G.players[target].tracks.IND -= 1 G.logger.write('{} IND is decreased to {}'.format( target, G.players[target].tracks.IND)) elif card.intelligence == 'Code_Break': G.temp.intel[player] = tdict() for cid in G.players[target].hand: card = G.objects.table[cid] card.visible.add(player) G.temp.intel[player][cid] = card G.objects.updated[cid] = card G.logger.write('{} may view {}\'s hand for one turn'.format( player, target)) elif card.intelligence == 'Mole': G.logger.write( '{} may view {}\'s secret vault, and possibly achieve a tech therein' ) vault = G.players[target].secret_vault G.logger.write('{}\'s secret vault contains: {}'.format( target, ', '.join(vault)), player=player) options = xset() for cid in G.players[player].hand: card = G.objects.table[cid] if card.obj_type == 'investment_card' and 'top' in card: if card.top in vault and is_achievable_tech( G, player, card.top): options.add((card.top, cid)) if card.bottom in vault and is_achievable_tech( G, player, card.bottom): options.add((card.bottom, cid)) if len(options): # any tech can be achieved openly or in secret options = xset((xset(['open', 'secret']), options)) options.add(('accept', )) G.temp.mole = target code = adict() code[player] = options else: raise Exception('Unknown intelligence card type: {}'.format( card.intelligence)) del G.temp.hack return code # is None unless mole was played
def switch_ownership(G, tile, owner): G.objects.updated[tile._id] = tile if 'disputed' in tile: if owner in tile.aggressors: tile.aggressors.remove(owner) if len(tile.aggressors) == 0: make_undisputed(G, tile) pop = tile['pop'] res = tile['res'] msg = '' if 'owner' in tile and tile.owner in G.players: G.players[tile.owner].territory.remove(tile._id) G.players[tile.owner].tracks.POP -= pop G.players[tile.owner].tracks.RES -= res if pop > 0 or res > 0: msg = ' (gaining POP={} RES={})'.format(pop, res) G.logger.write('{} has taken control of {}{}'.format(owner, tile._id, msg)) if 'blockaded' in tile: del tile.blockaded if 'unsupplied' in tile: del tile.unsupplied G.players[owner].territory.add(tile._id) G.players[owner].tracks.POP += pop G.players[owner].tracks.RES += res if 'capital' in tile: owner_info = G.players[owner] nation = tile.alligence # take control of all unoccupied tiles in nation for tilename in G.nations.territories[nation]: other = G.tiles[tilename] if other._id != tile._id and len(other.units) == 0: switch_ownership(G, other, owner) if nation in G.nations.status: # minor switches side if tile.owner in G.players: G.players[tile.owner].satellites.remove(nation) owner_info.diplomacy.satellites.add(nation) G.nations.groups[G.nations.designations[nation]].remove(nation) G.nations.designations[nation] = owner G.nations.groups[owner].add(nation) else: # something bigger -> major/great power flag = False for rival in G.players: faction = G.players[rival] if nation in faction.members: flag = True if nation == faction.stats.great_power: # MainCapital if rival == owner: del faction.stats.fallen G.logger.write('{} has been liberated!'.format( tile._id)) else: G.logger.write( '{} has fallen! ({} production is zero)'. format(tile._id, tile.owner)) faction.stats.fallen = owner # TODO: maybe add conquered great power to satellites??? # rule 2.21 defeat of Major Power's Capital: permanently remove # all national units from play for tilename in G.nations.territories[nation]: other = G.tiles[tilename] u_remove = [] for uid in other.units: if uid in G.players[rival].units: u_remove.append(uid) for uid in u_remove: remove_from_play(G, uid) else: # SubCapital from MajorPower # TODO: liberating Great Powers or satellites adds them back properly (not just satellite) assert rival != owner, 'regaining great powers is not supported currently' G.logger.write('{} has fallen.'.format(nation)) # wipe out all major power units (nation) for uid, unit in faction.units.items(): if unit.nationality == nation: remove_unit(G, unit) # turn all colonies into armed minors for colony in faction.members[nation]: if colony != nation: G.nations.status[colony] = tdict() G.nations.status[colony].units = tdict() convert_to_armed_minor(G, colony) # add major power as satellite del faction.homeland[nation] G.nations.groups[rival].remove(nation) G.nations.designations[nation] = owner G.nations.groups[owner].add(nation) else: for member in faction.members: states = faction.members[member] if nation in states: # colony flag = True # colony becomes a satellite states.remove(nation) G.logger.write('{} captures {}'.format( owner, nation)) owner_info.diplomacy.satellites.add(nation) G.nations.groups[ G.nations.designations[nation]].remove(nation) G.nations.designations[nation] = owner G.nations.groups[owner].add(nation) break assert flag, 'No nation was captured: {}'.format(nation, tile._id) tile.owner = owner if check_victory_by_military(G, owner): set_game_won(G, owner, 'military') raise GameEnds
def government_post_phase(G, player=None, action=None): if len(G.temp.move_to_post) and action is not None: action, = action if action == 'accept': G.temp.move_to_post[player] = False elif action in G.players[player].hand: discard_cards(G, action) elif action in G.players[player].secret_vault: reveal_tech(G, player, action) else: # G.temp.move_to_post[player] = False #deactivate removing influence!!! decrement_influence(G, action) action = None code = encode_post_gov_actions(G) if len(code): return code # diplomacy resolution (check for control, discard diplomacy_cards), handsize, update tracks # resolve diplomacy discard_cards(G, *G.temp.diplomacy_cards) del G.temp.diplomacy_cards for nation, (fname, val) in G.temp.diplomacy.items(): for _ in range(val): increment_influence(G, fname, nation) del G.temp.diplomacy # check for control new_sats = tdict() for nation, dipl in G.diplomacy.neutrals.items(): if nation not in G.diplomacy.influence: if dipl.faction is None: continue else: faction = G.players[dipl.faction] faction.diplomacy[diplvl[dipl.value]].remove(nation) pop, res = compute_tracks(G.nations.territories[nation], G.tiles) faction.tracks.POP -= pop faction.tracks.RES -= res G.logger.write( '{} lost influence over {} (losing POP={} RES={})'.format( dipl.faction, nation, pop, res)) dipl.value = 0 dipl.faction = None else: inf = G.diplomacy.influence[nation] val = min(inf.value, 3) gainer = None loser = None if nation == 'USA': # handle USA separately if dipl.faction is None: if G.players[inf.faction].stats.enable_USA: gainer = inf.faction elif dipl.faction == inf.faction: if G.players[ dipl. faction].stats.enable_USA and dipl.value != val: G.players[dipl.faction].diplomacy[diplvl[ dipl.value]].remove(nation) else: if G.players[dipl.faction].stats.enable_USA: loser = dipl.faction G.players[dipl.faction].diplomacy[diplvl[ dipl.value]].remove(nation) if G.players[inf.faction].stats.enable_USA: gainer = inf.faction else: if dipl.faction is None: gainer = inf.faction elif dipl.faction != inf.faction: loser = dipl.faction gainer = inf.faction G.players[dipl.faction].diplomacy[diplvl[ dipl.value]].remove(nation) elif dipl.value == val: # no change required continue else: # value has changed #G.players[inf.faction].diplomacy[diplvl[dipl.value]].remove(dipl.faction) #@@@@ G.players[inf.faction].diplomacy[diplvl[ dipl.value]].remove(nation) faction = G.players[inf.faction] faction.diplomacy[diplvl[val]].add(nation) dipl.faction = inf.faction dipl.value = val if val >= 3: new_sats[nation] = inf.faction # update tracks tmsg = '' if gainer is not None or loser is not None: pop, res = compute_tracks(G.nations.territories[nation], G.tiles) if gainer is not None: G.players[gainer].tracks.POP += pop G.players[gainer].tracks.RES += res tmsg += ' ({} gains POP={}, RES={})'.format( gainer, pop, res) if loser is not None: G.players[loser].tracks.POP -= pop G.players[loser].tracks.RES -= res tmsg += ' (lost by {})'.format(loser) if nation == 'USA' and not faction.stats.enable_USA: G.logger.write('{} has {} influence in the USA'.format( inf.faction, inf.value)) else: dname = dipname[val] G.logger.write('{} becomes {} of {}{}'.format( nation, dname, inf.faction, tmsg)) G.temp.new_sats = new_sats if len(new_sats): # plan a satellite phase to place garrison troops add_next_phase(G, 'Satellite') raise PhaseComplete