【️C语言-游戏设置】---三子棋(N满)

简介: 【️C语言-游戏设置】---三子棋(N满)

📘游戏基本介绍:

48bd7cd7dcef5cfe93c4fa559402f6cc_4be14780d54040dab67baec81bf2dc28.png


嘻嘻,想必大家都玩过吧,有时上课玩,下课玩儿,玩的不亦乐乎。哈哈!


规则:双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子连成一条线的一方则视为胜利者。


让我们重温经典,从新拾起我们儿时的回忆。把它带入C世界。


📙基本功能分配:

📕A.游戏相关定义–game.h

简单介绍:

  • game.h这个头文件就像海上巨轮的总舵,总舵发出一个个的指令 ,指挥着船员合理进行工作。game.h也是如此“指挥”着game.c从而实现游戏的运行。

这里包含几个关键的点,让我们一起来看看吧😁


- 头文件集合地:

#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>

这里(游戏)包含了我们会使用的几个头文件,我们可以把这些头文件放在game.h里,这样我们在其他板块引用game.h即可使用其他文件。


- 引用方式:

#include"game.h"
//这里用的是" "而不是<>哦!
  • define的整数定义:
#define ROW 3
#define COL 3
#define WZQ 3

这也是三子棋盘可以变化为N子棋盘的原因,所以这个相当于一个很不错的优化。


- 关键函数的定义:

//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);

//打印棋盘
void print_board(char board[ROW][COL], int row, int col);

//玩家下棋
void player_move(char board[ROW][COL], int row, int col);

//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);

//判断输赢
char who_is_win(char board[ROW][COL], int row, int col);


在这里定义关键函数,在我看来其实是梳理程序的一部,建立游戏实现框架,我尝试把这个部分屏蔽,并不影响游戏的运行。


好吧,总部大佬我们已经知道了,接下来我们来看看游戏躯干吧!


game.h


#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
#define WZQ 3


//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);

//打印棋盘
void print_board(char board[ROW][COL], int row, int col);

//玩家下棋
void player_move(char board[ROW][COL], int row, int col);

//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);

//判断输赢
char who_is_win(char board[ROW][COL], int row, int col);


📕B. 测试的逻辑–test.c

  • test.c我认为它是游戏的躯干,主题,毕竟主函数在这不是嘛(虽然很细)。好吧,我们来慢慢认识它吧。
int main()
{
  //游戏测试
  test();

  return 0;

}

a.游戏菜单–menu函数

  • 这个菜单与游戏设计的menu一样,直接上链接
void menu()
{
  printf("******************************\n");
  printf("********  1、play   **********\n");
  printf("********  0、eixt   **********\n");
  printf("******************************\n");
} 

b.游戏总框架–test函数:

1.游戏可持续性的实现

  • 这里我们为了是程序实现可持续性,用到了do-while循环来实现。在通过选项判断是否循环,或者进入下个部分。
  • 通过上面菜单,我们有三种选择:
  • 1.进行游戏,进入game()函数。但未脱离循环,函数执行完,仍在循环内。
  • 2.退出游戏,脱离循环,结束程序。
  • 3.非法输入,强行输入其他字符,无法识别,重新输入,继续循环。

- 综上,我们会选择采取Switch语句并且我们可以确定while的判断条件为input输入是否为0。

—————————————————————————代码如下——————————————————————

void test()
{
  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);
}
  • 这里也是 游戏实现框架–game函数与我们简要讲的game.c有着逻辑关系

2.game函数框架:

1.game()函数来理清框架,把游戏逻辑全部理清,是游戏实现的索引。我们用具代码来看看吧。

2.在我看来其实和test.c很相像。

3.具体内容我们就不在这里赘述,我们在game.c中来看吧!

