学C的第十三天【应用多文件的形式实现 三子棋 程序(重点);练习:1. 打印9*9乘法口诀表、2. 求10个整数中的最大值、3. 分数加减交叉计算、4. 数一下 1到 100 的整数中出现了多少个9】

简介: 9.数组的应用实例1:三子棋(综合以前学习的知识)三子棋的实现:(重点都在注释中) 1. 游戏不退出,继续玩下一把(循环)2. 应用多文件的形式写代码

9.数组的应用实例1:三子棋(综合以前学习的知识)

三子棋的实现:(重点都在注释中

 

 

1. 游戏不退出,继续玩下一把(循环)

2. 应用多文件的形式写代码

 

game.h        --        游戏函数的声明

#pragma once
//游戏相关的自定义函数 声明 写到game.h中
#include <stdio.h> 
#include <stdlib.h> //rand函数需要的头文件
#include <time.h> //time函数需要的头文件
//直接把头文件包含在自定义头文件中,当别的文件包含本头文件时,
//这个头文件里的头文件也会被包含
//定义宏常量:行数ROW  列数COL 
//,之后想修改,直接修改头文件里的这两个宏常量就可以
#define ROW 3 
#define COL 3
// 1.  InitBoard(); 用于初始化数组,将空格全部初始化为空格
void InitBoard(char board[ROW][COL], int row, int col);
// 2.  DisplayBoard():打印数组(棋盘)
void DisplayBoard(char board[ROW][COL], int row, int col);
// 3. 玩家下棋:
void PlayerMove(char board[ROW][COL], int row, int col);
// 4. 电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
// 5. 判断输赢(返回对应的符号):
//玩家赢 -- ‘*’
//电脑赢 -- ‘#’
//平局 -- ‘Q’
//继续 -- ‘C’
char IsWin(char board[ROW][COL], int row, int col);

03f9a9e9060d43e3bc40e64fe3bfede9.png

game.c        --        游戏函数的实现

#define _CRT_SECURE_NO_WARNINGS 1
//游戏相关的自定义函数 代码 写到game.c中
#include "game.h"
// 1.  InitBoard(); 用于初始化数组,将空格全部初始化为空格
void InitBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++) // 遍历行
  {
    int j = 0;
    for (j = 0; j < col; j++) // 遍历列
    {
      board[i][j] = ' '; // 将空格全部初始化为空格
    }
  }
}
// 2.  DisplayBoard():打印数组(棋盘)
//版本1:都是空格,什么都看不见
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
//  int i = 0;
//  for ( i = 0; i < row; i++) // 遍历行
//  {
//    int j = 0;
//    for (j = 0; j < col; j++) // 遍历列
//    {
//      printf("%c", board[i][j]);
//    }
//    // 打印完一行后换行
//    printf("\n");
//  }
//}
//版本2:只能打印对应的行,不能打印对应的列(列被”写死“了)
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
//  int i = 0;
//  for (i = 0; i < row; i++) // 遍历行
//  {
//    //1. 打印数据
//    printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//
//    //2. 打印分割线
//    if (i < row - 1) //只有中间才需要打印分割线,最后一行不打印分割线
//    {
//      printf("---|---|---\n");
//    }
//      
//  }
//}
//版本3: 实现多行多列,边写边想边实现
void DisplayBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++) // 遍历行
  {
    //1. 打印数据
    int j = 0;
    for (j = 0; j < col; j++)
    {
      printf(" %c ", board[i][j]); // 先打印数据
      if (j < col-1) // 最后一行不打印竖杠
      {
        printf("|"); // 再打印竖杠
      }
    }
    // 打印完一行后换行
    printf("\n");
    //2. 打印分割线
    if (i < row - 1)//只有中间才需要打印分割线,最后一行不打印分割线
    {
      int j = 0;
      for (j = 0; j < col; j++)
      {
        printf("---");
        if (j < col - 1) // 最后一行不打印竖杠
        {
          printf("|"); // 再打印竖杠
        }
      }
      printf("\n");
    }
  }
}
// 3. 玩家下棋:
void PlayerMove(char board[ROW][COL], int row, int col)
{
  // 让玩家通过坐标选择下棋位置
  int x = 0;
  int y = 0;
  printf("玩家下棋>: \n");
  while (1) //输入成功了再break跳出循环
  {
    printf("请输入下棋的坐标,中间使用空格>:");
    scanf("%d %d", &x, &y);
    //判断输入是否正确(二维数组行和列都是从0开始的,但玩家不一定知道)
    if (x >= 1 && x <= row && y >= 1 && y <= col) //坐标合法
    {
      //判断是否可以落子
      if (board[x-1][y-1] == ' ') //可以落子
        //board[x-1][y-1]:输入是1行1列,其实是0行0列
      {
        //落子了就把空格换成 * 号
        board[x - 1][y - 1] = '*';
        break;
      }
      else //不能落子
      {
        printf("坐标被占用,不能落子,重新输入坐标\n");
      }
    }
    else //坐标非法
    {
      printf("坐标非法,重新输入\n"); 
    }
  }
}
// 4. 电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
  int x = 0; // 让x随机生成 0 -- (row-1) 的值
  int y = 0; // 让y随机生成 0 -- (col-1) 的值
  printf("电脑下棋:>\n");
  //数组的下标已经约定了,不会越界,但还有可能被占用
  while (1)
  {
    x = rand() % row; //结果为 0 -- (row-1) 的值
    y = rand() % col; //结果为 0 -- (col-1) 的值
    if (board[x][y] == ' ') //如果随机坐标为空格,则落子
    {
      board[x][y] = '#';
      break; //落子成功则跳出循环
    }
    //若不是空格,则继续循环出一个随机坐标,直至落子成功
  }
}
// 5. 判断输赢(返回对应的符号):
//玩家赢 -- ‘*’
//电脑赢 -- ‘#’
//平局 -- ‘Q’
//继续 -- ‘C’
// 5(补充):判断棋盘是否已满
int IsFull(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++) //遍历行
  {
    int j = 0;
    for (j = 0; j < col; j++) //遍历列
    {
      if (board[i][j] == ' ')
      {
        return 0; 
        //整个数组中有找到空格,则返回0
      }
    }
  }
  //整个数组中没有找到空格(棋盘已满),则返回1
  return 1;
}
char IsWin(char board[ROW][COL], int row, int col)
{
  //赢 (判断三行三列和对角线)
    // 判断 三行 是否有连成一线的
  int i = 0;
  for (i = 0; i < row; i++)
  {
    if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
      //同行第一个元素等于第二个元素,第二个元素等于第三个元素,判断其中一个元素是否为空格
    { 
      return board[i][0]; 
      //因为玩家赢时,同行上都是 ‘*’,所以直接返回行上的其中一个元素就行
    }
  }
    // 判断 三列 是否有连成一线的
  for (i = 0; i < col; i++)
  {
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    {
      return board[0][i];
      //因为电脑赢时,同行上都是 ‘#’,所以直接返回行上的其中一个元素就行
    }
  }
    // 判断 对角线 是否有连成一线的
      //其中一条对角线
  if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
  {
    return board[1][1];
  }
      //另一条对角线
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
  {
    return board[1][1];
  }
  //平局 (上面四个return都没执行的话,则执行下面的代码)
    //自定义函数IsFull()函数用于判断棋盘是否已满
  if (IsFull(board, row, col) == 1) //如果返回值为1,说明棋盘已满,平局
  {
    return 'Q';
  }
  //继续 (没有赢,也没平局,继续下棋)
  return 'C';
}

