算法:扑克牌相关的一个简单功能示意(纯C实现)
中午逛博园的时候看到这个题目,兴致盎然,稍微实现了一下
题目以及原文地址:C++算法编程题(一)扑克牌发牌
题目要求:
程序描述:
一副纸牌有52张,4种花色,每种花色13张。我们能用一个整数m就表示出所有的52种情况,规则是:
m / 13: =0: 红心,=1: 方块,=2: 梅花,=3: 黑桃
m % 13: =0:2,=1:3,=2:4 .... =8:10,=9:J,=10:Q,=11: K,=12:A
比如:m = 15 就表示:方块4 m=38表示:梅花A
我们希望用程序模拟1副扑克牌随机抽取13张,发给某人的过程。
发牌后需要排序:规则是:先按花色,再按点数。花色的大小顺序是:梅花、方块、红心、黑桃。点数的顺序是:2、3、4、…. 10、J、Q、K、A。
然后,挑选出最大的连续牌型。规则是:连续张数多的大。张数相等的则花色大的大(此时与点数无关)。
直接上代码吧
1 // -*- encoding: utf-8 -*- 2 3 /** 4 * Copyright 博客园-本文作者. All Rights Reserved. 5 * Author: kevin 6 * since: 2013-11-29 7 */ 8 #include<stdio.h> 9 #include<stdlib.h> 10 #include<stdbool.h> 11 12 #define POKER_NUM 52 13 #define EACH_SUIT_NUM 13 14 #define CARDS_NUM 13 15 16 int main(int argc, char *argv[]){ 17 void printCards(int [], int); 18 void initCards(int [], int); 19 int cmp(const void *, const void *); 20 int find(int [], int, int []); 21 22 // 1. 发牌 23 int cards[CARDS_NUM]; 24 initCards(cards, CARDS_NUM); 25 printf("发牌: "); 26 printCards(cards, CARDS_NUM); 27 28 // 2. 排序 29 qsort(cards, CARDS_NUM, sizeof(int), cmp); 30 printf("排序: "); 31 printCards(cards, CARDS_NUM); 32 33 // 3. 挑出最大牌型 34 int result[CARDS_NUM]; 35 int num = find(cards, CARDS_NUM, result); 36 printf("结果: "); 37 printCards(result, num); 38 39 return 0; 40 } 41 42 43 /* 44 * 随机挑出num张牌 45 * 如果只是从52张不同牌里先后挑出13张牌, 46 * 本函数的do-while的重复使用几率低于19.5% 47 */ 48 void initCards(int cards[], int num){ 49 srand(time(NULL)); 50 51 bool existed = false; 52 int chosen; 53 int i; 54 for(i=0; i < num; i++){ 55 do{ 56 existed = false; 57 chosen = rand() % POKER_NUM; 58 59 int j; 60 for(j = 0; j < i; j++){ 61 if(cards[j] == chosen){ 62 existed = true; 63 break; 64 } 65 } 66 }while(existed); 67 cards[i] = chosen; 68 } 69 } 70 71 72 /** 73 * 按照规则(题目设定有点怪) 74 * 编号规则: 0-红心 1-方块 2-梅花 3-黑桃 75 * 排序规则: 梅花 > 方块 > 红心 > 黑桃 76 * 此处排完后,不管花色还是点数都是从小到大 77 * 78 * * 如果题设排序有变化,修改下本函数就可以了 79 */ 80 int cmp(const void * a, const void * b){ 81 int aa = *(int *)a, bb= *(int *)b; 82 int aSuit = suit(aa), bSuit = suit(bb); 83 int aValue = value(aa), bValue = value(bb); 84 if(aSuit == 3){ 85 if(bSuit == 3) 86 return intcmp(aValue, bValue); 87 else 88 return -1; 89 }else{ 90 if(bSuit == 3) 91 return 1; 92 else{ 93 int t = intcmp(aSuit, bSuit); 94 if(t != 0) 95 return t; 96 else 97 return intcmp(aValue, bValue); 98 } 99 } 100 } 101 102 /** 103 * 注意: 104 * 1. 参数result初始长度必须大于或等于返回结果 105 * 2. 参数cards内的值必须是排好序的 106 */ 107 int find(int cards[], int len, int result[]){ 108 int magic[EACH_SUIT_NUM] = {0}; //存储每个起点后的跟随个数 109 int max = magic[0]; //记录每个串的跟随长度(串存在的话) 110 int pos = 0; //记录最长串的起始位置 111 112 int i = 0; 113 while(i < len){ 114 int x = i; //保存下起始位置 115 while(next(cards[i]) == cards[++i]){ 116 magic[x] += 1; 117 } 118 if(max < magic[x]){ 119 max = magic[x]; 120 pos = x; 121 } 122 } // 本问题的核心部分应该是在这个嵌套循环里,结果在magic数组里 123 124 // 将最长串复制到结果数组里 125 for(i = 0; i < max + 1; i++){ 126 result[i] = cards[pos++]; 127 } 128 return max+1; 129 } 130 131 // 本张牌的下一张,-1表示下一张牌没有 132 int next(int m){ 133 if(value(m) >= EACH_SUIT_NUM - 1) 134 return -1; 135 else 136 return m + 1; 137 } 138 139 // 比较整型大小 140 inline int intcmp(int a, int b){ 141 if(a < b) return -1; 142 else if(a > b) return 1; 143 else return 0; 144 } 145 146 // 花色:0-红心 1-方块 2-梅花 3-黑桃 147 inline int suit(int a){ 148 return a / EACH_SUIT_NUM; 149 } 150 151 // 计算同花色内的序号值 152 inline int value(int a){ 153 return a % EACH_SUIT_NUM; 154 } 155 156 /** 157 * 打印输出函数,此处输出形式与其它部分无关,可自行定义 158 * 此处每个中文按3个char算,英文按1个char算 159 */ 160 const char values[][3]= {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; 161 const char suits[][7] = {"红心", "方块", "梅花", "黑桃"}; 162 void printCards(int cards[], int len){ 163 int s, v; 164 int i; 165 for(i = 0; i < len; i++){ 166 s = suit(cards[i]); 167 v = value(cards[i]); 168 printf("%s%s ", suits[s], values[v]); 169 } 170 printf("\n"); 171 } 172 173 //END
* 非windows系统下完美运行,win系统下推荐使用MinGW编译器; 2000年以前的编辑器编译器就把最后个打印函数改改吧,也能跑
认真写好每份代码,认真权衡每种模式应用范围和场景,认真理解工具和库的优劣,认真做自己。