示例#1
0
    def from_string(self, string, on_error='raise'):
        """ Builds the clause from a string
            :param string: The string to use to build the clause
            :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
        """
        province, coast = string.split('/') if '/' in string else [
            string, None
        ]

        # Province with coast
        # Syntax: (STP NCS)
        if province and coast:
            str_province = self._alias_from_string.get(province, province)
            str_coast = self._alias_from_string.get('/' + coast, '')

            if not str_coast:
                self.error(on_error, 'Unknown coast "%s".' % '/' + coast)
                return

            self._str = str_province + str_coast
            self._bytes = add_parentheses(
                bytes(Token(from_str=str_province)) +
                bytes(Token(from_str=str_coast)))

        # Province without coast
        # Syntax: ADR
        else:
            str_province = self._alias_from_string.get(string, string)
            self._str = str_province
            self._bytes = bytes(Token(from_str=str_province))
示例#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 test_tokens():
    """ Test all tokens """
    for token in ExpectedTokens:
        token_str = token.name[-3:]
        token_bytes = token.value.to_bytes(2, byteorder='big')
        token_from_str = Token(from_str=token_str)
        token_from_bytes = Token(from_bytes=token_bytes)
        assert str(token_from_str) == token_str
        assert str(token_from_bytes) == token_str
        assert bytes(token_from_str) == token_bytes
        assert bytes(token_from_bytes) == token_bytes
示例#4
0
    def from_bytes(self, daide_bytes, on_error='raise'):
        """ Builds the clause from a byte array

            :param daide_bytes: The bytes to use to build the clause
            :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
            :return: The remaining (unparsed) bytes
        """
        str_group_bytes, remaining_bytes = break_next_group(daide_bytes)

        # Can't find the string
        if not str_group_bytes:
            self.error(
                on_error,
                'Unable to find a set of parentheses to extract the string clause.'
            )
            return daide_bytes

        # Extract its content
        nb_bytes = len(str_group_bytes)
        self._bytes = str_group_bytes
        self._str = ''.join([
            str(Token(from_bytes=str_group_bytes[pos:pos + 2]))
            for pos in range(2, nb_bytes - 2, 2)
        ])
        return remaining_bytes
示例#5
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)))
示例#6
0
 def from_string(self, string, on_error='raise'):
     """ Builds the clause from a string
         :param string: The string to use to build the clause
         :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
     """
     self._bytes = bytes(Token(from_int=int(string)))
     self._int = int(string)
示例#7
0
 def from_string(self, string, on_error='raise'):
     """ Builds the clause from a string
         :param string: The string to use to build the clause
         :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
     """
     self._bytes = add_parentheses(b''.join(
         [bytes(Token(from_str=char)) for char in string]))
     self._str = string
示例#8
0
def str_to_bytes(daide_str):
    """ Converts a str into its bytes representation
        :param daide_str: A DAIDE string with tokens separated by spaces
        :return: The bytes representation of the string

        Note: Integers starts with a '#' character
    """
    buffer = []
    str_split = daide_str.split(' ') if daide_str else []
    for word in str_split:
        if word == '':
            buffer.append(bytes(Token(from_str=' ')))
        elif word[0] == '#':
            buffer.append(bytes(Token(from_int=int(word[1:]))))
        else:
            buffer.append(bytes(Token(from_str=word)))
    return b''.join(buffer)
示例#9
0
    def from_string(self, string, on_error='raise'):
        """ Builds the clause from a string
            :param string: The string to use to build the clause
            :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
        """
        str_season = self._alias_from_string.get(
            '%s.%s' % (string[0], string[-1]), '')
        str_year = string[1:-1]

        if not str_season or not str_year:
            self.error(on_error, 'Unknown season and/or year "%s".' % string)
            return

        self._str = string
        self._bytes = add_parentheses(
            bytes(Token(from_str=str_season)) +
            bytes(Token(from_int=int(str_year))))
