C#五子棋

模块一

一、首先在Program.cs中设置初始运行窗体为InitialForm,代码如下:

代码位置:gobang\Gobang\Program.cs

    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new InitialForm());
    }

二、然后为名为StartGame的button控件添加单击事件,用于显示选择模式窗口,代码如下:

代码位置:gobang\Gobang\初始界面.cs

    private void StartGame_Click(object sender, EventArgs e)
    {
        SelectModesForm selectModesForm = new SelectModesForm();//创建选择模式窗体对象
        this.Visible = false;//使初始见面不可见
        selectModesForm.ShowDialog();//显示选择模式窗口
        this.Visible = true;//使其可见
    }

模块二

一、首先为名为StartGame的button控件添加单击事件,用于显示双人游戏窗口,代码如下:

代码位置:gobang\Gobang\选择模式窗口.cs

    private void StartGame_Click(object sender, EventArgs e)
    {
        TwoPlayersForm twoPlayersForm = new TwoPlayersForm();
        this.Visible = false;
        twoPlayersForm.ShowDialog();
        this.Visible = true;
    }

二、然后为名为button1的button控件添加单击事件,用于显示人机游戏窗口,代码如下:

代码位置:gobang\Gobang\选择模式窗口.cs

        private void button1_Click(object sender, EventArgs e)
        {
            AiPlayersForm aiPlayersForm = new AiPlayersForm();
            this.Visible = false;
            aiPlayersForm.ShowDialog();
            this.Visible = true;
        }

三、最后为名为button2的button控件添加单击事件,用于返回主界面,代码如下:

代码位置:gobang\Gobang\选择模式窗口.cs

    private void button2_Click(object sender, EventArgs e)
    {
        this.Visible = false;
        InitialForm initialForm = new InitialForm();
        initialForm.Visible = true;
    }

模块三

一、定义枚举类型PieceType用于获取棋子类型,代码如下:

代码位置:Gobang\Gobang\PieceType.cs

namespace Gobang
{
   enum PieceType//棋子类型
    {
        BLACK, WHITE, NONE//黑棋、白棋、无棋子
    }
}

二、首先定义棋子类Piece用于创建棋子,代码如下:

代码位置:Gobang\Gobang\Piece.cs

using System.Drawing; //提供对 GDI + 基本图形功能的访问权限

namespace Gobang
{
  abstract  class Piece : PictureBox  //创建抽象棋子类继承与PictureBox,防止意外建立新Piece对象
    {
        private static readonly int IMAGE_WIDTH = 50;  //定义棋子宽度
        public Piece (int x, int y)  //棋子构造函数
        {
            this.BackColor = Color.Transparent;   //背景为透明
            this.Location = new Point(x-IMAGE_WIDTH/2, y-IMAGE_WIDTH/2);  //棋子坐标
            this.Size = new Size(IMAGE_WIDTH, IMAGE_WIDTH);//棋子大小
        }
        public abstract PieceType GetPieceType();//多态获得棋子类型
        public abstract Image GetNextImage();//多态获得下一个棋子的图片
    }
}

三、定义黑棋类BlackPiece,代码如下:

代码位置:Gobang\Gobang\BlackPiece.cs

using System.Drawing;//提供对 GDI + 基本图形功能的访问权限

    namespace Gobang
{
    class BlackPiece : Piece//继承自Piece类
  {
    public BlackPiece(int x , int y) : base (x , y) //把x,y坐标传入基类Piece的构造函数中
    {
            this.Image = Properties.Resources.black; //指定黑棋图片
    }
    public override PieceType GetPieceType()//改写基类Piece中的GetPieceType方法
    {
        return PieceType.BLACK;//返回棋子类型为黑棋
    }
    public override Image  GetNextImage()//改写基类Piece中的GetNextImage方法
    {
        return Properties.Resources.white;//返回下一个棋子的图片
    }
  }
}

四、定义白棋类WhitePiece,代码如下:

代码位置:Gobang\Gobang\BlackPiece.cs

using System.Drawing;//提供对 GDI + 基本图形功能的访问权限

