纸牌游戏设计制作要点(C语言)
在本站看了一些C语言纸牌游戏设计的一些算法,此不置评。
下面列举设计要点和简洁算法供大家参考。
程序设计解决问题的方法就是算法,也就是功能函数 function ( )。
完整源码可参阅本人在本站的博文《纸牌游戏炸金花设计制作》以及其他纸牌游戏设计制作。
纸牌游戏设计的几个要点:
设计纸牌、画出纸牌、洗牌算法、界面设计文字打印,按游戏规则计算分数比大小定输赢。
transcards ( ){ //传入 num 0-51转换为 cardnum, cardstyle
//牌序号转为牌点和牌花色,画出牌张 }
cardback ( ){ //发牌时隐藏牌面显示牌背图案 }
shuffle_cards ( ){ //洗牌设计 }
print_t ( ){ //打印标题提示等美术文字
//传入参数 sx,sy, t$, tsize=text size }
cal_score ( ){ //计算分数,传入为c1,c2,c3,c4,c5 输出 gscore }
下面是要点的源码:
全局变量声明
canvas cs ; //画布,picturebox 用于画程序界面和显示纸牌
string s,ss ; //print text
string ss0,ss1,ss2,ss3,ss4,ss5; //print text
int sx,sy,dx,dy,px,py; //draw 绘画定位x,y
int i,j,n,t,k; //t = times
int num,num1 ; //select card number
int pn ; //发牌计数
int pnum[54]; //洗牌后的牌序列
int cardnum,cardstyle; //牌点牌花色
string cas1,cas2,cas4; //牌点牌花色图案$
string cas3,cas5 ; //牌背花色, 下注图案
double Rn; //random 洗牌
string t$; //提示文字
int tsize; //textsize
int users1,users2,users3; //东北西玩家分数
int bankers ; //庄家分数 score
int bs,us1,us2,us3 ; //计算分数 banker & users
int c1,c2,c3,c4,c5 ; //calculate score
int c1s,c2s,c3s,c4s,c5s ; //calculate score
int b1,b2,b3,b4,b5 ; //庄家和玩家都杂牌时比大小
int b1s,b2s,b3s,b4s,b5s ; //玩家都杂牌时比大小
int csh1,csh2,csh3,csh4,csh5 ; //玩家5张牌花色
int bf1,bf2 ; //计算分数比大小
int cc[5] ; //计算比分排序
int temp ; //排序
int spn[5]; //user south 牌序列
int epn[5]; //user east 牌序列
int npn[5]; //user north 牌序列
int wpn[5]; //user west 牌序列
int nn,wn,sn,en ; //北西南东牌序号
int gscore ; //输入c1c2c3计算return各家分数
int bet ; //赌注,预设10,20,30
int zu1,zu2,zu3,zu4 ; //北西南东下注数
int wnum ; //庄家和3玩家id切换,1, 2,3 4
int isdo; //1 可发牌翻牌可计算分,0 不可
//纸牌序列:
//cardP num 0 to 12 黑桃 A234..JQK
//cardP num 13 to 25 红心 A234..JQK
//cardP num 26 to 38 梅花 A234..JQK
//cardP num 39 to 51 方块 A234..JQK
// VB6,VS2007 编程:设picturebox:
// cardP(54)图片数组
// 图片高宽为单张纸牌图大小
// 预制扑克牌序列图片底图,程序启动时按序将
// 每单张图片BitBlt..SRCCOPY到图片数组,
// cardP (i)就是整付牌的图片,洗牌发牌都要用到。
// 本程序简化用 num 序号表示54张牌
transcards (){
//传入 num 0-51转换为 cardnum, cardstyle
//牌序号转为牌点和牌花色,画出牌面
//**** draw cards 圆角 ****
cs.SetColor (255,0,0,60); //黑色框线
cs.DrawRect (px+10,py-30,px+109,py+122);
cs.DrawRect (px,py-20,px+117,py+112);
cs.DrawCircle (px+10,py-20,9);
cs.DrawCircle (px+10,py+112,9);
cs.DrawCircle (px+108,py+113,9);
cs.DrawCircle (px+108,py-20,9);
cs.SetColor (255,250,250,250); //牌面白色
cs.DrawRect (px+12,py-28,px+107,py+120);
cs.DrawRect (px+2,py-18,px+115,py+111);
cs.DrawCircle (px+12,py-19,9);
cs.DrawCircle (px+12,py+111,9);
cs.DrawCircle (px+106,py+111,9);
cs.DrawCircle (px+106,py-19,9);
//******* 画出牌面
cardnum=(num-num/13*13)+1;
cardstyle=num/13;
cas1=intToString(cardnum);
if(cardnum==1) cas1="A";
if(cardnum==11) cas1="J";
if(cardnum==12) cas1="Q";
if(cardnum==13) cas1="K";
if (cardstyle==0) cas2="♠";
if (cardstyle==1) cas2="❤";
if (cardstyle==2) cas2="♣";
if (cardstyle==3) cas2="🔶";
if(cardstyle==0||cardstyle==2) {
cs.SetColor (255,0,0,0); }
if(cardstyle==1||cardstyle==3) {
cs.SetColor (255,250,0,0); }
cs.SetTextSize (30); //画纸牌花色
n=0;
if (cardnum==10) n=8;
cs.DrawText (cas1,px+15-n,py+2);
cs.DrawText (cas2,px+8,py+35);
cs.SetTextSize (60);
cs.DrawText (cas4,px+37,py+93);
cs.Update ();
}//transcards ()
cardback (){ //draw cards back picture
//发牌时隐藏牌面显示牌背图案
//**** draw cards 圆角 ****
cs.SetColor (255,0,0,60); //黑色框线
cs.DrawRect (px+10,py-30,px+109,py+122);
cs.DrawRect (px,py-20,px+117,py+112);
cs.DrawCircle (px+10,py-20,9);
cs.DrawCircle (px+10,py+112,9);
cs.DrawCircle (px+108,py+113,9);
cs.DrawCircle (px+108,py-20,9);
cs.SetColor (255,0,150,150); //牌背蓝色
cs.DrawRect (px+12,py-28,px+107,py+120);
cs.DrawRect (px+2,py-18,px+115,py+111);
cs.DrawCircle (px+12,py-19,9);
cs.DrawCircle (px+12,py+111,9);
cs.DrawCircle (px+106,py+111,9);
cs.DrawCircle (px+106,py-19,9);
cs.SetTextSize(70);
cs.DrawText (cas3,px+18,py+70); //show 背花
cs.Update ();
}//cardback ()
shuffle_cards (){ //洗牌设计
cs.SetColor (255,0,120,0); //backcolor
cs.DrawRect (2,2,718,900);
cs.Update ();
for (i=0;i<=51;i++){ pnum[i]=-1 ; }
pn=0; //发牌计数清0
//** 洗牌 **********************
for (i=0;i<=51;i++){ //洗牌
ResetPiece: //已生成牌有相同则重新生成
Rn=random()*52; //随机洗牌
num=(int )(Rn);
pnum[i]=num ;
for (k=0;k<i; k++){
if (num==pnum[k]) goto ResetPiece ; }
}
for (k=0;k<=51;k++){ //显示牌背面图案
px=(k-k/13*13)*48+15;
py=k/13*170+100;
//cardback (); //洗牌后可显示牌背或不显示
}
cs.Update ();
// showcard(); //用于洗牌查验测试,游戏时注释掉
}//shuffle_cards ()
print_t (){ //打印标题提示等美术文字
//** 传入参数:位置 sx , sy,字串 t$,文字尺寸tsize
cs.SetFillMode (1);//0不填色,1填色
cs.SetTextStyle (0); //0正常,1粗体
ss0=t$ ;
cs.SetTextSize (tsize);
cs.SetColor (255,0,200,60);
cs.DrawText (ss0,sx+2,sy+3);
cs.SetColor (255,250,120,0);
cs.DrawText (ss0,sx,sy);
cs.SetFillMode (0);//0不填色,1填色
cs.SetColor (255,250,250,0);
cs.DrawText (ss0,sx,sy);
cs.SetFillMode (1);//0不填色,1填色
cs.Update ();
}//print _t ()
gamestart (){ //游戏 ”梭哈” >>> 开局发牌
shuffle_cards () ; //洗牌
clearOutput(); //清除测试输出
renewscreen (); //画界面
putbet () ; //设置筹码
//游戏开局时先发2张牌,一暗一明,然后轮流下注
for (i=0;i<3;i++){ //init 北西南东
npn[i]=-1 ; wpn[i]=-1 ; spn[i]=-1 ; epn[i]=-1 ; }
// 发牌时各家底注为 10
zu1=10 ; zu2=10 ; zu3=10 ; zu4=10 ;
wnum=1 ; //开局预设东家
change_id () ; //切换玩家
//*******显示"庄家"...文字及分数和下注数
ss=intToString (bankers);
s=intToString (zu1);
t$="庄家 "+" "+ss +" "+s;
sx=235; sy=60; tsize=40;
print_t ();
ss=intToString (users3);
s=intToString (zu4);
t$="西家 "+" "+ss+" "+s ;
sx=20; sy=520; tsize=40;
print_t ();
ss=intToString (users2);
s=intToString (zu3);
t$="南家 "+" "+ss+" "+s ;
sx=235; sy=850; tsize=40;
print_t ();
t$="东家 " ;
sx=620; sy=520; tsize=40;
print_t ();
ss=intToString (users1);
s=intToString (zu2);
t$=ss+" "+s ;
sx=440; sy=520; tsize=40;
print_t ();
//**** 发牌 >> ** 发牌顺序 北西南东
//transcards (int num) 传入num=0--51显示牌面
px=180; py=120; //北家
npn[0]=pnum[0];
num=npn[0]; nn=0 ;
px=nn*60+180 ;
cardback ();
sleep (500) ;
px=5; py=340; //西家
wpn[0]=pnum[1];
num=wpn[0]; wn=0 ;
px=wn*40+5 ;
cardback ();
sleep (500) ;
px=180; py=670; //南家
spn[0]=pnum[2];
num=spn[0]; sn=0 ;
px=sn*60+180 ;
cardback ();
sleep (500) ;
px=435; py=340; //东家
epn[0]=pnum[3];
num=epn[0]; en=0 ;
px=en*40+435 ;
cardback ();
sleep (500) ;
px=180; py=120; //北家
npn[1]=pnum[4];
num=npn[1]; nn=1 ;
px=nn*60+180 ;
transcards ();
sleep (500) ;
px=5; py=340; //西家
wpn[1]=pnum[5];
num=wpn[1]; wn=1 ;
px=wn*40+5 ;
transcards ();
sleep (500) ;
px=180; py=670; //南家
spn[1]=pnum[6];
num=spn[1]; sn=1 ;
px=sn*60+180 ;
transcards ();
sleep (500) ;
px=435; py=340; //东家
epn[1]=pnum[7];
num=epn[1]; en=1 ;
px=en*40+435 ;
transcards ();
pn=7 ; //已发8张牌
isdo=1 ; //开局后方可发牌 deal ()
}//gamestart ()
//游戏是安卓单机版设计,故
//游戏规则稍加改动,以北家为庄家,
//比分大小关键:相同对子时要比散牌点大小
//都是散牌时要逐张牌比大小,比较复杂
//如都是金花也要逐张牌比大小
//相同分数时逐张比大小,比花色大小,
//本游戏暂不设比花色大小,只要对四花色加权就可比出大小
//(bs&&user n<100)为散牌, 500+ 为同花
//**** 计算赢家分数 ** 首三张加权 ****
//** bs 北家,us1 西家 , us2 南家 , us3 东家
//最大分值为赢家,输家赔分,赢家独得
//此安卓版手机游戏改为坐庄制,玩家与庄家比分
//**** 梭哈游戏计分规则:
// 皇家同花顺 AKQJT 500+400+ =900+
// 炸弹 AAAA ......> 2222 700+
// 葫芦 AAAKK 33222 600+
// 同花 A♡Q♡J♡8♡5♡ 500+
// 顺子 AKQJT ==> A5432 400+
// 三条 AAA23 222K8 300+
// 双对子 AAKK◇ ==> 3322♤ 200+
// 对子 AA○◇♧ ==> 22♧◇○ 100+
// 散牌 按牌面计分 A +计 14分 =>> 2 +计 2分
//梭哈5 张牌比分计算稍微复杂些
cal_score (){ //梭哈游戏比分计算
//计算分数,输入为c1,c2,c3,c4,c5 输出 gscore
//为计分:c1->c5 换算为 1 ->> 13 (A ->> K )序
c1s=(c1-c1/13*13)+1; //牌点
c2s=(c2-c2/13*13)+1;
c3s=(c3-c3/13*13)+1;
c4s=(c4-c4/13*13)+1;
c5s=(c5-c5/13*13)+1;
csh1=c1/13 ; csh2=c2/13 ; csh3=c3/13 ;
csh4=c4/13 ; csh5=c5/13 ; //花色
if (c1s==1) c1s=14 ; //A 计点分为 14
if (c2s==1) c2s=14 ;
if (c3s==1) c3s=14 ;
if (c4s==1) c4s=14 ;
// if (c5s==1) c5s=14 ;
// 计算各家总分,
// 同花顺>四条>葫芦>同花>顺子>三条>对子加权
// 5张散牌或同花计分较复杂,要逐张牌比大小,
// 设置在翻牌result () 对比计算
gscore=c1s+c2s+c3s+c4s+c5s ;
//gscore = 5张牌合计分
//皇家同花顺:AKQJT 加权,最大
//若是同花加顺子:同花500+顺子400+ => 900+
//四条,99992 ,4连张炸弹
if (c1s==c2s&&c1s==c3s&&c1s==c4s){
gscore=c1s*4+700 ;
goto putout ; }
if (c2s==c3s&&c2s==c4s&&c2s==c5s){
gscore=c1s*4+700 ;
goto putout ; }
//葫芦AAAKK , 33222
if (c1s==c2s&&c1s==c3s&&c4s==c5s){
gscore=c1s*3+600 ;
goto putout ; }
if (c1s==c2s&&c3s==c4s&&c3s==c5s){
gscore=c3s*3+600 ;
goto putout ; }
if(csh1==csh2&&csh1==csh3&&csh1==csh4&&csh1==csh5){ //同花♡♡♡♡♡
gscore=gscore+500 ; }
if(c5s==(c4s-1)&&c4s==(c3s-1)&&c3s==(c2s-1)&&c2s==(c1s-1)){
//AKQJT 460分 ==>> 65432 顺子
gscore=gscore+400 ; }
if(c1s==14&&c2s==5&&c3s==4&&c4s==3&&c5s==2) { //A5432 =A 顺子 最小
gscore=gscore-13+400 ; }
//三条 AAA23 22234 比三条大小即可,不加权
if (c1s==c2s&&c1s==c3s){
gscore=c1s*3+300 ;
goto putout ; }
if (c2s==c3s&&c2s==c4s){
gscore=c2s*3+300 ;
goto putout ; }
if (c3s==c4s&&c3s==c5s){
gscore=c3s*3+300 ;
goto putout ; }
//双对子 AAKK6 33225
if (c1s==c2s&&c3s==c4s){
gscore=c1s*3+c3s*2+200 ;
goto putout ; }
if (c2s==c3s&&c4s==c5s){
gscore=c2s*3+c4s*2+200 ;
goto putout ; }
if (c1s==c2s&&c4s==c5s){
gscore=c1s*3+c4s*2+200 ;
goto putout ; }
//对子: 相同对子情况较少故散牌不加权
if (c1s==c2s) gscore=c1s*4+100 ;
if (c2s==c3s) gscore=c2s*4+100 ;
if (c3s==c4s) gscore=c3s*4+100 ;
if (c4s==c5s) gscore=c4s*4+100 ;
// **** 算法测试:print "..." 显示牌面 *******
putout :
//显示大牌点 AKQJ
ss1=intToString (c1s) ;
if (c1s==1||c1s==14) ss1="A" ;
if (c1s==13) ss1="K" ;
if (c1s==12) ss1="Q" ;
if (c1s==11) ss1="J" ;
ss2=intToString (c2s) ;
if (c2s==1||c2s==14) ss2="A" ;
if (c2s==13) ss2="K" ;
if (c2s==12) ss2="Q" ;
if (c2s==11) ss2="J" ;
ss3=intToString (c3s) ;
if (c3s==1||c3s==14) ss3="A" ;
if (c3s==13) ss3="K" ;
if (c3s==12) ss3="Q" ;
if (c3s==11) ss3="J" ;
ss4=intToString (c4s) ;
if (c4s==1||c4s==14) ss4="A" ;
if (c4s==13) ss4="K" ;
if (c4s==12) ss4="Q" ;
if (c4s==11) ss4="J" ;
ss5=intToString (c5s) ;
if (c5s==1||c5s==14) ss5="A" ;
if (c5s==13) ss5="K" ;
if (c5s==12) ss5="Q" ;
if (c5s==11) ss5="J" ;
//**** 测试 print test ** return gscore ****
//calculate & putout gscore, return gscore
print " " ; // 算法测试检验,可注释掉
print "取得牌面 = ",ss1 ," 牌序 ", c1s ;
print "取得牌面 = ",ss2 ," 牌序 ", c2s ;
print "取得牌面 = ",ss3 ," 牌序 ", c3s ;
print "取得牌面 = ",ss4 ," 牌序 ", c4s ;
print "取得牌面 = ",ss5 ," 牌序 ", c5s ;
// print "return gscore = ",gscore ;
}//cal_score ()
cal_score (){ //三张牌的炸金花比分计算较为简单
//计算分数,输入为c1,c2,c3, 输出 gscore
//为计分:c1,c2,c3 换算为 1 ->> 13 (A ->> K )
c1s=(c1-c1/13*13)+1; //牌点
c2s=(c2-c2/13*13)+1;
c3s=(c3-c3/13*13)+1;
csh1=c1/13 ; csh2=c2/13 ; csh3=c3/13 ; //花色
if (c1s==1) c1s=14 ;
if (c2s==1) c2s=14 ;
if (c3s==1) c3s=14 ;
// 计算各家总分,豹子金花顺子对子加权
// 3张杂牌或同花计分较复杂,要逐张牌比大小,
// 翻牌result () 对比计算
gscore=c1s+c2s+c3s ; //3张牌合计分
if (c1s==c2s&&c1s==c3s){ //豹子
gscore=c1s*3+600 ;
goto putout ; }
//金花顺 = 300+ 200+
if (csh1==csh2&&csh1==csh3){ //金花
gscore=gscore+300 ; }
if (c3s==(c2s-1)&&c2s==(c1s-1)){ //顺子
gscore=gscore+200 ; }
if (c1s==14&&c2s==3&&c3s==2) {
//A32 = A23 顺子 算A顺子加30 大于K顺子
gscore=gscore+30+200 ; }
//对子 加权
if (c1s==c2s) gscore=c1s*4+100 ;
if (c2s==c3s) gscore=c2s*4+100 ;
// 若有豹子则 杂花 235 吃豹子
if (bs>600){ // 庄家有豹子
if (csh1>csh2||csh1<csh3){ //杂花
if (gscore==10) gscore=gscore+700 ; } }
// **** 测试:显示牌面 *******
putout :
ss1=intToString (c1s) ;
if (c1s==1||c1s==14) ss1="A" ;
if (c1s==13) ss1="K" ;
if (c1s==12) ss1="Q" ;
if (c1s==11) ss1="J" ;
ss2=intToString (c2s) ;
if (c2s==1||c2s==14) ss2="A" ;
if (c2s==13) ss2="K" ;
if (c2s==12) ss2="Q" ;
if (c2s==11) ss2="J" ;
ss3=intToString (c3s) ;
if (c3s==1||c3s==14) ss3="A" ;
if (c3s==13) ss3="K" ;
if (c3s==12) ss3="Q" ;
if (c3s==11) ss3="J" ;
//**** 测试 print test ** return gscore ****
// putout:
//calculate & putout gscore, return gscore
print " " ; // 算法测试检验,可注释掉
print "取得牌面 = ",ss1 ," 牌序 ", c1s ;
print "取得牌面 = ",ss2 ," 牌序 ", c2s ;
print "取得牌面 = ",ss3 ," 牌序 ", c3s ;
// print "return gscore = ",gscore ;
}//cal_score ()
//**** End ****