大一新生必会的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多个字,真的花了我很多时间捏,如果对大家有帮助的话希望多多点赞和关注,谢谢大家啦!我们一起进步啦!

目录
相关文章
|
19天前
|
存储 机器学习/深度学习 人工智能
【AI系统】微分计算模式
本文深入探讨了自动微分技术,这是AI框架中的核心功能。自动微分分为前向微分和后向微分两种模式,主要通过雅克比矩阵实现。前向模式适用于输出维度大于输入的情况,而后向模式则更适合多参数场景,广泛应用于现代AI框架中。文章还详细解释了这两种模式的工作原理、优缺点及应用场景。
34 2
【AI系统】微分计算模式
|
1天前
|
人工智能 Serverless API
《智能导购 AI 助手构建》解决方案评测:极具吸引力的产品,亟待完善的教程文档
《智能导购 AI 助手构建》解决方案评测:极具吸引力的产品,亟待完善的教程文档
38 7
|
1天前
|
人工智能 安全 搜索推荐
AI 驱动研发模式升级,蓝凌软件探索效率提升之道
蓝凌软件在引入通义灵码后取得了较明显的效果。目前,蓝凌软件已使用灵码的开发人员中,周活跃用户占比超过90%、根据代码库自动生成的代码占比超33%、代码智能补全占比29%,代码注释率提升了15%,有效提升了产品代码工程化的效能。
|
1月前
|
人工智能 搜索推荐 API
Perplexica:开源 AI 搜索引擎,Perplexity AI 的开源替代品,支持多种搜索模式、实时信息更新
Perplexica 是一款开源的 AI 驱动搜索引擎,支持多种搜索模式和实时信息更新,适用于个人、学术和企业等不同场景。
160 6
Perplexica:开源 AI 搜索引擎,Perplexity AI 的开源替代品,支持多种搜索模式、实时信息更新
|
25天前
|
人工智能 并行计算 调度
【AI系统】CUDA 编程模式
本文介绍了英伟达GPU的CUDA编程模型及其SIMT执行模式,对比了SIMD和SIMT的特点,阐述了SIMT如何提高并行计算效率和编程灵活性。同时简要提及了AMD的GPU架构及编程模型,包括最新的MI300X和ROCm平台。
51 5
|
29天前
|
人工智能 弹性计算 网络安全
一键玩转CoAI:AI工程变现新模式
CoAI是一款强大的AI管理软件,支持多种大模型如OpenAI、通义千问等,具备丰富的UI设计、多模型管理、弹性计费等功能,既适合个人使用也支持企业级部署,帮助用户轻松管理和商业化AI能力。
|
2月前
|
自然语言处理 IDE 测试技术
通义灵码史上最全使用教程:秀一秀AI编程新肌肉
通义灵码是阿里云推出的一款智能编码辅助工具,基于通义大模型,提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等功能。它支持 Visual Studio Code 和 JetBrains IDEs,适配多 IDE 原生设计,帮助开发者高效、流畅地编码。官方提供了详细的下载和安装指南,以及丰富的功能介绍和使用指南。
473 3
|
2月前
|
C语言 开发者
C语言实现猜数字小游戏(详细教程)
C语言实现猜数字小游戏(详细教程)
|
2月前
|
编译器 C语言 C++
VSCode安装配置C语言(保姆级教程)
VSCode安装配置C语言(保姆级教程)
|
4月前
|
人工智能
Suno教程篇:音乐小白也能使用Suno AI零门槛创作音乐?从此只听AI写的歌!
本文是一篇Suno AI音乐创作工具的教程,指导音乐小白如何使用Suno AI零门槛创作音乐,包括准备工作、基础使用、歌曲风格的选择、歌词填入技巧,以及通过实例展示如何为不同场景生成背景音乐。
Suno教程篇:音乐小白也能使用Suno AI零门槛创作音乐?从此只听AI写的歌!