C#三子棋游戏

这是学C#这么久以来老师第一次布置的算是个完整的小项目了,自己在规定时间做完后又找资料优化了一下,把它弄成不规则窗体了,但是拖动功能没有完美的实现。

遇到的问题:鼠标左键点住窗体,只要一拖动,鼠标指针就跑到窗体的左上角了,即相对窗体坐标(0,0)。

以下是部分功能及界面介绍:

登录界面:

C#三子棋游戏_第1张图片

玩家姓名不能为空,如果为空点击“开始游戏”会弹出警告

游戏主界面:

C#三子棋游戏_第2张图片

玩家为红色棋子,电脑为黑色棋子。棋盘用的是PictureBox控件,你也可以用按钮。

点击“开始”,即可开始游戏,可选择玩家先下或者电脑先下棋子:

C#三子棋游戏_第3张图片

下面是游戏过程,玩家赢的情况:

C#三子棋游戏_第4张图片

当然还有电脑赢,平局的情况。

右边的倒计时是100秒,100秒过后可以再战:

C#三子棋游戏_第5张图片

成绩统计的是这100秒之内玩家的战况(玩家赢、输一局平局的次数):

C#三子棋游戏_第6张图片

下面是帮助界面:

C#三子棋游戏_第7张图片

界面就这些,关键是后台代码,涉及到很多方面,这里介绍部分:

先看下部分变量的声明:

ContractedBlock.gif ExpandedBlockStart.gif Code
 1         int time = 100//计时器倒计时
 2         int[,] A = new int[33]; //棋盘数组
 3         int i; //用户所下棋位横坐标
 4         int j; //用户所下棋位纵坐标
 5         int x; //计算机所下棋位横坐标
 6         int y; //计算机所下棋位纵坐标
 7         string picName; //存放用户点击棋位的名字
 8         public static int winUserNum = 0//玩家赢的次数
 9         public static int winPCNum = 0//电脑赢的次数
10         public static int drawNum = 0//平局次数
11         public static string user; //玩家姓名
12         PictureBox[,] pics = new PictureBox[33];//将棋盘的9个PictureBox控件定义到一个数组里

 

将棋盘的9个PictureBox控件绑定到一个数组里(这是个不错的主意):

我放在了默认构造函数里了

注意:控件命名和数组变量名字有联系,这样就可以很方便的编辑每个控件了!

         当数组值为1时,表示这个棋是人下的,并且把控件图片改为红色棋子图片

         当数组值为-1时,表示这个棋是电脑下的,并且把控件图片改为黑色棋子图片

         当数组值为0时,表示这个棋位为空(默认为0)

