大一新生必会的c语言五子棋!PVP,PVE,EVE模式都有,还有智能的AI部分,复盘等内容!一看就会的五子棋教程,确定不来看看吗?

简介: 大一新生必会的c语言五子棋!PVP,PVE,EVE模式都有,还有智能的AI部分,复盘等内容!一看就会的五子棋教程,确定不来看看吗?

目录

1.主函数

2.主菜单的打印(图形化界面的学习)

3.棋盘的打印

4.PVP部分

5.复盘部分(文件操作的学习)

6.AI部分(计分法的学习)

7.PVE部分

8.EVE部分

1.主函数:

#define _CRT_SECURE_NO_WARNINGS        
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include<graphics.h>
#include<stdlib.h>
int r[4][4] = { { 241,180,515,226 }, {241,230,460,276},{241,282,460,333 }, {285,386,460,424 } };
int flag = 0;
int flag3 = 0;
int count = 0;
int arr[16][16] = { 0 };
int score[16][16] = { 0 };
int ret = 0;
int r1[4] = { 530,30,660,75 };
int r4[4] = { 530,200,680,250 };
int r5[4] = { 530,260,640,300 };
int r6[4] = { 530,320,640,350 };
int r7[4] = { 530,380,640,410 };
RECT R1 = { r1[0], r1[1], r1[2], r1[3] };//矩阵指针
RECT R4 = { r4[0], r4[1], r4[2], r4[3] };
RECT R5 = { r5[0], r5[1], r5[2], r5[3] };
RECT R6 = { r6[0], r6[1], r6[2], r6[3] };
RECT R7 = { r7[0], r7[1], r7[2], r7[3] };
int main()
{
  menu();
  return 0;
}

在主函数中我们引出了menu菜单,方便菜单的打印。在主函数之前我们引用了很多全局变量,在后面的函数中都会用到。

2.主菜单的打印(图形化界面的学习)

void menu()
{
  initgraph(520, 550);//初始化界面
  IMAGE back;//定义图片接收
  loadimage(&back, _T("背景图片.png"));//接收图片
  putimage(0, 0, &back);//输出图片

这里我们需要将图片导入,首先要将我们的exe框的大小初始化一下,随后将图片导入并接收,需要注意的是我们要将导入的图片的名字与loadimage()里的名字保存一致哦。

putimage里的(0,0)表示的是从(0,0)起始坐标开始放图片。

        图片的原图在这,需要的老铁们可以自取。

运行后的结果是这样的:

接下来我们要像在游戏中用鼠标选择“开始游戏”一样,这里就涉及到到鼠标的操作和按钮跳转的操作。

MOUSEMSG m;//鼠标指针
  while (1)
  {
    m = GetMouseMsg();//获取一条鼠标消息
    if (m.uMsg == WM_LBUTTONDOWN)//当鼠标落下时
    {
      switch (button_judge(m.x, m.y))
      {
      case 0:
        break;
      case 1:
        closegraph();
        PVE();
        break;
      case 2:
        closegraph();
        EVE();
        break;
      case 3:
        closegraph();
        PVP();
        break;
      case 5:
        closegraph();
        exit(0);
      }
    }
  }
}

要获得鼠标消息首先要用MOUSEMSG获得鼠标指针,用while(1)循环进行选择。那么我们是如何选择操作的呢?

       我们用m获取鼠标消息,我们用m.uMsg == WM_LBUTTONDOWN判断是否是鼠标的左击也就是点击。当我们鼠标在exe上面左击一个地方就会保存他的坐标(m.x,m.y)。要想选择操作,就要判断鼠标点击的地方在哪个选项的矩形边框内,是选择人机对战,还是人人对战还是退出游戏都是通过鼠标的左击完成。

       注意这里的图片上的文字是我在ps上写入的,人机对战,机器对战,人人对战矩形的坐标我们是通过画图软件来观察他的像素坐标的。这里的二位数组就是我们定义的全局变量。

       我们的鼠标只要点击在该矩形边框内,就会选择该模式。

        随后我们用一个按钮函数来根据选择的位置选择相应的游戏。

int button_judge(int x, int y)//判断点击的是哪个按钮
{
  if (x > r[0][0] && x<r[0][2] && y>r[0][1] && y < r[0][3])
    return 1;//人机
  if (x > r[1][0] && x<r[1][2] && y>r[1][1] && y < r[1][3])
    return 2;//机器
  if (x > r[2][0] && x<r[2][2] && y>r[2][1] && y < r[2][3])
    return 3;//人人对战
  if (x > r[3][0] && x<r[3][2] && y>r[3][1] && y < r[3][3])
    return 5;//退出
  return 0;
}

3.棋盘的打印

void print_board()
{
  initgraph(800, 525);
  //贴图    
  IMAGE back1;//定义图片接收
  loadimage(&back1, _T("棋盘.png"));//接收图片
  putimage(0, 0, &back1);//输出图片
  int i = 0;
  for (i = 15; i <= 542; i += 32)
  {
    line(i, 5, i, 517);
  }
  for (i = 5; i <= 525; i += 32)
  {
    line(15, i, 527, i);
  }
    //将边框画粗
  line(16, 5, 16, 517);
  line(528, 5, 528, 517);
  line(15, 6, 527, 6);
  line(15, 518, 527, 518);
}

  一样的,我们将我们的这张图片导入exe中。

在画图软件中我们可以知道图片的长和宽,这里我们要打印15*15的棋盘,就要通过计算,算出需要我们话的线的数量和长度。这里的line()函数放的是两个横纵坐标,代表一条线,我们最后将边框重新画了一遍,就是为了将其边框加粗。

//绘制矩阵
  fillrectangle(r7[0], r7[1], r7[2], r7[3]);
  setbkmode(TRANSPARENT);//设置透明文字背景
  settextcolor(BLACK);//设置字体颜色
  setfillcolor(WHITE);
  drawtext(_T("退出"), &R7, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  fillrectangle(r1[0], r1[1], r1[2], r1[3]);
  drawtext(_T("返回主菜单"), &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

这里我们是在图片上绘制矩形边框并且在图片上打印文字,fillrectangle内的分别代表矩形左上角和右下角的坐标,正好四个数字就可以画出该矩形。同时我们要将背景设为透明,不然文字会被图片覆盖,随后设置文字的颜色。实际效果是这样的:

4.PVP部分:

       接下来就到我们的人人对战代码的书写,首先我们将二位数组初始化,再在棋盘上打印一个矩形边框方便提示用户下棋。

void PVP()
{
  memset(arr, 0, sizeof(int[16][16]));
  print_board();
  fillrectangle(r4[0], r4[1], r4[2], r4[3]);
  drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  int x = 0, y = 0;
  int a, b, i, j;
  flag = 0;
  count = 0;

同样的我们保存鼠标的消息,因为我们要将棋子下在格子上而不是乱下,所以我们要将我们下棋的位置四舍五入到最近的格子上。

MOUSEMSG m;//保存鼠标消息
  while (1)
  {
    m = GetMouseMsg();
    for (i = 1; i < 16; i++)
    {
      for (j = 1; j < 16; j++)
      {
        if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16)
        {
          x = i * 32 + 15;
          y = j * 32 + 5;
          a = i;
          b = j;
        }
      }
    }

当然,为了防止越界,我们用MessageBox提示用户是否越界并判断玩家所下位置是否有棋,提示以后玩家重新下棋,用continue继续循环。

if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      if (arr[a][b])
      {
        MessageBox(NULL, "这里已经有了", "提示", MB_OK);
        continue;
      }
      if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527)
      {
        MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK);
        continue;
      }

我们先让黑方下棋,初始化flag=0,如果flag为偶数,则下黑棋,为奇数下白棋,每次flag++即可。下棋的话我们用solidcircle就可以画出一个圆形棋子,当然,画棋子之前要用setfillcolor规定棋子的颜色!每一个棋子下完以后要在我们的二维数组内,黑棋用1表示,白棋用2表示。在每次下一个棋之后,我们还要判断输赢。

if (flag % 2 == 0)
      {
        setfillcolor(WHITE);
        fillrectangle(r4[0], r4[1], r4[2], r4[3]);
        drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示
        setfillcolor(BLACK);
        solidcircle(x, y, 12);
        flag++;
        count++;
        arr[a][b] =1;
        ret = is_win(arr, count);
        if (ret)
        {
          judge_winPVP(ret);
          break;
        }
      }
      else
      {
        setfillcolor(WHITE);
        fillrectangle(r4[0], r4[1], r4[2], r4[3]);
        setfillcolor(BLACK);
        drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        setfillcolor(WHITE);
        solidcircle(x, y, 12);
        arr[a][b] = 2;
        flag++;
        count++;
        ret = is_win(arr, count);
        if (ret)
        {
          judge_winPVP(ret);
          break;
        }
      }
    }
  }

    判断输赢的函数有两个

int is_win(int arr[16][16], int count)
{
  int i = 0;
  int j = 0;
  //竖行
  for (i = 1; i < 16; i++)
  {
    for (j = 1; j < 12; j++)
    {
      if (arr[i][j] == arr[i][j + 1] && arr[i][j + 1] == arr[i][j + 2] && arr[i][j + 2] == arr[i][j + 3] && arr[i][j + 3] == arr[i][j + 4] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
  //横行
  for (j = 1; j < 16; j++)
  {
    for (i = 1; i < 12; i++)
    {
      if (arr[i][j] == arr[i + 1][j] && arr[i + 1][j] == arr[i + 2][j] && arr[i + 2][j] == arr[i + 3][j] && arr[i + 3][j] == arr[i + 4][j] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
  //右下
  for (j = 1; j < 12; j++)
  {
    for (i = 1; i < 12; i++)
    {
      if (arr[i][j] == arr[i + 1][j + 1] && arr[i + 1][j + 1] == arr[i + 2][j + 2] && arr[i + 2][j + 2] == arr[i + 3][j + 3] && arr[i + 3][j + 3] == arr[i + 4][j + 4] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
  //左下
  for (i = 1; i < 12; i++)
  {
    for (j = 15; j > 4; j--)
    {
      if (arr[i][j] == arr[i + 1][j - 1] && arr[i + 1][j - 1] == arr[i + 2][j - 2] && arr[i + 2][j - 2] == arr[i + 3][j - 3] && arr[i + 3][j - 3] == arr[i + 4][j - 4] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
//平局
  if (count == 225)
    return 4;
  return 0;
}

    这里我们返回存入arr数组里的值,随后在判断输赢的函数里判断输赢。

void judge_winPVP(int t)
{
  if (t == 1)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("黑棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 2)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("白棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 4)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  setfillcolor(WHITE);
  fillrectangle(r6[0], r6[1], r6[2], r6[3]);
  drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}

一局结束以后,我们要选择是返回主菜单还是复盘还是退出该游戏,所以我们要继续用鼠标做出选择。

while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3])
      {
        closegraph();
        fupanPVP();
      }
      else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3])
      {
        closegraph();
        menu();
      }
    }
  }
}

像这样,一局PVP就下完了。

5.复盘部分(文件操作的基本学习)

       留心的老铁应该会发现复盘这一操作,我们如何让一局下过的棋重新复盘一遍呢,这就需要文件操作的知识了。

FILE* file = fopen("PVP.txt", "w");
  fclose(file);
  FILE* fq = fopen("PVP.txt", "a+");

这里我们将txt文件以写的形式打开,之前txt内的数据就会全部删除,随后我们再以追加的方式读入数据。

       我们在将棋子存入二维数组以后,再将他存入文件中。

//黑棋:           
                arr[a][b] = 1;
        fprintf(fq, "%d ", a);
        fprintf(fq, "%d ", b);
//白棋
                arr[a][b] = 2;
        fprintf(fq, "%d ", a);
        fprintf(fq, "%d ", b);

复盘函数:

void fupanPVP()
{
  int a, b;
  int r4[4] = { 530,200,680,250 };
  RECT R4 = { r4[0], r4[1], r4[2], r4[3] };
  flag = 0;
  count = 0;
  print_board();
  FILE* fq = fopen("PVP.txt", "a+");
  memset(arr, 0, sizeof(int[16]));
  while (fscanf_s(fq, "%d %d ", &a, &b) == 2)
  {
    if (flag % 2 == 0)
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示
      setfillcolor(BLACK);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 1;
    }
    else
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      setfillcolor(WHITE);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 2;
    }
    Sleep(500);
  }
  ret = is_win(arr, count);
  judge_winPVP(ret);
}

同样的我们以a+追加的方式读入数据,用fscanf()读入数据,存入二维数组,在exe界面上进行一定的操作画棋子,判断输赢等操作与PVP一样,不同的是我们要用Sleep函数使下棋有时间的停顿,这样才可以更真实。

6.AI部分

计算每个空白的落子点的“权值”,然后再权值最大的点落子

以后,可以在这个基础之上,实现多个层次的计算.

对于每个空白点,分别计算周围的八个方向

为了使AI更智能,在计算分数时,电脑可以先假设对方下这个点时的结果来先打个分,随后在假设电脑自己下这个位置的结果来打个分。这里我们假设玩家下黑棋,电脑下白棋,

选择轮到电脑下棋。

void computer(int arr[16][16])
{
  int i, x, y, k, r, c;
  int persennum = 0;
  int ainum = 0;
  int emptynum = 0;
  memset(score, 0, sizeof(int[16][16]));
  for (r = 1; r < 16; r++)
  {
    for (c = 1; c < 16; c++)
    {
      if (arr[r][c] == 0)
      {
        int direction[4][2] = { {1,0},{1,1},{0,1},{-1,1} };
        //规定正方向
        for (k = 0; k < 4; k++)
        {
          x = direction[k][0];
          y = direction[k][1];
          //遍历不同方向
          //清空积分器
          persennum = 0;
          ainum = 0;
          emptynum = 0;
          //预测人下棋的分数(防御)
          // 
          //正向
          for (i = 1; i <= 4; i++)
          {
            if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 2)
            {
              persennum++;
            }
            //玩家的棋子
            else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0)
            {
              emptynum++;
              break;
            }
            //空白的棋子
            else
            {
              break;
            }
          }
          //反向
          for (i = 1; i <= 4; i++)
          {
            if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 2)
            {
              persennum++;
            }
            //玩家的棋子
            else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0)
            {
              emptynum++;
              break;
            }
            //搜索到空白的棋子,停止搜索
            else
            {
              break;
            }
            //搜索到越界的棋子和ai棋子,停止搜索
          }
          //杀二
          if (persennum == 1)
          {
            score[r][c] += 10;
          }
          //杀三
          else if (persennum == 2)
          {
            //死三
            if (emptynum == 1)
              score[r][c] += 30;
            //活三
            else if (emptynum == 2)
              score[r][c] += 40;
          }
          //杀四
          else if (persennum == 3)
          {
            //死四
            if (emptynum == 1)
              score[r][c] += 60;
            //活四
            else if (emptynum == 2)
              score[r][c] += 200;
          }
          //杀五
          else if (persennum == 4)
          {
            score[r][c] += 20000;
          }
          //清空
          emptynum = 0;
          //预测ai的分数(进攻)
          //正向
          for (i = 1; i <= 4; i++)
          {
            if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 1)
            {
              ainum++;
            }
            //玩家的棋子
            else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0)
            {
              emptynum++;
              break;
            }
            //空白的棋子
            else
            {
              break;
            }
          }
          //反向
          for (i = 1; i <= 4; i++)
          {
            if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 1)
            {
              ainum++;
            }
            //玩家的棋子
            else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0)
            {
              emptynum++;
              break;
            }
            //搜索到空白的棋子,停止搜索
            else
            {
              break;
            }
            //搜索到越界的棋子和ai棋子,停止搜索
          }
          //杀二
          if (ainum == 0)
          {
            score[r][c] += 5;
          }
          if (ainum == 1)
          {
            score[r][c] += 10;
          }
          //杀三
          else if (ainum == 2)
          {
            //死三
            if (emptynum == 1)
              score[r][c] += 25;
            //活三
            else if (emptynum == 2)
              score[r][c] += 50;
          }
          //杀四
          else if (ainum == 3)
          {
            //死四
            if (emptynum == 1)
              score[r][c] += 55;
            //活四
            else if (emptynum == 2)
              score[r][c] += 300;
          }
          //杀五
          else if (ainum == 4)
          {
            score[r][c] += 999999;
          }
        }
      }
    }
  }
}

注意:这里我们用全局的二位数组score来保存分数,以便后面寻找最大分数点的操作。      

打分的详细表格如下:

将所有的分数存入score数组以后,我们就写一个函数寻找最大的分数。

void find_max(int* x, int* y, int arr[16][16])
{
  int max = 0;
  int n = 0;
  int maxpoint[225][2];
  memset(maxpoint, 0, sizeof(int[225][2]));
  for (int i = 1; i <= 15; i++)
  {
    for (int j = 1; j <= 15; j++)
    {
      if (arr[i][j] == 0)
      {
        if (score[i][j] > max)
        {
          max = score[i][j];
          *x = i;
          *y = j;
        }
      }
    }
  }
  for (int i = 1; i <= 15; i++)
  {
    for (int j = 1; j <= 15; j++)
    {
      if (score[i][j] == max)
      {
        maxpoint[n][0] = i;
        maxpoint[n++][1] = j;
      }
    }
  }
  srand((unsigned int)time(0));
  int index = rand() % n;
  *x = maxpoint[index][0];
  *y = maxpoint[index][1];
}

 这里值得注意的是,如果我们有几个地方的分数一样并且都是最大,我们就需要电脑随机找一个点下,这样使ai更真实,也让机器对战的每一盘不在一样。(如果不随机下,每一盘棋子可能都会出现一模一样的情况)。我们将所有的最大分数都存起来,再以time为种子生成随机数。

7.PVE部分:

在写完ai部分后我们就可以写我们的人机对战和机器对战了。

       与人人不同的是,我们要先确定先后手,即电脑先手还是玩家先手,我们在messagebox提示以后,让用户进行选择。

void PVE()
{
  int x = 0, y = 0;
  int a = 0, b = 0, i = 0, j = 0;
  memset(arr, 0, sizeof(int[16][16]));
  FILE* file = fopen("PVE.txt", "w");
  fclose(file);
  count = 0;
  FILE* fq = fopen("PVE.txt", "a+");
  print_board();
  fillrectangle(r4[0], r4[1], r4[2], r4[3]);
  drawtext(_T("电脑先下"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  fillrectangle(r5[0], r5[1], r5[2], r5[3]);
  drawtext(_T("我先下"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  MOUSEMSG m;
  while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r4[0] && m.x<r4[2] && m.y>r4[1] && m.y < r4[3])
      {
        flag3 = 0;
        flag = 0;
        MessageBox(NULL, "电脑先手", "提示", MB_OK);
        break;
      }
      else if (m.x > r5[0] && m.x<r5[2] && m.y>r5[1] && m.y < r5[3])
      {
        flag3 = 1;
        flag = 1;
        MessageBox(NULL, "你先手", "提示", MB_OK);
        break;
      }
      else
      {
        MessageBox(NULL, "请选择先后", "提示", MB_OK);
      }
    }
  }

选择完后就是人机对战了

while (1)
  {
    //机器部分
    if (flag == 0)
    {
      setfillcolor(BLACK);
      solidcircle(271, 261, 12);
      arr[8][8] = 1;
      flag++;
      count++;
      fprintf(fq, "%d ", 8);
      fprintf(fq, "%d ", 8);
    }
    if (flag % 2 == 0)
    {
      Sleep(500);
      computer(arr);
      find_max(&i, &j,arr);
      setfillcolor(BLACK);
      solidcircle(i * 32 + 15, j * 32 + 5, 12);
      arr[i][j] = 1;
      fprintf(fq, "%d ", i);
      fprintf(fq, "%d ", j);
      setfillcolor(BLACK);
      drawtext(_T("该你下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      ret = is_win(arr, count);
      if (ret)
      {
        judge_winPVE(ret);
        break;
      }
      flag++;
      count++;
    }
    //人的部分
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      for (i = 1; i < 16; i++)
      {
        for (j = 1; j < 16; j++)
        {
          if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16)
          {
            x = i * 32 + 15;
            y = j * 32 + 5;
            a = i;
            b = j;
          }
        }
      }
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      if (arr[a][b])
      {
        MessageBox(NULL, "这里已经有了", "提示", MB_OK);
        continue;
      }
      if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527)
      {
        MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK);
        continue;
      }
      if (flag % 2 == 1)
      {
        setfillcolor(WHITE);
        fillrectangle(r4[0], r4[1], r4[2], r4[3]);
        solidcircle(x, y, 12);
        arr[a][b] = 2;
        flag++;
        count++;
        fprintf(fq, "%d ", a);
        fprintf(fq, "%d ", b);
        ret = is_win(arr, count);
        if (ret)
        {
          judge_winPVE(ret);
          break;
        }
      }
    }
  }
  fclose(fq);
  while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3])
      {
        closegraph();
        fupanPVE();
      }
      else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3])
      {
        closegraph();
        menu();
      }
    }
  }
}

这里唯一不同的是在选择电脑先手后我们要帮助电脑在棋盘正中间下一个棋子,其他的与人人对战相似,ai部分也在上面做过讲解,就不在赘述。

8.EVE部分:

机器对战就是两个ai对战,所以我们就让我们之前写的两个ai互相下棋即可。

void EVE()
{
  int x = 0, y = 0;
  int a = 0, b = 0, i = 0, j = 0;
  flag = 0;
  count = 0;
  memset(arr, 0, sizeof(int[16][16]));
  FILE* file = fopen("EVE.txt", "w");
  fclose(file);
  FILE* fq = fopen("EVE.txt", "a+");
  print_board();
  MOUSEMSG m;
  while (1)
  {
    //机器部分
    if (flag == 0)
    {
      setfillcolor(BLACK);
      solidcircle(271, 261, 12);
      arr[8][8] = 1;
      flag++;
      count++;
      fprintf(fq, "%d ", 8);
      fprintf(fq, "%d ", 8);
    }
    //玩家一
    if (flag % 2 == 0)
    {
      Sleep(310);
      computer(arr);
      find_max(&i, &j,arr);
      setfillcolor(BLACK);
      solidcircle(i * 32 + 15, j * 32 + 5, 12);
      arr[i][j] = 1;
      fprintf(fq, "%d ", i);
      fprintf(fq, "%d ", j);
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      drawtext(_T("P2下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      ret = is_win(arr, count);
      if (ret)
      {
        judge_winEVE(ret);
        break;
      }
      flag++;
      count++;
    }
    //P2:
    if (flag % 2 == 1)
    {
      Sleep(310);
      computer(arr);
      find_max(&i, &j,arr);
      setfillcolor(WHITE);
      solidcircle(i * 32 + 15, j * 32 + 5, 12);
      arr[i][j] = 2;
      fprintf(fq, "%d ", i);
      fprintf(fq, "%d ", j);
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      drawtext(_T("P1下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      ret = is_win(arr, count);
      if (ret)
      {
        judge_winEVE(ret);
        break;
      }
      flag++;
      count++;
    }
  }
  fclose(fq);
  while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3])
      {
        closegraph();
        fupanEVE();
      }
      else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3])
      {
        closegraph();
        menu();
      }
    }
  }
}

完整代码:

#define _CRT_SECURE_NO_WARNINGS        
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include<graphics.h>
#include<stdlib.h>
void menu();
//全局变量
int r[4][4] = { { 241,180,515,226 }, {241,230,460,276},{241,282,460,333 }, {285,386,460,424 } };
int flag = 0;
int flag3 = 0;
int count = 0;
int arr[16][16] = { 0 };
int score[16][16] = { 0 };
int ret = 0;
int r1[4] = { 530,30,660,75 };
int r4[4] = { 530,200,680,250 };
int r5[4] = { 530,260,640,300 };
int r6[4] = { 530,320,640,350 };
int r7[4] = { 530,380,640,410 };
RECT R1 = { r1[0], r1[1], r1[2], r1[3] };//矩阵指针
RECT R4 = { r4[0], r4[1], r4[2], r4[3] };
RECT R5 = { r5[0], r5[1], r5[2], r5[3] };
RECT R6 = { r6[0], r6[1], r6[2], r6[3] };
RECT R7 = { r7[0], r7[1], r7[2], r7[3] };
void find_max(int* x, int* y, int arr[16][16])
{
  int max = 0;
  int n = 0;
  int maxpoint[225][2];
  memset(maxpoint, 0, sizeof(int[225][2]));
  for (int i = 1; i <= 15; i++)
  {
    for (int j = 1; j <= 15; j++)
    {
      if (arr[i][j] == 0)
      {
        if (score[i][j] > max)
        {
          max = score[i][j];
          *x = i;
          *y = j;
        }
      }
    }
  }
  for (int i = 1; i <= 15; i++)
  {
    for (int j = 1; j <= 15; j++)
    {
      if (score[i][j] == max)
      {
        maxpoint[n][0] = i;
        maxpoint[n++][1] = j;
      }
    }
  }
  srand((unsigned int)time(0));
  int index = rand() % n;
  *x = maxpoint[index][0];
  *y = maxpoint[index][1];
}
int button_judge(int x, int y)//判断点击的是哪个按钮
{
  if (x > r[0][0] && x<r[0][2] && y>r[0][1] && y < r[0][3])
    return 1;//人机
  if (x > r[1][0] && x<r[1][2] && y>r[1][1] && y < r[1][3])
    return 2;//机器
  if (x > r[2][0] && x<r[2][2] && y>r[2][1] && y < r[2][3])
    return 3;//rr
  if (x > r[3][0] && x<r[3][2] && y>r[3][1] && y < r[3][3])
    return 5;//退出
  return 0;
}
void judge_winPVP(int t)
{
  if (t == 1)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("黑棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 2)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("白棋胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 4)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  setfillcolor(WHITE);
  fillrectangle(r6[0], r6[1], r6[2], r6[3]);
  drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
void judge_winPVE(int t)
{
  if (t == 1)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("电脑胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 2)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("你胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 4)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  setfillcolor(WHITE);
  fillrectangle(r6[0], r6[1], r6[2], r6[3]);
  drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
void judge_winEVE(int t)
{
  if (t == 1)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("P1胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 2)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("P2胜利"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  else if (t == 4)
  {
    setfillcolor(WHITE);
    fillrectangle(r5[0], r5[1], r5[2], r5[3]);
    setfillcolor(RED);
    drawtext(_T("打平了"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  }
  setfillcolor(WHITE);
  fillrectangle(r6[0], r6[1], r6[2], r6[3]);
  drawtext(_T("复盘"), &R6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
int is_win(int arr[16][16], int count)
{
  int i = 0;
  int j = 0;
  //竖行
  for (i = 1; i < 16; i++)
  {
    for (j = 1; j < 12; j++)
    {
      if (arr[i][j] == arr[i][j + 1] && arr[i][j + 1] == arr[i][j + 2] && arr[i][j + 2] == arr[i][j + 3] && arr[i][j + 3] == arr[i][j + 4] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
  //横行
  for (j = 1; j < 16; j++)
  {
    for (i = 1; i < 12; i++)
    {
      if (arr[i][j] == arr[i + 1][j] && arr[i + 1][j] == arr[i + 2][j] && arr[i + 2][j] == arr[i + 3][j] && arr[i + 3][j] == arr[i + 4][j] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
  //右下
  for (j = 1; j < 12; j++)
  {
    for (i = 1; i < 12; i++)
    {
      if (arr[i][j] == arr[i + 1][j + 1] && arr[i + 1][j + 1] == arr[i + 2][j + 2] && arr[i + 2][j + 2] == arr[i + 3][j + 3] && arr[i + 3][j + 3] == arr[i + 4][j + 4] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
  //左下
  for (i = 1; i < 12; i++)
  {
    for (j = 15; j > 4; j--)
    {
      if (arr[i][j] == arr[i + 1][j - 1] && arr[i + 1][j - 1] == arr[i + 2][j - 2] && arr[i + 2][j - 2] == arr[i + 3][j - 3] && arr[i + 3][j - 3] == arr[i + 4][j - 4] && arr[i][j] != 0)
        return arr[i][j];
    }
  }
  if (count == 225)
    return 4;
  return 0;
}
void print_board()
{
  initgraph(800, 525);
  //贴图    
  IMAGE back1;//定义图片接收
  loadimage(&back1, _T("棋盘.png"));//接收图片
  putimage(0, 0, &back1);//输出图片
  int i = 0;
  for (i = 15; i <= 542; i += 32)
  {
    line(i, 5, i, 517);
  }
  for (i = 5; i <= 525; i += 32)
  {
    line(15, i, 527, i);
  }
  line(16, 5, 16, 517);
  line(528, 5, 528, 517);
  line(15, 6, 527, 6);
  line(15, 518, 527, 518);
  //绘制矩阵
  fillrectangle(r7[0], r7[1], r7[2], r7[3]);
  setbkmode(TRANSPARENT);//设置透明文字背景
  settextcolor(BLACK);//设置字体颜色
  setfillcolor(WHITE);
  drawtext(_T("退出"), &R7, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  fillrectangle(r1[0], r1[1], r1[2], r1[3]);
  drawtext(_T("返回主菜单"), &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
void fupanPVP()
{
  int a, b;
  int r4[4] = { 530,200,680,250 };
  RECT R4 = { r4[0], r4[1], r4[2], r4[3] };
  flag = 0;
  count = 0;
  print_board();
  FILE* fq = fopen("PVP.txt", "a+");
  memset(arr, 0, sizeof(int[16]));
  while (fscanf_s(fq, "%d %d ", &a, &b) == 2)
  {
    if (flag % 2 == 0)
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示
      setfillcolor(BLACK);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 1;
    }
    else
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      setfillcolor(WHITE);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 2;
    }
    Sleep(500);
  }
  ret = is_win(arr, count);
  judge_winPVP(ret);
}
void fupanPVE()
{
  int a, b;
  int r4[4] = { 530,200,680,250 };
  RECT R4 = { r4[0], r4[1], r4[2], r4[3] };
  count = 0;
  flag = flag3;
  print_board();
  FILE* fq = fopen("PVE.txt", "a+");
  memset(arr, 0, sizeof(int[16]));
  while (fscanf_s(fq, "%d %d ", &a, &b) == 2)
  {
    if (flag % 2 == 0)
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 1;
    }
    else
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 2;
    }
    Sleep(500);
  }
  ret = is_win(arr, count);
  judge_winPVE(ret);
}
void fupanEVE()
{
  int a, b;
  int r4[4] = { 530,200,680,250 };
  RECT R4 = { r4[0], r4[1], r4[2], r4[3] };
  count = 0;
  flag = 0;
  print_board();
  FILE* fq = fopen("EVE.txt", "a+");
  memset(arr, 0, sizeof(int[16]));
  while (fscanf_s(fq, "%d %d ", &a, &b) == 2)
  {
    if (flag % 2 == 0)
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 1;
    }
    else
    {
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(WHITE);
      solidcircle(a * 32 + 15, b * 32 + 5, 12);
      flag++;
      count++;
      arr[a][b] = 2;
    }
    Sleep(500);
  }
  ret = is_win(arr, count);
  judge_winPVP(ret);
}
void computer(int arr[16][16])
{
  int i, x, y, k, r, c;
  int persennum = 0;
  int ainum = 0;
  int emptynum = 0;
  memset(score, 0, sizeof(int[16][16]));
  for (r = 1; r < 16; r++)
  {
    for (c = 1; c < 16; c++)
    {
      if (arr[r][c] == 0)
      {
        int direction[4][2] = { {1,0},{1,1},{0,1},{-1,1} };
        //规定正方向
        for (k = 0; k < 4; k++)
        {
          x = direction[k][0];
          y = direction[k][1];
          //遍历不同方向
          //清空积分器
          persennum = 0;
          ainum = 0;
          emptynum = 0;
          //预测人下棋的分数(防御)
          // 
          //正向
          for (i = 1; i <= 4; i++)
          {
            if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 2)
            {
              persennum++;
            }
            //玩家的棋子
            else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0)
            {
              emptynum++;
              break;
            }
            //空白的棋子
            else
            {
              break;
            }
          }
          //反向
          for (i = 1; i <= 4; i++)
          {
            if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 2)
            {
              persennum++;
            }
            //玩家的棋子
            else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0)
            {
              emptynum++;
              break;
            }
            //搜索到空白的棋子,停止搜索
            else
            {
              break;
            }
            //搜索到越界的棋子和ai棋子,停止搜索
          }
          //杀二
          if (persennum == 1)
          {
            score[r][c] += 10;
          }
          //杀三
          else if (persennum == 2)
          {
            //死三
            if (emptynum == 1)
              score[r][c] += 30;
            //活三
            else if (emptynum == 2)
              score[r][c] += 40;
          }
          //杀四
          else if (persennum == 3)
          {
            //死四
            if (emptynum == 1)
              score[r][c] += 60;
            //活四
            else if (emptynum == 2)
              score[r][c] += 200;
          }
          //杀五
          else if (persennum == 4)
          {
            score[r][c] += 20000;
          }
          //清空
          emptynum = 0;
          //预测ai的分数(进攻)
          //正向
          for (i = 1; i <= 4; i++)
          {
            if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 1)
            {
              ainum++;
            }
            //玩家的棋子
            else if (r + i * y <= 15 && c + i * x <= 15 && arr[r + i * y][c + i * x] == 0)
            {
              emptynum++;
              break;
            }
            //空白的棋子
            else
            {
              break;
            }
          }
          //反向
          for (i = 1; i <= 4; i++)
          {
            if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 1)
            {
              ainum++;
            }
            //玩家的棋子
            else if (r - i * y >= 1 && c - i * x >= 1 && arr[r - i * y][c - i * x] == 0)
            {
              emptynum++;
              break;
            }
            //搜索到空白的棋子,停止搜索
            else
            {
              break;
            }
            //搜索到越界的棋子和ai棋子,停止搜索
          }
          //杀二
          if (ainum == 0)
          {
            score[r][c] += 5;
          }
          if (ainum == 1)
          {
            score[r][c] += 10;
          }
          //杀三
          else if (ainum == 2)
          {
            //死三
            if (emptynum == 1)
              score[r][c] += 25;
            //活三
            else if (emptynum == 2)
              score[r][c] += 50;
          }
          //杀四
          else if (ainum == 3)
          {
            //死四
            if (emptynum == 1)
              score[r][c] += 55;
            //活四
            else if (emptynum == 2)
              score[r][c] += 300;
          }
          //杀五
          else if (ainum == 4)
          {
            score[r][c] += 999999;
          }
        }
      }
    }
  }
}
void PVP()
{
  memset(arr, 0, sizeof(int[16][16]));
  print_board();
  fillrectangle(r4[0], r4[1], r4[2], r4[3]);
  drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  int x = 0, y = 0;
  int a, b, i, j;
  flag = 0;
  count = 0;
  FILE* file = fopen("PVP.txt", "w");
  fclose(file);
  FILE* fq = fopen("PVP.txt", "a+");
  MOUSEMSG m;//保存鼠标消息
  while (1)
  {
    m = GetMouseMsg();
    for (i = 1; i < 16; i++)
    {
      for (j = 1; j < 16; j++)
      {
        if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16)
        {
          x = i * 32 + 15;
          y = j * 32 + 5;
          a = i;
          b = j;
        }
      }
    }
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      if (arr[a][b])
      {
        MessageBox(NULL, "这里已经有了", "提示", MB_OK);
        continue;
      }
      if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527)
      {
        MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK);
        continue;
      }
      if (flag % 2 == 0)
      {
        setfillcolor(WHITE);
        fillrectangle(r4[0], r4[1], r4[2], r4[3]);
        drawtext(_T("该白方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在R3中输入文字,水平居中,垂直居中,单行显示
        setfillcolor(BLACK);
        solidcircle(x, y, 12);
        flag++;
        count++;
        arr[a][b] = 1;
        fprintf(fq, "%d ", a);
        fprintf(fq, "%d ", b);
        ret = is_win(arr, count);
        if (ret)
        {
          judge_winPVP(ret);
          break;
        }
      }
      else
      {
        setfillcolor(WHITE);
        fillrectangle(r4[0], r4[1], r4[2], r4[3]);
        setfillcolor(BLACK);
        drawtext(_T("该黑方下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        setfillcolor(WHITE);
        solidcircle(x, y, 12);
        arr[a][b] = 2;
        fprintf(fq, "%d ", a);
        fprintf(fq, "%d ", b);
        flag++;
        count++;
        ret = is_win(arr, count);
        if (ret)
        {
          judge_winPVP(ret);
          break;
        }
      }
    }
  }
  fclose(fq);
  while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3])
      {
        closegraph();
        fupanPVP();
      }
      else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3])
      {
        closegraph();
        menu();
      }
    }
  }
}
void PVE()
{
  int x = 0, y = 0;
  int a = 0, b = 0, i = 0, j = 0;
  memset(arr, 0, sizeof(int[16][16]));
  FILE* file = fopen("PVE.txt", "w");
  fclose(file);
  count = 0;
  FILE* fq = fopen("PVE.txt", "a+");
  print_board();
  fillrectangle(r4[0], r4[1], r4[2], r4[3]);
  drawtext(_T("电脑先下"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  fillrectangle(r5[0], r5[1], r5[2], r5[3]);
  drawtext(_T("我先下"), &R5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  MOUSEMSG m;
  while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r4[0] && m.x<r4[2] && m.y>r4[1] && m.y < r4[3])
      {
        flag3 = 0;
        flag = 0;
        MessageBox(NULL, "电脑先手", "提示", MB_OK);
        break;
      }
      else if (m.x > r5[0] && m.x<r5[2] && m.y>r5[1] && m.y < r5[3])
      {
        flag3 = 1;
        flag = 1;
        MessageBox(NULL, "你先手", "提示", MB_OK);
        break;
      }
      else
      {
        MessageBox(NULL, "请选择先后", "提示", MB_OK);
      }
    }
  }
  while (1)
  {
    //机器部分
    if (flag == 0)
    {
      setfillcolor(BLACK);
      solidcircle(271, 261, 12);
      arr[8][8] = 1;
      flag++;
      count++;
      fprintf(fq, "%d ", 8);
      fprintf(fq, "%d ", 8);
    }
    if (flag % 2 == 0)
    {
      Sleep(500);
      computer(arr);
      find_max(&i, &j,arr);
      setfillcolor(BLACK);
      solidcircle(i * 32 + 15, j * 32 + 5, 12);
      arr[i][j] = 1;
      fprintf(fq, "%d ", i);
      fprintf(fq, "%d ", j);
      setfillcolor(BLACK);
      drawtext(_T("该你下棋了"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      ret = is_win(arr, count);
      if (ret)
      {
        judge_winPVE(ret);
        break;
      }
      flag++;
      count++;
    }
    //人的部分
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      for (i = 1; i < 16; i++)
      {
        for (j = 1; j < 16; j++)
        {
          if (abs(m.x - i * 32 - 15) < 16 && abs(m.y - j * 32 - 5) < 16)
          {
            x = i * 32 + 15;
            y = j * 32 + 5;
            a = i;
            b = j;
          }
        }
      }
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      if (arr[a][b])
      {
        MessageBox(NULL, "这里已经有了", "提示", MB_OK);
        continue;
      }
      if (m.x < 15 || m.x>517 || m.y < 5 || m.y > 527)
      {
        MessageBox(NULL, "你下的棋子超出范围", "提示", MB_OK);
        continue;
      }
      if (flag % 2 == 1)
      {
        setfillcolor(WHITE);
        fillrectangle(r4[0], r4[1], r4[2], r4[3]);
        solidcircle(x, y, 12);
        arr[a][b] = 2;
        flag++;
        count++;
        fprintf(fq, "%d ", a);
        fprintf(fq, "%d ", b);
        ret = is_win(arr, count);
        if (ret)
        {
          judge_winPVE(ret);
          break;
        }
      }
    }
  }
  fclose(fq);
  while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3])
      {
        closegraph();
        fupanPVE();
      }
      else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3])
      {
        closegraph();
        menu();
      }
    }
  }
}
void EVE()
{
  int x = 0, y = 0;
  int a = 0, b = 0, i = 0, j = 0;
  flag = 0;
  count = 0;
  memset(arr, 0, sizeof(int[16][16]));
  FILE* file = fopen("EVE.txt", "w");
  fclose(file);
  FILE* fq = fopen("EVE.txt", "a+");
  print_board();
  MOUSEMSG m;
  while (1)
  {
    //机器部分
    if (flag == 0)
    {
      setfillcolor(BLACK);
      solidcircle(271, 261, 12);
      arr[8][8] = 1;
      flag++;
      count++;
      fprintf(fq, "%d ", 8);
      fprintf(fq, "%d ", 8);
    }
    //玩家一
    if (flag % 2 == 0)
    {
      Sleep(310);
      computer(arr);
      find_max(&i, &j,arr);
      setfillcolor(BLACK);
      solidcircle(i * 32 + 15, j * 32 + 5, 12);
      arr[i][j] = 1;
      fprintf(fq, "%d ", i);
      fprintf(fq, "%d ", j);
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      drawtext(_T("P2下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      ret = is_win(arr, count);
      if (ret)
      {
        judge_winEVE(ret);
        break;
      }
      flag++;
      count++;
    }
    //P2:
    if (flag % 2 == 1)
    {
      Sleep(310);
      computer(arr);
      find_max(&i, &j,arr);
      setfillcolor(WHITE);
      solidcircle(i * 32 + 15, j * 32 + 5, 12);
      arr[i][j] = 2;
      fprintf(fq, "%d ", i);
      fprintf(fq, "%d ", j);
      setfillcolor(WHITE);
      fillrectangle(r4[0], r4[1], r4[2], r4[3]);
      setfillcolor(BLACK);
      drawtext(_T("P1下棋"), &R4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
      ret = is_win(arr, count);
      if (ret)
      {
        judge_winEVE(ret);
        break;
      }
      flag++;
      count++;
    }
  }
  fclose(fq);
  while (1)
  {
    m = GetMouseMsg();
    if (m.uMsg == WM_LBUTTONDOWN)
    {
      if (m.x > r7[0] && m.x<r7[2] && m.y>r7[1] && m.y < r7[3])
      {
        exit(0);
      }
      else if (m.x > r6[0] && m.x<r6[2] && m.y>r6[1] && m.y < r6[3])
      {
        closegraph();
        fupanEVE();
      }
      else if (m.x > r1[0] && m.x<r1[2] && m.y>r1[1] && m.y < r1[3])
      {
        closegraph();
        menu();
      }
    }
  }
}
void menu()
{
  initgraph(520, 550);//初始化界面
  IMAGE back;//定义图片接收
  loadimage(&back, _T("背景图片.png"));//接收图片
  putimage(0, 0, &back);//输出图片
  MOUSEMSG m;//鼠标指针
  while (1)
  {
    m = GetMouseMsg();//获取一条鼠标消息
    if (m.uMsg == WM_LBUTTONDOWN)//当鼠标落下时
    {
      switch (button_judge(m.x, m.y))
      {
      case 0:
        break;
      case 1:
        closegraph();
        PVE();
        break;
      case 2:
        closegraph();
        EVE();
        break;
      case 3:
        closegraph();
        PVP();
        break;
      case 5:
        closegraph();
        exit(0);
      }
    }
  }
}
int main()
{
  menu();
  return 0;
}

这篇博客有26000多个字,真的花了我很多时间捏,如果对大家有帮助的话希望多多点赞和关注,谢谢大家啦!我们一起进步啦!

目录
相关文章
|
14天前
|
存储 XML 人工智能
深度解读AI在数字档案馆中的创新应用:高效识别与智能档案管理
基于OCR技术的纸质档案电子化方案,通过先进的AI能力平台,实现手写、打印、复古文档等多格式高效识别与智能归档。该方案大幅提升了档案管理效率,确保数据安全与隐私,为档案馆提供全面、智能化的电子化管理解决方案。
113 48
|
7天前
|
人工智能 文字识别 运维
AI多模态的5大核心关键技术,让高端制造实现智能化管理
结合大模型应用场景,通过AI技术解析高端制造业的复杂设备与文档数据,自动化地将大型零件、机械图纸、操作手册等文档结构化。核心技术包括版面识别、表格抽取、要素抽取和文档抽取,实现信息的系统化管理和高效查询,大幅提升设备维护和生产管理的效率。
|
7天前
|
机器学习/深度学习 人工智能 安全
AI与旅游业:旅行规划的智能助手
在数字化浪潮中,人工智能(AI)正重塑旅游业。本文探讨了AI如何通过个性化推荐、智能预测与预警、语音交互与虚拟助手、增强现实体验及可持续发展,提升旅行规划的效率、安全性和趣味性,推动旅游业创新与变革。
|
9天前
|
人工智能 自然语言处理 关系型数据库
从数据到智能,一站式带你了解 Data+AI 精选解决方案、特惠权益
从 Data+AI 精选解决方案、特惠权益等,一站式带你了解阿里云瑶池数据库经典的AI产品服务与实践。
|
10天前
|
人工智能 安全 搜索推荐
AI与能源管理:智能电网的未来
本文探讨了AI与智能电网的融合及其对能源管理的深远影响。智能电网利用先进的信息、通信和AI技术,实现电力的自主、智能化、高效管理。AI在精准预测电力需求、实时监测与故障诊断、智能能源调度、个性化能源服务和优化可再生能源利用等方面发挥关键作用,推动能源管理的高效、智能和可持续发展。
|
11天前
|
机器学习/深度学习 人工智能 自然语言处理
AI与法律行业:智能法律咨询
在科技飞速发展的今天,人工智能(AI)正逐渐渗透到法律行业,特别是在智能法律咨询领域。本文探讨了AI在智能法律咨询中的应用现状、优势及挑战,并展望了其未来发展前景。AI技术通过大数据、自然语言处理等手段,提供高效、便捷、低成本且个性化的法律服务,但同时也面临数据隐私、法律伦理等问题。未来,AI将在技术升级、政策推动和融合创新中,为用户提供更加优质、便捷的法律服务。
|
13天前
|
机器学习/深度学习 人工智能 搜索推荐
AI在金融领域的应用:智能投资顾问
【10月更文挑战第31天】随着AI技术的快速发展,智能投资顾问在金融领域的应用越来越广泛。本文介绍了智能投资顾问的定义、工作原理、优势及未来发展趋势,探讨了其在个人财富管理、养老金管理、机构风险管理及量化交易中的典型应用,并分析了面临的挑战与机遇。智能投资顾问以其高效、低成本、个性化和全天候服务的特点,正逐步改变传统投资管理方式。
|
7天前
|
机器学习/深度学习 人工智能 自然语言处理
当前AI大模型在软件开发中的创新应用与挑战
2024年,AI大模型在软件开发领域的应用正重塑传统流程,从自动化编码、智能协作到代码审查和测试,显著提升了开发效率和代码质量。然而,技术挑战、伦理安全及模型可解释性等问题仍需解决。未来,AI将继续推动软件开发向更高效、智能化方向发展。
|
11天前
|
机器学习/深度学习 人工智能 自然语言处理
AI在医疗领域的应用及其挑战
【10月更文挑战第34天】本文将探讨人工智能(AI)在医疗领域的应用及其面临的挑战。我们将从AI技术的基本概念入手,然后详细介绍其在医疗领域的各种应用,如疾病诊断、药物研发、患者护理等。最后,我们将讨论AI在医疗领域面临的主要挑战,包括数据隐私、算法偏见、法规合规等问题。
33 1
|
9天前
|
机器学习/深度学习 人工智能 算法
AI在医疗领域的应用与挑战
本文探讨了人工智能(AI)在医疗领域的应用,包括其在疾病诊断、治疗方案制定、患者管理等方面的优势和潜力。同时,也分析了AI在医疗领域面临的挑战,如数据隐私、伦理问题以及技术局限性等。通过对这些内容的深入分析,旨在为读者提供一个全面了解AI在医疗领域现状和未来发展的视角。
42 10