WinForm-简单21点纸牌小游戏

纸牌游戏有很多种玩法,C#代码写的纸牌游戏,网上也能找到不少,从中也能学习到不少知识,自己动手也写一个,算是记录下学习过程吧.

纸牌21点的玩法也比较简单,就是看谁手中的所有牌相加是21点,或是离21点的数字最近,最大者赢.照着这样思路开始编写代码.

牌面A到10按牌面数字算点数,J,Q,K,大小王都算10点;

定义一个纸牌父类PKFather

 public enum PokerColour
{ Diamond,//方块=0
Club, //梅花=1
Heart, //红桃=2
Spade, //黑桃=3
Wang,
}
public enum Rank //牌面点数
{
One = ,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
XWang,
DWang,
}
public abstract class PKFather
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public Rank Rank { get; set; }//牌面点数
public PokerColour PkColour { get; set; }//牌面花色;红桃,黑桃,方片,梅花; public PKFather(int x,int y,int width,int height,Rank rank,PokerColour pkColour)
{
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
this.Rank = rank;
this.PkColour = pkColour; }
public abstract void Draw(Graphics g);
}

父类中定义了两个枚举,Rank用做牌面点数,PokerColour用做牌的花色,其实牌的花色在21点这个小游戏中用不上,只是在剪裁纸牌图片时需要.纸牌的图片如下:

WinForm-简单21点纸牌小游戏

整 个一副牌都在一个图片中,这两个枚举值等于提供了行列坐标,剪裁图片时更方便些,用法在后面的代码中,抽象方法Draw在子类中实现。

 class RPoker:PKFather
{
Image image = Resources.card;//图片在资源文件中
public RPoker(int x, int y, int width, int height, Rank rank, PokerColour pkcolour)
: base(x, y, width, height, rank,pkcolour)
{ } public override void Draw(System.Drawing.Graphics g)
{
Rectangle rect = new Rectangle(this.X, this.Y, Width, Height);//要裁切图片的位置大小
switch (this.PkColour)
{
case PokerColour.Diamond:
g.DrawImage(image, rect, new Rectangle(((int)Rank - ) * Width, (int)(PkColour + ) * Height, Width, Height), GraphicsUnit.Pixel);
break;
case PokerColour.Club:
g.DrawImage(image, rect, new Rectangle(((int)Rank - ) * Width, (int)(PkColour + ) * Height, Width, Height), GraphicsUnit.Pixel);
break;
case PokerColour.Heart:
g.DrawImage(image, rect, new Rectangle(((int)Rank - ) * Width, (int)(PkColour - ) * Height, Width, Height), GraphicsUnit.Pixel);
break;
case PokerColour.Spade:
g.DrawImage(image, rect, new Rectangle(((int)Rank - ) * Width, (int)(PkColour - ) * Height, Width, Height), GraphicsUnit.Pixel);
break;
case PokerColour.Wang:
g.DrawImage(image, rect, new Rectangle(((int)Rank - ) * Width, (int)PkColour * Height, Width, Height), GraphicsUnit.Pixel);
break;
default:
break;
} }
}

子类RPoker继承自PKFather,实现抽象方法Draw,用来绘制具体的纸牌。将纸牌的图片加入项目的资源文件步骤是,在解决方案资源管理器中,选中项目,依次点开 Properties->Resources.resx (双击该文件)->在打开的窗口中选菜单"添加资源"->添加现有文件;选中要加入的图片,点确定就成了。更简便的方法是当双击Resources.resx文件在vs中打开后,直接拖入图片,就可完成添加图片的步骤。Image image = Resources.card;将图片资源赋值给image,这样在后面的代码中,就可以对image中的纸牌图片进行剪裁,提取了。

生成54张牌

 private void GetCard()
{
for (int j = ; j <= ; j++)
{
switch (j)
{
case :
for (int k = ; k < ; k++)
{
allCard.Add(new RPoker( * k, j, , , (Rank)k, (PokerColour)j));
}
break;
case :
for (int k = ; k < ; k++)
{
allCard.Add(new RPoker( * k, j * , , , (Rank)k, (PokerColour)j));
}
break;
case :
for (int k = ; k < ; k++)
{
allCard.Add(new RPoker( * k, j * , , , (Rank)k, (PokerColour)j));
}
break;
case :
for (int k = ; k < ; k++)
{
allCard.Add(new RPoker( * k, j * , , , (Rank)k, (PokerColour)j));
}
break;
case :
for (int k = ; k < ; k++)
{
allCard.Add(new RPoker( * k, j * , , , (Rank)k + , (PokerColour)j));
}
break;
default:
break;
}
}
}

其中固定的数值,都是在整张图片提取成单张牌时具体尺寸

洗牌代码;

           // 定义随机数
Random random = new Random();
// 从数组的最后一个数开始递减
for (int i = allCard.Count - ; i > ; i--)
{
// 随机下标
int index = random.Next(, i);
// 随机出来的数与最后位置的数交换
RPoker temp = allCard[i];
allCard[i] = allCard[index];
allCard[index] = temp;
}

这种随机打乱的洗牌方法可以有很多种,找到合适的方法就可。

两个类完成后,其余的代码都写到到界面Form中,运行后的界面:

WinForm-简单21点纸牌小游戏

主要记录代码编写过程,界面就简单来了。

 /// <summary>
