WinForm-简单21点纸牌小游戏
纸牌游戏有很多种玩法,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中的代码,逻辑也比较简单,水平所限程序也算完成了,不足之处还望高手能够指出。