Last active
July 24, 2016 08:07
-
-
Save haasn/40ca6c650a46fbe68fcc39985e5999f1 to your computer and use it in GitHub Desktop.
HeroLine DPS calculator -- NOTE: moved to https://github.com/haasn/heroline
This file contains 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 characters
import Control.Monad (replicateM, guard) | |
import Data.Ord (comparing) | |
import Data.List (maximumBy) | |
-- Type definitions | |
data Item = Item | |
{ name :: String | |
, wdmg :: Int | |
, udmg :: Int | |
, admg :: Int | |
, wspeed :: Int | |
, cleave :: Int | |
, cdr :: Int | |
, cc :: Int | |
, chd :: Int | |
, life :: Int | |
, vamp :: Int | |
} deriving Eq | |
item :: Item | |
item = Item { name = "", wdmg = 0, udmg = 0, wspeed = 0, cleave = 0, cdr = 0, | |
cc = 0, chd = 0, admg = 0, life = 0, vamp = 0 } | |
instance Monoid Item where | |
mempty = item | |
mappend a b = Item | |
{ name = name a ++ "+" ++ name b | |
, wdmg = wdmg a + wdmg b | |
, udmg = max (udmg a) (udmg b) | |
, admg = max (admg a) (admg b) | |
, wspeed = wspeed a + wspeed b | |
, cleave = cleave a + cleave b | |
, cdr = cdr a + cdr b | |
, cc = cc a + cc b | |
, chd = chd a + chd b | |
, life = life a + life b | |
, vamp = vamp a + vamp b | |
} | |
-- Hero base stats | |
type Hero = (Item, Item -> Bool) | |
warden :: Hero | |
warden = (item | |
{ name = "Warden" | |
, wdmg = 32 + 59*2 + 30*3 -- base, level, bonus | |
, wspeed = 6 + 59*5 + 30*6 + 50 -- trait, level, bonus, aura | |
, cleave = 150 | |
, cdr = 50 + 15 + 10 | |
}, cond) | |
where cond i = cdr i >= 100 | |
bmBase :: Item | |
bmBase = item | |
{ name = "Blademaster" | |
, wdmg = 28 + 59*2 + 30*3 | |
, wspeed = 6 + 59*5 + 30*6 + 150 -- trait, level, bonus, aura | |
, cc = 25 | |
, chd = 1100 | |
} | |
bm :: Hero | |
bm = (bmBase, const True) | |
bmHP :: Int -> Hero | |
bmHP hp = (bmBase, \i -> life i >= hp) | |
bmVampHP :: Int -> Hero | |
bmVampHP hp = (bmBase, \i -> life i >= hp && vamp i > 0) | |
-- Item list | |
kang :: Item | |
kang = item | |
{ name = "Kang" | |
, wdmg = 900 | |
, cleave = 30 | |
} | |
glaive :: Item | |
glaive = item | |
{ name = "Firestrike Glaive" | |
, wdmg = 700 | |
, cdr = 30 | |
, udmg = 25 | |
} | |
seren :: Item | |
seren = item | |
{ name = "Serendipity" | |
, wspeed = 100 | |
, wdmg = 1000 | |
} | |
coil :: Item | |
coil = item | |
{ name = "Alexandrite Coil" | |
, wspeed = 200 | |
, wdmg = 750 | |
} | |
shatter :: Item | |
shatter = item | |
{ name = "Sunshatter" | |
, wdmg = 650 | |
, vamp = 5 | |
} | |
signet :: Item | |
signet = item | |
{ name = "Bloodstone Signet" | |
, life = 25000 | |
, wdmg = 750 | |
} | |
seal :: Item | |
seal = item | |
{ name = "Rhinestone Seal" | |
, life = 15000 | |
, wdmg = 450 | |
, wspeed = 100 | |
} | |
wall :: Item | |
wall = item | |
{ name = "Hellscream's Shield Wall" | |
, life = 40000 | |
, wdmg = 500 | |
} | |
weave :: Item | |
weave = item | |
{ name = "Blackfang Weave" | |
, life = 40000 | |
, wspeed = 100 | |
, admg = 15 | |
} | |
items :: [Item] | |
items = [kang, glaive, seren, coil, shatter, signet, seal, wall, weave] | |
-- DPS calculation | |
single :: Item -> Double | |
single i = get wdmg * (1 + get udmg / 100) * (1 + get wspeed / 100) | |
* (1 + crit) * (1 + get admg / 100) / rate | |
where get f = fromIntegral (f i) | |
crit = (get cc / 100) * (get chd / 100 - 1) | |
rate = 1.20 -- hard swing rate | |
multi :: Item -> Double | |
multi i = single i * (get cleave / 100) | |
where get f = fromIntegral (f i) | |
mix :: Double -> Item -> Double | |
mix n i = (single i + n * multi i) / (n+1) | |
-- Optimization (brute force) | |
distribute :: Int -> [a] -> [[a]] | |
distribute 0 _ = [[]] | |
distribute _ [] = [] | |
distribute n (x:xs) = do | |
c <- [0..n] | |
r <- distribute (n-c) xs | |
return $ replicate c x ++ r | |
optimize' :: Hero -> (Item -> Double) -> Item | |
optimize' (base, cond) dmg = maximumBy (comparing dmg) $ do | |
build <- distribute 6 items | |
let stats = mconcat (base : build) | |
guard (cond stats) | |
return stats | |
optimize :: Hero -> (Item -> Double) -> (Double, String) | |
optimize hero dmg = (dmg b, name b) | |
where b = optimize' hero dmg |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment