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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【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循环使玩家输入没有被占用且合法的坐标正确落子后在跳出循环。


相关文章
|
20天前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
57 10
|
19天前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
27 1
|
1月前
|
机器学习/深度学习 人工智能 算法
揭开深度学习与传统机器学习的神秘面纱:从理论差异到实战代码详解两者间的选择与应用策略全面解析
【10月更文挑战第10天】本文探讨了深度学习与传统机器学习的区别,通过图像识别和语音处理等领域的应用案例,展示了深度学习在自动特征学习和处理大规模数据方面的优势。文中还提供了一个Python代码示例,使用TensorFlow构建多层感知器(MLP)并与Scikit-learn中的逻辑回归模型进行对比,进一步说明了两者的不同特点。
63 2
|
1月前
|
存储 搜索推荐 C语言
深入C语言指针,使代码更加灵活(二)
深入C语言指针,使代码更加灵活(二)
|
1月前
|
存储 程序员 编译器
深入C语言指针,使代码更加灵活(一)
深入C语言指针,使代码更加灵活(一)
|
1月前
|
C语言
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
|
1月前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
34 3
|
1月前
|
SQL 监控 关系型数据库
SQL错误代码1303解析与处理方法
在SQL编程和数据库管理中,遇到错误代码是常有的事,其中错误代码1303在不同数据库系统中可能代表不同的含义
|
1月前
|
SQL 安全 关系型数据库
SQL错误代码1303解析与解决方案:深入理解并应对权限问题
在数据库管理和开发过程中,遇到错误代码是常见的事情,每个错误代码都代表着一种特定的问题
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
33 3

推荐镜像

更多