1.  InitBoard(); 用于初始化数组,将空格全部初始化为空格

image.png

2.  DisplayBoard():打印数组(棋盘)

image.png

3. PlayerMove():玩家下棋

image.png

4. ComputerMove():电脑下棋

image.png

5. IsFull():判断输赢(返回对应的符号):
玩家赢 -- ‘*’
电脑赢 -- ‘#’
平局 -- ‘Q’
继续 -- ‘C’


image.png

test.c        --        测试游戏

#define _CRT_SECURE_NO_WARNINGS 1
//1. 游戏不退出,继续玩下一把(循环)
//2. 应用多文件的形式写代码
#include "game.h" //包含自己定义的头文件
void menu()
{
  printf("***********************************\n");
  printf("**********    1.play    ***********\n");
  printf("**********    0.exit    ***********\n");
  printf("***********************************\n");
}
void game()
{
/*
1. 游戏在走的过程中要进行数据的存储,三子棋可以使用3*3的二维数组
  即  char board[3][3];
2. 没下棋之前数组中存放空格,下棋后将空格替换成字符
*/
  char board[ROW][COL] = { 0 };
  InitBoard(board, ROW, COL); //传递 数组名,行数,列数
  // 用于初始化数组,将空格全部初始化为空格
  // 将游戏相关的自定义函数代码写到game.c中
  // 打印棋盘
  DisplayBoard(board, ROW, COL);
//下棋:
  char ret = 0; //接受判断输赢的符号
//让玩家一直下:
  while (1)
  {
    //玩家下棋:
    PlayerMove(board, ROW, COL);
    //落子后再打印棋盘看棋盘情况
    DisplayBoard(board, ROW, COL);
    //判断输赢(三子相连)
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    //电脑下棋:
    ComputerMove(board, ROW, COL);
    //落子后再打印棋盘看棋盘情况
    DisplayBoard(board, ROW, COL);
    //判断输赢
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
  }
  //写在while循环外面的话,只用写一次
  if (ret == '*')
  {
    printf("玩家赢\n");
  }
  else if (ret == '#')
  {
    printf("电脑赢\n");
  }
  else
  {
    printf("平局");
  }
}
int main()
{
  int input = 0;
  //rand函数调用之前得调用srand,
  //整个程序只用调一次,所以放在主函数中
  srand((unsigned int)time(NULL));
//1. 游戏不退出,继续玩下一把(循环) 
  do //不管三七二十一,先打印菜单
  {
    menu(); //打印游戏菜单
    printf("请选择:>");
    scanf("%d", &input); //1 0 其它
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("选择错误,重新选择:\n");
      break;
    }
  } while (input); 
  //当input为0时停止循环退出游戏
  //当input非0时继续循环
  return 0;
}

