erynwells.me/scripts/import-nethack-logfile.py
2022-04-16 18:20:59 +00:00

135 lines
3.8 KiB
Python
Executable file

#!/usr/bin/env python3
# Eryn Wells <eryn@erynwells.me>
'''
Converts a Nethack logfile (or record file) to JSON for easier parsing by my
website's templating engine.
See https://nethackwiki.com/wiki/Logfile for information about the format of these
logfiles.
'''
import argparse
import datetime
import json
import os.path
import subprocess
import sys
DUNGEONS = {
0: 'The Dungeons of Doom',
1: 'Gehennom',
2: 'The Gnomish Mines',
3: 'The Quest',
4: 'Sokoban',
5: 'Fort Ludios',
6: "Vlad's Tower",
7: 'The Elemental Planes',
}
# The "dungeon level" field is normally positive, but negatives indicate one of these
# levels.
SPECIAL_DUNGEON_LEVELS = {
-5: 'Astral Plane',
-4: 'Plane of Water',
-3: 'Plane of Fire',
-2: 'Plane of Air',
-1: 'Plane of Earth',
}
RACES = {
'Elf': 'Elf',
'Gno': 'Gnome',
'Hum': 'Human',
}
ROLES = {
'Mon': 'Monk',
'Pri': 'Priest',
'Ran': 'Ranger',
'Rog': 'Rogue',
'Sam': 'Samurai',
}
GENDERS = {
'Fem': 'Female',
}
ALIGNMENTS = {
'Law': 'Lawful',
'Neu': 'Neutral',
'Cha': 'Chaotic',
}
def parse_args(argv, *a, **kw):
parser = argparse.ArgumentParser(*a, **kw)
parser.add_argument('logfile', help='Path to the Nethack log file to convert')
args = parser.parse_args(argv)
return args
def main(argv):
args = parse_args(argv[1:], prog=argv[0])
if not os.path.isfile(args.logfile):
print('Given path is not a real file!', file=sys.stderr)
return -1
hostname = subprocess.check_output(['hostname', '-s']).decode('ascii').strip()
records = []
with open(args.logfile) as logfile:
for record in logfile.readlines():
fields = record.split(maxsplit=15)
dungeon_number = int(fields[2])
dungeon_name = DUNGEONS[dungeon_number]
dungeon_level = int(fields[3])
if dungeon_level > 0:
dungeon_level_descriptive = f"Level {dungeon_level}"
else:
dungeon_level_descriptive = SPECIAL_DUNGEON_LEVELS[dungeon_level]
start_date = datetime.datetime.strptime(fields[9], '%Y%m%d').strftime('%Y-%m-%d')
end_date = datetime.datetime.strptime(fields[8], '%Y%m%d').strftime('%Y-%m-%d')
name, cause_of_death = (s.strip() for s in fields[15].split(',', maxsplit=1))
role = fields[11]
race = fields[12]
gender = fields[13]
alignment = fields[14]
records.append({
'score': int(fields[1]),
'dungeon': {
'n': int(fields[2]),
'name': dungeon_name,
'level': {'n': dungeon_level, 'descriptive': dungeon_level_descriptive},
},
'end_date': end_date,
'start_date': start_date,
'character': {
'name': name,
'abbreviated': f'{name}-{role}-{race}-{gender}-{alignment}',
'max_level': int(fields[4]),
'hp': {'n': int(fields[5]), 'max': int(fields[6])},
'role': {'short': role, 'descriptive': ROLES[role]},
'race': {'short': race, 'descriptive': RACES[race]},
'gender': {'short': gender, 'descriptive': GENDERS[gender]},
'alignment': {'short': alignment, 'descriptive': ALIGNMENTS[alignment]},
},
'death': {'n': int(fields[7]), 'cause': cause_of_death},
'system': {
'hostname': hostname,
'user_id': int(fields[10]),
'nethack_version': fields[0],
}
})
json.dump(records, sys.stdout, indent=2)
print('\n')
if __name__ == '__main__':
import sys
result = main(sys.argv)
sys.exit(0 if not result else result)