示例#1
0
    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)
示例#2
0
    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))
示例#3
0
    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))
示例#4
0
    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])
示例#5
0
 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))
示例#6
0
 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))
示例#7
0
    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)
示例#8
0
    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
示例#9
0
 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))
示例#10
0
 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)))
示例#11
0
 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)
示例#12
0
    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)
示例#13
0
    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))
示例#14
0
    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]])
示例#15
0
    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)))
示例#16
0
    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)
示例#17
0
    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)))
示例#18
0
    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
示例#19
0
    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