棋牌类益智游戏,要求四个数字运算结果等于二十四,一起来玩玩吧!这个游戏用扑克牌更容易来开展。拿一副牌,抽去大小王后(初练也可以把J/Q/K/大小王也拿去),剩下1~10这40张牌(以下用1代替A)。任意抽取4张牌(称为牌组),用加、减、乘、除(可加括号,高级玩家也可用乘方开方与阶乘运算)把牌面上的数算成24。每张牌必须用且只能用一次。如抽出的牌是3、8、8、9,那么算式为(9-8)×8×3=24
对于此类问题,最先考虑到的是穷举算法,也就是在计算机的算力范围内,通过每个结果的穷举,最终得除整个问题集合。
首先,对于只有数字,那么它的全排列有4!= 24种可能的排列情况。
然后是在其中插入运算符,由于只有三个运算符,那么三个运算符全排列的话也是 43 = 64种表示方法,两者再任意组合,那么就有了1536种计算结果。再加上运算过程中的括号,分别有一个括号两个括号两种分类,其中一个括号能有5种方式,分别是(a+b)+c+d,a+(b+c)+d,a+b+(c+d),(a+b+c)+d,a+(b+c+d) 两个括号能有1种方式,(a+b)+ (c+d),故总的只有一种。因此加起来是六种方法,总的算出来有9216种结果,因此完全可以靠穷举来获得结果。
主要的算法就是表达式的计算,最开始想利用逆波兰表达式通过入栈出栈进行计算得到表达式的结果,但是通过查找资料发现,python种有一个表达式的计算函数,可以直接实现字符串表达式的计算,比如eval(‘8+9+10+11’) = 38,所以就不需要通过复杂的入栈出栈的操作来计算表达式的值。
次要的算法就是构建全排列的数字和字符表达式集合,python种可以通过iteratools来实现全排列的构建和使用,也可以使用穷举的办法来实现全排列的构建。本次程序使用循环来实现排列的构建。
初始化操作:
数据结构初始化:
func = []
func2 = []
game = []
result = []
result2 = []
result3 = []
result4 = []
evaluate = []
# 产生随机数
# nums = [randint(1,13) for i in range(4)]
# 运算符集合
operations = ['+','-','*','/']
游戏初始化
def gameInit():
nums = [randint(1, 13) for i in range(4)]
# 防止得出的数没有结果
while gameStart(nums) == []:
nums = [randint(1, 13) for i in range(4)]
return nums
以每一种的排列方式作为一个列表,然后将其输入一个新的列表,也就是每一种数字的排列作为一个数字列表,然后直接用数字列表来操作。
# 数字全排列可能出现的组合
for i in range(4):
for j in range(4) :
for k in range(4):
for l in range(4):
if i != j and i != k and i != l and j != k and j != l and k != l:
func.append([nums[i],nums[j],nums[k],nums[l]])
同样的原理,但是基于运算符能够重复,于是乎就不用去限定下表是否相等,直接排列存在func2[]列表种就行
# 运算符全排列可能出现的组合
for i in range(4):
for j in range(4):
for k in range(4):
func2.append([operations[i],operations[j],operations[k]])
# 两者以一定的规则组合
for num in func:
# print(type(num))
for ope in func2:
num1 = num.copy()
num1.insert(1,ope[0])
num1.insert(3,ope[1])
num1.insert(5,ope[2])
result.append(num1)
# 括两个数的括号与表达式的介结合
for i in range(0,5,2):
for res in result:
rescopy = res.copy()
rescopy.insert(i,'(')
rescopy.insert(i+4,')')
result2.append(rescopy)
# 括三个数的括号与表达式结合
for i in range(0,3,2):
for res in result:
rescopy = res.copy()
rescopy.insert(i,'(')
rescopy.insert(i+6,')')
result3.append(rescopy)
# 两个括号系列
for res in result:
rescopy = res.copy()
rescopy.insert(0,'(')
rescopy.insert(4,')')
rescopy.insert(6,'(')
rescopy.insert(10,')')
result4.append(rescopy)
# 合并并转化成字符串
result = result2 + result3 + result4
for res in result:
res = [str(i) for i in res]
# print(str(res))
evaluate.append(''.join(res))
# 计算表达式结果
for eva in evaluate:
try:
if eval(eva) == 24:
game.append(eva)
except:
pass
# 正式游戏
def gameing():
point = 0
life = 3
nums = gameInit()
print("给出的四张牌为:" + str(nums))
games = gameStart(nums)
while life > 0:
start = time.time() # 获取开始时间
game = input("请在120秒内输入你的运算式:")
end = time.time() - start # 获取结束时间
if end > 120: # 限制时间
print("您已超时!")
life = life - 1
continue
gamecopy = game
gamecopy = gamecopy.replace('J','11')
# print(gamecopy)
gamecopy = gamecopy.replace('Q','12')
# print(gamecopy)
gamecopy = gamecopy.replace('k','13')
# print(gamecopy)
if gamecopy in games:
print("正确,进入下一题!")
point = point + 20 # 加分
nums = gameInit() # 获取新的组合
games = gameStart(nums)
else:
print("结果不正确!")
life = life - 1
nums = gameInit() # 获取新的组合
games = gameStart(nums)
print("游戏结束,你的分数为:" + str(point))
name = input("请输入你的名字,以便我们存入高分榜单")
with open('TopList.txt','a') as file:
file.write(name + str(point) + '\n')
利用itertools优化全排列的四个循环
import itertools
nums = [1,2,3,4]
alllist = []
for each_list in itertools.permutations(nums,4):
str_list = [str(num) for num in each_list]
alllist.append(str_list)
print(alllist)
利用zip函数来实现两者的两两混合,其中定义的两个函数是用来获取所有的数字数列和操作符列表,可以在实际使用过程中替换。
def get_allNumList():
return [['1','2','3','4'],['2','3','4','5']]
def get_allOpeList():
return [['+','-','*']]
num_and_list_mixs = []
for str_list in get_allNumList():
for op_list in get_allOpeList():
op_list.append('')
num_and_list_mix = zip(str_list,op_list)
num_and_list_mixs.append(num_and_list_mix)
print(num_and_list_mixs)
解决一个算法问题的过程中,遵循以下规则:
最后应该从多方面测试。