6
\$\begingroup\$

Intro

Cookie Clicker is a popular browser game in which the player has to click a cookie to gain... Cookies!
The player can buy upgrades which will automatically farm cookies for you. Sometimes a golden cookie will enter the screen, which will provide a bonus upon clicking it.

Challenge

This challenge will not be about clicking a cookie. It will be about automating the cookie.
The player starts off with 0 cookies, and will gain cookies on every game tick. The goal of the challenge is to calculate the amount of ticks it takes to reach a certain amount of cookies.

Input

Your program or function will have 2 input parameters.
The first parameter is the goal, which is simply the amount of cookies you need to finish.
The second parameter is a list of upgrades the player can buy. The format of the list will be explained in further detail in the paragraph Upgrades - List format.
For sake of convenience, you may assume that the input is always in the correct format. You don't have to deal with bad input.

Output

Your program or function should print or return the amount of ticks it takes before the player has reached the goal amount of cookies.

Upgrades

Every game-tick will earn the player some cookies. These are based on the upgrades of the player. If a player has no upgrades, the cookie production will be 1 cookie per tick. Once the player reaches enough cookies to buy an upgrade, he will automatically purchase it (before the next tick happens).
When the player has enough cookies after a tick to buy multiple upgrades, he will attempt to buy all possible upgrades, starting with the cheapest.

List format

[[100, '+', 1],[1000, '*', 2],[10000, '*', 10]
This is an unordered list which contains 3 upgrades. The first parameter of an upgrade is the price of the upgrade. The second parameter is the effect of the upgrade and the third parameter is the effect amount.
The input list will contain no upgrades with the same price.
The only possible effects are + (addition) and * (multiplication).
[100, '+', 1] means that the cookie production will increase by 1 at a cost of 100 cookies.

Golden cookies

Every 1000 ticks, the player will find a golden cookie. When this happens, the player will receive a bonus of 10% (rounded down) of his cookie amount. If the player has 1000 cookies at tick 1000, he will have 1100 cookies before tick 1001 happens.

Order of events

After every tick a couple of actions can occur.

  1. If the player has enough cookies, end the game
  2. If the player has enough cookies, purchase upgrades
  3. If the amount of ticks is a multiple of 1000; Golden cookie

Example input + output

(0    , [])                              -> 0
(100  , [])                              -> 100
(1    , [[10, '+', 1]])                  -> 1
(10   , [[10, '+', 1]])                  -> 10
(1000 , [[100, '*', 2], [10, '+', 1]])   -> 310
(10000, [[10, '+', 1], [100, '*', 2]])   -> 2263

Detailed example

(1000 , [[100, '*', 2], [10, '+', 1]])   -> 310

ticks: 8, cookies: 8, production: 1
ticks: 9, cookies: 9, production: 1
ticks: 10, cookies: 0, production: 2
ticks: 11, cookies: 2, production: 2
ticks: 58, cookies: 96, production: 2
ticks: 59, cookies: 98, production: 2
ticks: 60, cookies: 0, production: 4
ticks: 61, cookies: 4, production: 4
ticks: 70, cookies: 40, production: 4
ticks: 80, cookies: 80, production: 4
ticks: 260, cookies: 800, production: 4
ticks: 280, cookies: 880, production: 4
ticks: 300, cookies: 960, production: 4
ticks: 309, cookies: 996, production: 4
ticks: 310, cookies: 1000, production: 4 -- done

Disclaimer

I will not be held responsible for any addictions caused by this challenge.

Happy golfing!

\$\endgroup\$
  • 1
    \$\begingroup\$ Totally unrelated, but if anyone gets really, really adicted to CC: github.com/niwhsa9/Cookie-Clicker-Bot \$\endgroup\$ – Ashwin Gupta Apr 5 '16 at 22:21
  • 1
    \$\begingroup\$ Related problem at the Google Code Jam. Google got me addicted to the game :p \$\endgroup\$ – aditsu Apr 6 '16 at 19:52
  • \$\begingroup\$ Some questions: are the upgrades ordered by cost? Can multiple upgrades be bought together in one tick? If there are multiple upgrades to choose from at a certain time, which one should be bought first? \$\endgroup\$ – aditsu Apr 6 '16 at 20:01
  • \$\begingroup\$ @aditsu the input list isn't ordered. They can, but the player will always attempt to buy the cheaper upgrades first. Edited the OP \$\endgroup\$ – Bassdrop Cumberwubwubwub Apr 6 '16 at 21:03
  • \$\begingroup\$ Ok, so the upgrades can be listed in any order. Can there be 2 upgrades with the same cost? If so, which one to buy first? \$\endgroup\$ – aditsu Apr 6 '16 at 21:14
2
\$\begingroup\$

Python2, 177 Bytes

def f(g,u):
 c=t=0;r=1
 while c<g:
    c+=r;t+=1
    if c>=g:break
    u=sorted(u)
    if u[0][0]<=c:
        h=u.pop(0);c-=h[0]
        exec('r'+h[1]+'=h[2]')
    if t%1000<1:c+=c//10
 return t
\$\endgroup\$
  • \$\begingroup\$ You should be able to golf it further by only using 1-space indents. Also, for ==0, use <1. \$\endgroup\$ – Blue Apr 6 '16 at 15:15
  • \$\begingroup\$ @Blue He probably used tabs, but SE converts them to 4 spaces. \$\endgroup\$ – Rɪᴋᴇʀ Apr 6 '16 at 17:54
  • \$\begingroup\$ Also, exec'r'+h[1]+'=h[2]' is shorter than your if/else statement. \$\endgroup\$ – Rɪᴋᴇʀ Apr 6 '16 at 17:59
  • \$\begingroup\$ And if you use python 2, the // can be replaced with /. \$\endgroup\$ – Rɪᴋᴇʀ Apr 6 '16 at 17:59
  • 1
    \$\begingroup\$ In Python 2, you can mix indents, so space and tab can be used for two different indentation levels for only one byte each. \$\endgroup\$ – Mego Apr 7 '16 at 2:45
1
\$\begingroup\$

CJam, 66

q~1$aa+$0{_W$<{{_2$0=0=<!}{\(~X@~:X;@\-}wT):T1e3%{_A/+}|X+}0?}h];T

