【C语言小游戏】三子棋(井字棋)(中)

简介: 【C语言小游戏】三子棋(井字棋)
void print_board(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
    if (i < row - 1)
    {
      printf("---|---|---\n");
    }
  }
}

运行结果如下所示

可是这样的话,我们会发现,这样其实就被写死了,以后想要修改就很难修改了。比如我们将行和列都改为十的话。就会发现和我们所设想的棋盘大大不符合

(3)更进一步优化

所以我们要改。要优化代码,那么怎么优化呢?其实我们可以在我们上面的代码上进行修改,我们上面的代码是由两次打印,我们将两次打印都进行展开。具体到每一列上操作。第一次打印就把一个数据和一个|字符当成一组逻辑,第二次打印就把---|当成一组逻辑。当然每一组逻辑最后一次是不需要打印|的。所以根据这些分析,我们已经可以推导出代码了

void print_board(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    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("---");
        if (j < col - 1)
        {
          printf("|");
        }
      }
      printf("\n");
    }
  }
}

运行结果为

可见符合了我们的预期。

7.截止至目前已经实现功能,所写的代码展示

作为一个新手,刚开始写这种小游戏的时候,常常读着读着就已经晕了。这是因为新手暂时还没有一种全局的目光。所以为了方便读者理解,我们将截止至目前已经实现的代码在此处进行一下展示方便读者更好的阅读下去。

test.c模块

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void meau()
{
  printf("********************************\n");
  printf("********     1.play      *******\n");
  printf("********     0.exit      *******\n");
  printf("********************************\n");
}
void game()
{
  char board[ROW][COL];
  init_board(board, ROW, COL);
  print_board(board, ROW, COL);
}
void test()
{
  int input = 0;
  do
  {
    meau();
    printf("请输入>:\n");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      printf("进入三子棋游戏\n");
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("选择错误,请重新选择\n");
      break;
    }
  } while (input);
}
int main()
{
  test();
  return 0;
}

game.c模块

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void init_board(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      board[i][j] = ' ';
    }
  }
}
void print_board(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    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("---");
        if (j < col - 1)
        {
          printf("|");
        }
      }
      printf("\n");
    }
  }
}

game.h模块

#pragma once
#include<stdio.h>
#define ROW 3
#define COL 3
//头文件声明函数
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void print_board(char board[ROW][COL], int row, int col);

8. 玩家下棋(player_move)

有了棋盘,自然就需要下棋了。

(1)玩家下棋函数的定义和声明

void player_move(char board[ROW][COL], int row, int col);

(2)实现玩家下棋

我们要让玩家下棋,那么我们不妨就让玩家通过输入坐标来进行下棋,如下图所示,这样的话,就可以使玩家输入一个坐标。

有了坐标,我们首先要通过这个坐标来判断是否在我们棋盘的范围内,也就是是否合法,而且要注意的是,玩家可不是程序员,他们不知道这个数组的下标是从0开始的,所以我们要在玩家输入的坐标上-1,而且我们这样应该是一个循环,坐标非法时候需要重新输入坐标,当我成功下棋以后,我们可以在里面放入一个break语句来打破循环。

坐标合法,但是如果这个位置之前有人下过棋了呢,这种情况也是不允许的,所以我们要在坐标合法里面加入一条判断,这个位置是一个空格字符,不能有棋子。

(提示:此处存在一处错误,这是我们之前所讲过的经典的错误标准的零分,细心的你发现了吗,没有发现的话,那就接着往下看吧!后文会讲解的)

(3)测试玩家下棋模块

我们试着测试一下,在test.c种加入打印棋盘,方便我们查看

运行结果为

输入成功案例

坐标非法案例

此处位置已经被下了棋案例

这部分我们可以使用两次玩家下棋来完成我们先将test.c在进行一次玩家输入和打印,这是因为我们目前这是第一次下棋,只有在第二次下棋才会出现这种情况

我们试着下棋

我们发现居然不符合我们的预期了!!!,这是怎么回事呢,其实这个错误细心的同学肯定在前文中已经发现了。

(4)经典的错误标准的零分

这个错误有太多人犯了,所以在此处故意设下了一个坑,当然也是提醒大家,细心的重要性。当然这个错误看似简单,但是在这个一个很简单的项目里可不简单,即便我在前文中提醒过此处有一个经典错误标准零分,但还是有人找不到,那如果将整个游戏写完之后在想找到这个错误是很困难的。这么一个小错误对于这个游戏而言是很致命的。而这个错误很难发现,所以这就再次提醒大家,一定要细心,细心。写一部分测一部分。否则未来在企业中,那种超大规模的代码想要调试出来是极其困难的!!!

修改后再次测试

这下就是符合我们的预期了

(5)玩家下棋的代码

void player_move(char board[ROW][COL], int row, int col)
{
  int x = 0; int y = 0;
  printf("玩家下棋\n");
  while (1)
  {
    printf("请输入坐标>:\n");
    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("坐标非法,请重新输入\n");
    }
  }
}

9.电脑下棋(computer_move)

(1)电脑下棋函数的声明和定义

我们发现我们使用了一个while循环,这样是为了实现电脑和人交互下棋。

void computer_move(char board[ROW][COL], int row, int col);

(2)电脑下棋的具体实现

电脑下棋是如何实现的呢,我们可以制作一个简单版本的电脑下棋。也就是让电脑随机下。当然想让电脑智能下棋的话对于目前的阶段还是比较困难的。我们目前只完成电脑随机下。想要让电脑随机下你,那么就必须得要让电脑产生一个随机的坐标,这个坐标不能非法,也必须在一个没有下过棋子的位置才可以,这样一思考,其实就简单了。这可比我们的人下棋要简单一点。唯一一点需要注意的就是如何生成随机坐标。其实随机坐标的生成也不难理解,我们之前在讲解猜数字小游戏的时候已经讲解过了。这里给出链接:猜数字小游戏详解,有了随机坐标。那么电脑下棋的步骤也就很简单了。

具体实现如下

当然有些人觉得这个电脑下棋的代码有一些没有必要的东西,比如x和y不需要+1,如果这样做,还能少了一层判断。因为他是电脑内部操作的。不需要玩家来认识,这样做当然是可以的,但是我们这样写形式上与玩家下棋一致。更容易理解。

(3)电脑下棋的代码测试

还是和之前一样,写一点测一点,满足我们的预期。

(4)电脑下棋的代码展示

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

10.判断输赢

我们已经实现了玩家和电脑的下棋,那么游戏肯定是有输赢的,我们接下来来实现游戏的输赢

(1)判断输赢的声明和定义以及判断输赢的基本逻辑

我们思考一下游戏一共有多少种状态呢?

答案是四种,分别为,电脑赢,玩家赢,平局,游戏继续

我们将电脑赢记作#

玩家赢记作*

平局记作 Q

游戏继续记作C

这样一来的话,我们就可以构建出我们的函数了,吧目前的数组和行列传给他,他生成一个返回值。然后根据这个返回值就能判断出游戏的状态,从而得出结论了

函数的定义和声明如下

char is_win(char board[ROW][COL], int row, int col);

输赢的基本逻辑实现如下

相关文章
|
1月前
|
C语言 C++
【C语言】编写“猜数字“小游戏
【C语言】编写“猜数字“小游戏
|
2月前
|
定位技术 API C语言
C语言——实现贪吃蛇小游戏
本文介绍了一个基于Windows控制台的贪吃蛇游戏的实现方法。首先,需调整控制台界面以便更好地显示游戏。接着,文章详细描述了如何使用Win32 API函数如`COORD`、`GetStdHandle`、`GetConsoleCursorInfo`等来控制控制台的光标和窗口属性。此外,还介绍了如何利用`GetAsyncKeyState`函数实现键盘监听功能。文中还涉及了`&lt;locale.h&gt;`库的使用,以支持本地化字符显示。
59 1
C语言——实现贪吃蛇小游戏
|
1月前
|
C语言 定位技术 API
【C语言】实践:贪吃蛇小游戏(附源码)(二)
【C语言】实践:贪吃蛇小游戏(附源码)
【C语言】实践:贪吃蛇小游戏(附源码)(二)
|
1月前
|
C语言 开发者
C语言实现猜数字小游戏(详细教程)
C语言实现猜数字小游戏(详细教程)
|
1月前
|
C语言
【C语言】实践:贪吃蛇小游戏(附源码)(三)
【C语言】实践:贪吃蛇小游戏(附源码)
|
1月前
|
存储 API C语言
【C语言】实践:贪吃蛇小游戏(附源码)(一)
【C语言】实践:贪吃蛇小游戏(附源码)
|
1月前
|
C语言
C语言贪吃蛇小游戏来啦!
C语言贪吃蛇小游戏来啦!
30 0
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
35 3
|
12天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
28 6
|
1月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
36 10