第二个mini project是实现游戏cookie clicker。这个游戏本身很无聊。
这次的Project完全没有算法难度,估计这次的Project的用意是让人体会将实际问题建模为类和翻译为代码。
1 数学知识准备
1.1 求和相关的数学公式(略)
log运算 https://class.coursera.org/principlescomputing-001/wiki/view?page=log_and_exp
数学表达式 https://class.coursera.org/principlescomputing-001/wiki/view?page=math_expressions
1.2 Log 和Plotting
通过Log和plotting来判断多项式的维度。
log(y)=log(axn)
log(y)=log(a)+nlog(x)
If the data points (xi,yi) lie on y=axn, then they must satisfy the equation
log(yi)=log(a)+nlog(xi)
where log(a) and n are constants. This observation suggests a strategy for determining whether the data points lie close to a polynomial function. Plot the data points (log(xi),log(yi)) and check whether these data points lie near a straight line. If they do, the original data points (xi,yi) lie near a polynomial function. Moreover, the degree of this polynomial is simply the slope of this line.
Many plotting packages support this kind of analysis by offering a log/log plotting option. Under this option, the axes are labelled with the various values of the x and y. However, these labels and the plotted data are positioned at the locationslog(x) and log(y). For example, plots with axes labeled 1,10,100,1000,... are usually log/log plots.
2 Higher-Order Functions
2.1 把函数作为另外一个函数的参数
def double(val):
return 2 * val
def square(val):
return val ** 2
def twice(func, val):
return func(func(val));
print twice(double,3)
print twice(square,3)
2.2 demo: area under curve
def area(func, low, high, stepsize):
total = 0;
loc = low;
while loc<high:
total += func(loc) * stepsize;
loc +=stepsize;
return total
def g(x):
return x;
def h(x):
return x **2;
print area(g, 0, 10, 0.01)
print area(h, 0, 10, 0.01)
3 使用map
把函数作为map的参数
list1 = [1,3,6,8,9]
list2 = [x*2 for x in list1]
print list2
def double(val):
return 2 * val
list3 = map(double, list1)
print list3
4 使用filter
把函数作为filter的参数
def even(val):
if val % 2 == 0:
return True
else:
return False
list4 = filter(even, list3)
print list4
4 mini-project
Note that simulate_clicker is a higher-order function: it takes a strategy function as an argument!
5 我的代码:
"""
Cookie Clicker Simulator 最后提交测试的时候,有一个case中的一个数字有些小问题,得到98分,还没有找到问题原因。
"""
import simpleplot
import math
# Used to increase the timeout, if necessary
import codeskulptor
codeskulptor.set_timeout(20)
import poc_clicker_provided as provided
# Constants
SIM_TIME = 10000000000.0
class ClickerState:
"""
Simple class to keep track of the game state.
"""
def __init__(self):
self._total_game_cookies = 0.0
self._current_cookies= 0.0
self._current_time = 0.0
self._current_cps = 1.0
self._history_list = [(0.0, None, 0.0, 0.0)]
def __str__(self):
"""
Return human readable state
"""
# res = ""
# for each_item in self.history_list:
# res += str(each_item) + "\n"
# return res
return "\nmy total cookies: "+str(self._total_game_cookies) + "\ncurrent cookies: " + str(self._current_cookies) + "\ncurrent time: " + str(self._current_time) + "\ncurrent CPS: " +str(self._current_cps)
def get_cookies(self):
"""
Return current number of cookies
(not total number of cookies)
Should return a float
"""
return self._current_cookies
def get_cps(self):
"""
Get current CPS
Should return a float
"""
return self._current_cps
def get_time(self):
"""
Get current time
Should return a float
"""
return self._current_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)
"""
return self._history_list
def time_until(self, cookies):
"""
Return time until you have the given number of cookies
(could be 0 if you already have enough cookies)
Should return a float with no fractional part
"""
if cookies <= self.get_cookies():
return 0.0
else:
return float(math.ceil((cookies-self.get_cookies())/self.get_cps()))
def wait(self, time):
"""
Wait for given amount of time and update state
Should do nothing if time <= 0
"""
if time<=0:
return
# 如何真正模拟How to simulate waiting for the given amout of time?
self._current_time += time
self._current_cookies += time * self._current_cps
self._total_game_cookies += time * self._current_cps;
def buy_item(self, item_name, cost, additional_cps):
"""
Buy an item and update state
Should do nothing if you cannot afford the item
"""
if self._current_cookies < cost:
return
self._history_list.append((self._current_time, item_name, cost, self._total_game_cookies))
self._current_cookies -= cost;
self._current_cps += additional_cps
# print str(item_name) + "--" + str(self._current_time) + "--" + str(self._current_cookies) + "--" + str(self._current_cps) + "--" + str(self._total_game_cookies)
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 game.
"""
# Replace with your code
build_info_clone = build_info.clone()
new_clikcer_state = ClickerState()
while new_clikcer_state.get_time()<duration:
# print "A-1"
if new_clikcer_state.get_time()>duration: #本句可省略?
break
suggested_item = strategy(new_clikcer_state.get_cookies(), new_clikcer_state.get_cps(),duration - new_clikcer_state.get_time(), build_info_clone)
# print "A-2"
if suggested_item == None:
new_clikcer_state.wait(duration - new_clikcer_state.get_time())
# print "A-3"
else:
cookies_needed = build_info_clone.get_cost(suggested_item)
cps_added = build_info_clone.get_cps(suggested_item)
time_needed = new_clikcer_state.time_until(cookies_needed)
# print "A-4"
if time_needed + new_clikcer_state.get_time() > duration:
new_clikcer_state.wait(duration - new_clikcer_state.get_time())
# print "A-5"
else:
new_clikcer_state.wait(time_needed)
new_clikcer_state.buy_item(suggested_item, cookies_needed, cps_added)
build_info_clone.update_item(suggested_item)
# print "A-6"
# print "A-7"
if new_clikcer_state.get_time()==duration:
suggested_item = strategy(new_clikcer_state.get_cookies(), new_clikcer_state.get_cps(),duration - new_clikcer_state.get_time(), build_info_clone)
if suggested_item != None:
cookies_needed = build_info_clone.get_cost(suggested_item)
cps_added = build_info_clone.get_cps(suggested_item)
if cookies_needed<=new_clikcer_state.get_cookies():
new_clikcer_state.buy_item(suggested_item, cookies_needed, cps_added)
build_info_clone.update_item(suggested_item)
return new_clikcer_state
#return ClickerState()
def strategy_cursor(cookies, cps, time_left, build_info):
"""
Always pick Cursor!
Note that this simplistic strategy does not properly check whether
it can actually buy a Cursor in the time left. Your strategy
functions must do this and return None rather than an item you
can't buy in the time left.
"""
return "Cursor"
def strategy_none(cookies, cps, time_left, build_info):
"""
Always return None
This is a pointless strategy that you can use to help debug
your simulate_clicker function.
"""
return None
def strategy_cheap(cookies, cps, time_left, build_info):
"""cheap Strategy"""
pricelist = {}
funding = cookies + cps * time_left
for item in build_info.build_items():
if build_info.get_cost(item) <= funding:
pricelist[build_info.get_cost(item)] = item
if len(pricelist) > 0:
return pricelist[min(pricelist)]
else:
return None
def strategy_expensive(cookies, cps, time_left, build_info):
"""Expensive Strategy"""
pricelist = {}
funding = cookies + cps * time_left
for item in build_info.build_items():
if build_info.get_cost(item) <= funding:
pricelist[build_info.get_cost(item)] = item
if len(pricelist) > 0:
return pricelist[max(pricelist)]
else:
return None
def strategy_best(cookies, cps, time_left, build_info):
"""Best Strategy"""
pricelist = {}
funding = cookies + cps * time_left
for item in build_info.build_items():
if build_info.get_cost(item) <= funding:
pricelist[build_info.get_cps(item)/build_info.get_cost(item)] = item
if len(pricelist) > 0:
return pricelist[max(pricelist)]
elif len(pricelist) == 0:
return None
def run_strategy(strategy_name, time, strategy):
"""
Run a simulation with one strategy
"""
state = simulate_clicker(provided.BuildInfo({"Cursor":[15.0,50.0]},1.15), time, 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)
# run_strategy("Cursor", 16, strategy_cursor)
# 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()