简单的麻将ai算法
写一个麻将的小游戏,需要自动出牌的ai算法,自己动手写了一个,虽然不是很聪明,但惊讶于它的简单,就记录一下。用python来实现的。
- 先归纳麻将的规则。看似很复杂的麻将规则,可以用一个公式来表示。胡牌 = AA and (AAA or AAAA or ABC)
AA:是麻将
AAA:是碰牌
AAAA:是杠牌
ABC:是连牌 - 牌的表示。用数字来表示麻将牌,如11-19表示一万到九万,31-39表示一条到九条,51-59表示一筒到九筒。为什么条子和筒子之间要隔着10个数字呢,是为了算法的实现。
- 判断胡牌。用一个递归函数来判断胡牌。牌cardList要求按牌面的数字大小,从小到大排列。
# cardList: 是手上的牌,需要从小到大排列
def match(cardList, majiang=False):
if len(cardList) == 0 and majiang:
return True
rst = False
# AA
if not majiang and len(cardList) >= 2 and cardList[0] == cardList[1]:
list1 = [] + cardList
list1.pop(0)
list1.pop(0)
rst = match(list1, True)
# AAA
if not rst and len(cardList) >= 3 and cardList[0] == cardList[1] == cardList[2]:
list1 = [] + cardList
list1.pop(0)
list1.pop(0)
list1.pop(0)
rst = match(list1, majiang)
# AAAA
if not rst and len(cardList) >= 4 and cardList[0] == cardList[1] == cardList[2] == cardList[3]:
list1 = [] + cardList
list1.pop(0)
list1.pop(0)
list1.pop(0)
list1.pop(0)
rst = match(list1, majiang)
# ABC
if not rst and len(cardList) >= 3:
list1 = []
a = cardList[0]
b = False
c = False
for i in range(1, len(cardList)):
if not b and cardList[i] == a + 1:
b = True
elif not c and cardList[i] == a + 2:
c = True
else:
list1.append(cardList[i])
if(b and c):
rst = match(list1, majiang)
return rst
- 判断出牌。出牌就是要把手上最没用的一张牌打出去。先给手上所有的牌都计算一个分值,得分最低的牌就是最没用的牌。怎么给每张牌计算分值呢?
如下图,牌面x的分值计算方法。如AAAA这样的牌,得分最高,不会被打掉;如AC这样差一些的牌,得分比较低,被打掉的可能性就增大。
不但要计算手上的牌,还要考虑未出现的牌。如手上有AC这样的牌,但未出现的牌中还有比较多的A,B牌。那么凑出AAA或ABC牌的几率加大了,得分也高一些,被打出去的概率也小一些。但是,未出现的牌再多,也比不上手里已经有ABC这样成型的牌来的实际,所以未出现的牌的分值要低一些。比如,手上的牌计100分,那未出现的牌只能计5分。
para = [10, 2, 1]
scale = 50
# cards:手上的牌
# dark:未出现过的牌
def cardsScore(cards, dark):
scores = []
for c in cards:
score = 0
for cc in cards:
gap = abs(cc - c)
if gap < 3:
score += para[gap] * scale
for cc in dark:
gap = abs(cc - c)
if gap < 3:
score += para[gap]
scores.append(score)
return scores
- 测试。通过测试,简单几行代码实现的ai算法,还是很容易胡牌的。四个这样的ai对局,95%可以胡牌,有5%会黄,没ai胡牌。可以调整para和scale的值,来提高ai的智力。