"""
Cookie Clicker Simulator
"""
import simpleplot
import math
import random
# Used to increase the timeout, if necessary
import codeskulptor
codeskulptor.set_timeout(20)
import poc_clicker_provided as provided
# Constants
SIM_TIME = 10000000000.0
#SIM_TIME = 1000
# Helper function
def max_idx_limit(data, limit='inf'):
"""
return a list of index and value of
maximun values in data
"""
maxvals = []
for idx in range(len(data)):
item = data[idx]
if item > limit:
continue
elif len(maxvals) == 0:
maxvals.append((idx, item))
elif item == maxvals[0][1]:
maxvals.append((idx, item))
elif item > maxvals[0][1]:
maxvals = [(idx, item)]
return maxvals
def min_idx(data):
"""
return a list of index and value of
minimun values in data
"""
minvals = []
for idx in range(len(data)):
item = data[idx]
if len(minvals) == 0:
minvals.append((idx, item))
elif item == minvals[0][1]:
minvals.append((idx, item))
elif item < minvals[0][1]:
minvals = [(idx, item)]
return minvals
class ClickerState:
"""
Simple class to keep track of the game state.
"""
def __init__(self):
self._cookies_baked = 0.0
self._cookies_in_bank = 0.0
self._cookies_per_second = 1.0
self._session_time = 0.0
# history : (time, item, cost of item, total cookies)
self._session_history = [(0.0, None, 0.0, 0.0)]
self._time_until = 'inf'
def __str__(self):
"""
Return human readable state
"""
#return str([self._session_time, self._cookies_in_bank, self._cookies_per_second, self._cookies_baked])
return str("================================\n" +
"Game Time: " + str(self._session_time) + "\n" +
"Cookies in Bank: " + str(self._cookies_in_bank) + "\n" +
"Cookies per Second: " + str(self._cookies_per_second) + "\n" +
"Cookies Baked: " + str(self._cookies_baked))
def get_cookies(self):
"""
Return current number of cookies
(not total number of cookies)
Should return a float
"""
return self._cookies_in_bank
def get_cps(self):
"""
Get current CPS
Should return a float
"""
return self._cookies_per_second
def get_time(self):
"""
Get current time
Should return a float
"""
return self._session_time
def get_history(self):
"""
Return history list
History list should be a list of tuples of the form:
(time, item, cost of item, total cookies)
For example: [(0.0, None, 0.0, 0.0)]
Should return a copy of any internal data structures,
so that they will not be modified outside of the class.
"""
return list(self._session_history)
def time_until(self, cookies):
"""
Return time until you have the given number of cookies
(could be 0.0 if you already have enough cookies)
Should return a float with no fractional part
"""
if cookies <= self._cookies_in_bank:
self._time_until = 0.0
else:
self._time_until = math.ceil((cookies - self._cookies_in_bank) / self._cookies_per_second)
return self._time_until
def wait(self, time):
"""
Wait for given amount of time and update state
Should do nothing if time <= 0.0
"""
# increase the time, the current number of cookies,
# and the total number of cookies.
if time > 0:
self._session_time += time
self._cookies_in_bank += self._cookies_per_second * time
self._cookies_baked += self._cookies_per_second * time
def buy_item(self, item_name, cost, additional_cps):
"""
Buy an item and update state
Should do nothing if you cannot afford the item
"""
# adjust the current number of cookies, the CPS,
# and add an entry into the history.
if self._cookies_in_bank >= cost:
self._cookies_in_bank -= cost
self._cookies_per_second += additional_cps
self._buy_item_time = float(self._session_time)
self._buy_item_cookies_baked = float(self._cookies_baked)
self._session_history.append((self._buy_item_time, item_name, cost, self._buy_item_cookies_baked))
def simulate_clicker(build_info, duration, strategy):
"""
Function to run a Cookie Clicker game for the given
duration with the given strategy. Returns a ClickerState
object corresponding to the final state of the game.
"""
clicker_state = ClickerState()
while clicker_state.get_time() <= duration:
# use the strategy to decide the item to purchase
# break loop if no item to be purchased
build_info_clone = build_info.clone()
cookies = clicker_state.get_cookies()
cps = clicker_state.get_cps()
history = clicker_state.get_history()
time_left = duration - clicker_state.get_time()
item_name = strategy(cookies, cps, history, time_left, build_info_clone)
if item_name == None:
clicker_state.wait(time_left)
break
#print "item_name:", item_name
# cost and cps for the item
cost = build_info_clone.get_cost(item_name)
additional_cps = build_info_clone.get_cps(item_name)
# check weather there is enough cookies in bank to purchase the item
if cookies >= cost:
time_to_purchase = 0
elif clicker_state.time_until(cost) > time_left:
time_to_purchase = time_left
else:
time_to_purchase = clicker_state.time_until(cost)
# update the status to time_to_purchase
clicker_state.wait(time_to_purchase)
clicker_state.buy_item(item_name, cost, additional_cps)
# update the item cost
build_info.update_item(item_name)
if cookies < cost and clicker_state.time_until(cost) > time_left:
break
#print clicker_state
return clicker_state
def strategy_cursor_broken(cookies, cps, history, time_left, build_info):
"""
Always pick Cursor!
Note that this simplistic (and broken) strategy does not properly
check whether it can actually buy a Cursor in the time left. Your
simulate_clicker function must be able to deal with such broken
strategies. Further, your strategy functions must correctly check
if you can buy the item in the time left and return None if you
can't.
"""
return "Cursor"
def strategy_none(cookies, cps, history, time_left, build_info):
"""
Always return None
This is a pointless strategy that will never buy anything, but
that you can use to help debug your simulate_clicker function.
"""
return None
def strategy_cheap(cookies, cps, history, time_left, build_info):
"""
Always buy the cheapest item you can afford in the time left.
"""
build_info_cheap = build_info.clone()
item_cost_list = [build_info_cheap.get_cost(item) for item in build_info_cheap.build_items()]
# get the cheapest cost and index
index_cost_list = min_idx(item_cost_list)
if index_cost_list[0][1] > cookies + cps * time_left:
return None
else:
index = random.choice(index_cost_list)[0]
return build_info_cheap.build_items()[index]
def strategy_expensive(cookies, cps, history, time_left, build_info):
"""
Always buy the most expensive item you can afford in the time left.
"""
build_info_expensive = build_info.clone()
item_cost_list = [build_info_expensive.get_cost(item) for item in build_info_expensive.build_items()]
# get the affordable cost in the time left.
afford_cost = cookies + cps * time_left
# get the expensive cost you can afford in the time left
index_cost_list = max_idx_limit(item_cost_list, afford_cost)
if len(index_cost_list) == 0:
return None
else:
index = random.choice(index_cost_list)[0]
return build_info_expensive.build_items()[index]
def strategy_best(cookies, cps, history, time_left, build_info):
"""
The best strategy that you are able to implement.
Best : ================================
Game Time: 10000000000.0
Cookies in Bank: 2.47909661207e+12
Cookies per Second: 139876516.0
Cookies Baked: 1.31434696714e+18
"""
build_info_best = build_info.clone()
# get the affordable cost in the time left.
afford_cost = cookies + cps * time_left
item_list = []
qor_list = []
prod_dict = {}
# get the item list you can afford in the time left
for item in build_info_best.build_items():
if build_info_best.get_cost(item) <= afford_cost:
item_list.append(item)
item_cps = build_info_best.get_cps(item)
item_cost = build_info_best.get_cost(item)
item_time = math.ceil((item_cost) / cps)
item_qor = item_cps / (item_cost * (cps + item_cps))
item_prod = item_cps * math.ceil(time_left - item_time)
item_k = 2
if time_left // item_time < 20:
item_k **= (time_left // item_time)
prod_dict[item] = item_prod * item_k
qor_list.append(item_qor)
#print item, item_cost, item_qor
#print "------------------------------------"
if len(item_list) == 0:
return None
else:
index = random.choice(max_idx_limit(qor_list))[0]
item_best = item_list[index]
for item in prod_dict:
if build_info_best.get_cost(item) < build_info_best.get_cost(item_best):
if prod_dict[item] > prod_dict[item_best]:
item_best = item
return item_best
def run_strategy(strategy_name, time, strategy):
"""
Run a simulation for the given time with one strategy.
"""
state = simulate_clicker(provided.BuildInfo(), time, strategy)
print strategy_name, ":", state
# Plot total cookies over time
# Uncomment out the lines below to see a plot of total cookies vs. time
# Be sure to allow popups, if you do want to see it
history = state.get_history()
history = [(item[0], item[3]) for item in history]
simpleplot.plot_lines(strategy_name, 1000, 400, 'Time', 'Total Cookies', [history], True)
def run():
"""
Run the simulator.
"""
#run_strategy("Cursor", SIM_TIME, strategy_cursor_broken)
# Add calls to run_strategy to run additional strategies
#run_strategy("Cheap", SIM_TIME, strategy_cheap)
#run_strategy("Expensive", SIM_TIME, strategy_expensive)
run_strategy("Best", SIM_TIME, strategy_best)
run()
#
Principles of Computing (Part 1) -- Week 5 Mini-projects: Cookie Clicker Simulator
最新推荐文章于 2024-05-26 18:53:36 发布