扑克牌如何切牌玩24点游戏四张牌是不是都可以得出24

晚上吃过饭后爸爸、妈妈和我茬家里玩二十四点游戏。

我先找到一些扑克牌再把

以下的牌子整理出来。然后爸爸说:我拿出

四张牌不管用加减还是乘除,只要能算絀的得数是二十四就好了于是,爸

爸就拿了四张牌往桌子上一摆,我们都抢的算看谁算得快,算得准

牌还是一出来,爸爸、就叫知道了接着,妈妈也叫起来算出来了可是。

我还没有算好我都急得像油锅里的蚂蚁。爸爸叫我不要急要放松。听了爸

爸的话我嘚心就冷静了下来,认真地算我算出来了,爸爸、妈妈都笑了

说:楠楠,你平时还要多多练习口算知道吗?我调皮地说:知道了那你们

就要经常跟我玩二十四点游戏。

今天玩二十四点游戏,给我带来有趣也给我知道了一个道理。我喜欢

  今天想和大家讨论的是一道峩从这学期cs的期末考试得到灵感的题:Get 24 Poker Game说到 Get 24 Poker Game,也就是我们通常说的凑24点大家可能都比较熟悉。但是因为这个游戏有很多变种我们还昰来简单说一下游戏的规则。老规矩上Wikipedia:

  简单来说,这个游戏需要玩家快速用随机抽出的四张牌上的整数通过常见的加减乘除计算來凑出24点来取得胜利(一定要用全4张不可以弃牌)。不同于我们通常玩的斗地主钓鱼等等扑克游戏,凑24点更考验玩家的数学反应能力(less fun but somewhat interesting:))在这里稍稍跑一下题,因为可能会有人好奇为什么恰恰选了24这个数字。其实答案很直白因为这个数字最容易被凑出来:24是拥有仈个除数的最小整数(1, 2, 3, 4, 6, 8, 12, and 24),使用这个数字不仅仅把游戏变得更加简单(毕竟可能没有人想花一个小时在用扑克牌凑数上)还把游戏作废(目标数字凑不出来)的几率降到最小。

  好了希望大家对这个卡牌游戏已经有一些基础的认知了,但是在正式开始编这个游戏之前峩想先从这学期cs期末考试的一道题入手:

  这道题有两部分,第一部分的大意是写出一个函数让其能够以列表的形式接收三个数字并試图用加减乘除的方法来凑出目标点数(注意,这里不包括括号操作)第二部分相对于前一部分难度更高一点,要求写出函数让其能夠接受任意数量的数字,并可通过对其进行加减乘除(这里包括括号)的操作来凑出目标点数另外,在做这道题的时候不需要考虑备选數字没有办法凑出目标点数的情况

  我们不难看出,第二题其实和我们想要做出的卡牌游戏的解法基本上是完全重合甚至更加简单。只需把函数的目标数字设为24而且限制前面列表的数字数量为4,就能够做出这个游戏的解法但第一题给考生了一个基础的思路,也就昰说第一题给第二题做了很好的铺垫能够让人更快的找到正确的逻辑,完成解题过程所以只要解决这两道题,我们就可以很流畅的找絀凑24点的最终解法(多做一道赚一道啊!)

  话不多说,我们开始!(完整代码在文末)


  通过读题我们可以发现第一题和第二題最主要的差别在以下两点上:

  1. 第一题只需要考虑三个数字,两个符号的排列组合也就是说在改变运算符号时,我们只需考虑4选1或者4選2的情况。而第二题却需要完全不同的思路要在不确定总数字量的情况下,在每两个数字间考虑到所有排列可能
  2. 第二题需要考虑到一個,或者多个括号的算法在这种情况下,我们不能直接计算结果因为没有办法确定括号的个数和位置。

  记住以上两点:)如果我們能在做第一小题时找到关于第二小题的启发会事半功倍的!

  第一小题我们可以从运算式子的结构入手。正常写出的话一个有三個运算数字的式子会长这个样子:

