背景介绍

排行榜通常是游戏中为了激发玩家的一种策略,那么对于开发人员来说如何完成一个排行榜的设计呢?如果这个排行榜是动态的如何才能高效的对比出结果呢?如果排行榜实时性较高如何给用户展示出用户是进步了还是退步了呢?带着这些问题我们一步步开始探究。可能我实现的方式并不高效期待你能够提出宝贵的意见。所有代码可以到这里github

排名

假设我们要实现排行榜功能肯定避免不了排序,那么是怎么排序比较好呢?当用户查询自己的战绩时再去查数据库?那样就会使用户体验变差了!如果用户量非常大可能排序会让用户不耐烦。好那么我们就使用后台定时去计算排名,这样就可以避免用户体验差了,我们可以选择用redis缓存结果。好开始写demo

a=[{'score': 123,'name': 'frank'},{'name': 'jack','score': 44},{'name': 'susan','score': 188},{'name': 'lisa','score': 99}
]b=[{'score': 12,'name': 'frank'},{'name': 'jack','score': 44},{'name': 'susan','score': 223},{'name': 'lisa','score': 99}
]

可以看到我们的数据目前是非常简单的,只有用户名和战绩分数两个项。下面我们开始给他排序,注意我们需要根据score来排序,使用python非常容易实现。

sorted(a, lambda x,y: cmp(x.get('score'), y.get('score')))


可以看到我们目前的链表是按照score来排序了!那么如何才能知道用户是上升了几名还是下降了几名呢?这个很容易想到与上次数据对比即可,这样我们就有下面的函数了。

def trend_pk(old_list, new_list):return a_new_list

如果要实现两个列表的对比难免要一个循环语句,这时候我们是循环new_list还是old_list呢?显然我们知道old_list可以为空,也就是第一次执行排名对比的时候。好那么我们就可以选择new_list来循环了。

def trend_pk(old_list, new_list):for i in new_list:passreturn new_list

有了循环语句我们自然需要改变些什么,设想如果一个用户出现在排行榜上了他肯定应该得到些什么,也许是奖品也许只是一个名次等。好那么我们需要判断这个用户是不是第一次上榜,所以自然想到去看看历史列表有没有他。

def trend_pk(old_list, new_list):for i in new_uid_list:if i in old_uid_list:passelse:passreturn new_list

回头看看数据结构,我们发现i其实是这样的。

    {'score': 123,'name': 'frank'}

这个可不是用户的唯一标示,我们需要的是用户名或者身份证id等。所以我们需要提取一下用户的唯一标示也就是这里的用户名。

def trend_pk(old_list, new_list):old_uid_list = [i.get('name') for i in old_list]new_uid_list = [i.get('name') for i in new_list]for i in new_list:if i in old_uid_list:passelse:passreturn new_list

现在我们有了一个uid_list列表,我可以很轻松的得到用户名,但是我们希望这些用户是已经按照分数排好序的。我们可以这样做:

def trend_pk(old_list, new_list):# You should read both list from redisold_list = sorted(old_list, lambda x,y: cmp(x.get("score"), y.get("score")))new_list = sorted(new_list, lambda x,y: cmp(x.get("score"), y.get("score")))old_uid_list = [i.get('name') for i in old_list]new_uid_list = [i.get('name') for i in new_list]for i in new_uid_list:if i in old_uid_list:passelse:passreturn new_list

上面的代码的if语句只判断uid是否在列表里面即可,此时我们需要做的就是对uid是否有历史记录分别做不同处理。

def trend_pk(old_list, new_list):# You should read both list from redisold_list = sorted(old_list, lambda x,y: cmp(x.get("score"), y.get("score")))new_list = sorted(new_list, lambda x,y: cmp(x.get("score"), y.get("score")))old_uid_list = [i.get('name') for i in old_list]new_uid_list = [i.get('name') for i in new_list]for i in new_uid_list:index = new_uid_list.index(i)if i in old_uid_list:old_index = old_uid_list.index(i)new_list[index].update({'trend': trend_pk_tool(old_index, index)})else:new_list[index].update({'trend':'1'})return new_list