ContractedBlock.gif ExpandedBlockStart.gif Code
        public frmMain()
        {
            InitializeComponent();
            pics[
00= pic00;
            pics[
01= pic01;
            pics[
02= pic02;
            pics[
10= pic10;
            pics[
11= pic11;
            pics[
12= pic12;
            pics[
20= pic20;
            pics[
21= pic21;
            pics[
22= pic22;
        }

 

以下是一些方法:

 如果是电脑下棋,考虑以下几种可能:

(1)自己有没有2个连着的棋子并且第三个棋位为空,如果有,电脑则可以直接下到空棋位,电脑便赢

(2)如果(1)不成立,电脑就判断玩家是否已经有2个连续的棋子且第三个为空,即:电脑要阻挡玩家赢

(3)如果(2)也不成立,则电脑随机找一个空位下棋,电脑随机下起用到随机数的生成

这里用循环语句遍历每个控件数组,寻找是否有数组元素的值为0,1,或-1,通过计算,进而判断是否有连续2个棋子的可能,请仔细研究!

ContractedBlock.gif ExpandedBlockStart.gif Code
 1         #region 判断电脑自己下的棋子是否有2个棋子在一直线,且第3个为空
 2         private bool twoChessPC()
 3         {
 4             for (int i = 0; i < 3; i++)
 5             {
 6                 if (A[i, 0+ A[i, 1+ A[i, 2== -2)
 7                 {
 8                     for (int j = 0; j < 3; j++)
 9                     {
10                         if (A[i, j] == 0)
11                         {
12                             A[i, j] = -1;
13                             pics[i, j].Image = imageList1.Images[1];
14                             pics[i, j].Enabled = false;
15                             return true;
16                         }
17                     }
18                 }
19             }
20 
21             for (int j = 0; j < 3; j++)
22             {
23                 if (A[0, j] + A[1, j] + A[2, j] == -2)
24                 {
25                     for (int i = 0; i < 3; i++)
26                     {
27                         if (A[i, j] == 0)
28                         {
29                             A[i, j] = -1;
30                             pics[i, j].Image = imageList1.Images[1];
31                             pics[i, j].Enabled = false;
32                             return true;
33 
34                         }
35                     }
36                 }
37             }
38 
39             if (A[00+ A[11+ A[22== -2)//-45度对角线
40             {
41                 for (int i = 0; i < 3; i++)
42                 {
43                     if (A[i, i] == 0)
44                     {
45                         A[i, i] = -1;
46                         pics[i, i].Image = imageList1.Images[1];
47                         pics[i, i].Enabled = false;
48                         return true;
49                     }
50                 }
51             }
52 
53             if (A[02+ A[11+ A[20== -2//45度对角线
54             {
55                 for (int i = 0; i < 3; i++)
56                 {
57                     if (A[i, 2 - i] == 0)
58                     {
59                         A[i, 2 - i] = -1;
60                         pics[i, 2-i].Image = imageList1.Images[1];
61                         pics[i, 2-i].Enabled = false;
62                         return true;
63                     }
64 
65                 }
66 
67             }
68             return false;
69         }
70         #endregion

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1         #region 判断电脑是否阻碍人
 2         private bool twoChessUser()
 3         {
 4             for (int i = 0; i < 3; i++)//阻止行 
 5             {
 6                 if (A[i, 0+ A[i, 1+ A[i, 2== 2)
 7                 {
 8                     for (int j = 0; j < 3; j++)
 9                     {
10                         if (this.A[i, j] == 0)
11                         {
12                             this.A[i, j] = -1;
13                             this.pics[i, j].Image = imageList1.Images[1];
14                             pics[i, j].Enabled = false;
15                             return true;
16                         }
17                     }
18                 }
19             }
20 
21             for (int j = 0; j < 3; j++)//阻止列 
22             {
23                 if (A[0, j] + A[1, j] + A[2, j] == 2)
24                 {
25                     for (int i = 0; i < 3; i++)
26                     {
27                         if (A[i, j] == 0)
28                         {
29                             A[i, j] = -1;
30                             pics[i, j].Image = imageList1.Images[1];
31                             pics[i, j].Enabled = false;
32                             return true;
33 
34                         }
35                     }
36                 }
37             }
38 
39             if (A[00+ A[11+ A[22== 2)//-45度对角线
40             {
41                 for (int k = 0; k < 3; k++)
42                 {
43                     if (A[k, k] == 0)
44                     {
45                         A[k, k] = -1;
46                         pics[k, k].Image = imageList1.Images[1];
47                         pics[k, k].Enabled = false;
48                         return true;
49                     }
50                 }
51             }
52 
53             if (A[02+ A[11+ A[20== 2//45度对角线
54             {
55                 for (int k = 0; k < 3; k++)
56                 {
57                     if (A[k, 2 - k] == 0)
58                     {
59                         A[k, 2 - k] = -1;
60                         pics[k, 2 - k].Image = imageList1.Images[1];
61                         pics[k, 2 - k].Enabled = false;
62                         return true;
63                     }
64 
65                 }
66 
67             }
68             return false;
69         }
70         #endregion

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1         #region 电脑随机下棋
 2         private bool radomPC()
 3         {
 4             Random ran = new Random();
 5             // 默认x和y都为0,所以先随机生成一次
 6             x = ran.Next(03);
 7             y = ran.Next(03);
 8 
 9             while (true)
10             {
11                 x = ran.Next(03); // 随机生成计算机要下棋子的横坐标
12                 y = ran.Next(03); // 随机生成计算机要下棋子的纵坐标
13                 if (A[x, y] == 0)
14                 {
15                     A[x, y] = -1;
16                     pics[x, y].Image = imageList1.Images[1];
17                     pics[x, y].Enabled = false;
18                     return true;
19                 }
20             }
21 
22         }
23         #endregion

 

下面是玩家下棋方法(这是我最感到满意的一个方法!)9个控件不用写9个事件,而是都调用同一个Click事件

ContractedBlock.gif ExpandedBlockStart.gif Code
 1         #region 玩家下棋,每一个棋子控件都调用此方法
 2         private void pic00_Click(object sender, EventArgs e)
 3         {
 4             PictureBox newPictureBox = (PictureBox)sender;
 5             picName = newPictureBox.Name;
 6             i = Convert.ToInt32(picName.Substring(31));
 7             j = Convert.ToInt32(picName.Substring(41));
 8 
 9             if (A[i,j] == 0)
10             {
11                 newPictureBox.Image = imageList1.Images[0];
12                 A[i, j] = 1;
13                 pics[i,j].Enabled=false;
14 
15                 if (peopleWin() == false)//判断玩家是否赢
16                 {
17                     if (draw() == false)//判断是否平局
18                     {
19                         chessPC();//电脑下棋
20                     }
21                 }
22             }
23             
24         }

以下3个方法是判断电脑是否赢、玩家是否赢、以及是否平局:

说明:这3个方法让我很不爽,因为是把其可能出现的所有情况都写出来了!试想:如果棋盘很大,比如250*250呢??!

         还是我的算法没学好,我想应该有好的方法,比如上边判断电脑是否阻挡玩家一样,用循环实现!

如果大家谁有好的算法可以解决这个问题,请告知,谢谢!

ContractedBlock.gif ExpandedBlockStart.gif Code
 1         #region 判断电脑是否胜利
 2         private bool computerWin()
 3         {
 4             if ((A[00== -1 & A[01== -1 & A[02== -1| (A[10== -1 & A[11== -1 & A[12== -1| (A[20== -1 & A[21== -1 & A[22== -1| (A[00== -1 & A[10== -1 & A[20== -1| (A[01== -1 & A[11== -1 & A[21== -1| (A[02== -1 & A[12== -1 & A[22== -1| (A[00== -1 & A[11== -1 & A[22== -1| (A[20== -1 & A[11== -1 & A[02== -1)
 5 
 6             )
 7             {
 8                 MessageBox.Show("很遗憾,你输了!");
 9                 picEnabledFlase();
10                 winPCNum++;
11                 return true;
12             }
13             else
14             {
15                 return false;
16             }
17 
18         }
19         #endregion
20 
21         #region 判断玩家是否胜利
22         private bool peopleWin()
23         {
24             if ((A[00== 1 & A[01== 1 & A[02== 1| (A[10== 1 & A[11== 1 & A[12== 1| (A[20== 1 & A[21== 1 & A[22== 1| (A[00== 1 & A[10== 1 & A[20== 1| (A[01== 1 & A[11== 1 & A[21== 1| (A[02== 1 & A[12== 1 & A[22== 1| (A[00== 1 & A[11== 1 & A[22== 1| (A[20== 1 & A[11== 1 & A[02== 1))
25             {
26                 MessageBox.Show("恭喜,你赢了!");
27                 picEnabledFlase();
28                 winUserNum++;
29                 return true;
30             }
31             else
32             {
33                 return false;
34             }
35         }
36         #endregion
37 
38         #region 判断是否平局
39         private bool draw()
40         {
41             if (A[00!= 0 & A[01!= 0 & A[02!= 0 & A[10!= 0 & A[11!= 0 & A[12!= 0 & A[20!= 0 & A[21!= 0 & A[22!= 0)
42             {
43                 MessageBox.Show("非常棒,平局!");
44                 drawNum++;
45                 return true;
46             }
47             else
48             {
49                 return false;
50             }
51 
52         }
53         #endregion

 

计时器以及统计成绩就不介绍了,这个很容易。

下面看下不规则窗体的实现:

给窗体设置一张背景图片,背景图片为不规则窗体的样式,图片的背景颜色需换一种没有用到的颜色(为了使之在运行时透明)

首先将窗体的FormBoderStyle设置为False

然后将TransparencyKey的颜色设置为何窗体背景图片的背景颜色一样,这样运行程序时此颜色就为透明色了

例如次程序:

C#三子棋游戏_第8张图片

 

然后给窗体添加2个按钮,最小化和关闭,下面是改变这2个按钮形状的代码:

注意,这里代码是写在按钮的Paint事件里的!

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1         #region 自定义一个关闭按钮
 2         private void btnClose_Paint(object sender, PaintEventArgs e)
 3         {
 4             //初始化一个GraphicsPath类的对象
 5             System.Drawing.Drawing2D.GraphicsPath myGraphicsPath  = new 
 6             System.Drawing.Drawing2D.GraphicsPath();
 7             //用AddEllipse方法创建椭圆
 8             myGraphicsPath.AddEllipse(332015);
 9             //将控件的Region属性设置为上面创建的GraphicsPath对象
10             btnClose.Region = new Region(myGraphicsPath);
11             btnClose.Text = "×";
12 
13         }
14         #endregion
15 
16         ////关闭按钮的Click事件
17         private void btnClose_Click(object sender, EventArgs e)
18         {
19             Application.Exit();
20         }
21 
22         #region 自定义一个最小化按钮
23         private void btnMin_Paint(object sender, PaintEventArgs e)
24         {
25             //初始化一个GraphicsPath类的对象
26             System.Drawing.Drawing2D.GraphicsPath myGraphicsPath = new
27             System.Drawing.Drawing2D.GraphicsPath();
28             //用AddEllipse方法创建椭圆
29             myGraphicsPath.AddEllipse(332015);
30             //将控件的Region属性设置为上面创建的GraphicsPath对象
31             btnMin.Region = new Region(myGraphicsPath);
32             btnMin.Text = "-";
33         }
34         #endregion
35 
36         //最小化按钮的Click事件
37         private void btnMin_Click(object sender, EventArgs e)
38         {
39             this.WindowState = FormWindowState.Minimized;
40         }

 

最后,把鼠标拖动的代码附上,这里我遇到了文章开头说到的拖动问题,希望大家谁知道,告诉我一下,再次感谢!

这里是方法是写在了窗体的MouseMove事件里:

ContractedBlock.gif ExpandedBlockStart.gif Code
        #region 鼠标拖动,这里遇到点问题还未解决
        
private void frmMain_MouseMove(object sender, MouseEventArgs e)
        {
            
int currX = 0;
            
int currY = 0;
            
if (e.Button == MouseButtons.Left)
            {
                currX 
= this.Left + e.X;
                currY 
= this.Top + e.Y;
                
this.SetDesktopLocation(currX, currY);
            }
        }
        
#endregion

 

这个三子棋的游戏就介绍到这里

转载于:https://www.cnblogs.com/nest/archive/2009/04/26/1443904.html

你可能感兴趣的:(C#三子棋游戏)