首先:你不必为我编码,除非你是一个超级棒的好人。但是因为你们都非常擅长编程并且比我和所有人都更了解它,所以它可能更容易(因为它可能不是太多的代码行)而不是一段一段地写下来试图让我理解它。
所以 - 我需要列出一些在新条目上更新的高分。 所以这就是:
第一步 - 完成
我有玩家输入的输入,它被作为一些计算的数据:
import time
import datetime
print "Current time:", time1.strftime("%d.%m.%Y, %H:%M")
time1 = datetime.datetime.now()
a = raw_input("Enter weight: ")
b = raw_input("Enter height: ")
c = a/b
第二步 - 制作高分榜
在这里,我需要某种字典或能读取之前条目的东西,并检查分数(c
)是否(至少)比“高”中的最后一个分数更好分数“,如果是,则会提示您输入您的姓名。
输入您的姓名后,它会将您的姓名,a
,b
,c
和时间发布在高分列表中。
这就是我想出来的,它绝对不起作用:
list = [("CPU", 200, 100, 2, time1)]
player = "CPU"
a = 200
b = 100
c = 2
time1 = "20.12.2012, 21:38"
list.append((player, a, b, c, time1))
list.sort()
import pickle
scores = open("scores", "w")
pickle.dump(list[-5:], scores)
scores.close()
scores = open("scores", "r")
oldscores = pickle.load(scores)
scores.close()
print oldscores()
我知道我做了一件非常愚蠢的事情,但无论如何,感谢您阅读本文,我希望您可以帮助我解决这个问题。 : - )
答案 0 :(得分:4)
首先,不要将list
用作变量名。它会遮挡built-in list
个对象。其次,避免使用普通日期字符串,因为使用datetime
对象更容易,这些对象支持正确的比较和简单的转换。
以下是您的代码的完整示例,其中包含用于帮助分割步骤的各个函数。我试图不使用任何更高级的模块或功能,因为你显然只是在学习:
import os
import datetime
import cPickle
# just a constants we can use to define our score file location
SCORES_FILE = "scores.pickle"
def get_user_data():
time1 = datetime.datetime.now()
print "Current time:", time1.strftime("%d.%m.%Y, %H:%M")
a = None
while True:
a = raw_input("Enter weight: ")
try:
a = float(a)
except:
continue
else:
break
b = None
while True:
b = raw_input("Enter height: ")
try:
b = float(b)
except:
continue
else:
break
c = a/b
return ['', a, b, c, time1]
def read_high_scores():
# initialize an empty score file if it does
# not exist already, and return an empty list
if not os.path.isfile(SCORES_FILE):
write_high_scores([])
return []
with open(SCORES_FILE, 'r') as f:
scores = cPickle.load(f)
return scores
def write_high_scores(scores):
with open(SCORES_FILE, 'w') as f:
cPickle.dump(scores, f)
def update_scores(newScore, highScores):
# reuse an anonymous function for looking
# up the `c` (4th item) score from the object
key = lambda item: item[3]
# make a local copy of the scores
highScores = highScores[:]
lowest = None
if highScores:
lowest = min(highScores, key=key)
# only add the new score if the high scores
# are empty, or it beats the lowest one
if lowest is None or (newScore[3] > lowest[3]):
newScore[0] = raw_input("Enter name: ")
highScores.append(newScore)
# take only the highest 5 scores and return them
highScores.sort(key=key, reverse=True)
return highScores[:5]
def print_high_scores(scores):
# loop over scores using enumerate to also
# get an int counter for printing
for i, score in enumerate(scores):
name, a, b, c, time1 = score
# #1 50.0 jdi (20.12.2012, 15:02)
print "#%d\t%s\t%s\t(%s)" % \
(i+1, c, name, time1.strftime("%d.%m.%Y, %H:%M"))
def main():
score = get_user_data()
highScores = read_high_scores()
highScores = update_scores(score, highScores)
write_high_scores(highScores)
print_high_scores(highScores)
if __name__ == "__main__":
main()
它现在所做的只是在没有高分或者击败最低分时才添加新分数。如果前面的分数少于5个,您可以将其修改为始终添加新分数,而不是要求它击败最低分数。然后在高分的大小> = 5
之后执行最低检查答案 1 :(得分:2)
我注意到的第一件事是你没有告诉list.sort()
排序应该基于每个条目的最后一个元素。默认情况下,list.sort()
将使用Python的默认排序顺序,它将根据每个条目的第一个元素(即名称)对条目进行排序,然后依次模式为第二个元素,第三个元素,依此类推。因此,您必须告诉list.sort()
要用于排序的项目:
from operator import itemgetter
[...]
list.sort(key=itemgetter(3))
这将根据每个元组中索引为3的项目(即第四个项目)对条目进行排序。
此外,print oldscores()
肯定不会起作用,因为oldscores
不是函数,因此您无法使用()
运算符调用它。 print oldscores
可能更好。
答案 2 :(得分:1)
你绝对不需要这里的字典。字典的重点是能够将键映射到值,而无需任何排序。你想要的是一个排序列表。你已经有了。
好吧,正如Tamás指出的那样,你实际上有一个按球员名称排序的列表,而不是得分。最重要的是,您希望按向下排序,而不是向上排序。你可以使用decorate-sort-undecorate模式,或者一个键函数,或者其他什么,但你需要做某事。此外,您已将其放在名为list
的变量中,这是一个非常糟糕的主意,因为它已经是list
类型的名称。
无论如何,您可以使用标准库中的bisect
模块找出是否在排序的list
中添加内容,以及在何处插入(如果是)。但是使用SortedCollection
或blist
之类的东西可能更简单。
以下是一个例子:
highscores = SortedCollection(scores, key=lambda x: -x[3])
现在,当你完成游戏时:
highscores.insert_right((player, a, b, newscore, time1))
del highscores[-1]
就是这样。如果你实际上不在前10名,你将被添加到#11,然后被删除。如果你进入前10名,那么你将被添加,旧的#10现在将被#11删除。
如果你不想像旧的街机游戏那样用10个假分数预填充列表,只需将其更改为:
highscores.insert_right((player, a, b, newscore, time1))
del highscores[10:]
现在,如果已经有10个分数,当你被添加时,#11将被删除,但如果只有3个,则没有被删除,现在有4个。
与此同时,我不确定你为什么要将新分数写入pickle
文件,然后再读回同样的东西。你可能想要在将高分数添加到列表,然后在添加后进行写作。
您还问过如何“美化列表”。那么,有三个方面。
首先,在代码中,(player, a, b, c, time1)
不是很有意义。当然,给变量提供更好的名称会有所帮助,但最终你仍然可以得出这样的事实:当访问列表时,你必须entry[3]
来获得分数或entry[4]
来获得时间。< / p>
至少有三种方法可以解决这个问题:
list
(或SortedCollection
)dict
代替tuple
s。代码变得更冗长,但更具可读性。您编写{'player': player, 'height': a, 'weight': b, 'score': c, 'time': time1}
,然后在访问列表时,您执行entry['score']
而不是entry[3]
。namedtuple
的集合。现在您实际上只需插入ScoreEntry(player, a, b, c, time1)
,或者您可以插入ScoreEntry(player=player, height=a, weight=b, score=c, time=time1)
,在给定的情况下更具可读性,并且它们的工作方式相同。您可以再次使用更易读的内容访问entry.score
或entry[3]
。namedtuple
。其次,如果您只是print
条目,它们看起来就像一团糟。处理它的方法是字符串格式化。而不是print scores
,你做的是这样的事情:
打印'\ n'。join(“{}:height {},weight {},得分{} at {}”。format(entry) 进入高分榜)
如果您使用的是class
或namedtuple
而不只是tuple
,您甚至可以按名称而不是按位置进行格式化,从而使代码更具可读性。
最后,高分文件本身是一个难以理解的混乱,因为pickle
不适合人类消费。如果您希望它是人类可读的,您必须选择一种格式,并编写代码以序列化该格式。幸运的是,CSV格式非常易读,大部分代码都是在csv
模块中为您编写的。 (您可能希望查看DictReader
和DictWriter
类,特别是如果您想要编写标题行。再次,需要更多代码的折衷以获得更多可读性。)
答案 3 :(得分:1)
以下是我注意到的事情。
这些行似乎顺序错误:
print "Current time:", time1.strftime("%d.%m.%Y, %H:%M")
time1 = datetime.datetime.now()
当用户输入高度和重量时,它们将作为字符串而非整数读入,因此您将在此行中获得TypeError:
c = a/b
您可以通过将a和b转换为浮动来解决此问题:
a = float(raw_input("Enter weight: "))
但是你可能需要将它包装在try / catch块中,以防用户放入垃圾,基本上任何无法转换为浮点数的东西。把整个事情放在一段时间,直到他们做对了。
所以,像这样:
b = None
while b == None:
try:
b = float(raw_input("Enter height: "))
except:
print "Weight should be entered using only digits, like '187'"
因此,在第二部分中,您不应该使用list
作为变量名,因为它是内置的,我将使用high_scores
。
# Add one default entry to the list
high_scores = [("CPU", 200, 100, 2, "20.12.2012, 4:20")]
你说你想要根据高分检查球员得分,看看它是否最好,但如果是这样的话,为什么要列出?为什么不只是一个条目?无论如何,这让我感到困惑,不确定你是否真的想要一个高分榜,或只是一个高分。
所以,我们只需添加分数,无论如何:
假设您已将他们的名字输入name
变量。
high_score.append((name, a, b, c, time1))
然后应用@Tamás的其他答案