【C语言】 -- 三子棋(代码+解析)1

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: 【C语言】 -- 三子棋(代码+解析)1

前言:

该篇文章是用C语言来实现三子棋的,是对之前的知识灵活运用加以巩固,如何合理的分块来写一个工程性的代码,大家仔细看看,哪里要有不对的地方请一定要指出来。


1、游戏规则

我们在玩三子棋的时候,用户先落子再是电脑落子,用户或者电脑玩家在3*3的棋盘上最终落子为行或列是三子连成,或者两个对角线是三子连成的,就认定哪一玩家胜出。如若棋盘下满都没出现三子连成认定为平局。


2、创建文件

我们需要分块来写不同用途的文件,在实现三子棋我们需要分三个文件,分别是:


game.h //头文件(包含所有需要的用到的头文件,define定义的常量,函数声明)


注:我们将2.1,2.2,2.3全部写在此文件中目的在于,game.c和test.c中调用这些内容时,只需要对我们自己写的game.h声明一次便可直接使用里面的内容。


game.c //游戏文件(里面分别写入所要用到功能函数)


test.c //测试文件(代码的整合)

2.1 头文件

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

2.2 用define定义行列

优点:如果我们后期需要改棋盘大小的时候只需要在这里改,一劳永逸,不用在整个程序中修改。

#define ROW 3
#define COL 3

2.3 函数声明

//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//显示棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//判断输赢
//玩家赢 -- '*'
//电脑赢 -- '#'
//平局   -- 'Q' 
//继续   -- 'C'
char IsWin(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);

3、游戏测试部分

3.1 主函数

这部分先写出玩游戏的逻辑

int main()
{
  int input = 0;
  do
  {
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("选择错误,重新选择\n");
      break;
    }
  } while (input);
  return 0;
}

对主函数内容的分析:

3.1.1 menu()函数(菜单函数)

void menu()
{
  printf("***********************\n");
  printf("\t1.play\n");
  printf("\t0.exit\n");
  printf("***********************\n");
}

效果展示:


3.1.2 switch语句

switch语句实现了用户在选择不同菜单的实现

效果展示:



3.1.3 do while语句

这里使用dowhile语句是实现先运行主函数,然后再进行选择,主函数会根据用户的选择进行实现不同的功能。

3.1.4 game()函数

在玩家选择数字 1 便会调用game()函数,实现以下功能。

void game()
{
  srand((unsigned int)time(NULL));
  //存放数据需要一个3*3的二维数组
  char board[ROW][COL] = { 0 };
  //初始化棋盘
  InitBoard(board, ROW, COL);
  //显示棋盘
  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);
    //判断输赢
    if (ret != 'C')
    {
      break;
    }
  }
  if ('*' == ret)
    printf("玩家赢\n");
  else if ('#' == ret)
    printf("电脑赢\n");
  else
    printf("平局\n");
}

game()函数中包含了初始化棋盘函数、显示棋盘函数、玩家下棋函数、电脑下棋函数、判断输赢函数的调用,这些函数在下面我们展开来分析。

game()函数我们在最后进行逻辑的解析。

4、游戏功能实现部分

游戏的实现逻辑

4.1 打印棋盘函数

首先我们需要打印出棋盘,棋盘是 3*3 的样式

头文件里面包含了行、列

定义DisplayBoard()函数打印棋盘,棋盘打印时包含了数据和分割行,代码实现:

void DisplayBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
        //数据
    for (j = 0; j < col; j++)
    {
      printf(" %c ",board[i][j]);
      if (j<col-1)
        printf("|");
    }
    printf("\n");
        //分割行
    if (i < row - 1)//---只打印两行
    {
      for (j = 0; j < col; j++)
      {
        printf("---");//每行需要3个---
        if(j<col-1)
          printf("|");
      }
    }
    printf("\n");
  }
}

效果展示:


4.2 初始化棋盘函数

定义InitBoard()函数,代码实现:

void InitBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)//3行
  {
    for (j = 0; j < col; j++)//3列
    {
      board[i][j] = ' ';
    }
  }
}

将棋盘初始化为空格。

4.3 玩家下棋

定义PlayerMove()函数,代码实现:

void PlayerMove(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("玩家下棋:>\n");
  while (1)
  {
    printf("请选择你要下棋的坐标:>");
    scanf("%d %d", &x, &y);
    if ((x>=1 && x<=row) && (y >= 1 && y <= col))
    {
      if (board[x - 1][y - 1] == ' ')
      {
        board[x - 1][y - 1] = '*';
        break;
      }
      else
      {
        printf("位置已被占用,请重新输入\n");
      }
    }
    else
    {
      printf("坐标非法,请重现输入坐标\n");
    }
  }
}

这里存在一个小细节,以及一些问题,相应的解决办法如下:


我们在写代码的时候知道第一个位置的坐标是(0,0),但是在玩家眼里第一个位置的坐标是(1,1),所以玩家输入的数字(x,y)是程序的(x-1,y-1)位置。


1.用户输入的坐标棋盘上没有怎么处理?


答:这里我们使用了if-else语句,如果坐标合法,那么玩家的棋子正常落子;如果坐标非法,程序会提醒"坐标非法,请重现输入坐标"的字样,利用while循环使玩家输入合法的坐标正确落子后在跳出循环。


2.用户输入的坐标已被占用怎么处理?


答:这里还是使用if-else语句,我们在初始化棋盘的时候用空格将每个位置占着,如果这个位置是空格,这个位置便会正常落子*;如果这个位置是非空格符号(本文中只会是*或者#),那么这个位置就是被占用了,程序会提醒"位置已被占用,请重新输入"的字样,利用while循环使玩家输入没有被占用且合法的坐标正确落子后在跳出循环。


相关文章
|
1月前
|
搜索推荐 UED Python
实现一个带有昼夜背景切换的动态时钟:从代码到功能解析
本文介绍了一个使用Python和Tkinter库实现的动态时钟程序,具有昼夜背景切换、指针颜色随机变化及整点和半点报时功能。通过设置不同的背景颜色和随机变换指针颜色,增强视觉吸引力;利用多线程技术确保音频播放不影响主程序运行。该程序结合了Tkinter、Pygame、Pytz等库,提供了一个美观且实用的时间显示工具。欢迎点赞、关注、转发、收藏!
134 94
|
1月前
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
272 11
|
2月前
|
自然语言处理 搜索推荐 数据安全/隐私保护
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
鸿蒙登录页面设计展示了 HarmonyOS 5.0(Next)的未来美学理念,结合科技与艺术,为用户带来视觉盛宴。该页面使用 ArkTS 开发,支持个性化定制和无缝智能设备连接。代码解析涵盖了声明式 UI、状态管理、事件处理及路由导航等关键概念,帮助开发者快速上手 HarmonyOS 应用开发。通过这段代码,开发者可以了解如何构建交互式界面并实现跨设备协同工作,推动智能生态的发展。
196 10
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
|
2月前
|
PHP 开发者 容器
PHP命名空间深度解析:避免命名冲突与提升代码组织####
本文深入探讨了PHP中命名空间的概念、用途及最佳实践,揭示其在解决全局命名冲突、提高代码可维护性方面的重要性。通过生动实例和详尽分析,本文将帮助开发者有效利用命名空间来优化大型项目结构,确保代码的清晰与高效。 ####
72 20
|
2月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
196 14
|
2月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
776 6
|
2月前
|
存储 网络协议 算法
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
94 5
|
2月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
63 5
|
1月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
63 23
|
1月前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
68 15

热门文章

最新文章

推荐镜像

更多