void game()
{

  char board[ROW][COL];
  //初始化棋盘
  init_board(board,ROW,COL);
  //打印棋盘
  print_board(board,ROW,COL);
  //玩家下棋
  char ret = 0;
  while (1)
  {
    //玩家下棋
    player_move(board, ROW, COL);
    print_board(board, ROW, COL);
    //判断输赢
    ret = who_is_win(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    //电脑下棋
    computer_move(board, ROW, COL);
    print_board(board, ROW, COL);
    //判断输赢
    ret = who_is_win(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
  }
  switch (ret)
  {
  case '#':
    printf("电脑胜利\n");
    break;
  case '*':
    printf("玩家胜利\n");
    break;
  default:
    printf("平局\n");
    break;
  }
  //游戏继续:'C'
  //电脑胜利:'#'
  //玩家胜利:'*'
  //平局:'P'

}

test.c

#include"game.h"

void menu()
{
  printf("******************************\n");
  printf("********  1、play   **********\n");
  printf("********  0、eixt   **********\n");
  printf("******************************\n");
} 
void game()
{

  char board[ROW][COL];
  //初始化棋盘
  init_board(board,ROW,COL);
  //打印棋盘
  print_board(board,ROW,COL);
  //玩家下棋
  char ret = 0;
  while (1)
  {
    //玩家下棋
    player_move(board, ROW, COL);
    print_board(board, ROW, COL);
    //判断输赢
    ret = who_is_win(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
    //电脑下棋
    computer_move(board, ROW, COL);
    print_board(board, ROW, COL);
    //判断输赢
    ret = who_is_win(board, ROW, COL);
    if (ret != 'C')
    {
      break;
    }
  }
  switch (ret)
  {
  case '#':
    printf("电脑胜利\n");
    break;
  case '*':
    printf("玩家胜利\n");
    break;
  default:
    printf("平局\n");
    break;
  }
  //游戏继续:'C'
  //电脑胜利:'#'
  //玩家胜利:'*'
  //平局:'P'

}

void test()
{
  //随机数生成器
  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);
}

int main()
{
  //游戏测试
  test();

  return 0;

}

📕C.游戏实现–game.c

  • game.c这里就是游戏核心的运行,也是游戏实现运行的关键。来吧,来吧,看看真正的实体吧😁

📗a.棋盘的建立:

这里棋盘建立主要是二维数组,实现的细节很多,好好听哦。


1.棋盘初始化–init函数

这里我们的是思路是建立所需棋盘大小并且还可以更改,这里大家联想到了什么。

对咯,就是game.h里的#define定义整数喽,棋盘需要变化只需要改变定义整数大小即可。


创建一个二维数组:


输入‘空格’完成初始化。

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] = ' ';//初始化
    }
  }
}

这些地方一定要调试检查,不然等代码后面多了,可能就不那么容易了。

有的朋友肯定会提出疑问,我打出来我看不到啊,怎么检查呢。

这里大家可以将数组初始化为‘*’;这样就便于检查喽。


2.棋盘打印–print函数

棋盘打印有很多细节,让我给大家慢慢道来!


首先我们要知道棋盘如何构成:

3e6898111c5b5d160fdfd7826d0a0951_d2650686bd2f4e4aa448d6f5cca23635.png


我们可以把棋盘拆分成两种类型来解释:

1.第一层是由“ | | ”构成的,我们还要拆分变为是由三个“ |”组成,但少了最后一个“|”

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

2.同样的道理,第二层我们可以细分为由三个“—|"组成,同样少了最后一个”|“这里就不插入代码筹字数咯。

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

OK,棋盘已经搭建好了,那便来战胜负吧。


📗b.下棋:

1.玩家下棋–player函数

玩家下棋我们就自定义个函数:void player_move(char board[ROW][COL], int row, int col);

函数需要注意哪些问题呢,下面两点值得注意:


1)程序员与玩家区别

棋盘的自述:


大家好,我是棋盘YYDS,由我来为大家介绍下,程序员和玩家眼中的我。

玩家眼中,我是1,2,3并排走的,坐标范围都1-3.

可是程序员眼中,一眼看穿我的本质,明白我是一个二维数组,所以程序员能够找出我的真实坐标。0,1,2.

但我想让两边都认识我,都不矛盾,那就写个函数吧。


从棋盘的自述中,我们明白了两者的区别,很明显发现,两者认识只是差一,故此,我们便用函数更改

        printf("请输入下棋坐标:>");
    int x = 0;
    int y = 0;
    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;
      }

2)判断输入是否合规

好了,意见统一,但要合法吧!有两法要记住。


~判断是否在范围限制内;

~判断是否输入重复;

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

2.电脑下棋–computer函数

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


1)生成范围内的随机数;

//随机数生成器
  srand((unsigned int) time(NULL));
//**生成器放在主函数哦**

随机数生成了,范围咋办,别急,来答案了。

//这里row==col,都等于3;
    int x = rand() % row;
    int y = rand() % col;
//取余一个数会得到比这个数小的结果,从而限定范围。

2)判断落子位置是否重复;

有空白就输入,没空白就算喽。

if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }

📗c.胜负判断–is_win函数

引入char who_is_win(char board[ROW][COL], int row, int col);


1.玩家/电脑胜利:

这里我是采用了计数的方法,大家可以借鉴借鉴哈。

并且玩家和电脑判断高度相似,我就拿玩家举例子喽。

电脑判断只需把‘*’改为‘#’。


1)行列判断


  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    int count1 = 0, count2 = 0; 
    //玩家处判断
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == '*')
      //行判断
        count1++;
      if (board[j][i] == '*')
      //列判断
        count2++;
      
    }
    switch (count1)
    {
    case WZQ:
      return '*'; 
    }
    switch (count2)
    {
    case WZQ:
      return '*';
    }
    