void game()


image.png

主程序


6d89b7d1cc6a47979ddddb7db192836a.png 

相关文章
|
7月前
|
机器学习/深度学习 编译器 C语言
【C语言】数据输出的域宽控制(如何在输出数据时控制0占位)(如何输出前导0)(保留几位小数)(乘法口诀表打印不齐)等问题
【C语言】数据输出的域宽控制(如何在输出数据时控制0占位)(如何输出前导0)(保留几位小数)(乘法口诀表打印不齐)等问题
109 0
|
7月前
|
存储 C语言
牛客网刷题总结(1.有序序列判断,2.获得月份天数,3.矩阵相等判定,4.矩阵转换,5.井字棋判断输赢,6.递归进行进制转化)
牛客网刷题总结(1.有序序列判断,2.获得月份天数,3.矩阵相等判定,4.矩阵转换,5.井字棋判断输赢,6.递归进行进制转化)
76 0
|
6月前
|
C语言
C语言学习记录——将三位数的个十百位单独打印,并求其和。
C语言学习记录——将三位数的个十百位单独打印,并求其和。
43 4
|
算法 搜索推荐 程序员
C语言第十三练——输入一个正整数,判断这个数是否是素数
C语言第十三练——输入一个正整数,判断这个数是否是素数
131 0
|
C语言
乘法口诀标的打印及解释
打印乘法口诀表可以说是c语言中一个很经典的一个简单程序了。 打印乘法口诀表的第一反应可能会是很难,怎么打印出这么多相乘的数呢。但是仔细想分析和考虑的话,其实很简单。那么我来说一下打印乘法口诀表的思路。
79 0
|
C语言 C++
C语言经典实例:1-10例:三角求和、显示所占字节数、自增自减运算while语句输出最小值、计算快递费用、学生成绩统计
C语言经典实例:1-10例:三角求和、显示所占字节数、自增自减运算while语句输出最小值、计算快递费用、学生成绩统计
C语言经典实例:1-10例:三角求和、显示所占字节数、自增自减运算while语句输出最小值、计算快递费用、学生成绩统计
C语言经典实例:11-20例:使用结构体输出学生成绩、编制万年历、验证哥德巴赫猜想、求二维数组最大最小值、数组求素数、数组元素排序、进制数的转换进制数的转换、找出次大值、重组数组(上)
C语言经典实例:11-20例:使用结构体输出学生成绩、编制万年历、验证哥德巴赫猜想、求二维数组最大最小值、数组求素数、数组元素排序、进制数的转换进制数的转换、找出次大值、重组数组(上)
C语言经典实例:11-20例:使用结构体输出学生成绩、编制万年历、验证哥德巴赫猜想、求二维数组最大最小值、数组求素数、数组元素排序、进制数的转换进制数的转换、找出次大值、重组数组(上)