<commit_before>import json
import pprint

try:
    config = json.load(open('padb.json'))
except IOError:
    print("""
****************************************************************
Error reading configuration. Create a file named 'padb.json'
in the current directory with an entry in the following format,
with the path to the Planetary Annihilation 'media' directory:

{
    "pa_root": "C:/Path/To/PlanetaryAnnihilation/PA/media"
}

****************************************************************
""")
    raise

PA_ROOT = config['pa_root']

# internal use, keyed by resource_name
UNITS = {}
WEAPONS = {}
AMMO = {}
THINGS = {}

# for inspection, using a friendly name
units = {}
weapons = {}

class Resources:
    def __init__(self, metal=0, energy=0):
        self.metal = metal
        self.energy = energy

    def __repr__(self):
        s = 'Resource('
        if self.metal:
            s += 'metal={}'.format(self.metal)
            if self.energy:
                s += ', '
        if self.energy:
            s += 'energy={}'.format(self.energy)
        s += ')'
        return s


class Thing:
    base = None

    def __init__(self, resource_name):
        with open(PA_ROOT + resource_name) as datafile:
            raw = json.load(datafile)

        if 'base_spec' in raw:
            base = self.__class__(raw['base_spec'])
            self.__dict__.update(base.__dict__)
            self.base = base

        self.resource_name = resource_name
        self.raw = raw

    @property
    def safename(self):
        """ A (hopefully) unique name that can be used in URLs """
        return self.resource_name.rsplit('/', 1)[1].split('.')[0]

    def report(self, show_all=False):
        out = []
        for k,v in self.__dict__.items():
            if not show_all and k in ('raw',):
                continue
            indent = len(k) + 2
            s = pprint.pformat(v)
            lines = s.split('\n')
            out.append('{}: {}'.format(k, lines[0]))
            out.extend(' '*indent + line for line in lines[1:])
        return '\n'.join(out)

    def __call__(self, show_all=False):
        """ Print info about this unit """
        print(self.report(show_all))


class Unit(Thing):
    unit_types = ()
    buildable_types = ''
    build_cost = 0
    health = 0
    weapons = ()
    build_arms = ()
    misc_tools = ()
    production = Resources()
    consumption = Resources()
    storage = Resources()
    move_speed = 0
    turn_speed = 0
    acceleration = 0
    brake = 0

    def __init__(self, resource_name):
        super().__init__(resource_name)
        UNITS[resource_name] = self

        self.name = self.raw.pop('display_name', self.safename)
        self.role = self.raw.pop('unit_name', self.name)
        self.description = self.raw.pop('description', '')

        if 'unit_types' in self.raw:
            self.unit_types = set()
            for unit_type in self.raw.pop('unit_types'):
                assert unit_type.startswith('UNITTYPE_')
                self.unit_types.add(unit_type[9:])

        if 'buildable_types' in self.raw:
            self.buildable_types = self.raw.pop('buildable_types')

        self.builds = set()
        self.built_by = set()

        if 'build_metal_cost' in self.raw:
            self.build_cost = self.raw.pop('build_metal_cost')
        if 'max_health' in self.raw:
            self.health = self.raw.pop('max_health')

        if 'tools' in self.raw:
            self.weapons = []
            self.build_arms = []
            self.misc_tools = []
            for tool in self.raw.pop('tools', ()):
                resource = tool['spec_id']
                tool_name = resource.rsplit('/')[-1].split('.')[0]
                try:
                    if 'weapon' in tool_name:
                        self.weapons.append(Weapon(resource))
                    elif 'build_arm' in tool_name:
                        self.build_arms.append(BuildArm(resource))
                    else:
                        self.misc_tools.append(Thing(resource))
                except IOError:
                        pass

        self.dps = sum(w.dps for w in self.weapons)
        self.salvo_damage = sum(w.damage for w in self.weapons)

        # Economy
        for field in ('consumption', 'production', 'storage'):
            data = self.raw.pop(field, {})
            base = getattr(self, field)
            setattr(self, field, Resources(base.metal, base.energy))
            if 'metal' in data:
                getattr(self, field).metal = data['metal']
            if 'energy' in data:
                getattr(self, field).energy = data['energy']

        self.build_rate = 0

        if ('Economy' not in self.unit_types and
            (self.production.metal or self.production.energy or
             self.storage.metal or self.storage.energy)):
            if not self.unit_types:
                self.unit_types = set(('Economy',))
            else:
                self.unit_types.add('Economy')

        self.tool_consumption = Resources()
        for tool in self.build_arms:
            self.tool_consumption.metal += tool.metal_consumption
            self.tool_consumption.energy += tool.energy_consumption
            self.build_rate += tool.metal_consumption

        self.weapon_consumption = Resources()
        for weapon in self.weapons:
            self.weapon_consumption.metal -= weapon.metal_rate
            self.weapon_consumption.energy -= weapon.energy_rate

        if not self.safename.startswith('base_'):
            units[self.safename] = self

        nav = self.raw.get('navigation', {})
        if 'move_speed' in nav:
            self.move_speed = nav.pop('move_speed')
        if 'turn_speed' in nav:
            self.turn_speed = nav.pop('turn_speed')
        if 'acceleration' in nav:
            self.acceleration = nav.pop('acceleration')
        if 'brake' in nav:
            self.brake = nav.pop('brake')

    @property
    def metal_rate(self):
        return (self.production.metal - self.consumption.metal
                - self.tool_consumption.metal - self.weapon_consumption.metal)

    @property
    def energy_rate(self):
        return (self.production.energy - self.consumption.energy
                - self.tool_consumption.energy - self.weapon_consumption.energy)

    @property
    def affects_economy(self):
        return bool(self.metal_rate or self.energy_rate or self.build_rate)

    def __repr__(self):
        return '<Unit: {!r}>'.format(self.role)