2)对角线判断

    int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    int count3 = 0, count4 = 0;
    for (j = 0; j < col; j++)
    {
            if (board[j][j] == '*')
            //这里判断的是主对角线
        count3++;
      if (board[j][ROW - 1 - j] == '*')
      //判断的是副对角线
        count4++;
    }   
         switch (count3)
    {
    case WZQ:
      return '*';
    }
    switch(count4)
    {
    case WZQ:
      return '*';
    }
}   

综上,其实我们可以把两种判断放在一起,通用一个循环,并且要注意一个点,就是count的归零。尤其小心哈


2.平局:

引入static int is_full(char board[ROW][COL], int row, int col);


~full_board函数

核心: 度过上面两个判断,判断是否还有空格,若无,则平局。

int i = 0;
  int count = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      if (board[i][j] != ' ')
      //这里是所有格子,判断是否有空格子
        count++;  
    }
  }
  if (count == ROW*COL)//这里是所有格子数量
    return 1;
  else
    return 0;

3.游戏继续:

上面所有都结束了,那只能是继续喽。


判断结束,返回字符,在宣布结果。


好了,游戏就讲完喽,三个代码分享如下:


game.c

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

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

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

static int is_full(char board[ROW][COL], int row, int col)
{
  int i = 0;
  int count = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    for (j = 0; j < col; j++)
    {
      if (board[i][j] != ' ')
        count++;  
    }
  }
  if (count == ROW*COL)
    return 1;
  else
    return 0;
  
}

char who_is_win(char board[ROW][COL], int row, int col)
{
  //玩家胜利或者电脑胜利:判断行n列n斜杠n
  
  int i = 0;
  for (i = 0; i < row; i++)
  {
    int j = 0;
    int count1 = 0, count2 = 0; 
    int count3 = 0, count4 = 0;
    //玩家处判断
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == '*')
        count1++;
      if (board[j][i] == '*')
        count2++;
      if (board[j][j] == '*')
        count3++;
      if (board[j][ROW - 1 - j] == '*')
        count4++;
    }
    switch (count1)
    {
    case WZQ:
      return '*'; 
    }
    switch (count2)
    {
    case WZQ:
      return '*';
    }
    switch (count3)
    {
    case WZQ:
      return '*';
    }
    switch(count4)
    {
    case WZQ:
      return '*';
    }

    //电脑处判断
    count1 = 0, count2 = 0;
    count3 = 0, count4 = 0;
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == '#')
        count1++;
      if (board[j][i] == '#')
        count2++;
      if (board[j][j] == '#')
        count3++;
      if (board[j][ROW - 1 - j] == '#')
        count4++;
    }
    switch (count1)
    {
    case WZQ:
      return '#';
    }
    switch (count2)
    {
    case WZQ:
      return '#';
    }
    switch (count3)
    { 
    case WZQ:
      return '#';
    }
    switch (count4)
    {
    case WZQ:
      return '#';
    }
  }

  if (is_full(board, ROW, COL) == 1)
      return 'P';
    
   return 'C';
}

篇幅太长咯,抱歉了哈!

最后美图奉上:

遥望彩霞,奔赴梦想,我们都在,一起加油(兄弟们)!!!

相关文章
|
1月前
|
C语言
C语言之斗地主游戏
该代码实现了一个简单的斗地主游戏,包括头文件引入、宏定义、颜色枚举、卡牌类、卡牌类型类、卡牌组合类、玩家类、游戏主类以及辅助函数等,涵盖了从牌的生成、分配、玩家操作到游戏流程控制的完整逻辑。
75 8
|
2月前
|
C语言
扫雷游戏(用C语言实现)
扫雷游戏(用C语言实现)
128 0
|
26天前
|
存储 算法 C语言
用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容
本文探讨了用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容,旨在为开发者提供全面的指导和灵感。
45 2
|
1月前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
34 1
|
2月前
|
编译器 C语言
猜数字游戏实现#C语言
猜数字游戏实现#C语言
99 1
|
2月前
|
存储 C语言
揭秘C语言:泊舟的猜数字游戏
揭秘C语言:泊舟的猜数字游戏
|
2月前
|
存储 C语言
C语言:设置地址为 0x67a9 的整型变量的值为 0xaa66
在C语言中,可以通过指针操作来实现对特定地址的访问和赋值。要将地址为 0x67a9 的整型变量值设为 0xaa66,可以先定义一个指向该地址的指针,并通过该指针对该内存位置进行赋值操作。需要注意的是,直接操作内存地址具有一定风险,必须确保地址合法且可写。代码示例应考虑字节序及内存对齐问题。
|
2月前
|
C语言
初学者指南:使用C语言实现简易版扫雷游戏
初学者指南:使用C语言实现简易版扫雷游戏
45 0
|
2月前
|
C语言
C语言扫雷游戏(详解)
C语言扫雷游戏(详解)
45 0
|
2月前
|
程序员 C语言
初识C语言之三子棋游戏
初识C语言之三子棋游戏
38 0