namespace Gobang
{
    class WhitePiece : Piece//继承自Piece类
    {
        public WhitePiece(int x, int y) : base(x, y)//把x,y坐标传入基类Piece的构造函数中
        {
            this.Image = Properties.Resources.white;//指定白棋图片
        }
        public override PieceType GetPieceType()//改写基类Piece中的GetPieceType方法
        {
            return PieceType.WHITE;//返回棋子类型为白棋
        }
        public override Image GetNextImage()//改写基类Piece中的GetNextImage方法
        {
            return Properties.Resources.black;//返回下一个棋子的图片
        }
    }
}

五、定义棋盘类Board用于存贮当前棋盘信息,代码如下:

代码位置:Gobang\Gobang\Board.cs

同样需要System.Drawing命名空间 using System.Drawing;

Ⅰ、成员变量

    public static readonly int NODE_COUNT = 15;   //棋盘规格
    public static readonly int STEP_SPAN_TIME = 30;//下棋间隔时间
    private static readonly Point NO_MATCH_NODE = new Point(-1, -1);//  设置无匹配点
    private static readonly int NODE_RADIUS = 20;  //点的半径
    public static readonly int OFFSET = 35;   //棋盘距离边界的距离
    public static readonly int NODE_DISTANCE = 70;  //每个结点之间的距离
    public Piece[,] pieces = new Piece[NODE_COUNT, NODE_COUNT];   //创建存贮棋子的二维数组
    private static Point lastPlacedNode = NO_MATCH_NODE;//最后一个棋子

Ⅱ、成员函数

1、为了使棋子落在正确的位置上,需要找到距离用户鼠标点击位置最近的结点

1)首先在一维方向找到最近结点,代码如下:

    public  int FindTheClosetNode(int pos)  
    {
        pos -= OFFSET;//坐标点减去棋盘边界
        int quotient = pos / NODE_DISTANCE;  //求商数
        int remainder = pos % NODE_DISTANCE; //求余数

        if (remainder <= NODE_RADIUS)   //如果余数小于所给半径范围
            return quotient;//返回商数即前一个点
        else if (remainder >= NODE_DISTANCE - NODE_RADIUS)  //如果余数大于所给半径范围且属于后一个点的范围内
            return quotient + 1;//返回后一个点
        else  //没有符合点
            return -1;//返回无匹配点
    }

2)然后在二维方向找到最近结点,代码如下:

    public Point FindTheClosetNode(int x, int y)
    {
        int nodeX = FindTheClosetNode(x);  //判断横向
        if (nodeX == -1)
            return NO_MATCH_NODE;//返回无匹配点

        int nodeY = FindTheClosetNode(y);  //判断纵向
        if (nodeY == -1)
            return NO_MATCH_NODE;//返回无匹配点

        return new Point(nodeX, nodeY);    //放回坐标

    }

2、得到最近落子结点后需要获取棋子真正的坐标位置,进行反运算,代码如下:

    public Point ConverToTruePosition(Point node)
    {
        Point TruePosition = new Point();//定义真正位置坐标点
        TruePosition.X = node.X * NODE_DISTANCE + OFFSET;//横向进行反运算
        TruePosition.Y = node.Y * NODE_DISTANCE + OFFSET;//纵向进行反运算
        return TruePosition;//返回坐标点
    }

3、放置棋子操作,代码如下:

    public Piece PlacePiece(int x, int y, PieceType type)
    {

        Point node = FindTheClosetNode(x, y);            //找到最近的点
        if (node == NO_MATCH_NODE)                 //如果没有最近点,不可放棋子,返回null
            return null;
        if (pieces[node.X, node.Y] != null)                //如果有最近点,检查是否有棋子存在
            return null;
        Point truepos = ConverToTruePosition(node);     //将node坐标转换为真正坐标     
        if (type == PieceType.BLACK)                 //如果没有棋子则把黑白棋子坐标存入二维数组中
            pieces[node.X, node.Y] = new BlackPiece(truepos.X, truepos.Y);//存入黑棋
        else if (type == PieceType.WHITE)
            pieces[node.X, node.Y] = new WhitePiece(truepos.X, truepos.Y);//存入白棋
        lastPlacedNode = node;                      //记录最后棋子的位置
        return pieces[node.X, node.Y];        //取出二维数组中的棋子
    }

4、获得最后一个棋子,代码如下:

