Created
December 17, 2012 15:13
-
-
Save badp/4319017 to your computer and use it in GitHub Desktop.
Revisions
-
badp revised this gist
Dec 17, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -230,7 +230,7 @@ def inputWeapon(): dmg = raw_input("Damage:") if "x" in dmg: dmg, pellets = dmg.split("x") pellets = int(pellets) else: pellets = 1 dmg = float(dmg) -
badp renamed this gist
Dec 17, 2012 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
badp created this gist
Dec 17, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,253 @@ """ This is terribly written but still it should give you a broad idea of whether or not a gun is better than the other or not. This keeps track of: * Damage * Fire rate * Reload time * Magazine * Elemental damage * Damage type (vs flesh, shield, armor) * Playthrough (by default the second) * Optionally accuracy (but not by default) * Optionally recoil (but not by default) Example execution: ================================= Damage:3316 Accuracy:95.7 Fire rate:8.7 Reload time:2.7 Magazine:25 Element (empty or f'ire, s'hock, c'orrosive, e'xplosive): s Elemental DPS:3191.1 Elemental chance:10 DPS: Damage( 17,892.65 Flesh, 17,892.65 Armor, 44,731.62 Shield) ================================= Damage:5255 Accuracy:91 Fire rate:5.5 Reload time:2.3 Magazine:24 Element (empty or f'ire, s'hock, c'orrosive, e'xplosive): s Elemental DPS:2823.9 Elemental chance:12.9 DPS: Damage( 21,022.29 Flesh, 21,022.29 Armor, 52,555.74 Shield) ================================= """ # The dumbest possible approach to measuring DPS from __future__ import division import collections from random import random from operator import itemgetter elementLength = {"fire": 8, "shock": 2, "corrosive": 8, "slag": 0, #8, "explosive": 0, None: 0} class Damage(): def __init__(self, flesh = 0, armor = 0, shield = 0): self.flesh = flesh self.armor = armor self.shield = shield def __iter__(self): yield self.flesh yield self.armor yield self.shield def __str__(self): return "Damage({0.flesh:10,.2f} Flesh, {0.armor:10,.2f} Armor, {0.shield:10,.2f} Shield)".format(self) def __add__(this, that): return Damage(*(a+b for a, b in zip(this, that))) def __mul__(this, that): return Damage(*(a*that for a in this)) def __truediv__(this, that): return Damage(*(a/that for a in this)) def add(self, value, element, playthrough): damage = damageMults[element][playthrough] * value self.flesh += damage.flesh self.armor += damage.armor self.shield += damage.shield damageMults = { #NESTED DICTIONARIES HO! None: {1: Damage(1 , 0.8 , 1), 2: Damage(1 , 0.8 , 1 )}, "slag": {1: Damage(1 , 0.8 , 1), 2: Damage(1 , 0.8 , 1 )}, "fire": {1: Damage(1.5, 0.75, 0.75), 2: Damage(1.75, 0.4 , 0.4)}, "shock": {1: Damage(1 , 1 , 2), 2: Damage(1 , 1 , 2.5)}, "corrosive": {1: Damage(0.9, 1.5, 0.75), 2: Damage(0.6 , 1.75, 0.4)}, "explode": {1: Damage(1 , 1 , 0.8), 2: Damage(1 , 1 , 0.8)} } Weapon = collections.namedtuple("Weapon", ["damage", "pelletCount", "accuracy", "fireRate", "reloadTime", "magazine", "element", "elementChance", "elementDPS"]) ##BonusStats = collections.namedtuple("BonusStats", ## ["health", ## "shield", ## "shieldDelay", ## "shieldRate", ## "melee", ## "grenade", ## "accuracy", ## "damage", ## "rate", ## "recoil", ## "reload", ## "elementChance", ## "elementDamage", ## "critical"]) #OH MY FUCKING GOD class BonusStats(tuple): 'BonusStats(health, shield, shieldDelay, shieldRate, melee, grenade, accuracy, damage, rate, recoil, reload, elementChance, elementDamage, critical)' __slots__ = () _fields = ('health', 'shield', 'shieldDelay', 'shieldRate', 'melee', 'grenade', 'accuracy', 'damage', 'rate', 'recoil', 'reload', 'elementChance', 'elementDamage', 'critical') def __new__(_cls, health, shield, shieldDelay, shieldRate, melee, grenade, accuracy, damage, rate, recoil, reload, elementChance, elementDamage, critical): 'Create new instance of BonusStats(health, shield, shieldDelay, shieldRate, melee, grenade, accuracy, damage, rate, recoil, reload, elementChance, elementDamage, critical)' return tuple.__new__(_cls, (health, shield, shieldDelay, shieldRate, melee, grenade, accuracy, damage, rate, recoil, reload, elementChance, elementDamage, critical)) @classmethod def _make(cls, iterable, new=tuple.__new__, len=len): 'Make a new BonusStats object from a sequence or iterable' result = new(cls, iterable) if len(result) != 14: raise TypeError('Expected 14 arguments, got %d' % len(result)) return result def __repr__(self): 'Return a nicely formatted representation string' return 'BonusStats(health=%r, shield=%r, shieldDelay=%r, shieldRate=%r, melee=%r, grenade=%r, accuracy=%r, damage=%r, rate=%r, recoil=%r, reload=%r, elementChance=%r, elementDamage=%r, critical=%r)' % self def _asdict(self): 'Return a new OrderedDict which maps field names to their values' return OrderedDict(zip(self._fields, self)) def _replace(_self, **kwds): 'Return a new BonusStats object replacing specified fields with new values' result = _self._make(map(kwds.pop, ('health', 'shield', 'shieldDelay', 'shieldRate', 'melee', 'grenade', 'accuracy', 'damage', 'rate', 'recoil', 'reload', 'elementChance', 'elementDamage', 'critical'), _self)) if kwds: raise ValueError('Got unexpected field names: %r' % kwds.keys()) return result def __getnewargs__(self): 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) def _itemgetter(x): def g(obj): return 1 + obj[x]/100 return g health = property(_itemgetter(0), doc='Alias for field number 0') shield = property(_itemgetter(1), doc='Alias for field number 1') shieldDelay = property(_itemgetter(2), doc='Alias for field number 2') shieldRate = property(_itemgetter(3), doc='Alias for field number 3') melee = property(_itemgetter(4), doc='Alias for field number 4') grenade = property(_itemgetter(5), doc='Alias for field number 5') accuracy = property(_itemgetter(6), doc='Alias for field number 6') damage = property(_itemgetter(7), doc='Alias for field number 7') rate = property(_itemgetter(8), doc='Alias for field number 8') recoil = property(_itemgetter(9), doc='Alias for field number 9') reload = property(_itemgetter(10), doc='Alias for field number 10') elementChance = property(_itemgetter(11), doc='Alias for field number 11') elementDamage = property(_itemgetter(12), doc='Alias for field number 12') critical = property(_itemgetter(13), doc='Alias for field number 13') zeroStats = BonusStats(0,0,0,0,0,0,0,0,0,0,0,0,0,0) #Example stormingVexation = Weapon(1140, 1, 92.9, 8.0, 2.5, 27, "shock", 1620.5, 18.7) myStats = BonusStats(7.6, 7.6, 6.8, 5.2, 5.6, 3.3, 6.8, 7.6, 7.6, 7.6, 7.2, 7.2, 4.3, 6.8) def dps(weapon, playthrough = 2, bonusStats = zeroStats, referenceTime = 60, accuracyAdjusting = lambda x: 1, # lambda x: x**(1/3), accountForRecoilInVastlyBogusWays = False): time = 0 damage = Damage(0,0,0) ammoCount = weapon.magazine recoilMalus = 0 while time <= referenceTime: time += 1/(weapon.fireRate * bonusStats.rate) for i in xrange(weapon.pelletCount): if random() < accuracyAdjusting(weapon.accuracy/100 * bonusStats.accuracy + recoilMalus): damage.add(weapon.damage * bonusStats.damage, weapon.element, playthrough) if weapon.element: if random() < weapon.elementChance/100 * bonusStats.elementChance: damage.add(weapon.elementDPS * bonusStats.elementDamage * elementLength[weapon.element], weapon.element, playthrough) #are elemental ticks actually affected as well? ammoCount -= 1 if accountForRecoilInVastlyBogusWays: recoilMalus -= 0.01 * 1/bonusStats.recoil if ammoCount == 0: time += weapon.reloadTime * bonusStats.reload ammoCount = weapon.magazine recoilMalus = 0 return damage/time # Weapon = collections.namedtuple("Weapon", # ["damage", # "pelletCount", # "accuracy", # "fireRate", # "reloadTime", # "magazine", # "element", # "elementChance", # "elementDPS"]) def inputWeapon(): elements = {"": None, "f": "fire", "s": "shock", "c": "corrosive", "g": "slag", "e": "explode"} dmg = raw_input("Damage:") if "x" in dmg: dmg, pellets = dmg.split("x") pellets = float(pellets) else: pellets = 1 dmg = float(dmg) accuracy = float(raw_input("Accuracy:")) fireRate = float(raw_input("Fire rate:")) reloadTime = float(raw_input("Reload time:")) magazine = int(raw_input("Magazine:")) element = elements[raw_input("Element (empty or f'ire, s'hock, c'orrosive, e'xplosive): ")] if element in ("fire", "shock", "corrosive"): elDPS = float(raw_input("Elemental DPS:")) chance = float(raw_input("Elemental chance:")) else: elDPS, chance = 0, 0 return Weapon(dmg, pellets, accuracy, fireRate, reloadTime, magazine, element, chance, elDPS) while True: print "=================================" wep = inputWeapon() print "" print "DPS: ", dps(wep)