示例#10
0
 def from_string(self, string, on_error='raise'):
     """ Builds the clause from a string
         :param string: The string to use to build this clause
         :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
     """
     str_unit_type = self._alias_from_string.get(string, '')
     if not str_unit_type:
         self.error(on_error, 'Unknown unit type "%s"' % string)
     self._str = string
     self._bytes = bytes(Token(from_str=str_unit_type))
示例#11
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)
示例#12
0
    def from_string(self, string, on_error='raise'):
        """ Builds the clause from a string
            :param string: The string to use to build this clause
            :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
        """
        # Not enough bytes to get a token
        if not string:
            self.error(on_error, '`string` cannot be empty or None')
            return

        # Getting the token
        self._bytes = bytes(Token(from_str=string))
        self._str = string
示例#13
0
    def from_bytes(daide_bytes, **kwargs):
        """ Builds a request from DAIDE bytes

            :param daide_bytes: The bytes representation of a request
            :return: The DaideRequest built from the bytes
        """
        if len(daide_bytes) < 2:
            return None
        initial_bytes = daide_bytes[:2]
        if initial_bytes not in __REQUEST_CONSTRUCTORS__:
            raise ValueError('Unable to find a constructor for %s' % str(Token(from_bytes=initial_bytes)))
        request = __REQUEST_CONSTRUCTORS__[initial_bytes](**kwargs)             # type: DaideRequest
        request.parse_bytes(daide_bytes)
        return request
示例#14
0
    def parse_bytes(self, daide_bytes):
        """ Builds the request from DAIDE bytes """
        assert len(daide_bytes) % 2 == 0, 'Expected request to have an even number of bytes. Got %d' % len(daide_bytes)
        self._bytes = daide_bytes

        # Building str representation
        while daide_bytes:
            token = Token(from_bytes=(daide_bytes[0], daide_bytes[1]))
            new_str = str(token)
            daide_bytes = daide_bytes[2:]
            pad = '' if (not self._str
                         or self._str[-1] == '('
                         or new_str == ')'
                         or (is_ascii_token(token) and new_str != '(')) else ' '
            self._str = self._str + pad + new_str
示例#15
0
def bytes_to_str(daide_bytes):
    """ Converts a bytes into its str representation
        :param daide_bytes: A DAIDE bytes with tokens separated by spaces
        :return: The bytes representation of the string

        Note: Integers starts with a '#' character
    """
    buffer = []
    length = len(daide_bytes) if daide_bytes else 0
    for i in range(0, length, 2):
        token = Token(from_bytes=(daide_bytes[i], daide_bytes[i + 1]))
        if is_integer_token(token):
            buffer.append('#' + str(token))
        else:
            buffer.append(str(token))
    return ' '.join(buffer)
示例#16
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)))
示例#17
0
    def from_bytes(self, daide_bytes, on_error='raise'):
        """ Builds the clause from a byte array
            :param daide_bytes: The bytes to use to build the clause
            :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
            :return: The remaining (unparsed) bytes
        """
        token_bytes, remaining_bytes = daide_bytes[:2], daide_bytes[2:]

        # Not enough bytes to get a token
        if not token_bytes:
            self.error(on_error,
                       'At least 2 bytes are required to build a token.')
            return remaining_bytes

        # Getting the token
        self._bytes = token_bytes
        self._str = str(Token(from_bytes=token_bytes))
        return remaining_bytes
示例#18
0
    def validate_resp_notifs(self, expected_resp_notifs):
        """ Validate that expected response / notifications are received regardless of the order
            :param expected_resp_notifs: the response / notifications to receive
        """
        while expected_resp_notifs:
            resp_notif_message = yield messages.DaideMessage.from_stream(self._stream)

            resp_notif = bytes_to_str(resp_notif_message.content)
            if Token(from_bytes=resp_notif_message.content[:2]) == tokens.HLO:
                resp_notif = resp_notif.split(' ')
                resp_notif[5] = expected_resp_notifs[0].split(' ')[5]
                resp_notif = ' '.join(resp_notif)
                self._is_game_joined = True

            LOGGER.info('[%d:%d] Received reply [%s]', self._id, self.stream.socket.fileno() + 1, str(resp_notif))
            LOGGER.info('[%d:%d] Replies in buffer [%s]', self._id, self.stream.socket.fileno() + 1,
                        ','.join(expected_resp_notifs))
            assert resp_notif in expected_resp_notifs
            expected_resp_notifs.remove(resp_notif)
示例#19
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)))
示例#20
0
    def from_bytes(self, daide_bytes, on_error='raise'):
        """ Builds the clause from a byte array
            :param daide_bytes: The bytes to use to build the clause
            :param on_error: The action to take when an error is encountered ('raise', 'warn', 'ignore')
            :return: The remaining (unparsed) bytes
        """
        if not daide_bytes:
            self.error(on_error, 'Expected at least 1 byte to parse a number')
            return daide_bytes

        number_bytes, remaining_bytes = daide_bytes[:2], daide_bytes[2:]
        number_token = Token(from_bytes=number_bytes)
        if not tokens.is_integer_token(number_token):
            self.error(on_error,
                       'The token is not an integer. Got %s' % number_token)
            return daide_bytes

        # Extract its content
        self._bytes = number_bytes
        self._int = int(number_token)
        return remaining_bytes
示例#21
0
def parse_order_to_bytes(phase_type, order_split):
    """ Builds an order clause from a byte array
        :param phase_type: The game phase
        :param order_split: An instance of diplomacy.utils.subject_split.OrderSplit
        :return: The order clause's bytes
    """
    buffer = []

    # FRANCE WAIVE
    if len(order_split) == 1:
        words = order_split.order_type.split()
        buffer.append(parse_string(Power, words.pop(0)))
        buffer.append(parse_string(OrderType, words.pop(0)))
    else:
        buffer.append(parse_string(Unit, order_split.unit))

        # FRANCE F IRI [-] MAO
        # FRANCE A IRI [-] MAO VIA
        if order_split.order_type == '-':
            # FRANCE A IRI - MAO VIA
            if order_split.via_flag:
                buffer.append(Token(tokens.CTO))
            else:
                buffer.append(Token(tokens.MTO))
        # FRANCE A IRO [D]
        elif order_split.order_type == 'D':
            if phase_type == 'R':
                buffer.append(Token(tokens.DSB))
            elif phase_type == 'A':
                buffer.append(Token(tokens.REM))
        # FRANCE A LON [H]
        # FRANCE A WAL [S] FRANCE F LON
        # FRANCE A WAL [S] FRANCE F MAO - IRI
        # FRANCE F NWG [C] FRANCE A NWY - EDI
        # FRANCE A IRO [R] MAO
        # FRANCE A LON [B]
        # FRANCE F LIV [B]
        else:
            buffer.append(parse_string(OrderType, order_split.order_type))

        # FRANCE A WAL S [FRANCE F LON]
        # FRANCE A WAL S [FRANCE F MAO] - IRI
        # FRANCE F NWG C [FRANCE A NWY] - EDI
        if order_split.supported_unit:
            buffer.append(parse_string(Unit, order_split.supported_unit))

        # FRANCE A WAL S FRANCE F MAO [- IRI]
        # FRANCE F NWG C FRANCE A NWY [- EDI]
        if order_split.support_order_type:
            # FRANCE A WAL S FRANCE F MAO - IRI
            if order_split.order_type == 'S':
                buffer.append(Token(tokens.MTO))
                buffer.append(
                    parse_string(Province, order_split.destination[:3]))
            else:
                buffer.append(Token(tokens.CTO))
                buffer.append(parse_string(Province, order_split.destination))
        # FRANCE F IRI - [MAO]
        # FRANCE A IRI - [MAO] VIA
        # FRANCE A IRO R [MAO]
        elif order_split.destination:
            buffer.append(parse_string(Province, order_split.destination))

        # FRANCE A IRI - MAO [VIA]
        if order_split.via_flag:
            buffer.append(parse_string(OrderType, order_split.via_flag))

    return b''.join([bytes(clause) for clause in buffer])