我自己写的52张牌发牌程序,请大家指教,接下来准备写网络对战部分
private void GetCard()
{
Hashtable cards = new Hashtable();
int tmp=0;
for (int i = 0 ; i < 4 ; i ++)
{
for (int m = 0 ; m <13 ; m ++)
{
tmp = ((Byte)(i) << 4)|((byte)m);
cards.Add((int)(i * 13 + m), (byte)tmp);
}
}
Hashtable tempcards = new Hashtable();
tempcards = (Hashtable)cards.Clone();
int[,] playerCard = new int[4, 13];
int mod = 52;
Random random = new Random();
for ( int k = 0 ; k < 3 ; k ++)
{
for (int j = 0 ; j < 13 ; j ++)
{
int cardId=(int)(Math.Floor((random.NextDouble() * 103) % mod--));
playerCard[k, j] = (byte)tempcards[cardId];
if (cardId != mod)
{
tempcards.Remove(cardId);
tempcards.Add(cardId,tempcards[mod]);
}
tempcards.Remove(mod);
}
}
for(int j = 0 ; j < 13 ; j ++)
{
playerCard[3, j] = (byte)tempcards[j];
}
}
问题点数:20、回复次数:44Top
1 楼raulredondo()回复于 2006-02-12 15:09:59 得分 0
搞不明白一个发牌写那么复杂
我觉得我的思路比较简单
把52张牌放到一个ArrayList里面,或者随便什么里面,hashtable也可以,但一定要可以remove的,然后用random.Next(ArrayList.Count)来产生一个整数,这个数字就对应ArrayList里面的那个牌,然后再把ArrayList里面的牌删了,这样就不会产生一样的牌Top
2 楼iasky(iasky)回复于 2006-02-12 15:55:32 得分 0
markTop
3 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-02-12 16:09:24 得分 0
楼上说的也只是少一个 for ( int k = 0 ; k < 3 ; k ++) 循环嘛。Top
4 楼sp1234(asp.net不是一个语言,是一个操作系统)回复于 2006-02-12 16:14:02 得分 0
也不是呀?内层循环才13个呀,循环体内总共执行39次呀?
随机抽取一张牌也要执行51次呀。
不过一张一张随机抽取,确实比较好理解。Top
5 楼JspAndAsp(为MVP而努力)回复于 2006-02-12 20:16:50 得分 0
To raulredondo,
你那样写的话,player 抓到一条龙的几率会很大,Random是跟着时间走的,所以连续两次会出现红2红3
To sp1234(半梦半醒之间,情人沙漠上好像只有我一颗不死的种子,
每次取13张牌,取三次,剩下13张肯定是下一个人的,所以不用取了,直接给第四个人
Top
6 楼charles_y(每天上网一小时)回复于 2006-02-12 20:34:53 得分 0
你搞复杂了,而且不符合实际大牌的过程
一般的做法,洗牌(即把牌顺序打乱),然后发牌,第一张,第二张....
必要的话加个切牌。Top
7 楼vosov(ask a favor of wind...)回复于 2006-02-12 20:46:05 得分 0
界面怎么做?有现成的控件吗Top
8 楼JspAndAsp(为MVP而努力)回复于 2006-02-12 21:41:00 得分 0
To charles_y(难得糊涂),
同时发4个人的牌,与每次取13张牌,一共取3次,在现实中都有人那么操作的,都是公平取样的,后者不好想,但是效率高于前者。
只要确保牌是打乱的,就可以。Top
9 楼charles_y(每天上网一小时)回复于 2006-02-12 21:49:05 得分 0
逻辑上还是有些不一样的,一个是发牌前牌的顺序已经确定,一个是没有确定,而前者更符合实际的发牌过程。
我帮别人做了一个texas holder的游戏,不过没有彻底完成Top
10 楼WeiWY(大海)回复于 2006-02-12 22:28:11 得分 0
关注网络对战部分Top
11 楼fenglik(风易)回复于 2006-02-13 08:43:09 得分 0
关注Top
12 楼itmingong(nous+wisdom+courage)回复于 2006-02-13 08:46:37 得分 0
不错哦,学习一下Top
13 楼huwei001982(michaelhuwei.cnblogs.com)回复于 2006-02-13 08:50:11 得分 0
搞不明白一个发牌写那么复杂
我觉得我的思路比较简单
把52张牌放到一个ArrayList里面,或者随便什么里面,hashtable也可以,但一定要可以remove的,然后用random.Next(ArrayList.Count)来产生一个整数,这个数字就对应ArrayList里面的那个牌,然后再把ArrayList里面的牌删了,这样就不会产生一样的牌
---------------------------------------
确定你不是在说笑?
把 ArrayList 里的牌删了, 说起来是一句 Remove 就完了, 你知道它内部是要循环查找整个 ArrayList 里的数据的吗? 这样的话, 每发一个牌就要循环一次, 你看看这效率......
又一个被 rad 害惨的人...Top
14 楼huwei001982(michaelhuwei.cnblogs.com)回复于 2006-02-13 08:59:26 得分 0
Dim ary As New ArrayList
Dim i, index, t As Int32
For i = 1 To 52
ary.Add(i)
Next
Dim rad As New Random
For i = 0 To 51
index = rad.Next(52)
t = DirectCast(ary(i), Int32)
ary(i) = ary(index)
ary(index) = t
Next
------------
这些就够了, 这是游戏编程书上的算法Top
15 楼charles_y(每天上网一小时)回复于 2006-02-13 09:48:56 得分 0
原来我写的,看看能不能提供一些思路,不对的地方大家指正,用的是C++
class CCard //一张牌
{
public:
int nFace; //点数
int nSuit; //花色
public:
void SetSuit(char *sSuitName);
void SetFace(char *sFaceName);
int CompairFace(CCard anotherCard);
int Compair(CCard anotherCard);
string GetSuitName();
string GetFaceName();
CCard();
virtual ~CCard();
};
class CDeck //一副牌
{
private:
CCard m_Cards[52];
int m_nDealIndex;
public:
void Init(); //初始化一副牌
void Shuffle();//洗牌
CCard DealACard();//发一张牌
CDeck();
virtual ~CDeck();
};
实现:
void CDeck::Init()
{
m_nDealIndex=0;
for(int i=0;i<=3;i++)
for(int j=0;j<=12;j++)
{
int nIndex=j+i*13;
this->m_Cards[nIndex].nFace=j+2;
this->m_Cards[nIndex].nSuit=i;
}
}
void CDeck::Shuffle()
{
srand( (unsigned)time( NULL ) );
for(int i=0;i<1000;i++) //一千次差不多了
{
int nCard1=rand()%52;
int nCard2=rand()%52;
CCard tempCard=m_Cards[nCard1];
m_cCards[nCard1]=m_Cards[nCard2];
m_cCards[nCard2]=tempCard;
}
}
CCard CDeck::DealACard()
{
assert(m_nDealIndex<=51);
return m_Cards[m_nDealIndex++];
}Top
16 楼johnsuna(缘来是e)回复于 2006-02-13 10:01:35 得分 0
楼主的确实复杂了点,简单就是美。Top
17 楼ccs02287(☆兜兜里有糖☆偶滴兜兜里有糖,你和我玩不?)回复于 2006-02-13 11:28:02 得分 0
顶下!Top
18 楼lxdonger(风清)回复于 2006-02-13 12:29:03 得分 0
支持 charles_y(难得糊涂) 的方法,比较的简单.Top
19 楼yf1025(小桥,流水,人家)回复于 2006-02-13 12:36:28 得分 0
学习Top
20 楼huxin2007(西门吹雪)回复于 2006-02-13 13:38:39 得分 0
我认为应该先洗牌,再按顺序发牌。
这是MSDN上发布Starter Kit中的21点纸牌游戏的洗牌方法,请大家参考:
public void Shuffle()
{
Random random = new Random();
for (int i = 0; i < cards.Count; i++)
{
int index1 = i;
int index2 = random.Next(cards.Count);
SwapCard(index1, index2);
}
}
private void SwapCard(int index1, int index2)
{
Card card = cards[index1];
cards[index1] = cards[index2];
cards[index2] = card;
}
其中carts是一个List<Card>Top
21 楼kagad(kagad)回复于 2006-02-13 14:08:38 得分 0
MARKTop
22 楼raulredondo()回复于 2006-02-13 15:39:30 得分 0
to huwei001982(編程浪子)
Remove的确是遍历的,但是这个发牌一共也只有52次循环,这点效率没有必要斤斤计较
你觉得效率低,那你说一个方法,效率又高抓牌又不会重复的
to 楼主
似乎Random不会这样,否则就不叫random了,实在不行大不了每次重新new一个出来Top
23 楼huwei001982(michaelhuwei.cnblogs.com)回复于 2006-02-13 17:15:39 得分 0
to huwei001982(編程浪子)
Remove的确是遍历的,但是这个发牌一共也只有52次循环,这点效率没有必要斤斤计较
你觉得效率低,那你说一个方法,效率又高抓牌又不会重复的
---------------------------------
我晕, 不是给你写出来了吗?
Dim ary As New ArrayList
Dim i, index, t As Int32
For i = 1 To 52
ary.Add(i)
Next
Dim rad As New Random
For i = 0 To 51
index = rad.Next(52)
t = DirectCast(ary(i), Int32)
ary(i) = ary(index)
ary(index) = t
Next
执行完后, ary 里面乱序的保存着 1..52 这几个数, 只进行52次循环Top
24 楼huwei001982(michaelhuwei.cnblogs.com)回复于 2006-02-13 17:16:57 得分 0
我和 huxin2007(西门吹雪)给出的算法是一样的Top
25 楼netpotRL(←≮华丽的括号≯→)┅┅(JAVA精神BEAN) (五车,又见五车)回复于 2006-02-13 18:24:23 得分 0
幸好一副牌只有54张,多来几张估计就要郁闷~~Top
26 楼JspAndAsp(为MVP而努力)回复于 2006-02-13 22:43:42 得分 0
又看了一遍Socket网络编程技术,准备开写了,先做进入牌局部分,每个User分配一个线程,假设有两个桌子,那么每个桌子都需要一个全局变量,控制这张桌子的人数。说起多线程就发毛,一边写一边study吧。Top
27 楼charles_y(每天上网一小时)回复于 2006-02-14 09:19:01 得分 0
晕
每个user分配一个线程.....
每个桌子一个全局变量.....
为什么要这样设计呢?Top
28 楼jrl5365(king007)回复于 2006-02-14 09:45:19 得分 0
好东西,学一下!~~好方法!~Top
29 楼Alex_li(Atomsoft)回复于 2006-02-14 10:07:27 得分 0
大家一起来开发如何
http://community.csdn.net/Expert/topic/4553/4553412.xml?temp=.146435Top
30 楼Alex_li(Atomsoft)回复于 2006-02-14 10:22:27 得分 0
To 楼主
你现在是不是已经整体设计好了?
有没有 大概的设计文档Top
31 楼kangfc(KFC)回复于 2006-02-14 10:33:57 得分 0
mark
====CSDN 小助手 V2.5 2005年11月05日发布====
CSDN小助手是一款脱离浏览器也可以访问Csdn论坛的软件
界面:http://blog.csdn.net/Qqwwee_Com/archive/2005/11/05/523395.aspx
下载:http://szlawbook.com/csdnv2
惊喜
无偿送域名(K i l l J a p a n e s e.com),请联系QQ32528568
先到先得。2005年11月21日 21:29分开始。
Top
32 楼csShooter(Sharp Shooter)回复于 2006-02-14 10:48:52 得分 0
markTop
33 楼Alex_li(Atomsoft)回复于 2006-02-14 10:50:51 得分 0
网络棋牌类游戏基本模块
1)通信部分
a) 可以使用 socket , webservice,http,remoting...
b) 定义好通信标准文档
c) 可以发生信息或文件
2) 界面部分
a) 控制用户操作UI
3) 规则和判断大小
4) 数据记录
Top
34 楼Alex_li(Atomsoft)回复于 2006-02-14 10:59:40 得分 0
网络棋牌类游戏基本模块
1)通信部分
a) 可以使用 socket , webservice,http,remoting...
b) 定义好通信标准文档
c) 可以发生信息或文件
2) 界面部分
a) 控制用户操作UI
b) 当前各用户状态
c) 用户聊天信息显示
d) 发牌处理
3) 规则和判断大小
a) 定义各牌的大小顺序
b) 比对出牌是否符合定义好的规则
c) 判断大小结果
4) 数据记录
a) 保存对战历史记录
b) 记录已经打出的牌
c) 记录用户自定义的规则
基本功能大概就是这些, 可以兼容 棋类和牌类游戏 , 棋类和牌类的游戏只需要 重写 UI 部分, 其它部分都是可以标准通用的.
"第三部分的规则和判断大小" 是为通用各种打法的需要
比如 2付牌的80分 , 3付牌的120分,4付牌的160分(6人打), 还可能支持斗地主,...
因为各地方的规则和打法是不同的, 所以需要独立并且是可以自定义的大小规则Top
35 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-02-14 11:00:17 得分 0
随便弄个Stack或者Queue,把牌乱序插入,然后再顺序发牌不就行了,效率高也符合发牌的规则。Top
36 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-02-14 11:03:59 得分 0
首先弄个ArrayList保存54张扑克牌,
然后弄个Stack,随机从ArrayList中抽一张牌插进去。并在ArrayList中把他移掉,用RemoveAt,不要用Remove。重复54次
然后从这个Stack中不断的Pop牌出来就行了。Top
37 楼xiangyuen(成绩是汗)回复于 2006-02-14 14:56:44 得分 0
学习Top
38 楼JspAndAsp(为MVP而努力)回复于 2006-02-15 10:58:31 得分 0
开发文档1.0,截止到打牌/叫牌之前:
1)以桥牌,拱猪两个游戏为规则,其中以桥牌为主.
2)一些重要变量的命名:UserID 用户名-------暂时不身份验证,只要传入用户名,即可加入游戏; desk 牌桌对象-------同一
游戏可以有很多牌桌同时游戏,牌桌数是常量,所以依次为desk1,desk2等;E,W,S,N-------牌桌位置属性; deskNO-------牌桌
号;deskNO-------牌桌号;其他变量以后再补充.
3)游戏主流程(适用于所有牌类,需要具体某一游戏时,再以桥牌为例进行描述)
1.Client(以下简称C):用户传递UserID--唯一,deskNO--欲加入牌桌的号码,position--牌桌位置Server(以下简称S):接收到用户加入牌桌请求,先判断游戏是否已经满员,是,则进入该桌该位置处旁观(可以看到该位置的牌);否,if该位置IsNULL(desk.N),则进入游戏,即desk.N=UserID,通知其他UserID这个新位置上的新人:send(UserID,message(newUserID,position)),接着判断是否所有座位都有人,有则给所有人发消息开始游戏 Send
(UserID1,BeginMessage);else 即该位置已有人,通入发请求的这个人该位置有人。
伪代码如下:
先取得发请求的UserID,deskNO,position
if (desk.status=Game.Full)
{
Send(UserID,"旁观",旁观位置,E位置UserID,S位置UserID,W位置UserID,N位置UserID);
}
else //desk.status=Game.UnFull
{
if IsNUll(desk.Position) //no user in this position
{
desk.Position=UserID;
//Join the game, notify other existed userID the new one
if !IsNull(desk.N)
{
Send(desk.N,newUserID,newUserID_Position);
}
....
if (!IsNull(desk.E) and !IsNull(desk.W) and !IsNull(desk.S) and !IsNull(desk.N))
{
//Start the game, 发牌
SendCard();
Send(desk.E,13张牌);
Send(desk.W,13张牌);
Send(desk.S,13张牌);
Send(desk.N,13张牌);
}
}
else // this position already has man on it
{
//notify this request User the message
Send(UserID,"This position has people on it.");
}
}
*暂不考虑切换不同游戏功能,所以不传递游戏类别
3.C:收到开始信息,通知Server收到13张牌
4.S:确定先手
桥牌:确定先叫牌的人,即上一局先叫牌的人顺时针下一家(因为桥牌先叫牌再打牌)
拱猪:确定先出牌的人,即上一局得猪的人
发送信息给所有人,谁是先手,C/S同时在各自的机器上开始计时,桥牌每人叫牌总时间4分,打牌总时间5分;拱猪每人每轮牌20秒.
Top
39 楼Alex_li(Atomsoft)回复于 2006-02-17 13:32:40 得分 0
upTop
40 楼pengjd(悲酥清风之冰霜之刃)回复于 2006-02-17 13:42:31 得分 0
关注Top
41 楼zlz_212(ShREk)回复于 2006-02-17 13:55:52 得分 0
关注Top
42 楼wooting(不醉)回复于 2006-02-17 14:49:43 得分 0
不错。Top
43 楼JspAndAsp(为MVP而努力)回复于 2006-02-17 16:54:01 得分 0
登陆是同步通信,(打牌)是异步通信。
主要是线程与委托的逻辑,还没有想明白,又看了一遍委托技术,而线程部分则需要补补课了。
通信标准文档部分:Send数据中包括UserID,数据类别(比如说发牌101;出牌102,结束103,分数104),数据值(多个值以逗号分隔),最后以#结束发送(反正都是ASCII,以后会换成不可见字符)。
登陆部分要送密码的哈希格式。
从TCPClient角度以简化编程(要用到GetStream)。Top
44 楼fenglik(风易)回复于 2006-04-28 08:26:26 得分 0
继续学习Top





