游戏中排行榜代码实现
游戏设计中常常使用排行榜,根据排行发送排名奖励。
排行容器的组成
记录排行的容器是一个由内部由vector和map组成的模板类
1.1.容器为什么这么设计
1.1.1vector部分的结构
其中vector里的元素使用的是pair, pair的first部分保存的是 uid(玩家ID),second部分保存的我们想要保存的任何信息(当然是一个类,或者结构体),然而vector的排列顺序是按照名词排列的
1.1.2. map的结构
map的first的部分也是uid,second部分是玩家的名词
1.1.3为什么使用vector和map的组合设计这么一个容器?
我们知道vector的优点是取值方便,map的优点是查找快速。
那么容器的有点有如下:1.1.3.1. 获得名次快速
通过map查找uid,快速拿到名词1.1.3.2通过名词,快速获得我们保存的信息
根据map查找的名次,我们作为vector的下标获取该玩家的信息。下面提供排行模板类的代码实现
#ifndef _RANKLIST_H_
#define _RANKLIST_H_#include <vector>
#include <algorithm>
using namespace std;
#include <boost/typeof/typeof.hpp>
#include <boost/unordered_map.hpp>
using boost::unordered_map;
#include "../common/const_def.h"template<typename RankKey, int Length = 1000, class Pr = greater<RankKey> >
class RankList
{
public:RankList(){}~RankList(){ clear();}void init(vector<pair<int64, RankKey> >& rank);bool modify(int64 uid, RankKey key);void remove(int64 uid, RankKey key);void erase(int64 uid);void clear();unsigned size() const;unsigned rank(int64 uid) const;//根据uid得到名次int64 getuid(unsigned rank) const;//根据名次得到uidconst RankKey* const getkey(int64 uid) const;//根据uid得到key信息vector<int64> partialUserList(unsigned start, unsigned length) const;//取出排名在[start + 1, start + length -1]范围内的uid;const vector<pair<int64, RankKey> > & get_vec_rank(){return rank_;}//取出全部Key信息//=RankList& operator=(const RankList& myRanklist){clear();this->index_ = myRanklist.index_;this->rank_ = myRanklist.rank_;return *this;}//[]const pair<int64, RankKey>* operator[](int index){if(index < 0 || index >= int(rank_.size())){return NULL;}return &this->rank_[index];}//构造RankList(const RankList& myRanklist){clear();this->index_ = myRanklist.index_;this->rank_ = myRanklist.rank_;}const RankKey* getkey(int64 uid);
protected:void sortall();void sort(unsigned index);void trim();void swap(unsigned indexA, unsigned indexB);private:vector<pair<int64, RankKey> > rank_; //uid, uid对应的数据unordered_map<int64, unsigned> index_; //uid, uid对应的排名
};template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::clear()
{vector<pair<int64, RankKey> > temp;init(temp);
}template<typename RankKey, class Pr>
static bool RankComp(const pair<int64, RankKey>& l, const pair<int64, RankKey>& r)
{ static Pr pr;return pr(l.second, r.second);
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::init(vector<pair<int64, RankKey> >& rank)
{rank_.swap(rank);sortall();trim();index_.clear();for (size_t i = 0; i < rank_.size(); i++)index_[rank_[i].first] = i;
}
template<typename RankKey, int Length, class Pr>
const RankKey* RankList<RankKey, Length, Pr>::getkey(int64 uid)
{BOOST_AUTO(it, index_.find(uid));if (it != index_.end())return &rank_[it->second].second;return NULL;
}template<typename RankKey, int Length, class Pr>
bool RankList<RankKey, Length, Pr>::modify(int64 uid, RankKey key)
{static Pr pr;BOOST_AUTO(it, index_.find(uid));size_t sz = rank_.size();// not in list now and will not be in listif (it == index_.end() && sz >= Length && !pr(key, rank_[sz-1].second))return false;if (it != index_.end()){rank_[it->second].second = key;}else{index_[uid] = rank_.size();rank_.push_back(make_pair(uid, key));} sort(index_[uid]);trim();return true;
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::erase(int64 uid)
{BOOST_AUTO(it, index_.find(uid));if (it == index_.end() || rank_.size() <= 0)return;unsigned indexCurrent = it->second, indexLast = rank_.size()-1;if (indexCurrent != indexLast)swap(indexCurrent, indexLast);rank_.pop_back();index_.erase(uid);if (indexCurrent != indexLast)sort(indexCurrent);
}template<typename RankKey, int Length, class Pr>
unsigned RankList<RankKey, Length, Pr>::rank(int64 uid) const
{BOOST_AUTO(it, index_.find(uid));if (it == index_.end())return 0;return it->second + 1;
}template<typename RankKey, int Length, class Pr>
vector<int64> RankList<RankKey, Length, Pr>::partialUserList(unsigned start, unsigned length) const
{vector<int64> v;if(start < 0)return v;size_t sz = rank_.size();for (size_t i = start; i < sz && i < start + length; i++)v.push_back(rank_[i].first);return v;
}template<typename RankKey, int Length, class Pr>
unsigned RankList<RankKey, Length, Pr>::size() const
{return rank_.size();
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::sortall()
{std::sort(rank_.begin(), rank_.end(), RankComp<RankKey, Pr>);
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::sort(unsigned index)
{static Pr pr;while (index > 0 && pr(rank_[index].second, rank_[index-1].second)){swap(index-1, index);index--;}size_t sz = rank_.size();while ( sz > 0 && index < sz-1 && pr(rank_[index+1].second, rank_[index].second)){swap(index, index+1);index++;}
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::swap(unsigned indexA, unsigned indexB)
{if (indexA >= rank_.size() || indexB >= rank_.size())return;std::swap(rank_[indexA], rank_[indexB]);index_[rank_[indexA].first] = indexA;index_[rank_[indexB].first] = indexB;
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::trim()
{size_t sz = rank_.size();while (sz > Length){index_.erase(rank_[sz-1].first);rank_.pop_back();sz--;}
}template<typename RankKey, int Length, class Pr>
void RankList<RankKey, Length, Pr>::remove(int64 uid, RankKey key)
{static Pr pr;BOOST_AUTO(it, index_.find(uid));size_t sz = rank_.size();// not in list now and will not be in listif (it == index_.end() && sz >= Length && !pr(key, rank_[sz-1].second))return;int nIndex = index_[uid];if (it != index_.end()){index_.erase(uid);for(size_t i = 0; i < rank_.size(); i++){if(rank_[i].first == uid)rank_.erase(rank_.begin()+i);}}sort(nIndex);trim();
}template<typename RankKey, int Length, class Pr>
int64 RankList<RankKey, Length, Pr>::getuid(unsigned rank) const
{if (index_.size() < rank)return 0;BOOST_AUTO(iter, index_.begin());for (; iter!=index_.end(); ++iter){if ((iter->second + 1)== rank){return iter->first;break;}}return 0;
}
template<typename RankKey, int Length, class Pr>
const RankKey* const RankList<RankKey, Length, Pr>::getkey(int64 uid) const
{BOOST_AUTO(it, index_.find(uid));if (it == index_.end())return NULL;return &(rank_[it->second].second);
}#endif
4.进一步说明排行榜的参数,以及排序问题
排行榜模板类,需要三个参数,template
template<typename RankKey, int Length, class Pr>
bool RankList<RankKey, Length, Pr>::modify(int64 uid, RankKey key)
{static Pr pr;BOOST_AUTO(it, index_.find(uid));size_t sz = rank_.size();// not in list now and will not be in list//在容器已经满的情况下,并且是新数据,并且新数据比最后一个元素还要小的时候,就不会计入排行榜if (it == index_.end() && sz >= Length && !pr(key, rank_[sz-1].second))return false;if (it != index_.end()){rank_[it->second].second = key;}else{index_[uid] = rank_.size();rank_.push_back(make_pair(uid, key));} //其中sort的个根据我们写好的排序规则进行排序sort(index_[uid]);//如果超出排行的限制,那么让排行榜的大小变为我们传入参数legth的大小trim();return true;
}
5.排行榜的应用
//定义我们保存数据内容,以及排序规则
struct RankKey
{RankKey(int score, int64 time, int64 uid) : m_score(score),m_time(time),m_uid(uid) {}bool operator >(const RankKey &that) const { if (m_score == that.m_score){if (m_time == that.m_time)return m_uid < that.m_uid;elsereturn m_time < that.m_time;}elsereturn m_score > that.m_score;}int getScore(){ return m_score;}int64 getUid(){ return m_uid;}int64 getTime() {return m_time;}
}RankList<RankKey, 100> m_levelRankList;//等级排行榜//当有数据更新或者有新数据时调用如下
for(int i = 0; i < 10; i++)
{int64 uid = i;time_t newtime= time(NULL) + i * 100;int lvl = i * 10;m_levelRankList.modify(uid, RankKey(lvl, newtime , uid));
}
//那么我们就进行了排行,假设我们想要根据排名发送奖励
//那么我们可以调用vector<int64> partialUserList(unsigned start, unsigned length) const;//取出排名在[start + 1, start + length -1]范围内的uid;获取排名的uid,然后调用发送邮件的函数接口进行,发送奖励//题外话,发送玩奖励一般调用clear,将排行榜清空,防止逻辑错误重复发奖
5.题外话:
其中排行榜的一般和另外一个map结合使用map<int64, int > m_mapAlldata//玩家uid,玩家的得分(这里保存所有玩家的数据,不管是否进入排行榜)
RankList<RankKey, 100> m_scoreRankList;//分数排行榜(这里仅仅保存进入排行榜的数据)一般情况下是先更新m_mapAlldata,然后更新排行榜(调用modify)
这样就实现了游戏中的排行榜
6 缺点
sort的时候,其实是对vector的操作,排序时挪动元素比较耗时
游戏中排行榜代码实现相关推荐
- 用 Redis 搞定游戏中的实时排行榜,附源码!
原文:segmentfault.com/a/1190000019139010 1. 前言 前段时间刚为项目(手游)实现了一个实时排行榜功能, 主要特性: 实时全服排名 可查询单个玩家排名 支持双维排序 ...
- threejs 微信小游戏中的离屏渲染做UI和排行榜
微信小游戏对threejs真的是一次桎酷啊...呵呵. 规定不能用html锁死了我们之前两个html标签的可能了... 不过微信还是允许了大家的离屏渲染,要不是我们在跳一跳之类的游戏中也看不到排行榜和 ...
- [原创]游戏中的实时排行榜实现
1. 前言 2. 排行榜分类 3. 思路 4. 实现 复合排序 4.1 等级排行榜 4.2 通天塔排行榜 4.3 坦克排行榜 5. 排名数据的动态更新 6. 取排行榜 7. Show The Code ...
- 有关计算机代码的游戏,七灯游戏是一款经典的益智类游戏。游戏中,有七盏灯排成一圈,如图a所示,初始时灯的开关状态随机生成,操作其中某一盏灯,则可以切换该灯的“开/关”状态,同时,这盏灯-组卷网...
七灯游戏是一款经典的益智类游戏.游戏中,有七盏灯排成一圈,如图a所示,初始时灯的开关状态随机生成,操作其中某一盏灯,则可以切换该灯的"开/关"状态,同时,这盏灯对面的两盏灯也会切换 ...
- 一行Java代码实现游戏中交换装备
摘要:JDK 1.5 开始 JUC 包下提供的 Exchanger 类可用于两个线程之间交换信息. 本文分享自华为云社区<一行Java代码实现两玩家交换装备[并发编程]>,作者:陈皮的Ja ...
- mc是用java写的吗_都说MC的代码特别差劲,你觉得它在所有游戏中,能排第几?...
原标题:都说MC的代码特别差劲,你觉得它在所有游戏中,能排第几? 虽然说我的世界这款游戏非常的好玩,销量世界第一,无论国内国外都非常的火热,但是大家都知道,一款游戏他的最原本的面貌是由一个又一个的代码 ...
- lua游戏代码_在游戏中如何使用LUA脚本语言
当你希望在你的游戏开始的时候读取一些信息,以配置你的游戏,这些信息通常都是放到一个文本文件中,在你的游戏启动的时候,你需要打开这个文件,然后解析字符串,找到所需要的信息. 或许你认为这样就足够了,为什 ...
- unity中通过代码控制游戏中画质
最近在开发项目的时候突然想到可以添加一个调整画质的按钮或者DropDown或者Slider的UI来控制游戏中的画质 因为我之前写过一篇关于DropDown的使用方法的博客 DropDown的使用方法地 ...
- java2d游戏代码_Java 2d游戏中的“JUMP”
我有这个代码,我想在java 2d游戏中启动一个跳转,事情是我的对象没有去任何地方,它只是停留在那里...我想我的对象跳,当我按下键和程序显示我的图像上下移动..我试图通过简单的repaint()方法 ...
最新文章
- 七、Linux串口编程
- 学习windows编程 day6 之模拟记事本
- 【AGC013D】Pilling Up dp
- 通过jconsole监控tomcat JVM 内存、线程、CPU
- 1381. 设计一个支持增量操作的栈
- JFinalConfig
- 信息安全系统设计基础实验一 2013521120135216
- 怎样从 Ubuntu 12.10 升级到 Ubuntu 13.04
- MySQL抽稀_Android GPS定位轨迹抽稀之道格拉斯-普克(Douglas-Peuker)算法详解
- 【eclipse反编译工具】最好的反编译工具
- redis HSCAN命令及jedis的hscan方法
- sublime text3和package control
- python数据分析之航空公司客户价值分析
- 感觉自己技术还可以?十几个外包平台分享给你,让你外包接到手软!
- java基础--狂神
- 历届奥斯卡最佳影片及下载地址
- 推荐一下十三款内网穿透工具(超全)
- springboot拦截器Interceptor
- Installation failed with message Failed to finalize session : INSTALL_FAILED_INVALID_APK:
- 【大数据入门核心技术-Tez】(四)Tez与Hdfs整合
热门文章
- hdoj 1878 欧拉回路
- 手机html编辑器微信,手机微信编辑器,秒书是唯一支持手机的微信编辑器
- 职业教育计算机教育美育,中职计算机职业素质教育
- Python使用pycrypto进行RSA长字符串加密
- 岭南师范学院专插本计算机,2019年岭南师范学院专插本招生专业
- Deepin linux安装五笔输入法
- spring cloud oauth2系列篇(三)password模式获取access_token
- Java_表达式和运算符(算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和三元运算符)
- CoaXPress接口助CMOS相机实现更高速率
- 西工大-网安学院-2021复试-面试题目