关于一种游戏规则的算法实现 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 I 生成的内容
jjdd
V2EX    程序员

关于一种游戏规则的算法实现

  •  
  • jjdd 2014-05-02 23:55:58 +08:00 3613 次点击
    这是一个创建于 4179 天前的主题,其中的信息可能已经有所发展或是发生改变。
    每个用户进入游戏后,系统随机推荐几个他以前从未挑战过的用户。一旦他挑战过了,就不再出现在这个推荐列表当中。

    该如何设计这个程序能让查询高效一些呢,用户有很多,把用户表和挑战记录表连表查询效率肯定低。这种情况下如何设计合理的程序呢?
    13 条回复    2014-05-05 11:17:27 +08:00
    Mutoo
        1
    Mutoo  
       2014-05-03 00:05:05 +08:00   3
    可以考虑使用布隆过滤器。这样不需要存储大量的冗余信息,只要一个二进制串就可以了。
    xatest
        2
    xatest  
       2014-05-03 00:42:15 +08:00   1
    为了简化问题,我假定2个前提,不知道你的实际需求是否容许。
    1. 挑战记录是有限个的,例如1024个。如果挑战记录超出了这个上限,那么很早很早以前挑战过的用户,还是有可能推荐给他。
    2. 挑战记录的上限不多,至少不像用户表那么大。
    挑战记录在插入时排序。查找一个用户是否挑战过,只要二分查找就行了,效率是O(Log(N))。比如N是1024,那最多10次比较就能判断。
    alexapollo
        3
    alexapollo  
       2014-05-03 01:04:31 +08:00   1
    在用户远大于1024时
    随机推荐用户,如果以挑战过继续随机推荐
    akfish
        4
    akfish  
       2014-05-03 11:33:46 +08:00   2
    如果用户数量固定,然后又不需要对对手做一定条件的限制的话,用不重复的伪随机数生成器,你只需要存储随机数种子就行了。
    随机数就是对手的唯一id,每次next。
    等于是用户一来,他挑战对手的顺序就已经决定了,不过对于用户而言,依然是随机的。

    如果用户数量要变化,或者要做参数过滤,分几坨就行了(比如按注册时间一坨,按等级一坨等等),然后每坨内用同样的方式index。
    akfish
        5
    akfish  
       2014-05-03 11:36:32 +08:00
    哦,不知道你的重复挑战是怎么定义的。
    如果A打过B,然后B打A也算重复的话,可以在B打A的时候取A的随机数种子,然后生成一遍看B自己的ID出现过没。
    kurtis
        6
    kurtis  
       2014-05-03 12:06:33 +08:00   1
    我的建议是,如果空间开销允许,可以拿空间换时间,
    例如:假设仍旧是最近1024个为上限,为每个用户开一个不超过1024长的可变数组(插入时要排序),
    挑战过或者被挑战过都记录在内。

    下次随机生成时只要跳过该数组内出现的用户即可。基本上生成随机用户是线性复杂度或者常数复杂度(用户数固定的话)。
    kurtis
        7
    kurtis  
       2014-05-03 12:14:13 +08:00
    顺便问一下,如何达到线性复杂度,需要说明吗?
    jjdd
        8
    jjdd  
    OP
       2014-05-03 15:39:54 +08:00
    @akfish 感谢回复。a挑战b等于b也挑战了a的
    akfish
        9
    akfish  
       2014-05-03 15:52:58 +08:00
    @jjdd 不谢,那没问题如上。伪随机数生成器是deterministic的,seed定了,每次序列都一样,最坏线性时间,每个用户多两个int字段,每次数据库读一次写一次。这样时间、存储、IO需要都不高。
    Sherlockhlt
        10
    Sherlockhlt  
       2014-05-03 19:11:08 +08:00
    @akfish
    这方法靠谱,赞一个!
    Sherlockhlt
        11
    Sherlockhlt  
       2014-05-03 19:14:02 +08:00
    @akfish
    不过用户数目是一直在增加的,用随机数似乎就无包括后面增加的一些用户了,比如用户人数是 1000 的时候随机到1999,那么就余数得到999,然后以后就再也无法和1999挑战了。
    akfish
        12
    akfish  
       2014-05-03 19:31:46 +08:00
    @Sherlockhlt 可以按一定规律把用户列表分出几个固定长度N的bucket,每个bucket一个ID K,用不重复的[1, N]区间的定长N伪随机数序列。
    存随机数的seed,当前用到的bucket ID,上一次打过的user ID。
    打完一个bucket的用户,再K++撸下一个的。
    这样可以解决用户数的增加的问题。

    对于未满的bucket,简单的做法是,ID越界检测,不存在的跳过就行了。缺点是bucket未满时被跳过的ID,用户就打不到了。
    当然可以bucket满了才能被随机到(在未满bucket里的用户依然能打别人),如果是按注册时间来分的话,等于顺便实现了新手保护规则。
    kurtis
        13
    kurtis  
       2014-05-05 11:17:27 +08:00   1
    平心而论, 很少看到认真讨论些东西的帖子,不少帖子是:买这个好吗,这种语言好吗,没有gf么办之类的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     6125 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 03:12 PVG 11:12 LAX 20:12 JFK 23:12
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86