class Weapon(Thing):
    rof = 0.0<commit_msg>Extract recon info from blueprints<commit_after>import json
import pprint

try:
    config = json.load(open('padb.json'))
except IOError:
    print("""
****************************************************************
Error reading configuration. Create a file named 'padb.json'
in the current directory with an entry in the following format,
with the path to the Planetary Annihilation 'media' directory:

{
    "pa_root": "C:/Path/To/PlanetaryAnnihilation/PA/media"
}

****************************************************************
""")
    raise

PA_ROOT = config['pa_root']

# internal use, keyed by resource_name
UNITS = {}
WEAPONS = {}
AMMO = {}
THINGS = {}

# for inspection, using a friendly name
units = {}
weapons = {}

class Resources:
    def __init__(self, metal=0, energy=0):
        self.metal = metal
        self.energy = energy

    def __repr__(self):
        s = 'Resource('
        if self.metal:
            s += 'metal={}'.format(self.metal)
            if self.energy:
                s += ', '
        if self.energy:
            s += 'energy={}'.format(self.energy)
        s += ')'
        return s


class Thing:
    base = None

    def __init__(self, resource_name):
        with open(PA_ROOT + resource_name) as datafile:
            raw = json.load(datafile)

        if 'base_spec' in raw:
            base = self.__class__(raw['base_spec'])
            self.__dict__.update(base.__dict__)
            self.base = base

        self.resource_name = resource_name
        self.raw = raw

    @property
    def safename(self):
        """ A (hopefully) unique name that can be used in URLs """
        return self.resource_name.rsplit('/', 1)[1].split('.')[0]

    def report(self, show_all=False):
        out = []
        for k,v in self.__dict__.items():
            if not show_all and k in ('raw',):
                continue
            indent = len(k) + 2
            s = pprint.pformat(v)
            lines = s.split('\n')
            out.append('{}: {}'.format(k, lines[0]))
            out.extend(' '*indent + line for line in lines[1:])
        return '\n'.join(out)

    def __call__(self, show_all=False):
        """ Print info about this unit """
        print(self.report(show_all))


