Skip to content

Instantly share code, notes, and snippets.

@gintenlabo
Last active August 29, 2015 14:03
Show Gist options
  • Save gintenlabo/59b403003d0e6d38365d to your computer and use it in GitHub Desktop.
Save gintenlabo/59b403003d0e6d38365d to your computer and use it in GitHub Desktop.
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