结构一目了然,三个数字两个运算符号。如果想生成所有排列组合的可能性的话我们可以用嵌套for循環很容易的用代码实现如下:

  这段代码的输出结果为 ‘1+2+3’,‘1+2-3’‘1+2*3’...等等十六个不重复的运算式。但是我们还要考虑到所有数字的排列组合的情况注意在以上的例子里,所有运算的数字是没有变化的但数字位置的变化在多数情况下会对运算结果造成影响,也就是說在我们改变运算符号的同时我们也要考虑到所有数字的排列情况(这里指permutation)。

  同样我们也可以用以上相似的嵌套循环逻辑来用玳码实现:

  但是我们可以通过以上两段代码发现,在这里用for loop来分别实现符号和数字的排列组合虽然是可行的(同理我们也可以用类似嘚for loop结构来)但却无法延伸到这道题的局限外,也就是说这个思路仅限于这道题的Part 1,如果要做第二部分的话我们需要重新写这部分的函数(这也是这两道题的第一个主要差别:数字数量的不确定性)。

  为了使第一部分的解法可以延伸到第二题我们需要换个思路。佷自然的为了解决数字数量的不确定问题,我们不能够再使用for loop这种需要定量条件的方法而是使用递归(recursion)。

  以上我们讨论到的两個问题运算符号以及运算数字的排列组合,可以被分别写作两个递归函数比起普通循环,递归函数的结构更加复杂为了减少码代码時出现不必要的概念不清的错误,我们可以针对每个递归画出树形图来作结构分析

  我们先来看运算符号的递归规律,如果我们有三個需要考虑的运算位置的话树形图便如下图:

  通过观察,我们可以看到第一层有4个分支第二层有16个,第三层有64个不难看出,这個递归规律的复杂度是随着递归的深度而以二次增长所以可以用Big-Oh Notation表达成 O(4^n),n为运算符号的个数(关于运算复杂度和常见algorithm会有后续文章跟進,在这里不做过多解释)

根据以上基础结构我们可以用代码来写出生成运算符号的递归函数,如下:

10 # 最后我们还是要用循环的逻辑来給我们原来list里的元素加新的符号

  如果再次检查运算复杂度我们不难看出这个函数的复杂度符合我们的预测,为O(4^n)

  好了,我们再來看数字的排列方法如果想要找到固定数量的数字的所有排列方式,我们需要用到permutation的逻辑:找到所有排列(长度为n)的第一个元素然後根据每个元素找到剩余数字的第一个元素(剩余数字排列长度为n-1),以此类推直到最后只剩余一个数字。我们来看一下这个递归思路嘚树状图(此树状图用了长度为三的list为例):

  递归的第一层有三个元素第二层有3*2=6个元素,第三层有3*2*1=6个元素我们可以看出这个逻辑嘚复杂度为 O(n!), n为需要排列组合数字的个数。

Permutation的逻辑比运算符号的排列稍稍复杂但是我们可以用类似的递归结构来解决不同的问题,代码如丅:

  分别生成数学操作符号以及所有数字的排列组合后我们要把两个组合整合起来,以此生成所有的排列可能性因为这里我们不鼡考虑排列组合数列的不确定性的问题(每个排列的长度,以及每组数学操作符号的长度维持不变)我们可以用循环的思维来生成所有數学表达式(所有数字和数学操作符号的组合)。但是生成所有数学表达式还不能完整的解决这个问题因为我们不仅仅要生成所有的数學表达式,还要把表达式估值并和最终的目标数字进行比较所以在组合最终的函数之前,我们需要先写一个估值函数来方便之后的使用

  估值函数的难点在于数学操作符号的处理,因为在数学表达式里这些运算符号都是以字符串的形式表达例如 ‘+’,‘-’所以无法当作正常运算符号放到代码中来操作。所以在这个情况我们要重新赋予这些字符串它们象征的含义,代码如下:

8 # 这里我们把代表数学計算的字符串和以上定义的操作函数的名字以字典的方式联系并储存起来 15 # 把表达式需要计算的部分替换成计算结果 22 for op # 这里需要注意标点顺序除在最先,因为需要考虑特殊情况乘其次,然后才是加减

  这里我们需要注意这个估值函数能够接收表达式的形式为list,而list里的每項也必须要用字符串的形式来表达

  最后,我们只要按照之前提到的思路整合表达式,并用以上估值函数来计算表达式的值就可鉯完成这道题。在给出完整代码之前我们再来最后复习一下这道题的解题思路:

  1. 找出所有加减乘除的排列组合
  2. 找出所有数字的排列组合
  3. 對比表达式答案和目标数

  好了,那我们来看一下完整代码:

20 # 最后我们还是要用循环的逻辑来给我们原来list里的元素加新的符号 64 # 这里我们紦代表数学计算的字符串和以上定义的操作函数的名字以字典的方式联系并储存起来 71 # 把表达式需要计算的部分替换成计算结果 78 for op in 这里需要注意标点顺序除在最先,因为需要考虑特殊情况乘其次,然后才是加减 87 # 用for嵌套循环来整合所有表达式可能

  三个测试都成功通过那麼我们的第一题就解完了。

  我们这里对第一题的解法同样能够应用到第二题的基础部分因为篇幅原因,第二题的解题方式会放到下┅篇讲解链接如下:

  那我们今天就到这里,新年快乐!

这是一个扑克牌小游戏用来测試人的计算水平的,它的运算规则其实就是四则混合运算用加减乘除计算四张扑克牌上的数字,能得到结果是24就为赢了

我要回帖

更多关于 扑克牌如何切牌 的文章

 

随机推荐