Advertisement
Guest User

Another quick & dirty high score script fix

a guest
Jun 24th, 2017
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.04 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # Copyright 2017 DBrickShaw
  4.  
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  6. # and associated documentation files (the "Software"), to deal in the Software without restriction,
  7. # including without limitation the rights to use, copy, modify, merge, publish, distribute,
  8. # sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  9. # furnished to do so, subject to the following conditions:
  10.  
  11. # The above copyright notice and this permission notice shall be included in all copies or
  12. # substantial portions of the Software.
  13.  
  14. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
  15. # NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  17. # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19.  
  20. import os, re, datetime
  21.  
  22. BACKGROUND_COLOR = '000000'
  23. FOREGROUND_COLOR = 'cccccc'
  24. COLOR1 = '00e400'
  25. COLOR2 = '0086b2'
  26.  
  27. COL_GRAD = ['d90000', 'b25900', 'd9d900', '00d900', '00a3d9', 'bf00ff']
  28.  
  29. TIME_FIELD_WIDTH = 6
  30. STATS_FIELD_WIDTH = 50
  31. STATS_INDENT = 16
  32.  
  33. class RunStats(object):
  34.     def __init__(self, file):
  35.         self.ending = 0
  36.         self.score = 0
  37.         self.location = 0
  38.         self.power_slots = 0
  39.         self.prop_slots = 0
  40.         self.util_slots = 0
  41.         self.weap_slots = 0
  42.         self.rating = 0
  43.         self.damage = 0
  44.         self.damage_taken = 0
  45.         self.turns_passed = 0
  46.         self.shots_fired = 0
  47.         self.melee = 0
  48.         self.max_alert = 0
  49.         self.low_sec = 0
  50.         self.hacks = 0
  51.         self.success_hacks = 0
  52.         self.actions = 0
  53.         self.visited = 0
  54.         self.route = []
  55.         self.play_time = 0
  56.        
  57.         self.parse(file)
  58.  
  59.     def parse(self, file):
  60.         for line in file:
  61.             line_split = line.split()
  62.            
  63.             if '---[' in line:
  64.                 self.ending = line.strip()
  65.            
  66.             # Performance
  67.             if 'TOTAL SCORE:' in line:
  68.                 self.score = int(line_split[-1])
  69.                
  70.             # Cogmind
  71.             if 'Location' in line:
  72.                 self.location = ' '.join(line_split[1:])
  73.            
  74.             # Parts
  75.             if 'Power (' in line:
  76.                 self.power_slots = int(re.sub("[^0-9.]", "", line_split[-1]))
  77.             if 'Propulsion (' in line:
  78.                 self.prop_slots = int(re.sub("[^0-9.]", "", line_split[-1]))
  79.             if 'Utility (' in line:
  80.                 self.util_slots = int(re.sub("[^0-9.]", "", line_split[-1]))
  81.             if 'Weapon (' in line:
  82.                 self.weap_slots = int(re.sub("[^0-9.]", "", line_split[-1]))
  83.                
  84.             # Peak State
  85.             if '[Rating:' in line:
  86.                 self.rating = int(re.sub("[^0-9.]", "", line_split[-1]))
  87.            
  88.             # Stats
  89.             if 'Damage Inflicted' in line:
  90.                 self.damage = int(line_split[-1])
  91.             if 'Damage Taken' in line:
  92.                 self.damage_taken = int(line_split[-1])
  93.             if 'Turns Passed' in line:
  94.                 self.turns_passed = int(line_split[-1])
  95.             if 'Shots Fired' in line:
  96.                 self.shots_fired = int(line_split[-1])
  97.             if 'Melee Attacks' in line:
  98.                 self.melee = int(line_split[-1])
  99.             if 'Maximum Alert Level' in line:
  100.                 self.max_alert = int(line_split[-1])
  101.             if 'Low Security (%)' in line:
  102.                 self.low_sec = int(line_split[-1])
  103.             if 'Total Hacks' in line:
  104.                 self.hacks = int(line_split[-1])
  105.             if 'Successful' in line:
  106.                 self.success_hacks = int(line_split[-1])
  107.             if 'Actions Taken' in line:
  108.                 self.actions = int(line_split[-1])
  109.                
  110.             # Route
  111.             if 'Regions Visited' in line:
  112.                 self.visited = int(line_split[-1])
  113.             if 'Route' in line:
  114.                 self.route = []
  115.                 for line in file:
  116.                     line_split = line.split()
  117.                     if not line.strip():
  118.                         break
  119.                     if '-------' in line:
  120.                         continue
  121.                     discovered_exits = False
  122.                     discovered_i = 0
  123.                     for i, token in enumerate(line_split):
  124.                         if '(' in token:
  125.                             discovered_exits = True
  126.                             discovered_i = i
  127.                             break
  128.                     if discovered_exits:
  129.                         self.route.append(' '.join(line_split[0:discovered_i]))
  130.                     else:
  131.                         self.route.append(line.strip())
  132.            
  133.             # Game
  134.             if 'Play Time:' in line:
  135.                 self.play_time = int(line_split[-2])
  136.  
  137.         # Derived Stats
  138.         self.score_per_turn = float(self.score) / self.turns_passed if self.turns_passed > 0 else 0.0
  139.         self.turns_per_min = float(self.turns_passed) / self.play_time if self.play_time > 0 else 0.0
  140.         self.success_hack_perc = (float(self.success_hacks) / self.hacks) * 100 if self.hacks > 0 else 0.0
  141.         self.actions_per_min = float(self.actions) / self.play_time if self.play_time > 0 else 0.0
  142.      
  143.        
  144.     def slot_config_plaintext(self):
  145.         return ('[' + str(self.power_slots) + '\\' + str(self.prop_slots) + '\\'
  146.                     + str(self.util_slots) + '\\' + str(self.weap_slots) + ']')
  147.                    
  148.     def __str__(self):            
  149.         return  ('{:<6}'.format(self.score) + '    ' + (' '*((STATS_FIELD_WIDTH-len(self.ending))/2)) + self.ending
  150.                 + '\n' + (' '*STATS_INDENT) + '{:<15}'.format(self.slot_config_plaintext())
  151.                     + 'Rating:    ' + ('%3d' % self.rating) + '  ' + ('{:^19}'.format(self.location))
  152.                 + '\n' + (' '*STATS_INDENT) + 'Shots:   ' + ('%4d' % self.shots_fired)
  153.                     + '  Melee:    ' + ('%4d' % self.melee) + '  Visited:         ' + ('%2d' % self.visited)
  154.                 + '\n' + (' '*STATS_INDENT) + 'Damage         Dealt: ' + ('%7d' % self.damage) + '  Taken:      ' + ('%7d' % self.damage_taken)
  155.                 + '\n' + (' '*STATS_INDENT) + 'Max Alert:  ' + str(self.max_alert) + '  Low Sec:  ' + ('%3d' % self.low_sec)
  156.                     + '%' + '  Hacks: ' + ('%3d' %  self.hacks)
  157.                     + ' (' + ('%5.1f' % self.success_hack_perc) + '%)'
  158.                 + '\n' + (' '*STATS_INDENT) + 'Turns: ' + ('%6d' % self.turns_passed) + '  Time:   ' + time_plaintext(self.play_time)
  159.                     + '  Actions:  ' + ('%9d' % self.actions)
  160.                 + '\n' + (' '*STATS_INDENT) + 'SPT: ' + ('%8.2f' % self.score_per_turn) + '  TPM:  ' + ('%8.2f' % self.turns_per_min)
  161.                     + '  APM:  ' + ('%13.2f' % self.actions_per_min))    
  162.  
  163.     def html_str(self, agg_stats):
  164.         return  (cstr('{:<6}'.format(self.score), COLOR1) + '    ' + (' '*((STATS_FIELD_WIDTH-len(self.ending))/2)) + cstr(self.ending, COLOR1)
  165.                 + '\n' + (' '*STATS_INDENT) + '[' + cstr(self.power_slots, COLOR1) + cstr('\\', COLOR2) + cstr(self.prop_slots, COLOR1) + cstr('\\', COLOR2)
  166.                     + cstr(self.util_slots, COLOR1) + cstr('\\', COLOR2) + cstr(self.weap_slots, COLOR1) + ']'
  167.                     + (' '*(15-len(self.slot_config_plaintext())))
  168.                     + 'Rating:    ' + cstr('%3d' % self.rating, grad_color(self.rating, agg_stats.min_rating, agg_stats.max_rating))
  169.                     + '  ' + cstr('{:^19}'.format(self.location), location_color(self.location))
  170.                 + '\n' + (' '*STATS_INDENT) + 'Shots:   ' + cstr('%4d' % self.shots_fired, COLOR1)
  171.                     + '  Melee:    ' + cstr('%4d' %self.melee, COLOR1) + '  Visited:         ' + cstr('%2d' % self.visited, COLOR1)
  172.                 + '\n' + (' '*STATS_INDENT) + 'Damage         Dealt: ' + cstr('%7d' % self.damage, COLOR1) + '  Taken:      ' + cstr('%7d' % self.damage_taken, COLOR1)
  173.                 + '\n' + (' '*STATS_INDENT) + 'Max Alert:  ' + cstr(self.max_alert, COLOR1) + '  Low Sec:  ' + cstr('%3d' % self.low_sec, COLOR1)
  174.                     + cstr('%', COLOR2) + '  Hacks: ' + cstr('%3d' %  self.hacks, COLOR1)
  175.                     + ' (' + cstr(('%5.1f' % self.success_hack_perc), COLOR1) + cstr('%', COLOR2) + ')'
  176.                 + '\n' + (' '*STATS_INDENT) + 'Turns: ' + cstr('%6d' % self.turns_passed, COLOR1) + '  Time:   ' + time_html(self.play_time)
  177.                     + '  Actions:  ' + cstr('%9d' % self.actions, COLOR1)
  178.                 + '\n' + (' '*STATS_INDENT) + 'SPT: '
  179.                     + cstr('%8.2f' % self.score_per_turn, grad_color(self.score_per_turn, agg_stats.min_score_per_turn, agg_stats.max_score_per_turn))
  180.                     + '  TPM:  ' + cstr('%8.2f' % self.turns_per_min, grad_color(self.turns_per_min, agg_stats.min_turns_per_min, agg_stats.max_turns_per_min))
  181.                     + '  APM:  '
  182.                     + cstr('%13.2f' % self.actions_per_min, grad_color(self.actions_per_min, agg_stats.min_actions_per_min, agg_stats.max_actions_per_min)))
  183.  
  184.                
  185. class AggregateRunStats(object):
  186.     def __init__(self, run_list):
  187.         self.run_list = run_list
  188.        
  189.         self.max_rating = max(run.rating for run in self.run_list)
  190.         self.max_score_per_turn = max(run.score_per_turn for run in self.run_list)
  191.         self.max_actions_per_min = max(run.actions_per_min for run in self.run_list)
  192.         self.max_turns_per_min = max(run.turns_per_min for run in self.run_list)
  193.         self.max_low_sec = max(run.low_sec for run in self.run_list)
  194.         self.max_hacks = max(run.hacks for run in self.run_list)
  195.         self.max_success_hack_perc = max(run.success_hack_perc for run in self.run_list)
  196.         self.max_damage = max(run.damage for run in self.run_list)
  197.        
  198.         self.min_rating = min(run.rating for run in self.run_list)
  199.         self.min_score_per_turn = min(run.score_per_turn for run in self.run_list)
  200.         self.min_actions_per_min = min(run.actions_per_min for run in self.run_list)
  201.         self.min_turns_per_min = min(run.turns_per_min for run in self.run_list)
  202.         self.min_low_sec = min(run.low_sec for run in self.run_list)
  203.         self.min_hacks = min(run.hacks for run in self.run_list)
  204.         self.min_success_hack_perc = min(run.success_hack_perc for run in self.run_list)
  205.         self.min_damage = min(run.damage for run in self.run_list)
  206.        
  207.        
  208. def cstr(string, color_hex):
  209.     return '<font color="#' + color_hex + '">' + str(string) + '</font>'
  210.  
  211. def time_plaintext(play_time):
  212.     if play_time > 60:
  213.         time_str = str(play_time / 60) + 'h' + str(play_time % 60) + 'm'
  214.     else:
  215.         time_str = str(play_time) + 'm'
  216.     return ('{:>' + str(TIME_FIELD_WIDTH) + '}').format(time_str)
  217.    
  218. def time_html(play_time):
  219.     if play_time > 60:
  220.         time_str = (cstr(play_time / 60, COLOR1)  + cstr('h', COLOR2)
  221.                 + cstr(play_time % 60, COLOR1) + cstr('m', COLOR2))
  222.     else:
  223.         time_str = cstr(play_time, COLOR1)  + cstr('m', COLOR2)
  224.     return (' '*(TIME_FIELD_WIDTH - len(time_plaintext(play_time).strip()))) + time_str
  225.  
  226. def grad_color(val, min, max):
  227.     ratio = float((val - min)) / (max - min) if (max - min) != 0 else 0.0;
  228.     for i, col_hex in enumerate(COL_GRAD):
  229.         if ratio <= float(i + 1) / len(COL_GRAD):
  230.             return col_hex
  231.     return FOREGROUND_COLOR
  232.    
  233. def location_color(loc):
  234.     if 'Materials' in loc or 'Scrapyard' in loc:
  235.         return '9e8664'
  236.     if 'Mines' in loc:
  237.         return '666666'
  238.     if 'Storage' in loc:
  239.         return 'b25900'
  240.     if 'Caves' in loc or 'Zion' in loc:
  241.         return '665233'
  242.     if 'Garrison' in loc:
  243.         return 'b20000'
  244.     if 'Factory' in loc:
  245.         return '9e9e9e'
  246.     if 'Research' in loc:
  247.         return 'bf00ff'
  248.     if 'Quarantine' in loc or 'Testing' in loc:
  249.         return '00b200'
  250.     if 'Armory' in loc:
  251.         return 'ff0000'
  252.     if 'Extension' in loc or 'Hub' in loc:
  253.         return '848400'
  254.     if 'Access' in loc:
  255.         return 'dedede'
  256.     if 'Command' in loc:
  257.         return '00a3d9'
  258.     if 'Warlord' in loc:
  259.         return 'b22d00'
  260.     return '00e100'
  261.    
  262.    
  263. if __name__ == '__main__':
  264.     # Load and sort all run stats
  265.     run_list = []
  266.     for filename in os.listdir('scores'):
  267.         if '.txt' in filename:
  268.             with open(os.path.join('scores', filename), 'r') as f:
  269.                 run_list.append(RunStats(f))
  270.     run_list = sorted(run_list, key=lambda run: run.score, reverse=True)
  271.     agg_stats = AggregateRunStats(run_list)
  272.     # Generate list of locations visisted
  273.     branch_set = set()
  274.     for run in run_list:
  275.         branch_set = branch_set | set(run.route)
  276.     branch_list = sorted(list(branch_set),
  277.         key=lambda branch: int(branch[0:branch.index('/')]) if '/' in branch else branch,
  278.         reverse=True)
  279.    
  280.     # Generate the high score plaintext output
  281.     datetime_str = datetime.datetime.now().strftime("%I:%M%p, %B %d, %Y")
  282.     out_str =  '\n -----------------------------\n'
  283.     out_str += '  --[ COGMIND HIGH SCORES ]--\n'
  284.     out_str += ' -----------------------------\n   '
  285.     out_str += datetime_str + '\n\n'
  286.     for i, run in enumerate(run_list):
  287.         if i > 0: out_str += '\n\n'
  288.         out_str += '{:<6s}'.format(str(i + 1) + '.') + str(run)
  289.     total_time = sum(run.play_time for run in run_list)
  290.     out_str += '\n\nTotal Time: ' + str(total_time / 60) + 'h' + str(total_time % 60) + 'm'
  291.     out_str += '\n\n Locations Visited'
  292.     out_str += '\n-------------------'
  293.     for branch in branch_list:
  294.         out_str += '\n' + str(branch)
  295.     # Write the plaintext output to file
  296.     with open(os.path.join(os.getcwd(), 'high_scores.txt'), 'w') as f:
  297.         f.write(out_str)
  298.     # Write the plaintext output to stdout
  299.     print out_str
  300.    
  301.     # Generate the high score HTML output
  302.     out_html = '<html><body text="#' + FOREGROUND_COLOR + '" bgcolor="#' + BACKGROUND_COLOR + '"><pre>'
  303.     out_html += '\n -----------------------------\n'
  304.     out_html += '  --[ ' + cstr('COGMIND HIGH SCORES', COLOR1) + ' ]--\n'
  305.     out_html += ' -----------------------------\n   '
  306.     out_html += cstr(datetime_str, COLOR1) + '\n\n'
  307.     for i, run in enumerate(run_list):
  308.         if i > 0: out_html += '\n\n'
  309.         out_html += cstr(i + 1, COLOR1) + '.' + (' '*(6-len(str(i))-1)) + run.html_str(agg_stats)
  310.     out_html += '\n\nTotal Time: ' + time_html(total_time)
  311.     out_html += '\n\n ' + cstr('Locations Visited', COLOR1)
  312.     out_html += '\n-------------------'
  313.     for branch in branch_list:
  314.         out_html += '\n' + cstr(branch, location_color(branch))
  315.     out_html += '</body></html>'
  316.     # Write the HTML output to file
  317.     with open(os.path.join(os.getcwd(), 'high_scores.html'), 'w') as f:
  318.         f.write(out_html)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement