美文网首页
高性能麻将胡算算法(回溯+剪枝)

高性能麻将胡算算法(回溯+剪枝)

作者: Teech | 来源:发表于2020-02-08 22:04 被阅读0次

麻将的胡牌算法算麻将中最主要的一个算法,这里说的算法是一个O(1)的算法,当然是用空间换时间了,如果我们可以把每个胡牌类型都实现存到hash表中,只需要把牌带进去查询就可以知道是否可胡了。
那到底hash表如何生成呢,这里来讲解一个回溯+剪枝的算法提前计算好所有的胡牌类型。先说明下牌型术语。

  • 牌型术语
    顺子 : 比如123 或者 345
    刻子 :333 或者 666
    将 : 22 或者 55

先只考虑一种花色,当牌可以胡时,一定是3N+2的组合,2做将,3N表示3N个顺子或者刻子。

  • 可以使用数组的下表来表示牌的值,数组的值表示牌的张数。
    比如array = {2,2,2,0,0,0,3,3,3},表示牌值1,2,3分别2张,牌值7,8,9分别是3张。

  • 针对不同花色,当只有一种花色为3n+2,其余花色都为3n,那么可以胡牌。所有要找到所有3n以及所有3n+2的数组。

  • 因为牌值的大小最大为9,如果找到了数组可以用一个64位整数存储,所以最终hash表的key可以是个64位整数(如果是8位多好,就可以用32位整数存储了)。

现在先来通过一个算法来找到值1到9中,所有的表示3N的组合。
思路:

  1. 通过加法添加,每次加3张牌,要么是加顺子 要么是加刻子

2.加顺子或者加刻子,只需要一个参数来表示,比如要加刻子{n,n,n},顺子{n,n+1,n+2}。这里需要注意的是加刻子时n小于等于9,顺子时n小于等于7

3.构建树,然后回溯。

//定义数组 array
gen3n(array,level)
    //这里之所以定义大于4层就退出不继续构造树,因为麻将的3n的张树最多12张
    if(level >= 4) return
    for i=1 to 16
        if i <= 9    //这里添加刻子
            array[i] = array[i] + 3
            if array[i] > 4  //麻将的张数不能超过4,剪枝
                 goto backtrace 
        else //这里添加顺子
            index = i-9
            array[index] = array[index]+1
            array[index+1] = array[index+1]+1
            array[index+2] = array[index+2]+1
            if array[index] > 4 OR  array[index+1] > 4 OR array[index+2] > 4//麻将的张数不能超过4,剪枝
              goto backtrace
        print(array) //这里可以把array转换成64整数,然后记录进hash表
        gen3n(array,level+1)
        //回退
     backtrace:
        if(i<=9)  
            array[i] = array[i]-3
        else
            index = i-9
            array[index] = array[index] -1
            array[index+1] = array[index+1] -1
            array[index+2] = array[index+2] -1

目前来说应该对如何生成3N的算法应该理解了,那么生成3n+2也简单了,先添加个将在来生成3N+2算法就可以了。
伪代码如下

gen3n2()
    //定义array
    for i= 1 to 9
        array.add({i,i})
        gen3n(array,0)
        array.remove({i,i})  //回溯

当时我们项目中这个工具,使用lua来编写的,生成所有的组合的时间在2秒左右,如果改成c++肯定要小于1秒的。这种事先生成data的工具对时间要求不敏感,因为生成一次终生可用。

说完了工具的伪代码,现在说说服务器胡牌判定的伪代码

check(array)
  //1:万 2:筒 3:条
  b3n2 = false //定义是否有3n2
  for i=1 to 3
    key = tokey(array[i]) //把这个一个花色的牌转换成key
    if hash3n2[key]  //在3N2的哈希表中查找到
        if b3n2 == true //之前花色已经查找到了3n2的key了,再次查找到3n2的key
          return false
        b3n2 = true
   else if hash3n[key]  //在3N的哈希表中查找到

   else  //在3N2以及3N+2的哈希表中都查找不到
      return false
  
  return true

服务器开始运行时加载data到hash表,这个表差不多一共占用5M内存左右,但是换来的是胡牌判定的O(1)的效率,这个很值得。这样麻将中几乎没有消耗性能的业务了。后面有空谈谈麻将AI的部分,也是通过预先生成一个牌型对应概率的做法,让AI模块变成非常高性能的模块。

相关文章

  • 高性能麻将胡算算法(回溯+剪枝)

    麻将的胡牌算法算麻将中最主要的一个算法,这里说的算法是一个O(1)的算法,当然是用空间换时间了,如果我们可以把每个...

  • 高性能麻将AI算法

    想要一个高性能的麻将AI算法,这个问题我们拆解成2个子集来思考,“高性能”,“麻将AI算法”,我们先针对麻将AI算...

  • [二叉树] 二叉树剪枝

    前言 剪枝操作是也算二叉树的一个基本操作之一,包括回溯算法等,剪枝的思想都是算法优化的一个重要考量,今天记录一下这...

  • 回溯算法

    回溯算法的原理是深度优先搜索(dfs),然后分析题目寻找剪枝的方法以此来优化算法,降低时间复杂度。 回溯算法有一个...

  • 大厂算法面试之leetcode精讲11剪枝&回溯

    大厂算法面试之leetcode精讲11剪枝&回溯 视频讲解(高效学习):点击学习[https://xiaochen...

  • 「回溯算法」专题介绍

    「回溯算法」专题介绍 第 1 节:从全排列问题开始理解回溯搜索算法 引言 大家好,今天要和大家分享的主题是“回溯算...

  • 回溯算法

    回溯算法 回溯算法介绍   回溯算法并不是非常复杂的算法, 很多人接触过但是未必知道这是回溯算法; 典型的回溯算法...

  • 麻将胡牌算法

    犹豫工作和自己学习了一些新的东西,今天打开博客吓自己一跳,原来自己这么久没有更新博客了。看来以后还是要坚持每周最少...

  • C语言单纯的模拟麻将胡牌算法!简单分析,不喜莫入

    麻将胡牌算法 不带赖子,14张牌,以筒子为例子,不考虑杂交系列,纯属探索性算法,并非完整麻将算法,请勿存在误区。单...

  • DFS+记忆化搜索

    dfs 和 bsf 和 回溯回溯是有剪枝的dfshttp://blog.csdn.net/fightforyour...

网友评论

      本文标题:高性能麻将胡算算法(回溯+剪枝)

      本文链接:https://www.haomeiwen.com/subject/birwxhtx.html