三子棋游戏

简介: 之前我们学过函数,数组,循环选择分支等等,我们今天就用现有的C语言知识编写一个小游戏——三子棋游戏。

    之前我们学过函数,数组,循环选择分支等等,我们今天就用现有的C语言知识编写一个小游戏——三子棋游戏。


说到三子棋,我们应该先构思所需要的内容。


1.构建一个游戏菜单界面


2.创建一个3*3的棋盘


3.选择先手(玩家先还是电脑先)


4.轮流下棋流程


5.判断胜负


此次游戏代码将分为两大模块,主函数体系和游戏函数体系


创建三子棋主函数


我们在主函数中,可以使用do while 函数进行游戏的循环在用switch嵌套创建一个主观菜单,让玩家进行循环游戏,也可以直接推出游戏,增加了游戏的开始界面。


代码如下:


void Screenmeau(void)
{
  printf("*******************\n");
  printf("******1.Play******\n");
  printf("******0.Exit*******\n");
  printf("*******************\n");
}
int main(void)
{ 
  int input = 0;
  do {
    Screenmeau();
    printf("请输入数字:");
    scanf("%d", &input);
    switch (input)
    {
      case 1:
        game();
        break;
      case 0:
        break;
      default:
        printf("请从新输入数字,0或1\n");
        break;
    }
  } while (input != 0);
  return 0;
}


通过选择0,可以结束游戏,选择1,进入游戏,选择其他数字则属于非法输入,需要重新选择。当我们选择1时,就可以进入游戏函数体系了。


游戏函数的创建与完善

当我们在主函数中的菜单进行选择进入游戏后,我们的第一大任务就是创建一个棋盘。棋盘的本质就是一个二维数组。那我们这次的目标为三子棋,我们可以使用#define ROW 3  和#define COL 3进行常量定义,在以后的使用或游戏的修改都提供了便利。


首先创建一个未被初始化的二维数组arr,将arr传入Array函数中进行初始化,arr中放入空格可以当作空棋盘。但如果打印棋盘给予玩家的视觉冲击很差,什么也看不见。所以我们应该将棋盘进行美化。


美化棋盘其实非常简单,可以在打印棋盘的同时,打印一些符号将棋盘鲜明化,利用for循环和一些if语句的镶嵌组合就可以将其完成。


见代码:


void Array(char arr[ROW][COL], int row, int col)//arr数组的初始化
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < col; j++)
    {
      arr[i][j] = ' ';
    }
  }
}
void Ddfinarray(char arr[ROW][COL], int row, int col)//棋盘的美化
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < col; j++)
    {
      printf(" %c ", arr[i][j]);
      if(j < col-1)
      printf("|");
    }
    printf("\n");
    for (int j = 0; j < col; j++)
    {
      printf("---");
      if (j < col - 1)
        printf("|");
    }
    printf("\n");
  }
}


美化的棋盘:


ec333c900c4441b6b8ebe04773b0e7ed.png


之前的代码只是准备工作,与玩家没有多大的关系,接下来我们将正式进入游戏的环节。


创建一个choosemeau函数让玩家选择,是玩家先下棋还是让电脑先。与主函数的思路一样,使用do while循环中间嵌套一个switch提供菜单让玩家进行选择。然后创建两个函数,一个是玩家的下棋函数,一个是电脑下棋函数,无论在上一环节选择1或者2,只是两个函数的先后执行顺序不同。所以先完成两个函数体。


int  Choosemeau(void)//选择先手菜单程序
{
  int a = 0;
  do {
    printf("********************\n");
    printf("*****1.玩家先 ******\n");
    printf("*****2.电脑先 ******\n");
    printf("********************\n");
    printf("请选择:");
    scanf("%d", &a);
    switch (a)
    {
      case 1:
        return 1;
      case 2:
        return 2;
      default:
        printf("只能输入1或2,请重新输入\n");
    }
  } while (1);
}


首先完成玩家下棋函数,提供两个变量,分别对应下棋的坐标,因为这个棋盘实质是一个二维数组,数组的第一个元素的下标为0,但是玩家不都是程序员,所以我们应当在玩家输入对应坐标后将其坐标减1,得到的值才是玩家心里所想的值。


为了使游戏更加严谨,作为程序员我们应该考虑更加全面。有两个问题,输入的值超出数组下标,玩家下棋的位置已有棋子。我们应该让程序避免出现这两个问题,我们可以用分支语句进行判断,如果玩家选择的位置的值是空格并且输入的坐标没有超出数组的下标,既可以落子,玩家的棋子用‘*’表示。反正系统将提醒非法落子,需要玩家重新输入两个合法的坐标。


void Playermove(char arr[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  while (1)
  {
    printf("请输入要下棋的横竖坐标:");
    scanf("%d %d", &x, &y);
    if (arr[x - 1][y - 1] == ' ')
    {
      if (x > 0 && x <= row && y >0 && y <= col)
      {
        arr[x - 1][y - 1] = '*';
        break;
      }
    }
    else
    {
      printf("非法落子\n");
    }
  }
}


完成玩家下棋函数后,我们将进行电脑下棋。


下棋的本质就是在arr二维数组中选择合适的两个下标,所以我们可以使用随机数函数rand()和srand()的函数,我们在主函数中引入srand((unsigned int )time(NULL));,就可以在函数中使用rand()函数中产生随机数(使用rand(),srand(),time()函数得引用头文件#include<stdlib.h>和#include<time.h>),将随机数%3就可以得到0-3的随机数。在电脑输入时我们只需要考虑落子位置是空位置(空格)即可,使用if判断即可,电脑落子用‘#’表示。


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


当玩家和电脑都走了一步之后,我们将棋盘展现出来,可以更直观的看出棋子的位置。所以我们可以在两个下棋函数运行完成后运行一下Ddfinarray函数,将棋盘打印出来即可。


如果现在运行程序,当棋盘被占满后会进入死循环,就相当于递归没退出程序。而退出的程序就是判断棋的输赢。


下棋的结果一般有四个:玩家赢,电脑赢,和棋,继续游戏。


无论玩家赢电脑赢还是和棋就可以结束循环了,但是继续游戏还需要我们继续下棋。所以我们现需要一个函数来判断棋盘是否下满,利用for循环对数组中的每个元素进行检测判断,如果没有空格就是棋盘下满了。这个函数需要有返回值供以后选择,如果棋盘满了则返回值为1,反之返回0。


三子棋的获胜条件就是让横竖斜都是同一种棋子,创建一个判断胜负的函数,在玩家和电脑每下一步棋后进行判断,并且这个函数有返回值char,返回的值在if判断条件时可以使用,如果返回的是’*‘时,则玩家赢,返回是‘#’电脑赢,返回是‘h’为和棋,返回c为继续。


这里就有一个非常巧妙的点,用数组判断横竖斜是否相等并且不等于空格,返回值为数组的符号,这样就可以用一个函数来提取其中的返回值即可,使用if就可以知道游戏的输赢。如果前面的横竖斜都没有相同的时,使用上一个函数的返回值当作下一个if的判断条件,即可判断出是否和棋。如果棋盘没有满将使用continue退出此次循环进行下一次两两下棋,直到得到结果,游戏结束。


游戏函数的主体:


void game(void)
{
  char arr[ROW][COL] = { 0 };
  Array(arr, ROW, COL);
  Ddfinarray(arr, ROW, COL);
  int a = Choosemeau();
  if (a == 1)
  { 
    while (1)
    {
      Playermove(arr, ROW, COL);
      Ddfinarray(arr, ROW, COL);
      Displayermove(arr, ROW, COL);
      Ddfinarray(arr, ROW, COL);
      char ch =Iswin(arr, ROW, COL);
      if (ch == '*')
      {
        printf("玩家赢\n");
        break;
      }
      else if (ch == '#')
      {
        printf("电脑赢\n");
        break;
      }
      else if (ch == 'c')
      {
        continue;
      }
      else
      {
        printf("和棋\n");
        break;
      }
    }
  }
  else
  {
    while (1)
    {
      Displayermove(arr, ROW, COL);
      Ddfinarray(arr, ROW, COL);
      Playermove(arr, ROW, COL);
      Ddfinarray(arr, ROW, COL);
      char ch = Iswin(arr, ROW, COL);
      if (ch == '*')
      {
        printf("玩家赢\n");
        break;
      }
      else if (ch == '#')
      {
        printf("电脑赢\n");
        break;
      }
      else if (ch == 'c')
      {
        continue;
      }
      else 
      {
        printf("和棋\n");
        break;
      }
    }
  }
}


判断棋盘是否下满函数:


int Isfull(char arr[ROW][COL], int row, int col)
{
  for (int i = 0; i < row; i++)
    for (int j = 0; j < col; j++)
    {
      if (arr[i][j] == ' ')
        return 1;
    }
}


判断输赢的函数:


char Iswin(char arr[ROW][COL], int row, int col)
{
  for(int i = 0; i < row; i++)
  {
    if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
      return arr[i][0];
  }
  for(int j = 0; j < col; j++)
  {
    if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[2][j] == '*')
      return arr[0][j];
  }
  if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[2][2] == '*')
  {
    return arr[0][0];
  }
   if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[2][2] == '#')
  {
     return arr[0][0];
  }
   if (Isfull(arr, ROW, COL))
     return 'c';
   else
     return 'h';
}


将这些函数结合一起就可以得到三子棋小游戏,现在让我们玩一下。


92a89acd1d7a4d97aaf53cf4a344a674.png

baf25301ff6e46f2b37827eeb0d170e9.png


小伙伴们快来实践一下吧!!!

目录
相关文章
|
传感器 编解码 数据处理
毕业设计|基于STM32单片机的水位浑浊度检测设计
毕业设计|基于STM32单片机的水位浑浊度检测设计
1714 0
|
Web App开发 iOS开发 Windows
ios获取原生系统应用的包名
ios获取原生系统应用的包名
3031 0
|
2月前
|
Linux 虚拟化 iOS开发
VMware Workstation Pro 25H2 Unlocker & OEM BIOS 2.7 - 在 Windows 和 Linux 上运行 macOS Tahoe
VMware Workstation Pro 25H2 Unlocker & OEM BIOS 2.7 - 在 Windows 和 Linux 上运行 macOS Tahoe
561 3
VMware Workstation Pro 25H2 Unlocker & OEM BIOS 2.7 - 在 Windows 和 Linux 上运行 macOS Tahoe
|
12月前
|
机器学习/深度学习 缓存 人工智能
RAG新突破:块状注意力机制实现超低延迟检索增强
检索增强生成(RAG)技术结合检索和生成模型,有效提升大型语言模型的知识获取能力。然而,高推理延迟限制了其在实时场景的应用。论文《Block-Attention for Low-Latency RAG》提出块状注意力机制,通过将输入序列划分为独立块并预先计算缓存KV状态,显著降低推理延迟。实验结果显示,该机制在保持模型准确性的同时,大幅提高了推理效率。
319 9
|
安全 前端开发 Android开发
鸿蒙开发|鸿蒙系统的介绍(为什么要学习鸿蒙开发|鸿蒙系统的官方定义|鸿蒙和安卓、ios的对比)
鸿蒙开发学习是一项探索性的工作,旨在开发一个全场景分布式操作系统,覆盖所有设备,让消费者能够更方便、更直观地使用各种设备。
1367 6
鸿蒙开发|鸿蒙系统的介绍(为什么要学习鸿蒙开发|鸿蒙系统的官方定义|鸿蒙和安卓、ios的对比)
|
前端开发 JavaScript 开发者
UI 框架:element-ui(二)
在当今快速发展的前端开发领域,用户界面的设计和交互体验日益成为软件成功的关键因素之一。Element UI,作为一款基于Vue.js的组件库,以其精美的界面和丰富的功能受到了广泛的关注与应用。它为开发者提供了一整套高质量的组件,帮助他们快速构建具有现代感的应用程序。 Element UI不仅注重美观的设计,还提供了良好的文档支持和社区活跃度,使得开发者能够轻松上手并解决实施过程中的各种问题。在这篇文章中,我们将深入探讨Element UI的基本特点、安装步骤,以及如何利用其强大的组件系统高效地构建用户友好的界面。无论您是初学者还是有经验的开发者,这篇文章都将为您开辟一条通向更高效开发的道路。
834 4
|
Web App开发 Java 测试技术
SAP OData 编程指南
SAP OData 编程指南
|
存储 JavaScript 前端开发
DOM 型 XSS 演示(附链接)
DOM 型 XSS 演示(附链接)
|
BI 数据安全/隐私保护
二维码活码和静态码有什么区别?
作为万物互联时代的“数字身份证”,二维码在物流运输、生产制造、会议签到、移动支付等行业广泛应用,极大地改变了人们的日常生活。接下来,我们就为大家科普一下二维码的类型,也就是活码和静态码。
578 0
|
Java API 开发者
java代码注释指南:三大注释解析与最佳实践
java代码注释指南:三大注释解析与最佳实践
1796 0