【C语言】升级版三子棋小游戏(棋盘界面美化+动画演示)

简介: 【C语言】升级版三子棋小游戏(棋盘界面美化+动画演示)

文章目录

游戏效果

三子棋,顾名思义就是:有一个三行三列的棋盘,然后玩家和电脑各自下棋。

游戏的运行如下:

  • 有一个3 x 3的一个棋盘
  • 玩家下棋用*表示
  • 电脑下棋用#表示
  • 下棋方式就是输入棋盘的坐标

代码规划

因为这是一个小游戏,涉及到游戏的代码比较多,不是几十行就能搞定的,所以我不可能全部写在一个test.c的文件里面去;

这里规划一下代码存放,创建三个文件:

  • test.c:游戏的测试逻辑
  • game.c:游戏的实现逻辑
  • game.h:游戏实现函数的声明

创建代码

这里使用的是VS2019

image.png

设置一下布局

image.png

游戏搭建

任何一个项目的实现,最重要的就是逻辑结构搭建,而各个功能的实现就是采取函数(模块化)进行细分;

所以我们需要搭建逻辑,那么逻辑结构是啥呢?

往下看👇

主函数

  • 运行游戏的时候,内容显示为:1.开始游戏;0.退出游戏;输入其他数字提示:输入错误,请重新输入!
  • 按1开始游戏
  • 按0退出游戏
int main()
{
  srand((unsigned int)time(NULL));
  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;
}

游戏game函数

前面的逻辑结构已经搭建,而我们需要实现的就是game()函数模块

game()函数实现的功能是什么呢?

  • 首先是数据存储到一个字符的二维数组中,数组的内容应该全部都是空格
  • 使用InitBoard()函数,初始化棋盘;
  • 使用DisplayBoard()函数,打印棋盘(3x3);
  • 玩家和电脑的对战模块,也就是:玩家下棋Player()函数和电脑下棋Compuer()函数;
  • 每一局对战后,都要判断电脑或玩家是否赢,所以需要一个判断输赢的IsWin();函数;
void game()
{
  char board[ROW][COL] = {0};
  InitBoard(board, ROW, COL);//初始化棋盘
  DisplayBoard(board, ROW, COL);//打印棋盘
  int ret = 0;
  while (1)
  {
    Player(board, ROW, COL);//玩家下棋
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    Computer(board, ROW, COL);//电脑下棋
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
  }
  if (ret == '*')
  {
    printf("恭喜您取得胜利!!!!!!!!!\n\n");
  }
  else if (ret == '#')
  {
    printf("你也太辣鸡了吧,电脑都下不赢\n");
  }
  else
  {
    printf("哎~~,你的技术不行啊,居然和电脑达成平手\n");
  }
}

菜单menu函数

菜单功能十分简单

代码示例如下:

void menu()
{
  printf("************************\n");
  printf("****EDC's Game World****\n");
  printf("******   1.Play   ******\n");
  printf("******   0.Exit   ******\n");
  printf("************************\n");
}

初始化棋盘InitBoard函数

既然是初始化函数,说明我们的要求就是把二维数组board初始化为全空格

void InitBoard(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++)
    {
      board[i][j] = ' '; //赋予空格
    }
  }
}

打印棋盘DisplayBoard函数

首先我们来设计一个棋盘,如下:

image.png

首先,看这个棋盘,是由带+的四行行,加上带|的四行组成

先来看看一组规则:斜杠+空格+空格+空格

image.png

image.png

image.png

image.png

再来看一组规则:+---+

image.png

image.png

image.png

image.png

最后因为我们下棋落子的地方在中间,也就是我红色标记的地方;

该地方需要用字符来输入,也就是用%c打印

image.png

代码如下:

void DisplayBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
    printf("+---+---+---+\n");//打印带+号的边界
    for (j = 0; j < col; j++)
    {
      printf("| %c ", board[i][j]);打印+号下面的内容
    }
    printf("|\n");//补上 最右边界
  }
  printf("+---+---+---+\n");//补最下面的+号边界
}

玩家下棋Player函数

玩家下棋采用的是坐标输入的方式;