Try it online

Explanation:

q~            read and evaluate the input (the goal and the array of upgrades)
1$aa+         append a dummy upgrade with the cost equal to the goal
               (to avoid the array becoming empty)
$             sort the upgrades lexicographically (so first by cost)
0             push 0, the initial number of cookies
{…}h          do-while loop, checking the last value as the condition
  _W$<        duplicate the number of cookies and check if it's smaller
               than the goal (at the bottom of the stack)
  {…}         if true… ("<condition><then part><else part>?" is an if statement)
    {…}       while… ("{condition}{block}w" is a while loop)
      _2$     duplicate the number of cookies and the array of upgrades
      0=0=    get the cost (first item) of the first upgrade
      <!      check if the number of cookies is not smaller than it
    {…}       do…
      \(      bring the array of upgrades to the top and take out the first upgrade
      ~       dump the price, effect (operator) and amount onto the stack
      X@      push X (cookie production) and bring the operator to the top
      ~:X;    evaluate the operator and store the result back in X
      @\-     subtract the price from the number of cookies
    w         (end) while
    T):T      increment T (the number of ticks, initially 0)
    1e3%      calculate T % 1000
    {…}|      if false (0) then…
      _A/+    add cookies/10 to the number of cookies (A=10)
    X+        add X (cookie production, initially 1) to the number of cookies
               to go to the next step
               since the result is not 0, the do-while loop continues
  0           else (if we reached the goal) push 0 to exit the loop
  ?           (end) if
];            pop everything left on the stack after the do-while loop
T             push T, the final number of ticks
\$\endgroup\$
0
\$\begingroup\$

Lua, 220 Bytes

Can't think of a way to golf it down for the moment, it's still pretty long mostly because lua doesn't let you use loops carelessly regarding the bit count ^^'

function f(g,u)c=0t=0r=1while(c<g)do c=c+r t=t+1if(c>=g)then break end
for i=1,#u do x=u[i]if(c>=x[1])then c=c-x[1]r=x[2]=="+"and r+x[3]or r*x[3]table.remove(u,i)break
end end c=t%1000<1 and c+c/10or c end return t end

Ungolfed

function f(g,u)
  c=0                       -- cookie counter
  t=0                       -- tick counter
  r=1                       -- cookie gain rate

  while(c<g)                -- iterate while cookie < goal
  do                        -- prevent returning 1 tick when the goal is 0
    c=c+r                   -- gain cookies
    t=t+1                   -- increment the tick counter
    if(c>=g)then break end  -- if we have enough cookies, exit
    for i=1,#u              -- iterate over the upgrades
    do
      x=u[i]                -- alias the current upgrade
      if(c>=x[1])           -- if we can, afford it
      then
        c=c-x[1]            -- deduce its price from our cookies
        r=x[2]=="+"         -- if it was an additive bonus
          and r+x[3]        -- add its value to the rate
          or r*x[3]         -- else multiply the rate by it
        table.remove(u,i)   --remove it from the list of upgrades
        break               -- exit the shop :D
      end
    end
    c=t%1000<1              -- every thousand ticks 
      and c+c/10            -- get a golden cookie
      or c                  -- every other ticks does nothing
  end
  return t                  -- return the number of ticks it took
end

Test Suite

You can copy paste the following code into this online compiler to run all the test cases.

function f(g,u)c=0t=0r=1while(c<g)do c=c+r t=t+1if(c>=g)then break end
for i=1,#u do x=u[i]if(c>=x[1])then c=c-x[1]r=x[2]=="+"and r+x[3]or r*x[3]table.remove(u,i)break
end end c=t%1000<1 and c+c/10or c end return t end
print(f(0,{}))
print(f(100,{}))
print(f(1,{{10,'+',1}}))
print(f(10,{{10,'+',1}}))
print(f(1000,{{10,'+',1},{100,'*',2}}))
print(f(10000,{{10,'+',1},{100,'*',2}}))
\$\endgroup\$
0
\$\begingroup\$

Javascript ES6, 138 bytes

f=(g,s,p=1,c=-1,t=0)=>(c+=p)<g?f(g,s[b=0]?s.slice(b=(z=s.sort()[0])[0]<=c):s,b?eval(`p${z[1]}${z[2]}`):p,(b?c-z[0]:c)*(t%1e3?1:1.1),t+1):t

Ungolfed:

p = 1;  // production
c = -1; // cookies, -1 to account for the first tick
t = 0;  // ticks
f = function(g, s, p, c, t) { // goal, upgrades, production, cookies, ticks
    c += p;        // add production to cookies
    if (c < g) {   // cookies < goal
        b = 0;     // reset buy flag to false

        var upgradeArray;
        if (s[0]) { // our upgrade array isn't empty
            var sortedArray = s.sort();
            var upgrade = sortedArray[0];
            b = upgrade[0] <= c;       // price <= cookies
            upgradeArray = s.slice(b); // if we buy something, we remove the upgrade from the array because [1,2,3].slice(1) -> [2,3]
        } else {                       // our upgrade list is empty
            upgradeArray = s;
        }

        var newProduction;
        if (b) {    // we buy something
            newProduction = eval('p' + upgrade[1] + upgrade[2]) // evaluate p+10 for example
        } else {
            newProduction = p; // production is unchanged
        }

        var newCookies;
        if (b) {    // we buy something
            newCookies = c - upgrade[0]; // substract price from cookies
        } else {
            newCookies = c;
        }

        if (t % 1e3 == 0) {    // ticks % 1000 == 0
            newCookies *= 1.1; // golden cookie
        }

        return f(  // recursive call
            g,     // the goal doesn't change
            upgradeArray,
            newProduction,
            newCookies,
            t+1    // add a tick
        )
    } else {       // we have enough cookies, so we
        return t;  // return the amount of ticks
    }
}

Try it here

f=(g,s,p=1,c=-1,t=0)=>(c+=p)<g?f(g,s[b=0]?s.slice(b=(z=s.sort()[0])[0]<=c):s,b?eval(`p${z[1]}${z[2]}`):p,(b?c-z[0]:c)*(t%1e3?1:1.1),t+1):t

D.innerHTML= [
    f(0    , []),
    f(100  , []),
    f(1    , [[10, '+', 1]]),
    f(10   , [[10, '+', 1]]),
    f(1000 , [[100, '*', 2], [10, '+', 1]]),
    f(10000, [[10, '+', 1], [100, '*', 2]])
].join(`<br>`)
<div id=D>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.