public Point LastPlacedNode { get { return lastPlacedNode; } }

5、判断是否可放置棋子,代码如下:

    public bool CanBePlaced(int x, int y)
    {

        Point node = FindTheClosetNode(x, y);             //找到最近的点

        if (node == NO_MATCH_NODE)     //如果没有最近点,不可放棋子,返回false
            return false;

        if (pieces[node.X, node.Y] != null)       //如果有最近点,检查是否有棋子存在
        {
            return false;
        }
        return true;
    }

6、获取棋子类型操作,代码如下:

    public PieceType GetPieceType(int nodeX, int nodeY)
    {
        if (pieces[nodeX, nodeY] == null)//如果棋子不存在,则返回无棋子
            return PieceType.NONE;
        else
            return pieces[nodeX, nodeY].GetPieceType();//否则返回棋子类型
    }

7、AI判断是否可放棋子,代码如下:

public bool AICanBePlaced(int x,int y)
{
int nodeX = FindTheClosetNode(x); //判断横向
if (nodeX == -1)
return false;

        int nodeY = FindTheClosetNode(y);  //判断纵向
        if (nodeY == -1)
            return false;
        else
            return true;
        }

8、重新游戏操作,代码如下:

    public void Reload()
    {
        lastPlacedNode = NO_MATCH_NODE;//设置最后一个棋子位置为无匹配点
        pieces = new Piece[NODE_COUNT, NODE_COUNT];//新建存贮棋子的二维数组
    }

六、定义GameManage类用于实现游戏的核心机制

代码位置:Gobang\Gobang\GameManage.cs

同样需要System.Drawing命名空间 using System.Drawing;

Ⅰ、成员变量

    public static int CurrentTime = Board.STEP_SPAN_TIME;// 设置当前剩余时间,默认当前剩余时间为下棋间隔时间
    private Board board = new Board();//创建board对象用于调用Board类中的方法,并进行重构
    private PieceType CurrentPlayer = PieceType.BLACK;//默认当前玩家为黑棋
    public static PieceType PastPlayer = PieceType.NONE;//默认上一步玩家为NONE
    private PieceType winner = PieceType.NONE;//默认赢家为NONE
    private int[,] Score = new int[Board.NODE_COUNT, Board.NODE_COUNT];//记录分数
    private List<Point> MaxPoint = new List<Point>();//记录得分最高点

Ⅱ、成员函数

1、判断是否可下棋,重构Borad中的方法,代码如下:

    public bool CanBePlaced(int x, int y) 
    {
        return board.CanBePlaced(x, y);
    }

2、下棋操作,重构Borad中的方法,并且实现交换棋手的功能,代码如下:

       public Piece PlacePiece(int x, int y)
        {

            Piece piece = board.PlacePiece(x, y, CurrentPlayer);//调用board的下棋操作

            if (piece != null)//如果可放棋子
            {
                //交换选手
                    if (CurrentPlayer == PieceType.BLACK)//如果当前玩家为黑棋
                    {
                        PastPlayer = PieceType.BLACK;//设置上一名玩家为黑棋
                        CurrentPlayer = PieceType.WHITE;//并指定当前玩家为白棋
                    }
                    else if (CurrentPlayer == PieceType.WHITE)//如果当前玩家为白棋
                    {
                        PastPlayer = PieceType.WHITE;//设置上一名玩家为白棋  
                        CurrentPlayer = PieceType.BLACK;//并指定当前玩家为黑棋
                    }
                return piece;//传出棋子
            }
            return null;
        }

3、检查是否有玩家获胜,代码如下:

    public  void CheckWiner()
    {
        int centerX = board.LastPlacedNode.X;//获得中心点 (即最后一个棋子)的横坐标
        int centerY = board.LastPlacedNode.Y;//获得中心点 (即最后一个棋子)的纵坐标

        //xDir yDir是循环固定的方向   checkxDir checkyDir是查找的方向
        for (int xDir = -1; xDir <= 1; xDir++) {
            for (int yDir = -1; yDir <= 1; yDir++) {
                //排除center棋子
                if (xDir == 0 && yDir == 0)
                    continue;
                //增加反向查找变量
                int reverse = 0;      //反向的次数,默认为零,最多反向一次
                int checkxDir = xDir;//动态查找和移动的方向X,可能会出现反向
                int checkyDir = yDir;//动态查找和移动的方向Y,可能会出现反向

                int count = 1;         //记录检查到同色连续的棋子,自己算一个
                int step = 0;           //记录动态查找需要的步数,最多四次
                int distance = 1;     //记录动态查找点和中心点之间的距离的绝对值,从一开始
                while (step < 4)
                {
                    step++;//查找步数加一
                    int targetX = centerX + distance * checkxDir;//获得所要检查位置横坐标
                    int targetY = centerY + distance * checkyDir;//获得所要检查位置纵坐标
                    //如果颜色不同,或超出边界,则进行反向查找,查找不做记录,距离恢复到一
                    if (targetX < 0 || targetX >= Board.NODE_COUNT ||
                        targetY < 0 || targetY >= Board.NODE_COUNT ||
                        board.GetPieceType(targetX, targetY) != PastPlayer)
                    {
                        reverse++;//反向次数加一
                        checkxDir = -checkxDir;//X坐标反向
                        checkyDir = -checkyDir;//Y坐标反向
                        step--;//查找步数不算-1
                        distance = 1;//记录恢复到1
                    }
                    else  //如果未出边界,且是同色棋子,则棋子个数加一同时距离加一
                    {
                        count++;//棋子个数加1
                        distance++;//距离加1
                    }
                    if (reverse == 2) //当反向次数为二时左右都没有同色棋子,退出本次循环
                    { break; }
                }
                if (count == 5)//检查是否有五颗相同棋子相邻
                {
                    winner = PastPlayer;//上一名玩家胜利
                    return;
                }
                if(CurrentTime==0)//检查是否当前剩余时间为零
                {
                    winner = PastPlayer;//上一名玩家胜利
                    return;
                }
            }
        }
    }

4、返回赢家,代码如下:

public PieceType Winner { get { return winner; }set { winner = value; } }