class Unit(Thing):
    unit_types = ()
    buildable_types = ''
    build_cost = 0
    health = 0
    weapons = ()
    build_arms = ()
    misc_tools = ()
    production = Resources()
    consumption = Resources()
    storage = Resources()
    move_speed = 0
    turn_speed = 0
    acceleration = 0
    brake = 0

    vision_radius = 0
    underwater_vision_radius = 0
    radar_radius = 0
    sonar_radius = 0

    def __init__(self, resource_name):
        super().__init__(resource_name)
        UNITS[resource_name] = self

        self.name = self.raw.pop('display_name', self.safename)
        self.role = self.raw.pop('unit_name', self.name)
        self.description = self.raw.pop('description', '')

        if 'unit_types' in self.raw:
            self.unit_types = set()
            for unit_type in self.raw.pop('unit_types'):
                assert unit_type.startswith('UNITTYPE_')
                self.unit_types.add(unit_type[9:])

        if 'buildable_types' in self.raw:
            self.buildable_types = self.raw.pop('buildable_types')

        self.builds = set()
        self.built_by = set()

        if 'build_metal_cost' in self.raw:
            self.build_cost = self.raw.pop('build_metal_cost')
        if 'max_health' in self.raw:
            self.health = self.raw.pop('max_health')

        if 'tools' in self.raw:
            self.weapons = []
            self.build_arms = []
            self.misc_tools = []
            for tool in self.raw.pop('tools', ()):
                resource = tool['spec_id']
                tool_name = resource.rsplit('/')[-1].split('.')[0]
                try:
                    if 'weapon' in tool_name:
                        self.weapons.append(Weapon(resource))
                    elif 'build_arm' in tool_name:
                        self.build_arms.append(BuildArm(resource))
                    else:
                        self.misc_tools.append(Thing(resource))
                except IOError:
                        pass

        self.dps = sum(w.dps for w in self.weapons)
        self.salvo_damage = sum(w.damage for w in self.weapons)

        # Economy
        for field in ('consumption', 'production', 'storage'):
            data = self.raw.pop(field, {})
            base = getattr(self, field)
            setattr(self, field, Resources(base.metal, base.energy))
            if 'metal' in data:
                getattr(self, field).metal = data['metal']
            if 'energy' in data:
                getattr(self, field).energy = data['energy']

        self.build_rate = 0

        if ('Economy' not in self.unit_types and
            (self.production.metal or self.production.energy or
             self.storage.metal or self.storage.energy)):
            if not self.unit_types:
                self.unit_types = set(('Economy',))
            else:
                self.unit_types.add('Economy')

        self.tool_consumption = Resources()
        for tool in self.build_arms:
            self.tool_consumption.metal += tool.metal_consumption
            self.tool_consumption.energy += tool.energy_consumption
            self.build_rate += tool.metal_consumption

        self.weapon_consumption = Resources()
        for weapon in self.weapons:
            self.weapon_consumption.metal -= weapon.metal_rate
            self.weapon_consumption.energy -= weapon.energy_rate

        if not self.safename.startswith('base_'):
            units[self.safename] = self

        nav = self.raw.get('navigation', {})
        if 'move_speed' in nav:
            self.move_speed = nav.pop('move_speed')
        if 'turn_speed' in nav:
            self.turn_speed = nav.pop('turn_speed')
        if 'acceleration' in nav:
            self.acceleration = nav.pop('acceleration')
        if 'brake' in nav:
            self.brake = nav.pop('brake')

        try:
            recon = self.raw['recon']['observer'].pop('items')
        except KeyError:
            recon = []

        for item in recon:
            if item['channel'] == 'sight':
                if item['layer'] == 'surface_and_air':
                    self.vision_radius = item['radius']
                elif item['layer'] == 'underwater':
                    self.underwater_vision_radius = item['radius']
            elif item['channel'] == 'radar':
                if item['layer'] == 'surface_and_air':
                    self.radar_radius = item['radius']
                elif item['layer'] == 'underwater':
                    self.sonar_radius = item['radius']


    @property
    def metal_rate(self):
        return (self.production.metal - self.consumption.metal
                - self.tool_consumption.metal - self.weapon_consumption.metal)

    @property
    def energy_rate(self):
        return (self.production.energy - self.consumption.energy
                - self.tool_consumption.energy - self.weapon_consumption.energy)

    @property
    def affects_economy(self):
        return bool(self.metal_rate or self.energy_rate or self.build_rate)

    def __repr__(self):
        return '<Unit: {!r}>'.format(self.role)


class Weapon(Thing):
    rof = 0.0
{'fraction_non_alphanumeric': 0.13565780014378145, 'fraction_numerical': 0.0031631919482386773, 'mean_word_length': 1.9800771208226222, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3412530', 'n_tokens_mistral': 4217, 'n_tokens_neox': 3992, 'n_words': 909}