吴昊品游戏核心算法 Round 15 (补遗篇) —— 吴昊教你玩UnderCut(毫无策略性的纸牌游戏的模拟)
牌类游戏很多,但是,真正经典的很少,方法都是类似的,模拟出来不是很难,难的在于规则的制定,以及对一定规则之下,所制定的策略,也就是说,模拟不难,难的是AI。费恩曼在他的《费恩曼物理学讲义》中有阐述过物理学研究者们在研究物理的时候就像是在研究一盘规则不确定的棋,一方面要找到规则是什么,另一方面,需要探索出为什么要运用这一规则来解决问题,这就是困难的地方了。
本文作为补遗篇,在德州扑克的基础上增加一款叫UnderCut的游戏,由于过于简单,运气成分过大,基本上不存在策略的存在而缺少游戏性,所以,在一些电脑或者手机平台上并没有以其改编出来的游戏,不过,作为棋牌的一个系列,这里予以收录。
UnderCut的步骤:
STEP 1: 每一轮,黑白双方各取N张牌(N由玩家自己决定,由此我们发现此游戏是纯粹凭借运气的,在理论上,只能说如果玩了无穷次的话,双方将打一个平手)
STEP 2: 依次出示各自的牌
STEP 3: 双方互相得到自己的点数,并进行下一轮的较量
UnderCut的规则:
(A) 如果两张牌数字相同,则没有比分
(B) 两张牌的数字差1,(称为陷入了UnderCut状态)
(B1)如果两张牌分别是1和2,出示较小数字牌的人获得6点
(B2)如果不是以上情况但却是情况(B),出示较小数字牌的人获得两张牌的点数之和
(C) 两张牌的数字相差值超过1,出示较大数字牌的人获得自己的点数
Solve:
这里我们可以看到,由于规则过于简单,我们只需要分三大类(四种情况)分别进行讨论,则可以将整个毫无策略性的纸牌游戏模拟出来。在数据结构上,我们利用两个数组将A和B出的牌(理论上应该是一样多)进行装填,这里假设每个人在一轮最多有20张牌(如果再多一些的话,也许一副扑克牌就不够用了!)
1 #include<stdio.h>
2 //用宏来定义一个常数
3 #define MAXN 20
4
5 int main()
6 {
7 //标志变量用于对空行的调节
8 int flag=1;
9 //每一轮出多少张牌
10 int N;
11 //用两个数组装填整轮的双方的牌,经济又实惠
12 int A[MAXN],B[MAXN];
13 //记录出轮数
14 while(scanf("%d",&N)&&N)
15 {
16 int i;
17 //分别读取玩家A,B的牌
18 for(int i=0;i<N;i++)
19 {
20 scanf("%d%d",&A[i],&B[i]);
21 }
22 //记录每一个玩家的牌点分
23 int pointsA=0;
24 int pointsB=0;
25 //对这一轮的玩家的每一张牌进行模拟
26 for(int i=0;i<N;i++)
27 {
28 //如果玩家A的点数比B要小
29 if(A[i]<B[i])
30 {
31 //B1情况
32 if(A[i]==1&&B[i]==2)
33 pointsA+=6;
34 //B2情况
35 else if(B[i]-A[i]==1)
36 pointsA+=(A[i]+B[i]);
37 //C情况
38 else
39 pointsA+=B[i];
40 }
41 //"对称美"
42 else if(A[i]>B[i])
43 {
44 if(A[i]==2&&B[i]==1)
45 pointsB+=6;
46 else if(A[i]-B[i]==1)
47 pointsB+=(A[i]+B[i]);
48 else
49 pointsB+=A[i];
50 }
51 //A情况,由于A和B的分数没有改变,所以这一情况忽略
52 }
53 //在这里,标志变量产生作用了,在第二行以后都有一个空行
54 if(flag++!=1) printf("\n");
55 printf("A has %d points. B has %d points.\n",pointsA,pointsB);
56 }
57 return 0;
58 }
59
60
61
2 //用宏来定义一个常数
3 #define MAXN 20
4
5 int main()
6 {
7 //标志变量用于对空行的调节
8 int flag=1;
9 //每一轮出多少张牌
10 int N;
11 //用两个数组装填整轮的双方的牌,经济又实惠
12 int A[MAXN],B[MAXN];
13 //记录出轮数
14 while(scanf("%d",&N)&&N)
15 {
16 int i;
17 //分别读取玩家A,B的牌
18 for(int i=0;i<N;i++)
19 {
20 scanf("%d%d",&A[i],&B[i]);
21 }
22 //记录每一个玩家的牌点分
23 int pointsA=0;
24 int pointsB=0;
25 //对这一轮的玩家的每一张牌进行模拟
26 for(int i=0;i<N;i++)
27 {
28 //如果玩家A的点数比B要小
29 if(A[i]<B[i])
30 {
31 //B1情况
32 if(A[i]==1&&B[i]==2)
33 pointsA+=6;
34 //B2情况
35 else if(B[i]-A[i]==1)
36 pointsA+=(A[i]+B[i]);
37 //C情况
38 else
39 pointsA+=B[i];
40 }
41 //"对称美"
42 else if(A[i]>B[i])
43 {
44 if(A[i]==2&&B[i]==1)
45 pointsB+=6;
46 else if(A[i]-B[i]==1)
47 pointsB+=(A[i]+B[i]);
48 else
49 pointsB+=A[i];
50 }
51 //A情况,由于A和B的分数没有改变,所以这一情况忽略
52 }
53 //在这里,标志变量产生作用了,在第二行以后都有一个空行
54 if(flag++!=1) printf("\n");
55 printf("A has %d points. B has %d points.\n",pointsA,pointsB);
56 }
57 return 0;
58 }
59
60
61