纸牌游戏有很多种玩法,C#代码写的纸牌游戏,网上也能找到不少,从中也能学习到不少知识,自己动手也写一个,算是记录下学习过程吧.
纸牌21点的玩法也比较简单,就是看谁手中的所有牌相加是21点,或是离21点的数字最近,最大者赢.照着这样思路开始编写代码.
牌面A到10按牌面数字算点数,J,Q,K,大小王都算10点;
定义一个纸牌父类PKFather
1 public enum PokerColour 2 { 3 4 Diamond,//方块=0 5 Club, //梅花=1 6 Heart, //红桃=2 7 Spade, //黑桃=3 8 Wang, 9 } 10 public enum Rank //牌面点数 11 { 12 One = 1, 13 Two, 14 Three, 15 Four, 16 Five, 17 Six, 18 Seven, 19 Eight, 20 Nine, 21 Ten, 22 Jack, 23 Queen, 24 King, 25 XWang, 26 DWang, 27 } 28 public abstract class PKFather 29 { 30 public int X { get; set; } 31 public int Y { get; set; } 32 public int Width { get; set; } 33 public int Height { get; set; } 34 public Rank Rank { get; set; }//牌面点数 35 public PokerColour PkColour { get; set; }//牌面花色;红桃,黑桃,方片,梅花; 36 37 public PKFather(int x,int y,int width,int height,Rank rank,PokerColour pkColour) 38 { 39 this.X = x; 40 this.Y = y; 41 this.Width = width; 42 this.Height = height; 43 this.Rank = rank; 44 this.PkColour = pkColour; 45 46 } 47 public abstract void Draw(Graphics g); 48 }
父类中定义了两个枚举,Rank用做牌面点数,PokerColour用做牌的花色,其实牌的花色在21点这个小游戏中用不上,只是在剪裁纸牌图片时需要.纸牌的图片如下:
整 个一副牌都在一个图片中,这两个枚举值等于提供了行列坐标,剪裁图片时更方便些,用法在后面的代码中,抽象方法Draw在子类中实现。
1 class RPoker:PKFather 2 { 3 Image image = Resources.card;//图片在资源文件中 4 public RPoker(int x, int y, int width, int height, Rank rank, PokerColour pkcolour) 5 : base(x, y, width, height, rank,pkcolour) 6 { 7 8 } 9 10 public override void Draw(System.Drawing.Graphics g) 11 { 12 Rectangle rect = new Rectangle(this.X, this.Y, Width, Height);//要裁切图片的位置大小 13 switch (this.PkColour) 14 { 15 case PokerColour.Diamond: 16 g.DrawImage(image, rect, new Rectangle(((int)Rank - 1) * Width, (int)(PkColour + 3) * Height, Width, Height), GraphicsUnit.Pixel); 17 break; 18 case PokerColour.Club: 19 g.DrawImage(image, rect, new Rectangle(((int)Rank - 1) * Width, (int)(PkColour + 1) * Height, Width, Height), GraphicsUnit.Pixel); 20 break; 21 case PokerColour.Heart: 22 g.DrawImage(image, rect, new Rectangle(((int)Rank - 1) * Width, (int)(PkColour - 1) * Height, Width, Height), GraphicsUnit.Pixel); 23 break; 24 case PokerColour.Spade: 25 g.DrawImage(image, rect, new Rectangle(((int)Rank - 1) * Width, (int)(PkColour - 3) * Height, Width, Height), GraphicsUnit.Pixel); 26 break; 27 case PokerColour.Wang: 28 g.DrawImage(image, rect, new Rectangle(((int)Rank - 14) * Width, (int)PkColour * Height, Width, Height), GraphicsUnit.Pixel); 29 break; 30 default: 31 break; 32 } 33 34 } 35 }
子类RPoker继承自PKFather,实现抽象方法Draw,用来绘制具体的纸牌。将纸牌的图片加入项目的资源文件步骤是,在解决方案资源管理器中,选中项目,依次点开 Properties->Resources.resx (双击该文件)->在打开的窗口中选菜单"添加资源"->添加现有文件;选中要加入的图片,点确定就成了。更简便的方法是当双击Resources.resx文件在vs中打开后,直接拖入图片,就可完成添加图片的步骤。Image image = Resources.card;将图片资源赋值给image,这样在后面的代码中,就可以对image中的纸牌图片进行剪裁,提取了。
生成54张牌
1 private void GetCard() 2 { 3 for (int j = 0; j <= 4; j++) 4 { 5 switch (j) 6 { 7 case 0: 8 for (int k = 1; k < 14; k++) 9 { 10 allCard.Add(new RPoker(71 * k, j, 71, 96, (Rank)k, (PokerColour)j)); 11 } 12 break; 13 case 1: 14 for (int k = 1; k < 14; k++) 15 { 16 allCard.Add(new RPoker(71 * k, j * 96, 71, 96, (Rank)k, (PokerColour)j)); 17 } 18 break; 19 case 2: 20 for (int k = 1; k < 14; k++) 21 { 22 allCard.Add(new RPoker(71 * k, j * 96, 71, 96, (Rank)k, (PokerColour)j)); 23 } 24 break; 25 case 3: 26 for (int k = 1; k < 14; k++) 27 { 28 allCard.Add(new RPoker(71 * k, j * 96, 71, 96, (Rank)k, (PokerColour)j)); 29 } 30 break; 31 case 4: 32 for (int k = 1; k < 3; k++) 33 { 34 allCard.Add(new RPoker(71 * k, j * 96, 71, 96, (Rank)k + 13, (PokerColour)j)); 35 } 36 break; 37 default: 38 break; 39 } 40 } 41 }
其中固定的数值,都是在整张图片提取成单张牌时具体尺寸
洗牌代码;
// 定义随机数 Random random = new Random(); // 从数组的最后一个数开始递减 for (int i = allCard.Count - 1; i > 0; i--) { // 随机下标 int index = random.Next(0, i); // 随机出来的数与最后位置的数交换 RPoker temp = allCard[i]; allCard[i] = allCard[index]; allCard[index] = temp; }
这种随机打乱的洗牌方法可以有很多种,找到合适的方法就可。
两个类完成后,其余的代码都写到到界面Form中,运行后的界面:
主要记录代码编写过程,界面就简单来了。
1 /// <summary> 2 /// allCard所有54张牌 3 /// </summary> 4 private List<RPoker> allCard = new List<RPoker>();//所有牌 5 private int TopCard;//计数 6 private int computerNumber;//计算机牌张数 7 8 private int playerNumber;//玩家牌张数 9 private int computerCount;//计算机牌点数 10 private int playerCount;//玩家牌点数 11 12 private void Form1_Load(object sender, EventArgs e) 13 { 14 15 GetCard(); 16 Shuffle(); 17 } 18 private void button2_Click(object sender, EventArgs e)//玩家要牌 19 { 20 allCard[TopCard].X = 200 + 25 * playerNumber; 21 allCard[TopCard].Y = 200; 22 allCard[TopCard].Draw(this.CreateGraphics()); 23 if (allCard[TopCard].Rank > Rank.Ten) 24 { 25 playerCount += 10; 26 playerNumber += 1; 27 } 28 else 29 { 30 playerCount += (int)allCard[TopCard].Rank; 31 playerNumber += 1; 32 } 33 TopCard++; 34 if (TopCard >= 54) 35 { 36 Shuffle(); 37 MessageBox.Show("新的一副牌!!"); 38 } 39 label2.Text = playerCount.ToString(); 40 label2.Refresh(); 41 label3.Text = playerNumber.ToString(); 42 label3.Refresh(); 43 if (playerCount > 21) 44 { 45 MessageBox.Show("玩家Player lose!"); 46 button1.Enabled = true; 47 button2.Enabled = false; 48 button3.Enabled = false; 49 50 } 51 } 52 53 private void button1_Click(object sender, EventArgs e)//开始游戏 54 { 55 this.Refresh(); 56 button1.Enabled = false; 57 label1.Text = ""; 58 label2.Text = ""; 59 label1.Refresh(); 60 label2.Refresh(); 61 computerNumber = 0; 62 playerNumber = 0; 63 playerCount = 0; 64 computerCount = 0; 65 //画玩家第一张牌 66 allCard[TopCard].X = 200; 67 allCard[TopCard].Y = 200; 68 allCard[TopCard].Draw(this.CreateGraphics()); 69 70 if (allCard[TopCard].Rank > Rank.Ten) 71 { 72 playerCount += 10; 73 playerNumber += 1; 74 } 75 else 76 { 77 playerCount += (int)allCard[TopCard].Rank; 78 playerNumber += 1; 79 } 80 TopCard++; 81 if (TopCard >= 54) 82 { 83 Shuffle(); 84 MessageBox.Show("新的一副牌!!"); 85 } 86 label2.Text = playerCount.ToString(); 87 label2.Refresh(); 88 label3.Text = playerNumber.ToString(); 89 label3.Refresh(); 90 91 //画计算机第一张牌 92 allCard[TopCard].X = 200; 93 allCard[TopCard].Y = 40; 94 allCard[TopCard].Draw(this.CreateGraphics()); 95 96 if (allCard[TopCard].Rank > Rank.Ten) 97 { 98 computerCount += 10; 99 computerNumber += 1; 100 } 101 else 102 { 103 computerCount += (int)allCard[TopCard].Rank; 104 computerNumber += 1; 105 } 106 TopCard++; 107 if (TopCard >= 54) 108 { 109 Shuffle(); 110 MessageBox.Show("新的一副牌!!"); 111 } 112 label1.Text = computerCount.ToString(); 113 label1.Refresh(); 114 label4.Text = computerNumber.ToString(); 115 label4.Refresh(); 116 117 //画玩家第二张牌 118 allCard[TopCard].X = 225; 119 allCard[TopCard].Y = 200; 120 allCard[TopCard].Draw(this.CreateGraphics()); 121 122 if (allCard[TopCard].Rank > Rank.Ten) 123 { 124 playerCount += 10; 125 playerNumber += 1; 126 } 127 else 128 { 129 playerCount += (int)allCard[TopCard].Rank; 130 playerNumber += 1; 131 } 132 TopCard++; 133 if (TopCard >= 54) 134 { 135 Shuffle(); 136 MessageBox.Show("新的一副牌!!"); 137 } 138 label2.Text = playerCount.ToString(); 139 label2.Refresh(); 140 label3.Text = playerNumber.ToString(); 141 label3.Refresh(); 142 143 //画计算机第二张牌 144 allCard[TopCard].X = 225; 145 allCard[TopCard].Y = 40; 146 allCard[TopCard].Draw(this.CreateGraphics()); 147
148 if (allCard[TopCard].Rank > Rank.Ten) 149 { 150 computerCount += 10; 151 computerNumber += 1; 152 } 153 else 154 { 155 computerCount += (int)allCard[TopCard].Rank; 156 computerNumber += 1; 157 } 158 TopCard++; 159 if (TopCard >= 54) 160 { 161 Shuffle(); 162 MessageBox.Show("新的一副牌!!"); 163 } 164 label1.Text = computerCount.ToString(); 165 label1.Refresh(); 166 label4.Text = computerNumber.ToString(); 167 label4.Refresh(); 168 button2.Enabled = true; 169 button3.Enabled = true; 170 } 171 172 private void button3_Click(object sender, EventArgs e)//玩家停牌 173 { 174 //玩家停牌 175 button2.Enabled = false; 176 button3.Enabled = false; 177 ComputerPlay(); 178 } 179 private void ComputerPlay()//电脑自行要牌 180 { 181 do 182 { 183 if (computerCount < 18) 184 { 185 allCard[TopCard].X = 200 + 25 * computerNumber; 186 allCard[TopCard].Y = 40; 187 allCard[TopCard].Draw(this.CreateGraphics()); 188 if (allCard[TopCard].Rank > Rank.Ten) 189 { 190 computerCount += 10; 191 computerNumber += 1; 192 } 193 else 194 { 195 computerCount += (int)allCard[TopCard].Rank; 196 computerNumber += 1; 197 } 198 TopCard++; 199 } 200 else 201 { 202 break; 203 } 204 } while (true); 205 label1.Text = computerCount.ToString(); 206 label1.Refresh(); 207 label4.Text = computerNumber.ToString(); 208 label4.Refresh(); 209 if (computerCount <= 21) 210 { 211 if (playerCount > computerCount) 212 { 213 MessageBox.Show("玩家Player win!"); 214 } 215 else 216 { 217 MessageBox.Show("电脑 win!"); 218 } 219 } 220 else 221 { 222 MessageBox.Show("玩家Player win!"); 223 } 224 button1.Enabled = true; 225 button2.Enabled = false; 226 button3.Enabled = false; 227 }
界面Form1中的代码,逻辑也比较简单,水平所限程序也算完成了,不足之处还望高手能够指出。