5、对当前棋盘空位进行评分,代码如下:

    public void CalculateScore()

    {
        int PersonNum = 0;//玩家棋子数目
        int BotNum = 0;//AI棋子数目
        int EmptyNum = 0;//空棋子数目
       Array.Clear(Score, 0, Score.Length);//初始化记录分数数组
        //遍历整个棋盘,对每个可落子点进行评分
        for (int row = 0; row < Board.NODE_COUNT; row++)
            for(int col=0; col<Board.NODE_COUNT; col++ )
                if(row>=0&&col>=0&&board.pieces[row,col]==null)//如果在此位置无棋子
                {
                    //则根据此空位四周八个方向的棋子分布情况对其进行评分
                    for(int y=-1;y<=1; y++)
                        for(int x=-1;x<=1;x++)
                        {
                            PersonNum = 0;
                             BotNum = 0;
                            EmptyNum = 0;

                            if (!(x==0&&y==0))//除去评分点
                            {
                                //对黑棋
                                for (int i = 1; i <= 4; i++)//对各个正方向上邻接的四个位置进行统计
                                {
                                    if (row + i * y > 0 && row + i * y < Board.NODE_COUNT &&
                                        col + i * x > 0 && col + i * x < Board.NODE_COUNT &&
                                        board.GetPieceType(row + i * y
                                        , col + i * x) == PieceType.BLACK)//如果统计的位置在棋盘范围内并且是黑棋
                                    {
                                        PersonNum++;//玩家棋子数加1
                                    }
                                    else if (row + i * y > 0 && row + i * y < Board.NODE_COUNT &&
                                        col + i * x > 0 && col + i * x < Board.NODE_COUNT &&
                                        board.GetPieceType(row + i * y
                                        , col + i * x) == PieceType.NONE)//如果统计的位置在棋盘范围内并且无棋子
                                    {
                                        EmptyNum++;//空棋子数加1
                                        break;
                                    }
                                    else
                                        break;
                                }

                                    for (int i = 1; i <= 4; i++)//对各个负方向上邻接的四个位置进行统计
                                    {
                                        if (row - i * y > 0 && row - i * y < Board.NODE_COUNT &&
                                            col - i * x > 0 && col - i * x < Board.NODE_COUNT &&
                                            board.GetPieceType(row - i * y
                                            , col - i * x) == PieceType.BLACK)//如果统计的位置在棋盘范围内并且是黑棋
                                        {
                                            PersonNum++;//玩家棋子数加1
                                        }
                                        else if (row - i * y > 0 && row - i * y < Board.NODE_COUNT &&
                                                    col - i * x > 0 && col - i * x < Board.NODE_COUNT &&
                                                    board.GetPieceType(row - i * y,
                                                    col - i * x) == PieceType.NONE)//如果统计的位置在棋盘范围内并且无棋子
                                        {
                                            EmptyNum++;//空棋子数加1
                                            break;
                                        }
                                        else
                                            break;
                                    }
                                
                                if (PersonNum == 1)          //杀二(空位周围有一颗黑棋)加10分
                                {
                                    Score[row, col] += 10;
                                }
                                else if (PersonNum == 2)  //杀三(空位周围有两颗黑棋在一条直线上)
                                {
                                    if (EmptyNum == 1)
                                        Score[row, col] += 30;//如果有一个空位加30分
                                    else if (EmptyNum == 2)
                                        Score[row, col] += 40;//如果有两个空位加40分
                                }
                                else if (PersonNum == 3) //杀四(空位周围有三颗黑棋在一条直线上)
                                {
                                    if (EmptyNum == 1)
                                        Score[row, col] += 60;//如果有一个空位加60分
                                    else if (EmptyNum == 2)
                                        Score[row, col] += 110;//如果有两个空位加110分
                                }
                                else if (PersonNum == 4)//杀五(空位周围有四颗黑棋在一条直线上)加10100分
                                    Score[row, col] += 10100;

                                EmptyNum = 0;//空棋子数置零

                                //对白棋
                                    for (int i = 1; i <= 4; i++)//对各个正方向上邻接的四个位置进行统计
                                {
                                        if (row + i * y > 0 && row + i * y < Board.NODE_COUNT &&
                                            col + i * x > 0 && col + i * x < Board.NODE_COUNT &&
                                            board.GetPieceType(row + i * y,
                                            col + i * x) == PieceType.WHITE)//如果统计的位置在棋盘范围内并且是白棋
                                    {
                                            BotNum++;//AI棋子数加一
                                        }
                                        else if (row + i * y > 0 && row + i * y < Board.NODE_COUNT &&
                                            col + i * x > 0 && col + i * x < Board.NODE_COUNT &&
                                            board.GetPieceType(row + i * y
                                            , col + i * x) == PieceType.NONE)//如果统计的位置在棋盘范围内并且无棋子
                                    {
                                            EmptyNum++;//空棋子数加一
                                            break;
                                        }
                                        else
                                            break;
                                    }
                                
                                    for (int i = 1; i <= 4; i++)//对各个负方向上邻接的四个位置进行统计
                                {
                                        if (row - i * y > 0 && row - i * y < Board.NODE_COUNT &&
                                            col - i * x > 0 && col - i * x < Board.NODE_COUNT &&
                                            board.GetPieceType(row - i * y
                                            , col - i * x) == PieceType.WHITE)//如果统计的位置在棋盘范围内并且是白棋
                                    {
                                            BotNum++;//AI棋子数加一
                                    }
                                        else if (row - i * y > 0 && row - i * y < Board.NODE_COUNT &&
                                            col - i * x > 0 && col - i * x < Board.NODE_COUNT &&
                                            board.GetPieceType(row - i * y,
                                           col - i * x) == PieceType.NONE)//如果统计的位置在棋盘范围内并且无棋子
                                    {
                                            EmptyNum++;//空棋子数加一
                                        break;
                                        }
                                        else
                                            break;
                                    }
                                
                                if (BotNum == 0)//普通下棋加5分
                                {
                                    Score[row, col] += 5;
                                }
                               else if (BotNum == 1)//活二(空位周围有一颗白棋且邻接位置无棋子)加10分
                                {
                                    Score[row, col] += 10;
                                }
                                else if (BotNum == 2)
                                {
                                    if (EmptyNum == 1)//死三(空位周围有两颗白棋在一条直线上且只有一个空位置)加25分
                                        Score[row, col] += 25;
                                    else if (EmptyNum == 2)//活三(空位周围有两颗白棋在一条直线上且有两个空位置)加50分
                                        Score[row, col] += 50;
                                }
                                else if (BotNum == 3)//如果空位周围有三颗白棋在一条直线上
                                {
                                    if (EmptyNum == 1)//死四(只有一个空位置)加55分
                                        Score[row, col] += 55;
                                    else if (EmptyNum == 2)//活四(有两个空位置)加100分
                                        Score[row, col] += 100;
                                }
                                else if (BotNum >= 4)//如果空位周围有四个以上的白棋在一条直线上加20000分
                                    Score[row, col] += 20000;

                            }

                        }
                }
    }

