def _build_retreat_phase(self, power): """ Builds the missing orders response for a retreat phase """ units_bytes_buffer = [] units_with_no_order = { unit: retreat_provinces for unit, retreat_provinces in power.retreats.items() } # Removing units for which we have orders for key, value in power.orders.items(): unit = key # Regular game {e.g. 'A PAR': '- BUR') if key[0] in 'RIO': # No-check game (key is INVALID, ORDER x, REORDER x) unit = ' '.join(value.split()[:2]) if unit in units_with_no_order: del units_with_no_order[unit] # Sorting by the unit's province ASC so results are deterministic for unit, retreat_provinces in sorted( units_with_no_order.items(), key=lambda key_val: key_val[0].split()[-1]): unit_clause = parse_string(Unit, '%s %s' % (power.name, unit)) retreat_clauses = [ parse_string(Province, province) for province in retreat_provinces ] units_bytes_buffer += [ add_parentheses( strip_parentheses(bytes(unit_clause)) + bytes(tokens.MRT) + add_parentheses(b''.join( [bytes(province) for province in retreat_clauses]))) ] self._bytes = bytes(tokens.MIS) + b''.join(units_bytes_buffer)
def __init__(self, power_name, passcode, level, deadline, rules, **kwargs): """ Builds the response :param power_name: The name of the power being played. :param passcode: Integer. A passcode to rejoin the game. :param level: Integer. The daide syntax level of the game :param deadline: Integer. The number of seconds per turn (0 to disable) :param rules: The list of game rules. """ super(HelloResponse, self).__init__(**kwargs) power = parse_string(Power, power_name) passcode = Token(from_int=passcode) if 'NO_PRESS' in rules: level = 0 variants = add_parentheses( bytes(tokens.LVL) + bytes(Token(from_int=level))) if deadline > 0: variants += add_parentheses( bytes(tokens.MTL) + bytes(Token(from_int=deadline))) variants += add_parentheses( bytes(tokens.RTL) + bytes(Token(from_int=deadline))) variants += add_parentheses( bytes(tokens.BTL) + bytes(Token(from_int=deadline))) if 'NO_CHECK' in rules: variants += add_parentheses(bytes(tokens.AOA)) self._bytes = bytes(tokens.HLO) \ + add_parentheses(bytes(power)) \ + add_parentheses(bytes(passcode)) \ + add_parentheses(bytes(variants))
def __init__(self, phase_name, order_bytes, results, **kwargs): """ Builds the response :param phase_name: The name of the current phase (e.g. 'S1901M') :param order_bytes: The bytes received for the order :param results: An array containing the error codes. """ super(OrderResultResponse, self).__init__(**kwargs) turn_clause = parse_string(Turn, phase_name) if not results or 0 in results: # Order success response result_clause = tokens.SUC else: # Generic order failure response result_clause = tokens.NSO self._bytes = bytes(tokens.ORD) + bytes(turn_clause) + add_parentheses(order_bytes) + \ add_parentheses(bytes(result_clause))
def __init__(self, powers_centers, map_name, **kwargs): """ Builds the response :param powers_centers: A dict of {power_name: centers} objects :param map_name: The name of the map """ super(SupplyCenterResponse, self).__init__(**kwargs) remaining_scs = Map(map_name).scs[:] all_powers_bytes = [] # Parsing each power for power_name in sorted(powers_centers): centers = sorted(powers_centers[power_name]) power_clause = parse_string(Power, power_name) power_bytes = bytes(power_clause) for center in centers: sc_clause = parse_string(Province, center) power_bytes += bytes(sc_clause) remaining_scs.remove(center) all_powers_bytes += [power_bytes] # Parsing unowned center uno_token = tokens.UNO power_bytes = bytes(uno_token) for center in remaining_scs: sc_clause = parse_string(Province, center) power_bytes += bytes(sc_clause) all_powers_bytes += [power_bytes] # Storing full response self._bytes = bytes(tokens.SCO) \ + b''.join([add_parentheses(power_bytes) for power_bytes in all_powers_bytes])
def __init__(self, power_name, **kwargs): """ Builds the response :param power_name: The name of the power being solo. """ super(SoloNotification, self).__init__(**kwargs) power = parse_string(Power, power_name) self._bytes = bytes(tokens.SLO) + add_parentheses(bytes(power))
def __init__(self, power_name, **kwargs): """ Builds the response :param power_name: The name of the power being played. """ super(PowerIsEliminatedResponse, self).__init__(**kwargs) power = parse_string(Power, power_name) self._bytes = bytes(tokens.OUT) + add_parentheses(bytes(power))
def __init__(self, request_bytes, **kwargs): """ Builds the response :param request_bytes: The bytes received for the request """ super(ParenthesisErrorResponse, self).__init__(**kwargs) self._bytes = bytes(tokens.PRN) + add_parentheses(request_bytes)
def _build_powers_clause(game_map): """ Build the powers clause Syntax: :: (powers) powers syntax: :: power power ... power syntax: :: AUS # Austria ENG # England FRA # France GER # Germany ITA # Italy RUS # Russia TUR # Turkey """ power_names = game_map.powers[:] power_names.sort() # (Powers): (power power ...) powers_clause = [ bytes(parse_string(Power, power_name)) for power_name in power_names ] powers_clause = add_parentheses(b''.join(powers_clause)) return powers_clause
def __init__(self, power_name, **kwargs): """ Builds the response :param power_name: The name of the power being played. """ super(PowerInCivilDisorderNotification, self).__init__(**kwargs) power = parse_string(Power, power_name) self._bytes = bytes(tokens.CCD) + add_parentheses(bytes(power))
def __init__(self, seconds, **kwargs): """ Builds the response :param seconds: Integer. The number of seconds before deadline """ super(TimeToDeadlineResponse, self).__init__(**kwargs) self._bytes = bytes(tokens.TME) + add_parentheses( bytes(Token(from_int=seconds)))
def __init__(self, request_bytes, error_index, **kwargs): """ Builds the response :param request_bytes: The bytes received for the request :param error_index: The index of the faulty token """ super(SyntaxErrorResponse, self).__init__(**kwargs) message_with_err = request_bytes[:error_index] + bytes( tokens.ERR) + request_bytes[error_index:] self._bytes = bytes(tokens.HUH) + add_parentheses(message_with_err)
def __init__(self, phase_name, powers_units, powers_retreats, **kwargs): """ Builds the response :param phase_name: The name of the current phase (e.g. 'S1901M') :param powers: A list of `diplomacy.engine.power.Power` objects """ super(CurrentPositionResponse, self).__init__(**kwargs) units_bytes_buffer = [] # Turn turn_clause = parse_string(Turn, phase_name) # Units for power_name, units in sorted(powers_units.items()): # Regular units for unit in units: unit_clause = parse_string(Unit, '%s %s' % (power_name, unit)) units_bytes_buffer += [bytes(unit_clause)] # Dislodged units for unit, retreat_provinces in sorted( powers_retreats[power_name].items()): unit_clause = parse_string(Unit, '%s %s' % (power_name, unit)) retreat_clauses = [ parse_string(Province, province) for province in retreat_provinces ] units_bytes_buffer += [ add_parentheses( strip_parentheses(bytes(unit_clause)) + bytes(tokens.MRT) + add_parentheses(b''.join( [bytes(province) for province in retreat_clauses]))) ] # Storing full response self._bytes = bytes( tokens.NOW) + bytes(turn_clause) + b''.join(units_bytes_buffer)
def __init__(self, order_bytes, results, **kwargs): """ Builds the response :param order_bytes: The bytes received for the order :param results: An array containing the error codes. """ super(ThanksResponse, self).__init__(**kwargs) if not results or 0 in results: # Order success response note_clause = tokens.MBV else: # Generic order failure response note_clause = tokens.NYU # Storing full response self._bytes = bytes(tokens.THX) + order_bytes + add_parentheses( bytes(note_clause))
def __init__(self, from_power_name, to_power_names, message, **kwargs): """ Builds the response """ super(MessageFromNotification, self).__init__(**kwargs) from_power_clause = bytes(parse_string(Power, from_power_name)) to_powers_clause = b''.join([ bytes(parse_string(Power, power_name)) for power_name in to_power_names ]) message_clause = str_to_bytes(message) self._bytes = bytes(tokens.FRM) \ + b''.join([add_parentheses(clause) for clause in [from_power_clause, to_powers_clause, message_clause]])
def _build_adjustment_phase(self, power): """ Builds the missing orders response for a build phase """ disbands_status = len(power.units) - len(power.centers) if disbands_status < 0: available_homes = power.homes[:] # Removing centers for which it's impossible to build for unit in [unit.split() for unit in power.units]: province = unit[1] if province in available_homes: available_homes.remove(province) disbands_status = max(-len(available_homes), disbands_status) self._bytes += bytes(tokens.MIS) + add_parentheses( bytes(Token(from_int=disbands_status)))
def __init__(self, phase_name, powers, daide_users, years_of_elimination, **kwargs): """ Builds the Notification """ super(SummaryNotification, self).__init__(**kwargs) powers_smrs_clause = [] # Turn turn_clause = parse_string(Turn, phase_name) for power, daide_user, year_of_elimination in zip( powers, daide_users, years_of_elimination): power_smr_clause = [] name = daide_user.client_name if daide_user else power.get_controller( ) version = daide_user.client_version if daide_user else 'v0.0.0' power_name_clause = bytes(parse_string(Power, power.name)) power_smr_clause.append(power_name_clause) # (name) name_clause = bytes(parse_string(String, name)) power_smr_clause.append(name_clause) # (version) version_clause = bytes(parse_string(String, version)) power_smr_clause.append(version_clause) number_of_centres_clause = bytes( Token(from_int=len(power.centers))) power_smr_clause.append(number_of_centres_clause) if not power.centers: year_of_elimination_clause = bytes( Token(from_int=year_of_elimination)) power_smr_clause.append(year_of_elimination_clause) power_smr_clause = add_parentheses(b''.join(power_smr_clause)) powers_smrs_clause.append(power_smr_clause) self._bytes = bytes( tokens.SMR) + bytes(turn_clause) + b''.join(powers_smrs_clause)
def _build_adjustment_phase(self, power): """ Builds the missing orders response for a build phase """ adjusts = [OrderSplitter(adjust) for adjust in power.adjust] build_cnt = sum(1 for adjust in adjusts if adjust.order_type == 'B') disband_cnt = sum(1 for adjust in adjusts if adjust.order_type == 'D') disbands_status = (len(power.units) + build_cnt) - (len(power.centers) + disband_cnt) if disbands_status < 0: available_homes = power.homes[:] # Removing centers for which it's impossible to build for unit in [unit.split() for unit in power.units]: province = unit[1] if province in available_homes: available_homes.remove(province) disbands_status = max(-len(available_homes), disbands_status) self._bytes += bytes(tokens.MIS) + add_parentheses( bytes(Token(from_int=disbands_status)))
def _build_adjacencies_clause(game_map): """ Build the adjacencies clause Syntax: :: (adjacencies) adjacencies syntax: :: (prov_adjacencies) (prov_adjacencies) ... prov_adjacencies syntax: :: province (unit_type adjacent_prov adjacent_prov ...) (unit_type adjacent_prov adjacent_prov ...) ... unit_type syntax: :: AMY # List of provinces an army can move to FLT # List of provinces a fleet can move to (FLT coast) # List of provinces a fleet can move to from the given coast adjacent_prov syntax: :: province # A province which can be moved to (province coast) # A coast of a province that can be moved to """ adjacencies = { } # {province: {'A': [], 'F': [], '/': []} army abuts, fleet abuts, / abuts # For each province for province in sorted( [loc.upper() for loc in game_map.locs if '/' not in loc]): province_type = game_map.area_type(province) if province_type == 'SHUT': continue # Creating empty list of adjacent provinces adjacencies.setdefault(province, {}) adjacencies[province].setdefault( 'A', []) # List of adjacent provinces where armies can move for province_w_coast in sorted(game_map.find_coasts(province)): coast = province_w_coast[3:] adjacencies[province].setdefault( coast, []) # List of adjacent provinces where fleets can move # Building list of adjacent provinces for coast in adjacencies[ province]: # 'A', '', '/NC', '/SC', '/EC', '/WC' # Army adjacencies if coast == 'A': for dest in sorted(game_map.dest_with_coasts[province]): if game_map.abuts('A', province, '-', dest): adjacencies[province]['A'].append( bytes(parse_string(Province, dest))) # Fleet adjacencies else: for dest in sorted(game_map.dest_with_coasts[province + coast]): if game_map.abuts('F', province + coast, '-', dest): adjacencies[province][coast].append( bytes(parse_string(Province, dest))) # If province has coasts ('/NC', '/SC'), removing the adjacency for fleets without coast if len(adjacencies[province]) > 2: del adjacencies[province][''] # Building adjacencies clause adjacencies_clause = [] for province in sorted(adjacencies): prov_adjacencies_clause = [bytes(parse_string(Province, province))] for coast in ('A', '', '/EC', '/NC', '/SC', '/WC'): if coast not in adjacencies[province]: continue if not adjacencies[province][coast]: continue # (Army adjacencies): (AMY adjacent_prov adjacent_prov ...) if coast == 'A': amy_adjacencies_clause = [bytes(tokens.AMY) ] + adjacencies[province][coast] amy_adjacencies_clause = add_parentheses( b''.join(amy_adjacencies_clause)) prov_adjacencies_clause.append(amy_adjacencies_clause) # (Fleet provinces): (FLT adjacent_prov adjacent_prov ...) elif coast == '': flt_adjacencies_clause = [bytes(tokens.FLT) ] + adjacencies[province][coast] flt_adjacencies_clause = add_parentheses( b''.join(flt_adjacencies_clause)) prov_adjacencies_clause.append(flt_adjacencies_clause) # (Fleet coast): (FLT coast) # (Fleet coast provinces): ((FLT coast) adjacent_prov adjacent_prov ...) else: flt_clause = bytes(tokens.FLT) coast_clause = bytes(parse_string(Province, coast)) coast_flt_adjacencies_clause = [add_parentheses(flt_clause + coast_clause)] \ + adjacencies[province][coast] coast_flt_adjacencies_clause = add_parentheses( b''.join(coast_flt_adjacencies_clause)) prov_adjacencies_clause.append( coast_flt_adjacencies_clause) # (Province adjacencies): (province (unit_type adjacent_prov adjacent_prov ...) # (unit_type adjacent_prov adjacent_prov ...) ...) prov_adjacencies_clause = add_parentheses( b''.join(prov_adjacencies_clause)) adjacencies_clause.append(prov_adjacencies_clause) # (Adjacencies): ((prov_adjacencies) (prov_adjacencies) ...) adjacencies_clause = add_parentheses(b''.join(adjacencies_clause)) return adjacencies_clause
def _build_provinces_clause(game_map): """ Build the provinces clause Syntax: :: (provinces) provinces syntax: :: (supply_centres) (non_supply_centres) supply_centres syntax: :: (power centre centre ...) (power centre centre ...) ... supply_centres power syntax: :: (power power ...) # This is currently not supported AUS # Austria ENG # England FRA # France GER # Germany ITA # Italy RUS # Russia TUR # Turkey UNO # Unknown power non_supply_centres syntax: :: province province ... # List of provinces """ unowned_scs = game_map.scs[:] unowned_scs.sort() # (Supply centers): ((power centre centre ...) (power centre centre ...) ...) # (Non supply centres): (province province ...) scs_clause = [] non_scs_clause = [] power_names_centers = [ (power_name, centers[:]) for power_name, centers in game_map.centers.items() ] power_names_centers.sort( key=lambda power_name_center: power_name_center[0]) # Parsing each power centers for power_name, centers in power_names_centers: centers.sort() power_scs_clause = [bytes(parse_string(Power, power_name))] for center in centers: power_scs_clause.append(bytes(parse_string(Province, center))) unowned_scs.remove(center) # (Power supply centers): (power centre centre ...) power_scs_clause = add_parentheses(b''.join(power_scs_clause)) scs_clause.append(power_scs_clause) # (Power supply centers): (power centre centre ...) power_scs_clause = [bytes(tokens.UNO)] power_scs_clause += [ bytes(parse_string(Province, center)) for center in unowned_scs ] power_scs_clause = add_parentheses(b''.join(power_scs_clause)) # (Supply centers): ((power centre centre ...) (power centre centre ...) ...) scs_clause.append(power_scs_clause) scs_clause = add_parentheses(b''.join(scs_clause)) provinces = game_map.locs[:] provinces.sort() for province in provinces: if game_map.area_type(province) == 'SHUT': continue province = province[:3].upper() province_clause = bytes(parse_string(Province, province)) if province_clause not in non_scs_clause and province not in game_map.scs: non_scs_clause.append(province_clause) # (Non supply centres): (province province ...) non_scs_clause = add_parentheses(b''.join(non_scs_clause)) # (Provinces): ((supply_centers) (non_supply_centres)) provinces_clause = [scs_clause, non_scs_clause] provinces_clause = add_parentheses(b''.join(provinces_clause)) return provinces_clause