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

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

4.4 电脑下棋

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

void ComputerMove(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("电脑下棋:>\n");
  while (1)
  {
    x = rand() % row;
    y = rand() % col;
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }
  }
}

这里也是存在一些问题,解决办法如下:


1.如何实现电脑随机输入一个坐标?


答:我们利用srand()函数来实现随机数字,但是srand()函数需要一个随机值,这里的随机值就是利用时间戳,因为时间在时刻改变着,不同的时间经过srand处理过后就得到了我们需要的随机值。因为要用时间戳,所以需要调用time函数,代码实现:

#include <time.h>

srand()函数的使用:

srand((unsigned int)time(NULL));

2.如何处理电脑随机坐标的合法性?

答:在使用srand()函数处理的随机值不再经过处理可能会出现大于棋盘的格数,所以我们需要再对srand()函数处理的随机值再进行处理,代码实现:

x = rand() % row;//0~2
y = rand() % col;//0~2

对srand传过来的随机值进行取模处理,我们的棋盘是3*3的,所以取模后得到的随机值是在0~2范围里。


3.如果出现坐标被占用的情况怎么处理?


答:我们使用while循环,如果给出的坐标位置判断不是空格,就说明是被占用,经过循环最后给出合法的坐标,实现落子后就会触发break跳出循环。

4.5 判断输赢

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

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[0][0] != ' ')
    return board[0][0];//如果连成,返回这个符号就是代表哪一玩家胜利
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
    return board[0][0];//如果连成,返回这个符号就是代表哪一玩家胜利
  //判断是否平局
  if (1 == IsFull(board, row, col))
  {
    return 'Q';
  }
  return 'C';
}

判断输赢的代码逻辑是根据游戏规则来写,行、列、对角线三子连成就认定哪一方胜出,若棋盘下满都没出现三子连成认定为平局。分别用这些符号表示:


4.5.1 三行连成

代码实现:

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];
  }

4.5.2 三列连成

代码实现:

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];
  }

4.5.3 两对角线连成

if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
    return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
    return board[0][0];

4.5.4 平局判断

如果棋盘被下满还是没有分出胜负便是平局。

如何判断是否棋盘被下满呢?

答:我们遍历棋盘的每一个格子,如果没有一个是空格了,就返回数字 1 ,否则返回数字 0 。

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

int IsFull(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++)
    {
      if (board[i][j] == ' ')
        return 0;
    }
  }
  return 1;
}

IsFull()函数仅仅实现棋盘格是否被占满。在IsWin()函数中判断返回值是否是 1 ,如果是就是平局,我们这里只对棋盘格被占满判断,只需要判断返回值 1 ,如果是0便是没有占满,不用考虑,继续下棋就行。

代码实现:

if (1 == IsFull(board, row, col))
  {
    return 'Q';
  }

判断 1 == IsFull(),就返回字符'Q'。(规定 Q 是平局)

5、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");
}

逻辑顺序:创建一个数组 -- 初始化棋盘 -- 打印棋盘 -- 玩家下棋 -- 打印棋盘 -- 判断输赢(赢/输/平局:本局结束;没结果:继续) -- 电脑下棋 -- 打印棋盘 -- 判断输赢 (赢/输/平局:本局结束;没结果:继续)

逻辑顺序图示:


6、整体效果展示


完整代码在代码仓库,入口在这:


https://gitee.com/xiaobai-is-working-hard-jy/c-language-jy/tree/master/game_%E4%B8%89%E5%AD%90%E6%A3%8B/game_%E4%B8%89%E5%AD%90%E6%A3%8B


相关文章
|
19天前
|
自然语言处理 搜索推荐 数据安全/隐私保护
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
鸿蒙登录页面设计展示了 HarmonyOS 5.0(Next)的未来美学理念,结合科技与艺术,为用户带来视觉盛宴。该页面使用 ArkTS 开发,支持个性化定制和无缝智能设备连接。代码解析涵盖了声明式 UI、状态管理、事件处理及路由导航等关键概念,帮助开发者快速上手 HarmonyOS 应用开发。通过这段代码,开发者可以了解如何构建交互式界面并实现跨设备协同工作,推动智能生态的发展。
131 10
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
|
1月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
153 14
|
1月前
|
存储 编译器 C语言
【C语言】数据类型全解析:编程效率提升的秘诀
在C语言中,合理选择和使用数据类型是编程的关键。通过深入理解基本数据类型和派生数据类型,掌握类型限定符和扩展技巧,可以编写出高效、稳定、可维护的代码。无论是在普通应用还是嵌入式系统中,数据类型的合理使用都能显著提升程序的性能和可靠性。
53 8
|
1月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
552 6
|
1月前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
1月前
|
存储 网络协议 算法
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
44 5
|
1月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
48 5
|
1月前
|
PHP 开发者 容器
PHP命名空间深度解析:避免命名冲突与提升代码组织####
本文深入探讨了PHP中命名空间的概念、用途及最佳实践,揭示其在解决全局命名冲突、提高代码可维护性方面的重要性。通过生动实例和详尽分析,本文将帮助开发者有效利用命名空间来优化大型项目结构,确保代码的清晰与高效。 ####
32 1
|
1月前
|
安全 搜索推荐 Unix
【C语言】《回调函数》详细解析
回调函数是指一个通过函数指针调用的函数。它允许将一个函数作为参数传递给另一个函数,并在特定事件发生时执行。这种技术使得编程更加灵活,可以动态决定在何时调用哪个函数。
50 1
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
71 1

推荐镜像

更多