首先我通过list自带的index函数获取到当前列表的位置,然后如果这个用户有历史记录我就去获取历史记录位置,然后通过一个函数对比这两个位置。不着急待会告诉大家这就对比函数怎么写的。继续看else部分表示如果这个用户没有历史记录,说明他第一次有记录那么这就是有进步。如果用户还关心自己当前到底排在第几名怎么办呢?

def trend_pk(old_list, new_list):# You should read both list from redisold_list = sorted(old_list, lambda x,y: cmp(x.get("score"), y.get("score")))new_list = sorted(new_list, lambda x,y: cmp(x.get("score"), y.get("score")))old_uid_list = [i.get('name') for i in old_list]new_uid_list = [i.get('name') for i in new_list]for i in new_uid_list:index = new_uid_list.index(i)if i in old_uid_list:old_index = old_uid_list.index(i)new_list[index].update({'trend': trend_pk_tool(old_index, index)})else:new_list[index].update({'trend':'1'})new_list[index].update({'rank':str(index)})return new_list

可以看到在return之前我们增加了一个rank字段。下面来看看我的trend_pk_tool是什么工具函数吧。

def trend_pk_tool(o, n):if o > n:return '1'elif o == n:return '0'else:return '-1'

简单吧!根据不同的对比结果返回不同的值,或许你还有跟简单的方法来写这个函数哦!想想看~~

快速获取个人战绩

为了快速获取增加的战况,首先肯定知道自己的用户名才能获得自己的战绩。好我们可以用字典的方式,那么刚才的列表要怎么变成列表呢?

def map_uid_to_score_info(score_list):redis_cache = {}for i in score_list:uid = i.get('name')redis_cache.update({uid:{'score':i.get('score'),'trend':i.get('trend'),'rank':i.get('rank')}})return redis_cache

好了!这次代码给得非常干脆,现在我们来看看运行结果吧!

if __name__ == '__main__':ret = trend_pk(a, b)redis_cache = map_uid_to_score_info(ret)print redis_cache

拿着我的demo给产品经理确认这数据是不是他想要的,他看了看说不对吧!这个成绩低的怎么排名在前面呢?这个问题怎么很简单只需要在sorted时指定一个参数即可。看看下面代码:

    old_list = sorted(old_list, lambda x,y: cmp(x.get("score"), y.get("score")), reverse=True)new_list = sorted(new_list, lambda x,y: cmp(x.get("score"), y.get("score")), reverse=True)

当榜单出现并列名次时如何解决

今天跟产品讨论了一个问题,如果出现并列第一的奖品该如何分配?榜单该如何排序?对于产品可能会想通过增加条款或者其他方式解决。而我首先想到的是按照第二条件进行再次排序。所以我想了想如何通过sorted进行多项匹配排序。

sample = [('d', 2), ('a', 4), ('b', 3), ('c', 2)]
print sorted(sample, key=lambda x:(x[1], x[0]))

运行结果是先按照数字排序,再按照字母排序的。

总结

那么在实战项目中我们需要注意些什么呢?首先我们需要用数据库,mysql查询到最新的记录,排名完成后保存到redis中。现实场景中可还可能对不同的排名派发奖品,如何将这些奖品进行兑换也是需要考虑的。

转载于:https://www.cnblogs.com/landpack/p/6286174.html