/// allCard所有54张牌
/// </summary>
private List<RPoker> allCard = new List<RPoker>();//所有牌
private int TopCard;//计数
private int computerNumber;//计算机牌张数 private int playerNumber;//玩家牌张数
private int computerCount;//计算机牌点数
private int playerCount;//玩家牌点数 private void Form1_Load(object sender, EventArgs e)
{ GetCard();
Shuffle();
}
private void button2_Click(object sender, EventArgs e)//玩家要牌
{
allCard[TopCard].X = + * playerNumber;
allCard[TopCard].Y = ;
allCard[TopCard].Draw(this.CreateGraphics());
if (allCard[TopCard].Rank > Rank.Ten)
{
playerCount += ;
playerNumber += ;
}
else
{
playerCount += (int)allCard[TopCard].Rank;
playerNumber += ;
}
TopCard++;
if (TopCard >= )
{
Shuffle();
MessageBox.Show("新的一副牌!!");
}
label2.Text = playerCount.ToString();
label2.Refresh();
label3.Text = playerNumber.ToString();
label3.Refresh();
if (playerCount > )
{
MessageBox.Show("玩家Player lose!");
button1.Enabled = true;
button2.Enabled = false;
button3.Enabled = false; }
} private void button1_Click(object sender, EventArgs e)//开始游戏
{
this.Refresh();
button1.Enabled = false;
label1.Text = "";
label2.Text = "";
label1.Refresh();
label2.Refresh();
computerNumber = ;
playerNumber = ;
playerCount = ;
computerCount = ;
//画玩家第一张牌
allCard[TopCard].X = ;
allCard[TopCard].Y = ;
allCard[TopCard].Draw(this.CreateGraphics()); if (allCard[TopCard].Rank > Rank.Ten)
{
playerCount += ;
playerNumber += ;
}
else
{
playerCount += (int)allCard[TopCard].Rank;
playerNumber += ;
}
TopCard++;
if (TopCard >= )
{
Shuffle();
MessageBox.Show("新的一副牌!!");
}
label2.Text = playerCount.ToString();
label2.Refresh();
label3.Text = playerNumber.ToString();
label3.Refresh(); //画计算机第一张牌
allCard[TopCard].X = ;
allCard[TopCard].Y = ;
allCard[TopCard].Draw(this.CreateGraphics()); if (allCard[TopCard].Rank > Rank.Ten)
{
computerCount += ;
computerNumber += ;
}
else
{
computerCount += (int)allCard[TopCard].Rank;
computerNumber += ;
}
TopCard++;
if (TopCard >= )
{
Shuffle();
MessageBox.Show("新的一副牌!!");
}
label1.Text = computerCount.ToString();
label1.Refresh();
label4.Text = computerNumber.ToString();
label4.Refresh(); //画玩家第二张牌
allCard[TopCard].X = ;
allCard[TopCard].Y = ;
allCard[TopCard].Draw(this.CreateGraphics()); if (allCard[TopCard].Rank > Rank.Ten)
{
playerCount += ;
playerNumber += ;
}
else
{
playerCount += (int)allCard[TopCard].Rank;
playerNumber += ;
}
TopCard++;
if (TopCard >= )
{
Shuffle();
MessageBox.Show("新的一副牌!!");
}
label2.Text = playerCount.ToString();
label2.Refresh();
label3.Text = playerNumber.ToString();
label3.Refresh(); //画计算机第二张牌
allCard[TopCard].X = ;
allCard[TopCard].Y = ;
allCard[TopCard].Draw(this.CreateGraphics());

if (allCard[TopCard].Rank > Rank.Ten)
{
computerCount += ;
computerNumber += ;
}
else
{
computerCount += (int)allCard[TopCard].Rank;
computerNumber += ;
}
TopCard++;
if (TopCard >= )
{
Shuffle();
MessageBox.Show("新的一副牌!!");
}
label1.Text = computerCount.ToString();
label1.Refresh();
label4.Text = computerNumber.ToString();
label4.Refresh();
button2.Enabled = true;
button3.Enabled = true;
} private void button3_Click(object sender, EventArgs e)//玩家停牌
{
//玩家停牌
button2.Enabled = false;
button3.Enabled = false;
ComputerPlay();
}
private void ComputerPlay()//电脑自行要牌
{
do
{
if (computerCount < )
{
allCard[TopCard].X = + * computerNumber;
allCard[TopCard].Y = ;
allCard[TopCard].Draw(this.CreateGraphics());
if (allCard[TopCard].Rank > Rank.Ten)
{
computerCount += ;
computerNumber += ;
}
else
{
computerCount += (int)allCard[TopCard].Rank;
computerNumber += ;
}
TopCard++;
}
else
{
break;
}
} while (true);
label1.Text = computerCount.ToString();
label1.Refresh();
label4.Text = computerNumber.ToString();
label4.Refresh();
if (computerCount <= )
{
if (playerCount > computerCount)
{
MessageBox.Show("玩家Player win!");
}
else
{
MessageBox.Show("电脑 win!");
}
}
else
{
MessageBox.Show("玩家Player win!");
}
button1.Enabled = true;
button2.Enabled = false;
button3.Enabled = false;
}

界面Form1中的代码,逻辑也比较简单,水平所限程序也算完成了,不足之处还望高手能够指出。

代码下载

上一篇:事务 ( 进程 ID 60) 与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲品


下一篇:详谈socket请求Web服务器过程(转)