Introduction:
Ranking is an essential component in game components. Designing a reusable ranking is essential. A ranking system must meet the following requirements:
- Rankings are generally restricted, for example, ranking only for the top 100
- There are generally multiple rankings, such as rankings of levels and gold coins.
- Sometimes the ranking list needs to be updated regularly, and sometimes it needs to be updated in real time.
Ranking system component diagram:
Create a ranking chart
Rank_obj_mgr_t rank_obj_mgr; rank_system_t rank_system (&Rank_obj_mgr );Enum{Level_rank=1};//! Ranking list, ranking top one hundredRank_system.create_ranklist (level_rank,100);
Typical Object Manager implementation:
Class Rank_obj_mgr_t { Public : Virtual Int Add ( Long ID, rank_obj_t * OBJ _){ Return M_objs.insert (make_pair (ID, OBJ _). Second = True ? 0 :- 1 ;} Virtual Void Del ( Long ID _) {m_objs.erase (ID _);} Virtual Rank_obj_t * Find ( Long ID _) {Map < Long , Rank_obj_t *>: iterator it = M_objs.find (ID _); Return It! = M_objs.end ()? It-> Second: NULL;} Template <Typename T> Void Foreach (T func _){ For (Map < Long , Rank_obj_t *>: iterator it = m_objs.begin (); it! = M_objs.end (); ++ It) {func _ (it -> Second );}} Private : Map < Long , Rank_obj_t *> M_objs ;};
The object must have multiple attribute values:
Class Rank_obj_t { Public : Rank_obj_t (): m_rank ( 0 ){} Virtual ~ Rank_obj_t (){} Virtual Long Get_attr ( Int Attrid ){ If (Attrid = level_rank) Return 100 ; // ! ExampleCodeOnly Return - 1 ;} Void Set_rank (INT attrid, Int Rank _) {m_rank = Rank _;} Int Get_rank (INT attrid) Const { Return M_rank ;} Private : Int M_rank ;};
Implementation of scheduled ranking:
In fact, it is achieved by the ordering of multimap.
VoidRanklist_t: Sort () {m_ranklist_sort_map.clear (); m_ranklist_cache_vt.clear (); sort_functor_t func (m_attr_id,&M_ranklist_sort_map, m_max_rank_num); m_rank_obj_mgr->Foreach(Func); resort_ranklist (1, M_ranklist_sort_map.begin (), m_ranklist_sort_map.end ());}
Real-time ranking:
Ranklist_t: sort_map_t: iterator ranklist_t: Find ( Long ATTR _, rank_obj_t * OBJ _) {pair <Sort_map_t: iterator, sort_map_t: iterator> ret = M_ranklist_sort_map.equal_range (ATTR _); For (Sort_map_t: iterator it = ret. First; it! = Ret. Second; ++ It ){ If (It-> second = OBJ _){ Return It ;}} Return M_ranklist_sort_map.end ();} Int Ranklist_t: update_obj (rank_obj_t * OBJ _){ Long Now_attr = OBJ _-> Get_attr (m_attr_id ); Int Old_rank = OBJ _-> Get_rank (m_attr_id ); If ( 0 = Old_rank) // ! Not added to ranking list {Sort_map_t: iterator it_new = M_ranklist_sort_map.insert (make_pair (now_attr, OBJ _)); Int Now_rank = 1 ; If (It_new! = M_ranklist_sort_map.begin () {sort_map_t: iterator ittmp = It_new; sort_map_t: iterator itbefore = -- Ittmp; now_rank = Itbefore-> second-> get_rank (m_attr_id) + 1 ;} Resort_ranklist (now_rank, it_new, m_ranklist_sort_map.end (); check_rank_num_limit (); Return - 1 ;} // ! You have joined the ranking list and checked whether the ranking has changed. // ! If the ranking does not change, return directly // ! You need to know the beginning of the change, the iterator introduced, and the change starting from the first few rankings. Long Old_attr = M_ranklist_cache_vt [old_rank]. old_attr; sort_map_t: iterator begin_change_it, end_change_it; Int Begin_change_rank = 1 ; If (Now_attr> old_attr) // ! Rankings may go up { If (Is_first (old_rank) | now_attr <= m_ranklist_cache_vt [old_rank- 1 ]. Old_attr ){ // ! Unchanged rank Return 0 ;} If (Is_last (old_rank )) // ! Last name {Sort_map_t: iterator tmp_it =Find (old_attr, OBJ _); m_ranklist_sort_map.erase (tmp_it); begin_change_it = M_ranklist_sort_map.insert (make_pair (now_attr, OBJ _); end_change_it = M_ranklist_sort_map.end ();} Else {Rank_obj_t * Next_obj = m_ranklist_cache_vt [old_rank + 1 ]. Rank_obj; sort_map_t: iterator tmp_it = Find (old_attr, OBJ _); m_ranklist_sort_map.erase (tmp_it); begin_change_it =M_ranklist_sort_map.insert (make_pair (now_attr, OBJ _); end_change_it = Find (next_obj-> Get_attr (m_attr_id), next_obj );} // ! Computing changes from the last few rankings If (Begin_change_it = M_ranklist_sort_map.begin () {begin_change_rank = 1 ;} Else {Sort_map_t: iterator pre_it = Begin_change_it; begin_change_rank = (++ Pre_it)-> second-> get_rank (m_attr_id) + 1 ;}} Else // ! The ranking may be backward { If (Is_last (old_rank) | now_attr> = m_ranklist_cache_vt [old_rank + 1 ]. Old_attr ){ // ! Unchanged rank Return 0 ;} If (Is_first (old_rank )) // ! Last name {Sort_map_t: iterator tmp_it = Find (old_attr, OBJ _); m_ranklist_sort_map.erase (tmp_it); end_change_it = M_ranklist_sort_map.insert (make_pair (now_attr, OBJ _)); ++ End_change_it; begin_change_it = M_ranklist_sort_map.begin (); begin_change_rank = 1 ;} Else {Rank_obj_t * Pre_obj = m_ranklist_cache_vt [old_rank- 1 ]. Rank_obj; sort_map_t: iterator tmp_it = Find (old_attr, OBJ _); m_ranklist_sort_map.erase (tmp_it); end_change_it = M_ranklist_sort_map.insert (make_pair (now_attr, OBJ _)); ++ End_change_it; begin_change_it = Find (pre_obj-> Get_attr (m_attr_id), pre_obj );} // ! Computing changes from the last few rankings Begin_change_rank = Old_rank;} resort_ranklist (begin_change_rank, begin_change_it, end_change_it ); Return - 1 ;} Int Ranklist_t: get_rank ( Int From _, Int To _, vector <rank_obj_t *> & RET _){ Int Begin = (from _> 0 & (Size_t) from _ <m_ranklist_cache_vt.size ())? From _:0 ; Int End = (to _> 0 & (Size_t) to _ <m_ranklist_cache_vt.size ())? To _: 0 ; End = End> begin? End: begin; For ( Int I = begin- 1 ; I <end; ++ I) {RET _. push_back (m_ranklist_cache_vt [I]. rank_obj );} Return 0 ;} Void Ranklist_t: resort_ranklist ( Int Rank _, sort_map_t: iterator it_begin _, sort_map_t: iterator it_end _) {rank_info_t tmp_info; For (Sort_map_t: iterator it = it_begin _; it! = It_end _; ++ It) {tmp_info.rank = Rank _ ++ ; Tmp_info.rank_obj = It-> Second; tmp_info.old_attr = Tmp_info.rank_obj-> Get_attr (m_attr_id); tmp_info.rank_obj ->Set_rank (m_attr_id, tmp_info.rank ); If (Tmp_info.rank> = ( Int ) M_ranklist_cache_vt.size () {m_ranklist_cache_vt.push_back (tmp_info );} Else {M_ranklist_cache_vt [tmp_info.rank - 1 ] = Tmp_info ;}}} Int Ranklist_t: check_rank_num_limit (){ If (M_ranklist_cache_vt.size () <=(Size_t) m_max_rank_num ){ Return 0 ;} M_ranklist_sort_map.erase ( -- (M_ranklist_sort_map.end (); m_ranklist_cache_vt.erase (m_ranklist_cache_vt.begin () + (M_ranklist_cache_vt.size ()- 1 )); Return - 1 ;}
Source code:
SVN checkout http://ffown.googlecode.com/svn/trunk/example/ranklist/