三子棋的实现(C语言)

简介: 这是一篇介绍如何用C语言实现三子棋小游戏的文章,从问题分析到代码讲解,非常详细的讲解,适合刚学完C语言基础知识的同学实践练习巩固 跟着敲就能学会(代码已放在文末)

首先:三子棋游戏用C语言实现的整体思路如下


将棋盘初始化:将一个3*3的字符数组元素全部初始化为‘ ’(空格)

要设置一个打印棋盘的函数,每次玩家和电脑落子后都调用一次这个函数打印更新的棋盘供玩家来看赛况

规则,落子标记   玩家:*      电脑:#

玩家下棋的规则:让玩家输入两个数,用空格隔开,表示要落子地点的坐标

电脑下棋:连续生成两个0-2的随机数,并下在非空格区域

判断输赢:当每行、每列或者正反对角线字符元素相同时,则判胜负,如果棋盘满了则为和棋,如果以上条件都不满足,则比赛继续

首先,打开vs,创建源文件 test.c 用来存放主函数以及这个项目主要的框架及代码的整体思路,创建一个头文件 game.h 来存放游戏中要使用到的各种头文件和宏定义及函数声明部分,再创建一个源文件 game.c 来具体实现三子棋的功能。


先做一个简易的菜单,注意:尽量将退出选项值设置为0,这要与后面的退出循环的判断条件对应

为了游戏玩完一把可以继续玩,我们在这里采用do...while对菜单以后进行循环

如上,里面使用switch-case语句对选项进行控制,这里记得每个case语句后面都得有break!不然程序运行后一定会出现bug。


接下来,我们就开始实现三子棋游戏的函数了


提前在头文件中定义数组的行和列,这个操作不是必要的,但可以让代码的可读性提高:看到代码就基本明白它的含义

第一步:对棋盘就行初始化


每次在源文件中定义一个函数都要在头文件game.h中进行函数声明,后面不在赘述,并且这些将函数大多数都将在game.c中实现,为了方便使用,我们将所有要用到的的头文件都放在game.h中,只需要在每个源文件中引用一下  #include"game.h"即可使用game.h里面的所有函数声明、头文件、宏定义等

初始化棋盘的实现(game.c)

数组中的空格就是游戏开始前棋盘中所放的元素,玩家或者电脑落子后,只需要根据落子坐标来对数组元素的值进行更改即可

第二步:打印棋盘部分

打印棋盘,首先要打印初始棋盘

先看一下我们要打印的初始棋盘的模板

第一行要打印的数据为 空格%c空格|空格%c空格|空格%c空格(刚开始时%c全部为空格)

第二行要打印的数据为 ---|---|---

|的是否打印可以由对列的循环控制,每一行打印完成都要加换行符

具体的实现过程可以由上述代码实现,注意要控制“|”的打印次数和“---|”的打印次数。可以认真研究一下这段代码。当玩家落子或者电脑落子后,调用一次这个打印棋盘的函数后,就可以清晰地看出整个对局的过程。


第三步:玩家下棋

要写玩家下棋的程序,首先,我们要知道,玩家看到的界面是这样


可以设置一个玩家下棋的函数,每当轮到玩家下棋的时候,调用这个函数即可


在函数中可以提示玩家输入要落子的坐标,如三子棋是3*3的棋盘,玩家想在中间落子,就要输入“2 2”即“数字空格数字”,我们就可以用两个变量接受玩家输入的两个值,然后再索引到数组位置,将对应位置的值的改为‘*’,将电脑生成的坐标对应的值改为‘#’。但由于玩家输入的值和数组的索引规则有区别,例如:玩家输入的为3 3,在数组中则对应的是坐标为2 2的位置。所以,我们还需要对玩家输入的值进行处理,将其变成数组中对应的坐标。

玩家落子后再打印一次棋盘即可。

第四步:电脑下棋


电脑下棋就要用到我们之前学习过的生成随机数的函数rand();不会的兄弟可以去这个网站看看rand - C++ Reference (cplusplus.com)


rand()%2即可得到0-2的随机数,将这个函数调用两次,用两个变量来接收生成的随机数,作为数组坐标,判断坐标对应数组元素是否为空格,若不为空格,就重新生成一次,直到坐标为空格为止。注意:调用rand函数前必须先调用srand函数和time函数,才能保证每次生成的随机数不相同。两个函数的具体功能 我放在下面了,不清楚的兄弟可以点来链接去看,我就不具体介绍了


srand - C++ Reference (cplusplus.com)  time - C++ Reference (cplusplus.com)

这两个函数只需要在主函数中调用这一次即可

他们对应的头文件,放在game.h中即可


第五步:判断输赢

设置一个循环,不停的循环下棋、打印棋盘、下棋、打印棋盘......直到一方胜利或者出现和棋为止


判断输赢就比较简单了,设置一个判断输赢的函数,在每次落子后都要调用这个函数对数组元素进行便遍历,看是否有一行相同、一列相同、对角线相同,或者棋盘已满却无输赢情况,如果有,就返回一个值,通过这个返回值即可判断胜负关系。如果没有上面的几种情况,则游戏继续进行


这里用一个技巧可以大大提高判断输赢时的效率,当判断出有一方达到胜利条件时,直接返回参与判断的数组元素中一个元素的值即可。例如如果电脑赢了,就自动返回‘#’;玩家赢了,就自动返回‘*’,即谁赢就返回谁的棋子标志。和棋返回‘Q’,继续游戏返回‘C’。在主函数中可以先判断函数返回值是否为‘C’,如果不是,再出循环进行胜负判断

函数的具体实现步骤如下

这样,一个简易的三子棋游戏(C语言)就做成了,我试玩一把

当你输入错误时会有提示,我最终惜败电脑,哈哈


另外,还可以在前面设置一个电脑先手还是玩家先手的判断,不过这个比较简单,大家可以自行完成,我将代码放在下面


game.h

#pragma once
#include<stdio.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 PlayerMove(char board[ROW][COL], int row,int col);
#include<stdlib.h>
#include<time.h>
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);

test.c

#include"game.h"
void menu1()
{
  printf("******************************\n");
  printf("********   1.play     ********\n");
  printf("********   0.exit     ********\n");
  printf("******************************\n");
}
void menu2()
{
  printf("******************************\n");
  printf("********   1.玩家先手 ********\n");
  printf("********   2.电脑先手 ********\n");
  printf("******************************\n");
}
void game()
{
  char board[ROW][COL] = { 0 };
  InitBoard(board, ROW, COL);//将数组进行初始化的函数
  DisplayBoard(board, ROW, COL);//打印棋盘
  char ret = 0;
  menu2();
  printf("请选择->:\n");
  int z = 0;
  scanf("%d", &z);
  while (1)
  {
    if (z == 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);//打印棋盘,看落子情况
      ret = IsWin(board, ROW, COL);//接受不同结果的返回值
      if (ret != 'C')
        break;
    }
    if (z == 2)
    {
      ComputerMove(board, ROW, COL);//电脑下棋
      DisplayBoard(board, ROW, COL);//打印棋盘,看落子情况
      ret = IsWin(board, ROW, COL);//接受不同结果的返回值
      if (ret != 'C')
        break;
            PlayerMove(board, ROW, COL);//玩家下棋
      DisplayBoard(board, ROW, COL);//打印棋盘,看落子情况
      ret = IsWin(board, ROW, COL);//接受不同结果的返回值
      if (ret != 'C')
        break;
    }
  }
  if (ret == '*')
    printf("玩家赢\n");
  if (ret == '#')
    printf("电脑赢\n");
  if (ret == 'Q')
    printf("平局\n");
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    menu1();
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      printf("三子棋游戏开始\n");
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入的数字不合法,请重新输入:\n");
      break;
    }
  } while (input);
  return 0;
}

game.c

#include"game.h"
//初始化棋盘
void InitBoard(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 DisplayBoard(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 PlayerMove(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  while (1)
  {
    printf("请玩家落子:");
    scanf("%d%d", &x, &y);
    if (x>= 1 && x<=row && y >=1 && y <= col && board[x - 1][y - 1] == ' ')
    {
      board[x - 1][y - 1] = '*';
      break;
    }
    else
      printf("落子有误,请重新落子\n");
  }
}
//电脑下棋
void ComputerMove(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;
    }
  }
}
//判断输赢
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][2] != ' ')
      return board[i][0];
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
      return board[0][i];
  }
  if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
    return board[0][0];
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[2][0] != ' ')
    return board[1][1];
  int j = 0;
  int flag = 0;
  for (i = 0; i < row; i++)
  {
    for (j = 0; j < col; j++)
    {
      if (board[i][j] == ' ')
        flag++;
    }
  }
  if (flag == 0)
    return 'Q';
  if (flag != 0)
    return 'C';
}
相关文章
|
6月前
|
C语言
以c语言为基础实现的简易三子棋
以c语言为基础实现的简易三子棋
40 1
|
6月前
|
C语言
c语言简单三子棋
c语言简单三子棋
|
6月前
|
算法 C语言 C++
【C语言实战项目】三子棋游戏
【C语言实战项目】三子棋游戏
59 1
|
6月前
|
C语言
C语言之三子棋小游戏
C语言之三子棋小游戏
|
6月前
|
C语言
用c语言实现三子棋
用c语言实现三子棋
26 0
|
5月前
|
C语言
【海贼王编程冒险 - C语言海上篇】C语言如何实现简单的三子棋游戏?
【海贼王编程冒险 - C语言海上篇】C语言如何实现简单的三子棋游戏?
28 1
|
6月前
|
C语言
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(二)
我们可以通过创建并定义符号常量NUMBER,来作为判断是否胜利的标准。如三子棋中,令NUMBER为3,则这八个方向中有任意一个方向达成3子连珠,则连珠的这个棋子所代表的玩家获胜。
62 1
|
6月前
|
算法 C语言 C++
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(一)
三子棋游戏设计的核心是对二维数组的把握和运用。
71 1
|
5月前
|
存储 C语言
三子棋(C语言版)
三子棋(C语言版)
|
6月前
|
编译器 C语言
【C语言入门小游戏】三子棋
【C语言入门小游戏】三子棋
51 0
【C语言入门小游戏】三子棋