6、AI走棋功能,代码如下:

    public Point AiPlacePiece()
    {
        CalculateScore();//首先对当前棋盘进行评分
        int MaxScore = 0;//设置最高分数,初始化为0
        //遍历当前棋盘上的每一个空位置,并记录分数最高的点
        for (int row = 0; row < Board.NODE_COUNT; row++)
        {
            for (int col = 0; col < Board.NODE_COUNT; col++)
            {
                Point AiPoint = new Point();
                if (board.pieces[row, col] == null)//如果是空位置
                {
                    
                    if (Score[row, col] > MaxScore)//如果当前点分数大于最高分数
                    {
                        MaxPoint.Clear();//清空记录分数最高点的List表
                        MaxScore = Score[row, col];//赋予新的最高分数
                        AiPoint = new Point(row * Board.NODE_DISTANCE + Board.OFFSET,
                                                          col * Board.NODE_DISTANCE + Board.OFFSET);//赋给该点的真正坐标位置
                        MaxPoint.Add(AiPoint);//记录到分数最高点的List表中
                    }
                    else if (Score[row, col] == MaxScore)//如果当前分数与最高分数相等,直接记录该位置
                    {
                        AiPoint = new Point(row * Board.NODE_DISTANCE + Board.OFFSET,
                                                          col * Board.NODE_DISTANCE + Board.OFFSET);
                        MaxPoint.Add(AiPoint);
                    }
                }
            }
        }
        //因为可能有多个空位置的分数都为最高分数,所以用随机数随机选定一个空位置
        Random ran = new Random();
        int a=ran.Next(0, MaxPoint.Count);
        MaxPoint.ToArray();
        return MaxPoint[a];
    }

7、悔棋功能

1)重新交换棋手,代码如下:

    public void BackChange()
    {
        if (CurrentPlayer == PieceType.BLACK)
        {
            PastPlayer = PieceType.BLACK;
            CurrentPlayer = PieceType.WHITE;
        }
        else if (CurrentPlayer == PieceType.WHITE)
        {
            PastPlayer = PieceType.WHITE;
            CurrentPlayer = PieceType.BLACK;
        }
    }

2)删除上一个棋子的位置信息,代码如下:

    public void Delete (Point p)
    {
        Point node= board.FindTheClosetNode(p.X, p.Y);
        board.pieces[node.X, node.Y] = null;//置空

    }

8、重新游戏功能,代码如下:

    public void Reload() 
    {
        CurrentPlayer = PieceType.BLACK;//重置当前玩家为
        winner = PieceType.NONE;
        board.Reload();
        CurrentTime = Board.STEP_SPAN_TIME+1;
    }

七、在用户实际使用过程中,方法和控件结合使用的具体实现:

代码位置:gobang\Gobang\人机游戏界面.cs

同样需要System.Drawing命名空间 using System.Drawing;

1、全局变量的定义:

    private GameManage game = new GameManage();//用于调用GameManage类中的相关方法
    private Board board = new Board();//用于调用Board类中的相关方法
    List<Piece> Pieces = new List<Piece>();//用于存放已经下过的棋子
    List<Point> Points = new List<Point>();//用于存放已经下过棋子对应的坐标位置

2、首先在窗体加载事件中设置定时器的时间间隔

        private void AiPlayersForm_Load(object sender, EventArgs e)
        {
            this.timer.Interval = 1000;//为倒计时服务,1000ms
            this.timercheck.Interval = 10;//为检查是否有玩家获胜服务,10ms
        }

3、用户点击"开始游戏"功能实现:

        private void BtnStart_Click_1(object sender, EventArgs e)
        {
            this.panel2.Enabled = true;//允许棋盘与用户交互
            this.timer.Enabled = true;//运行定时器
            this.timercheck.Enabled = true;//运行定时器
        }

4、设置两个Timer的Tick事件

1)对于timer要求实现倒计时功能:

    private void timer_Tick(object sender, EventArgs e)
    {
        GameManage.CurrentTime -= 1;//每个过1000ms当前倒计时减1
        this.LabTime.Text = GameManage.CurrentTime.ToString().Trim();//更新倒计时
    }

2)timercheck要求实现检查当前是否有玩家胜利并给出提示信息功能:

    private void timercheck_Tick_1(object sender, EventArgs e)
    {
        game.CheckWiner();//检查是否有玩家获胜
        if (game.Winner == PieceType.BLACK)//如果赢家是黑棋
        {
            //停止定时器
            timer.Stop();
            timercheck.Stop();
            //显示当前赢家信息并给出提示信息"玩家获胜!" 
            this.LabCurrentPlayer.Text = "获胜者:";
            this.PicCurrentPlayer.Image = Properties.Resources.black;
            MessageBox.Show("玩家获胜!", "游戏结束");
        }
        else if (game.Winner == PieceType.WHITE)//如果赢家是白棋
        {
            //停止定时器
            timer.Stop();
            timercheck.Stop();
            //显示当前赢家信息并给出提示信息"电脑获胜!" 
            this.LabCurrentPlayer.Text = "获胜者:";
            this.PicCurrentPlayer.Image = Properties.Resources.white;
            MessageBox.Show("电脑获胜!", "游戏结束");
        }
    }

5、在用户鼠标移动时,提示用户哪个位置可落子功能:

private void panel2_MouseMove_1(object sender, MouseEventArgs e)
{
    if (game.CanBePlaced(e.X, e.Y))//如果可放置棋子
        this.Cursor = Cursors.Hand;//鼠标标识变为手形光标
    else
        this.Cursor = Cursors.Default;//否则变为箭头光标
}

6、用户点击棋盘实现下子功能:

        private void panel2_MouseDown_1(object sender, MouseEventArgs e)
        {
            if (game.Winner != PieceType.NONE)//如果已经有赢家则不可再继续下棋
            {
                return;
            }
            Piece piece = game.PlacePiece(e.X, e.Y);//获得棋子
            if (piece != null)//如果当前位置无棋子,可下
            {
                Pieces.Add(piece);//记录到List<Piece>Pieces中
                Points.Add(e.Location);//记录到 List<Point> Points中
                this.panel2.Controls.Add(piece);//在棋盘上生成棋子
                this.PicCurrentPlayer.Image = piece.GetNextImage();//显示下一个玩家的图像
                GameManage.CurrentTime = Board.STEP_SPAN_TIME + 1;//间隔时间恢复至初始值
            }
        }

7、在用户下完棋抬起鼠标后AI走棋

    private void panel2_MouseUp_1(object sender, MouseEventArgs e)
    {
        if (board.AICanBePlaced(e.X, e.Y))//判断当前位置是否可下棋
        {
            if (game.Winner != PieceType.NONE)//如果已经有赢家则不可再继续下棋
            {
                return;
            }
            //获得分数最高棋子的位置信息
            Point Aipoint = new Point();
            Aipoint.X = game.AiPlacePiece().X;
            Aipoint.Y = game.AiPlacePiece().Y;
            Piece piece = game.PlacePiece(Aipoint.X, Aipoint.Y);
            if (piece != null)
            {
                Pieces.Add(piece);//记录到List<Piece>Pieces中
                Points.Add(Aipoint);//记录到 List<Point> Points中
                this.panel2.Controls.Add(piece);//在棋盘上生成棋子
                this.PicCurrentPlayer.Image = piece.GetNextImage();//显示下一个玩家的图像
                GameManage.CurrentTime = Board.STEP_SPAN_TIME + 1;//间隔时间恢复至初始值

            }
        }
    }

8、用户点击悔棋按钮实现的功能

    private void Back_Click(object sender, EventArgs e)
    {
        //对上一个棋子(人机棋子)
        this.panel2.Controls.Remove(Pieces[Pieces.Count-1]);//从棋盘上删除棋子图片
        game.Delete(Points[Points.Count - 1]);//在棋盘信息中删除棋子的位置信息
       //对上上一个棋子(玩家棋子)
        this.panel2.Controls.Remove(Pieces[Pieces.Count - 2]);//从棋盘上删除棋子图片
        game.Delete(Points[Points.Count - 2]);//在棋盘信息中删除棋子的位置信息

    }

9、用户点击认输按钮实现的功能

        private void GiveUp_Click(object sender, EventArgs e)
        {
            //给出提示信息,当用户确定后设置赢家为上一名玩家
            if (MessageBox.Show("确定要认输吗", "认输",
                    MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
            {
                game.Winner = GameManage.PastPlayer;
            }
        }

10、当用户点击重新游戏按钮实现的功能

    private void BtnReload_Click_1(object sender, EventArgs e)
    {
        game.Reload();//重置棋盘信息
        //重置当前玩家为黑棋
        this.LabCurrentPlayer.Text = "当前玩家:";
        this.PicCurrentPlayer.Image = Properties.Resources.black;
        this.panel2.Controls.Clear();            //清空棋盘上的棋子
        this.LabTime.Text = Board.STEP_SPAN_TIME.ToString();//设置倒计时为初始时间
        //重新启动定时器
        timer.Start();
        timercheck.Start();
    }

模块四(由于本模块与模块三实现方法基本类似,在此仅在不同之处做出说明)

不同点一:因为是双人游戏不需人机走棋,不用添加MouseUp事件

不同点二:悔棋功能的设计是针对悔棋方已下过棋,而对手玩家未下棋之前实现的。代码稍作改动:

        private void Back_Click(object sender, EventArgs e)
        {
            this.panel1.Controls.Remove(Pieces[Pieces.Count - 1]);//从棋盘上删除上一名玩家(悔棋方)的棋子
            game.Delete(Points[Points.Count - 1]);//从棋盘信息中删除上一名玩家(悔棋方)的棋子信息
            game.BackChange();//重新交换玩家
            this.PicCurrentPlayer.Image = Pieces[Pieces.Count - 2].GetNextImage();//设置当前玩家为悔棋方
        }

不同点三:在检查获胜方时,黑棋就代表黑棋玩家,白棋就代表白棋玩家。

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目:五子棋对弈 对弈规则如下: 主要功能是实现两人之间的对弈,在画好的棋盘上,两个玩家轮流选择自己的落子坐标,然后由五子棋系统自动识别判断游戏的进展,知道一方的五子连成一条线或者棋盘已经无法落子时游戏结束。 选定五子棋的棋盘大小为19*19,玩家可以在这个棋盘上选择落子坐标位置,通过在棋盘上显示不同的符号来代替不同玩家所下的棋子,“o”代表A玩家,“*”代表B玩家。玩家每次落子之后游戏系统都会对落子位置进行检查,如果落子坐标输入有错应提示错误,并要求玩家继续输入。 当出现同一玩家五子连成一线时,无论是行、列或是对角线的五子连线,都表示玩家游戏胜利,退出游戏 任务:编程实现以下功能 1. 欢迎主界面 提示玩家选择游戏开始,结束,设置悔棋次数等。 2. 绘制棋盘 该模块要求的功能是实现棋盘的显示及棋子的显示,,“o”代表A玩家,“*”代表B玩家。在每次下棋后要对棋盘进行刷新,将棋盘的状态变化为当前最新状态,然后等待另一个玩家下棋。 3. 玩家交替下棋 玩家能在棋盘上下棋,玩家每次选择好下棋的行和列坐标,并在该位置落子。 要求:a.提示当前玩家输入落子坐标 b.能判断用户输入的坐标是否正确(坐标超出范围或该处已有棋子) 4. 悔棋功能 玩家选择悔棋后刷新棋盘,删除前一次的落子,悔棋次数有限制。 5. 输赢判断 判断输赢模块的作用是每次玩家落子后判断是否已分出胜负,如果是,则返回胜利者相关信息。 6. 设计丰富的用户界面,方便用户操作 设计要求: ① 根据以上功能需求,自己定义合适的数据结构,并说明原因; ② 每个功能能提供友好的用户界面,方便用户操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值