游戏排行榜-Python实现相关推荐

  1. python开发的比较知名的游戏-游戏排行榜-Python实现

    背景介绍 排行榜通常是游戏中为了激发玩家的一种策略,那么对于开发人员来说如何完成一个排行榜的设计呢?如果这个排行榜是动态的如何才能高效的对比出结果呢?如果排行榜实时性较高如何给用户展示出用户是进步了还 ...

  2. Q新闻丨Java 9正式版恐再延期;顺丰菜鸟口水战涉及阿里云;编程语言排行榜Python第四;盲人程序员背百万字符,用耳朵编程...

    编辑|小智 本周要闻:Java 9 正式版有可能被推迟到 9 月 21 号发布:顺丰.菜鸟口水战始末,或涉及阿里云:Node.js 发布 v8.0.0:Visual Studio for Mac 版本 ...

  3. python写好的代码怎么给别人使用-10分钟学会用python写游戏!Python其实很简单!...

    原标题:10分钟学会用python写游戏!Python其实很简单! Python现在非常火,语法简单而且功能强大,很多同学都想学Python!所以在这里给各位看官们准备了高价值Python学习视频教程 ...

  4. python游戏程序-python游戏程序

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 易于阅读:python代码定义更清晰. 易于维护:源代码是相当容易维护的 ...

  5. 2048游戏的python实现

    2019独角兽企业重金招聘Python工程师标准>>> 一个2048小游戏的python实现 今天看了OSC网友xiaohui_hubei的2048游戏代码感觉很有意思,特意花时间玩 ...

  6. 将游戏成绩传到排名页面html,用野狗开发实时游戏排行榜

    创建wilddog应用 填写应用名称和应用ID就可以创建了.应用ID需要全网唯一 创建成功之后就可以在控制面板看到应用了. 1.引入SDK 2.创建引用 ref = Wilddog("htt ...

  7. 如何使用redis来实现常见的游戏排行榜

    前言 前面几篇文章给大家聊了下目前的常用的排行榜做法. 关于游戏排行榜设计开发的一些总结 游戏排行榜-跳表实现原理分析 那么这篇文章将给大家带来如何使用redis来实现常见的游戏排行榜功能. 为什么使 ...

  8. python去年软件排行_2017年编程语言排行榜,Python位居榜首(C语言需求最大)

    最近IEEE Spectrum 发布了编程语言交互式排行榜,为很多学习代码的朋友们详解各类代码语言的需求和占有率.为学习代码的朋友们能更加重视哪一种编程语言而有一个明确的方向.下面排行榜123网为你公 ...

  9. 单机android游戏排行榜,安卓单机手机游戏推荐_十大必玩单机手机游戏

    现在越来越多的人喜欢玩手机的单机游戏了.毕竟现在的手游市场局势都是快餐的联网手游居多.而很多单机手游是真的用心在做!下面小编给大家带来了手机单机游戏排行榜.安卓单机手机游戏推荐单机游戏无论是手机端还是 ...

最新文章

  1. git 创建新分支,合并分支等问题
  2. 030_jdbc-mysql事务
  3. microsoftsql新建登录用户登录失败_史上最简单的Spring Security教程(九):自定义用户登录失败页面...
  4. 如何重置/删除chrome的输入突出显示/焦点边框? [重复]
  5. 从C#中传递object到lua的一个问题
  6. 使用bind()和connect()函数
  7. 【企业架构】什么是 TOGAF? 企业架构方法论
  8. react好租客项目Day11-发布房源模块(js输入框防抖图片上传)项目打包项目优化(按需加载路由代码分割)
  9. matlab 转换为相对湿度
  10. dev C++遇到endl无法调试的解决方法
  11. 5455. 最多 K 次交换相邻数位后得到的最小整数
  12. SEEK学习论坛-JavaWeb开发实训课题 (数据库MySQL+js+Ajax+Servlet)
  13. 链式线性表和顺序线性表
  14. 数据分析+数据挖掘暑期实习碎碎念
  15. Partially written block detected 疑问及解决办法
  16. CentOS系统下Tomcat无法正常启动解决(8005端口不能启动)
  17. Do it for success
  18. Django - 创建工程 和 APP 与 开发工具
  19. C语言动态内存使用多文件实现通讯录,并可以保存在文件中
  20. 计算机专业英语词汇表RSTUVW

热门文章

  1. opencv 表识别 工业表智能识别 数字式表盘识别,指针式表盘刻度识别,分为表检测
  2. PHP版物流快递公司轨迹查询实现-中小快递公司适用
  3. php echo输出多了 date(): It is not safe to rely on the system‘s timezone settings
  4. 影响债市行情的主要因素_影响债券市场价格的一般经济因素有哪些
  5. 天地不仁,以万物为刍狗--[1971年萨姆派金帕暴力电影代表作][稻草狗/大丈夫]...
  6. windows下mysql 自定义函数 之http 实操
  7. wangEditor 修改 “视频”菜单,上传视频(替换原来的输入地址),三次修改
  8. 它是中国第二个稻城亚丁,未开发美得原始
  9. Win系统下打开串口转换USB口的RS232串口,打不开问题
  10. (八)Listener