玩家输入一个坐标,那么棋盘上的相应位置就应该用*表示;

输入坐标时候还要检验该位置是否已经落子了;

void Player(char board[ROW][COL], int row, int col)
{
  printf("请分别输入横纵坐标(输入数字请用空格隔开):> ");
  int x = 0;
  int y = 0;
  while (1)
  {
    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("该坐标位置已经落子,然后重新输入坐标:> ");
      }
    }
    else
    {
      printf("该坐标超界,请重新输入:> ");
    }
  }
    DisplayBoard(board, ROW, COL);//我们每下一次,都打印一下棋盘
}

上面代码中为什么要用x - 1y - 1呢?

因为数组的下标是从0开始的;

比如我们输入:1 2,而实际落子的地方用数组表示是应该是:0 1;

考虑到玩家不一定是程序员,他也不知道数组是从0开始数的,

电脑下棋Computer函数

由于是电脑下棋,我们无法操作,于是只有让电脑随机下了;

缺陷是电脑就有点智障了,哈哈哈!

void Computer(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("电脑下棋:> \n");
  while (1)
  {
    x = rand() % row; //电脑输入横坐标的范围:0~2
    y = rand() % col; //电脑输入纵坐标的范围:0~2
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }
  }
  DisplayBoard(board, ROW, COL);//打印棋盘
}

大家可能都注意到了srand((unsigned long)time(NULL)),这个函数经常跟rand函数一起使用,是对随机数发生器的初始化函数

在C语言中它们都位于<stdlib.h>头文件中

  • 原型:void srand(unsigned int seed)
  • 原型:void rand(void)

seed相当于一个种子,srand函数根据这个种子seed,设置一个随机的起点,rand函数就根据这个起点,返回一个随机数[seed , RAND_MAX]

rand函数每一次调用的时候,都会看看之前是否调用了srand函数,如果调用了,就会调用srand(seed)来初始化她的随机值,如果没有,则会默认的调用srand(1)来初始化它的值。

大家可能会问那调不调用不都一样吗?是的!

但是为了让每一次程序的调用都产生不同的值,所以经常使用系统时间来初始化,也就是time(NULL)

判断输赢IsWin函数

玩家或者电脑下子后,需要判断双方有一方是否赢;

IsWin的作用就是判断是否有一方赢;

其中:

  • 返回值:*代表玩家胜利
  • 返回值:Q代表双方平局
  • 返回值:#代表电脑胜利
  • 返回值:C代表游戏继续

判断胜利方法就是检查每行每列以及斜线是否有一样的,以及是否平局

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;
}
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][1] != ' ')
    {
      return board[i][1];
    }
  }
    //三列判断
  for (i = 0; i < col; i++)
  {
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
    {
      return board[1][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];
  }
  //判断平局
  if (1 == IsFull(board, ROW, COL))
  {
    return 'Q';
  }
  return 'C';
}

完整代码

  • test.c:游戏的测试逻辑
  • game.c:游戏的实现逻辑
  • game.h:游戏实现函数的声明

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
  printf("************************\n");
  printf("****EDC's Game World****\n");
  printf("******   1.Play   ******\n");
  printf("******   0.Exit   ******\n");
  printf("************************\n");
}
void game()
{
  char board[ROW][COL] = {0};
  InitBoard(board, ROW, COL);//初始化棋盘
  DisplayBoard(board, ROW, COL);//打印棋盘
  int ret = 0;
  while (1)
  {
    Player(board, ROW, COL);//玩家下棋
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    Computer(board, ROW, COL);//电脑下棋
    ret = IsWin(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
  }
  if (ret == '*')
  {
    printf("恭喜您取得胜利!!!!!!!!!\n\n");
  }
  else if (ret == '#')
  {
    printf("你也太辣鸡了吧,电脑都下不赢\n");
  }
  else
  {
    printf("哎~~,你的技术不行啊,居然和电脑达成平手\n");
  }
}
int main()
{
  srand((unsigned int)time(NULL));
  int input = 0;
  do
  {
    menu();
    printf("请选择:> ");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      //printf("玩游戏\n");
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void InitBoard(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++)
    {
      board[i][j] = ' ';
    }
  }
}
//ROW = 3行
//COL = 3列
void DisplayBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < row; i++)
  {
    printf("+---+---+---+\n");
    for (j = 0; j < col; j++)
    {
      printf("| %c ", board[i][j]);
    }
    printf("|\n");
  }
  printf("+---+---+---+\n");
}
void Player(char board[ROW][COL], int row, int col)
{
  printf("请分别输入横纵坐标(输入数字请用空格隔开)>: ");
  int x = 0;
  int y = 0;
  while (1)
  {
    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");
    }
  }
  DisplayBoard(board, ROW, COL);//打印棋盘
}
void Computer(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;
    }
  }
  DisplayBoard(board, ROW, COL);//打印棋盘
}
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;
}
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][1] != ' ')
    {
      return board[i][1];
    }
  }
  for (i = 0; i < col; i++)
  {
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
    {
      return board[1][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];
  }
  //判断平局
  if (1 == IsFull(board, ROW, COL))
  {
    return 'Q';
  }
  return 'C';
}

game.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void Player(char board[ROW][COL], int row, int col);
//电脑下棋
void Computer(char board[ROW][COL], int row, int col);
//判断输赢的代码
//玩家赢 - '*'
//电脑赢 - '#'
//平均 --- 'Q'
//继续 ----'C'
char IsWin(char board[ROW][COL], int row, int col);

动画演示


image.png

相关文章
|
4天前
|
C语言
【C语言】猜数字小游戏的一步一步实现2
【C语言】猜数字小游戏的一步一步实现
|
4天前
|
算法 C语言
【C语言】猜数字小游戏的一步一步实现1
【C语言】猜数字小游戏的一步一步实现
|
4天前
|
C语言
C语言之三子棋小游戏
C语言之三子棋小游戏
|
4天前
|
C语言
C语言之实现贪吃蛇小游戏篇(2)
C语言之实现贪吃蛇小游戏篇(2)
26 1
|
4天前
|
存储 小程序 编译器
C语言之三子棋小游戏的应用
C语言之三子棋小游戏的应用
|
4天前
|
算法 编译器 C语言
C语言猜数字小游戏(也包含python实现的用法)
本文基于VS2022、pycharm和前面的知识,写一个凭借分支与循环的小游戏,比如: 写一个猜数字游戏 游戏要求: 电脑自动生成1~100的随机数 玩家猜数字,猜数的过程中,根据猜测数据的大小给出大了或小了的反馈,直到猜对,游戏结束 在pyhton中生成随机数是比较简单的,可以直接导入random的包,直接生成随机数,导致写猜数字小游戏变成了判读语句和循环语句嵌套就能写出来,所以我不做过多的介绍了,可以直接看后面的代码展示,想了解更多的python可看python的基础知识,这里面有我在学习python的过程中写的笔记
35 0
|
4天前
|
C语言
爱上C语言:扫雷小游戏,展开一片功能实现
爱上C语言:扫雷小游戏,展开一片功能实现
爱上C语言:扫雷小游戏,展开一片功能实现
|
4天前
|
人工智能 机器人 测试技术
【C语言】C语言实现猜单词小游戏(源码+报告)【独一无二】
【C语言】C语言实现猜单词小游戏(源码+报告)【独一无二】
|
4天前
|
存储 定位技术 C语言
基于C语言实现扫雷小游戏
本文介绍了使用C语言实现扫雷小游戏的过程。扫雷是一款经典的单机游戏,玩家需要通过点击方格来揭示数字或地雷,最终清除所有非地雷方格。实现过程中,首先定义了游戏所需的数据结构,如游戏地图、玩家信息等。然后,实现了游戏的初始化、渲染、输入处理等核心功能。在游戏逻辑方面,处理了点击事件、数字计算和胜负判断等。通过不断优化和完善,最终完成了基于C语言的扫雷小游戏实现,为玩家提供了一种简单有趣的游戏体验。
28 0
|
4天前
|
机器学习/深度学习 小程序 C语言
C语言初学者:原来我也可以实现扫雷小游戏(简易版)!
C语言初学者:原来我也可以实现扫雷小游戏(简易版)!