Skip to content

Instantly share code, notes, and snippets.

@haasn
Last active July 24, 2016 08:07
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 haasn/40ca6c650a46fbe68fcc39985e5999f1 to your computer and use it in GitHub Desktop.
Save haasn/40ca6c650a46fbe68fcc39985e5999f1 to your computer and use it in GitHub Desktop.
HeroLine DPS calculator -- NOTE: moved to https://github.com/haasn/heroline
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