Skip to content

Instantly share code, notes, and snippets.

@alexjurkiewicz
Created March 15, 2016 01:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexjurkiewicz/2ff515578cda9a2d268b to your computer and use it in GitHub Desktop.
Save alexjurkiewicz/2ff515578cda9a2d268b to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""Calculate DCSS spell usage from morgues."""
import subprocess
import collections
total_dacts = collections.Counter()
def find_morgue_files(d):
"""Return a list of all morgue files. XXX Should be pure python."""
cmd = ['find', d, '-name', 'morgue-*-201*-*.txt', '-type', 'f']
return subprocess.check_output(cmd).splitlines()
def validate_morgue(data):
"""Raise an error if the morgue has a problem."""
if 'Dungeon Crawl Stone Soup' not in data[0]:
raise ValueError("Couldn't find version signature.")
if 'Began as a' not in data[3]:
raise ValueError("Couldn't find character.")
return True
def parse_player_combo(combo):
"""Stupid code to convert eg Vine Stalker Venom Mage into a char/bg tuple.
Currently normalises draconians.
XXX make not stupid.
"""
combo_split = combo.split()
if len(combo_split) == 2:
return combo_split
elif len(combo_split) == 4:
if combo_split[1] == 'Draconian':
return 'Draconian', ' '.join(combo_split[2:4])
else:
return ' '.join(combo_split[0:2]), ' '.join(combo_split[2:4])
else:
if combo_split[0] in ('Hill', 'Vine', 'High', 'Deep', 'Ice'):
return ' '.join(combo_split[0:2]), combo_split[2]
elif combo_split[1] == 'Draconian':
return 'Draconian', combo_split[2]
elif combo_split[1] in ('Fire', 'Ice', 'Earth', 'Air', 'Venom',
'Arcane', 'Death', 'Chaos', 'Abyssal'):
return combo_split[0], ' '.join(combo_split[1:3])
raise AttributeError(combo)
def parse_dacts(data):
"""Parse a morgue file and return dact data.
Crappy state machine.
"""
found_dacts = False
dact_section = None
dact_data = {}
for line in data:
if line.startswith('Action') and line.endswith('|| total'):
found_dacts = True
dact_columns = len(line.split('|')) - 1
continue
if found_dacts:
if line.startswith('-------------------------'):
continue
dact_line = line.split('|')
if len(dact_line) != dact_columns + 1:
# End of table
return dact_data
if ':' in dact_line[0]:
# Parse the section header and then remove it so other logic
# is kept the same.
dact_section = dact_line[0].split(':')[0]
dact_line[0] = dact_line[0].split(':')[1]
dact_data[dact_section] = {}
dact_name = dact_line[0].strip()
dact_data["%s-%s" %
(dact_section, dact_name)] = dact_line[-1].strip()
def process_morgue(path):
"""Process a morgue file."""
with open(path) as f:
data = f.read().splitlines()
# Don't need this stuff right now, just slows processing
# if not validate_morgue(data):
# print("Couldn't parse %s" % path)
# raise ValueError
# version = re.search('version (.*) \((console|webtiles)\)', data[0]).group(1)
# canonical_version = re.match('[0-9.]+', version).group(0)
# race, background = parse_player_combo(re.search('Began as an? (.*) on', data[3]).group(1))
dacts = parse_dacts(data)
if dacts:
for k, v in dacts.items():
total_dacts[k] += 1
if __name__ == '__main__':
morgues = find_morgue_files('morgue')
for morgue in morgues:
process_morgue(morgue)
print(total_dacts)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment