Instantly share code, notes, and snippets.
Last active
August 29, 2015 14:03
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save gintenlabo/59b403003d0e6d38365d to your computer and use it in GitHub Desktop.
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 Data.Array (Ix, Array, elems) | |
import Data.Array.ST (STArray, newArray, readArray, writeArray, runSTArray) | |
import Control.Monad.ST (ST, runST) | |
import Control.Monad (forM, forM_) | |
-- helper function to make STArray (When I use newArray simply, GHC says it is ambiguous) | |
newSTArray :: Ix i => (i, i) -> e -> ST s (STArray s i e) | |
newSTArray = newArray | |
-- Cookie Clicker Utilities | |
-- requires more type safety: newtype CpS = CpS Double, Cookies = Cookies Double, and so on | |
-- basic building data (ver 1.0465, thanks to http://cookieclicker.wikia.com/wiki/Buildings) | |
data Building = Cursor | Grandma | Farm | Factory | Mine | Shipment | | |
AlchemyLab | Portal | TimeMachine | AntimatterCondenser | Prism | |
deriving (Read, Show, Enum, Eq, Ord, Bounded, Ix) | |
basePrice :: Building -> Double | |
basePrice Cursor = 15 | |
basePrice Grandma = 100 | |
basePrice Farm = 500 | |
basePrice Factory = 3000 | |
basePrice Mine = 10000 | |
basePrice Shipment = 40000 | |
basePrice AlchemyLab = 200000 | |
basePrice Portal = 1666666 | |
basePrice TimeMachine = 123456789 | |
basePrice AntimatterCondenser = 3999999999 | |
basePrice Prism = 75000000000 | |
priceIncreaseRate :: Double | |
priceIncreaseRate = 1.15 | |
buildingPayBackRate :: Double | |
buildingPayBackRate = 0.5 | |
maxCpSPerBuild :: Building -> Double | |
maxCpSPerBuild Cursor = error "Efficiency of Cursor is depend on other buildings owned" | |
maxCpSPerBuild Grandma = error "Efficiency of Grandma is depend on Grandmas and Portals owned" | |
maxCpSPerBuild Farm = 160 | |
maxCpSPerBuild Factory = 448 | |
maxCpSPerBuild Mine = 1600 | |
maxCpSPerBuild Shipment = 4160 | |
maxCpSPerBuild AlchemyLab = 16000 | |
maxCpSPerBuild Portal = 266624 | |
maxCpSPerBuild TimeMachine = 1738256 | |
maxCpSPerBuild AntimatterCondenser = 35199936 | |
maxCpSPerBuild Prism = 352000000 | |
maxCpSForCursor :: Int -> Double | |
maxCpSForCursor buildingsExcludingCursors = n * 1532.6 + 0.8 where | |
n = fromIntegral buildingsExcludingCursors | |
maxCpSForGrandma :: Int -> Int -> Double | |
maxCpSForGrandma grandmas portals = (0.8 + grandmas' / 25 + portals' / 20) * 262144 where | |
grandmas' = fromIntegral grandmas | |
portals' = fromIntegral portals | |
-- Utilities for playing | |
data BuildingData = BuildingData { | |
buildingType :: Building, | |
buildingCount :: Int, | |
buildingPrice :: Double, | |
buildingCpS :: Double | |
} deriving (Read, Show, Eq) | |
priceOfNextBuilding :: Building -> Int -> Double | |
priceOfNextBuilding b n = basePrice b * priceIncreaseRate ^ n | |
makeBuildingData :: Building -> Int -> BuildingData | |
makeBuildingData b n = BuildingData b n (priceOfNextBuilding b n) (maxCpSPerBuild b) | |
makeCursorData :: Int -> Int -> BuildingData | |
makeCursorData buildingsExcludingCursors cursors = BuildingData { | |
buildingType = Cursor, | |
buildingCount = cursors, | |
buildingPrice = priceOfNextBuilding Cursor cursors, | |
buildingCpS = maxCpSForCursor buildingsExcludingCursors | |
} | |
makeGrandmaData :: Int -> Int -> BuildingData | |
makeGrandmaData portals grandmas = BuildingData { | |
buildingType = Grandma, | |
buildingCount = grandmas, | |
buildingPrice = priceOfNextBuilding Grandma grandmas, | |
buildingCpS = maxCpSForGrandma grandmas portals | |
} | |
adjustBuildingPriceAndCpS :: BuildingData -> BuildingData -> BuildingData | |
adjustBuildingPriceAndCpS ref toBeAdjusted = | |
BuildingData b n (price * price1 / price0) (cps * cps1 / cps0) where | |
BuildingData b n price cps = toBeAdjusted | |
BuildingData b1 n1 price1 cps1 = ref | |
BuildingData _ _ price0 cps0 = makeBuildingData b1 n1 | |
makeEffectiveBuildingData :: BuildingData -> Building -> Int -> BuildingData | |
makeEffectiveBuildingData (BuildingData Cursor n0 price cps) Cursor n1 = | |
BuildingData Cursor n1 (price * price1 / price0) cps where | |
price0 = priceOfNextBuilding Cursor n0 | |
price1 = priceOfNextBuilding Cursor n1 | |
makeEffectiveBuildingData ref@(BuildingData Portal portals _ _) Grandma grandmas = | |
adjustBuildingPriceAndCpS ref $ makeGrandmaData portals grandmas | |
makeEffectiveBuildingData ref b1 n1 = | |
adjustBuildingPriceAndCpS ref $ makeBuildingData b1 n1 | |
makeEffectiveCursorData :: BuildingData -> Int -> Int -> BuildingData | |
makeEffectiveCursorData ref buildingsExcludingCursors cursors = | |
adjustBuildingPriceAndCpS ref $ makeCursorData buildingsExcludingCursors cursors | |
chocolateEggBonus :: Double -> Double | |
chocolateEggBonus cookiesOwned = cookiesOwned * 0.05 | |
effectiveProductionForReset :: Double -> Double | |
effectiveProductionForReset prod = prod + chocolateEggBonus prod | |
paysOffIfBought :: Double -> Double -> BuildingData -> Bool | |
paysOffIfBought cookiesToBake currentCpS (BuildingData _ _ price cps) = | |
loss < gain where | |
loss = chocolateEggBonus (price - sellingPrice) | |
gain = effectiveProductionForReset (span * cps) | |
sellingPrice = price * priceIncreaseRate * buildingPayBackRate | |
span = cookiesToBake / (currentCpS + cps) | |
estimateFirstBuildingWon'tPayOff :: Double -> Double -> Building -> BuildingData -> BuildingData | |
estimateFirstBuildingWon'tPayOff cookiesToBake currentCpS b ref = lastBuildingWillPayOff where | |
lastBuildingWillPayOff = head $ dropWhile paysOff buildings | |
buildings = [makeEffectiveBuildingData ref b n | n <- [0..]] | |
paysOff = paysOffIfBought cookiesToBake currentCpS | |
estimateFirstBuildingsWon'tPayOff :: Double -> Double -> BuildingData -> [BuildingData] | |
estimateFirstBuildingsWon'tPayOff cookiesToBake currentCpS ref = elems $ runSTArray $ do | |
let estimate = estimateFirstBuildingWon'tPayOff cookiesToBake currentCpS | |
result <- newSTArray (minBound :: Building, maxBound) (undefined :: BuildingData) | |
forM_ [Farm ..] $ \b -> do | |
writeArray result b $ estimate b ref | |
portal <- readArray result Portal | |
writeArray result Grandma $ estimate Grandma portal | |
buildingsExcludingCursors <- do | |
buildings <- forM [Grandma ..] $ \b -> readArray result b | |
return $ sum [buildingCount building | building <- buildings] | |
let cursor0 = makeEffectiveCursorData ref buildingsExcludingCursors 0 | |
writeArray result Cursor $ estimate Cursor cursor0 | |
return result |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment