【C语言】自定义棋盘大小实现三子棋

简介: 【C语言】自定义棋盘大小实现三子棋

一、整个程序的实现思路及设计

实现思路

1.打印一个简单的菜单供玩家选择如下:

2.玩家下棋

3.电脑下棋

4.判断输赢

5.循环菜单是否要继续游戏

使用多文件的方式编写

  • test.c文件游戏的框架
  • game.c文件游戏的实现
  • game.h文件游戏函数的声明

二、test.c文件的设计

在主函数(main)中的设计

int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      //printf("三子棋\n");
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("请输入合理的选择\n");
      break;
    }
  } while (input);
  return 0;
}

使用menu()函数来打印菜单;

void menu()
{
  printf("***********************************\n");
  printf("************    1.paly     ********\n");
  printf("************    0.exit     ********\n");
  printf("***********************************\n");
}

使用do…while循环打印菜单;

使用srand()函数来随机生成电脑下的棋子;

使用switch根据玩家的选择来进行不同的实现;

游戏的实现放在game函数中;

void game()
{
  //char board[3][3] = { 0 };
  初始化棋盘
  //InitBoard(board, 3, 3);
  //定义一个数组用来存放数据
  char board[ROW][COL] = { 0 };
  //初始化棋盘
  InitBoard(board, ROW, COL);
  //打印棋盘
  DispalyBoard(board, ROW, COL);
  char ret = '0';
  while (1)
  {
    //玩家下棋
    PlayerMove(board, ROW, COL);
    //打印棋盘
    DispalyBoard(board, ROW, COL);
    ret=IsWin(board, ROW, COL);
    if (ret!='c')
    {
      break;
    }
    //电脑下棋
    ComputerMove(board, ROW, COL);
    //打印棋盘
    DispalyBoard(board, ROW, COL);
    ret=IsWin(board, ROW, COL);
    if (ret != 'c')
    {
      break;
    }
  }
  if (ret=='*')
  {
    printf("玩家赢\n");
  }
  else if (ret == '#')
  {
    printf("电脑赢\n");
  }
  else
  {
    printf("平局\n");
  }
}

整个test.c文件的代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
  printf("***********************************\n");
  printf("************    1.paly     ********\n");
  printf("************    0.exit     ********\n");
  printf("***********************************\n");
}
void game()
{
  //char board[3][3] = { 0 };
  初始化棋盘
  //InitBoard(board, 3, 3);
  //定义一个数组用来存放数据
  char board[ROW][COL] = { 0 };
  //初始化棋盘
  InitBoard(board, ROW, COL);
  //打印棋盘
  DispalyBoard(board, ROW, COL);
  char ret = '0';
  while (1)
  {
    //玩家下棋
    PlayerMove(board, ROW, COL);
    //打印棋盘
    DispalyBoard(board, ROW, COL);
    ret=IsWin(board, ROW, COL);
    if (ret!='c')
    {
      break;
    }
    //电脑下棋
    ComputerMove(board, ROW, COL);
    //打印棋盘
    DispalyBoard(board, ROW, COL);
    ret=IsWin(board, ROW, COL);
    if (ret != 'c')
    {
      break;
    }
  }
  if (ret=='*')
  {
    printf("玩家赢\n");
  }
  else if (ret == '#')
  {
    printf("电脑赢\n");
  }
  else
  {
    printf("平局\n");
  }
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    menu();
    printf("请选择:>");
    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.h文件的设计

此文件主要用来声明函数如下:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//版本一没有使用对象宏来定义,以后修改更加的麻烦,
//void InitBoard(char board[3][3], int row, int col);
//初始化棋盘,放置空格
void InitBoard(char board[ROW][COL], int row, int col);
//声明打印棋盘的函数
void DispalyBoard(char board[ROW][COL], int row, int col);
//声明玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//声明玩家下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL],int row,int col);

四、game.c文件的设计

1.使用InitBoard()函数初始化棋盘

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] = ' ';
    }
  }
}

2.使用DispalyBoard()函数打印棋盘

版本一:

void DispalyBoard(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]);
    }
    printf("\n");
  }
}

版本二:

void DispalyBoard(char board[ROW][COL], int row, int col)
{
  int i = 0;
  for (i = 0; i < row; i++)
  {
    //打印数据
    printf(" %c | %c | %c ", board[i][0], board[i][1], board[i][2]);
    printf("\n"); 
    //打印分割行
    if (i<row-1)
    {
      printf("---|---|---");
      printf("\n");
    }
  }
}

版本三:

void DispalyBoard(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)
    {
      int j = 0;
      for ( j = 0; j < col; j++)
      {
        printf("---");
        //最后一个|不打印所以也需要判断
        if (j<col-1)
        {
          printf("|");
        }
      }
      printf("\n");
    }
  }
}

就以上三个版本来说:

我觉得最好的就是第三个版本,因为要是想改变棋盘的大小只需要在game.h中修改对象宏的大小即可,前两个版本都有一定的缺陷,我建议使用第三个版本来实现棋盘的打印,这样可以使代码的可读性和后期的修改更好。

3.使用PlayerMove()函数实现玩家下棋

void PlayerMove(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  printf("请输入坐标:\n");
  while (1)
  {
    printf("玩家请输入,左边使用空格隔开:>");
    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");
    }
  }
}

以上的代码进行了两次判断:

  • 第一次是判断坐标输入是否合法(也就是坐标是否在棋盘的范围)
  • 第二次是判断坐标是否被占用,要是被占用就使用循环重新输入;

4.使用ComputerMove()函数实现电脑下棋

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

其中使用了rand()函数它的作用是生成随机的值

  • 使用rand()%row是来控制随机值的大小
  • 同时还要再主函数中使用srand()函数来声明
  • 再game.h头文件中还要引用两个头文件(stdlib.h和time.h)

5.使用IsWin()函数实现结果的判断

版本一:

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][0]!=' ')
    {
      return board[i][0];
    }
  }
  //列
  for (i = 0; i < col; i++)
  {
    if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    {
      return board[0][i];
    }
  }
  //对角线
  if (board[0][0]== board[1][1]&& board[1][1]== board[2][2]&&board[0][0]!=' ')
  {
    return board[0][0];
  }
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
  {
    return board[1][1];
  }
  //平局
  if (IsFull(board,row,col)==1)
  {
    return 'Q';
  }
  //继续
  return 'c';
}

版本二:

char IsWin(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++) {
      //不为空字符进入判断
      if (board[i][j] != ' ') {
        //如果列上连续的三个值相等就返回,注意j+2不能超过列
        if (j < col - 2 && board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2]) {
          return board[i][j];
        }
        //如果行上连续的三个值相等就返回,注意i+2不能超过行
        else if (i < col - 2 && board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j]) {
          return board[i][j];
        }
        //如果左斜线上连续的三个值相等就返回
        else if (i < row - 2 && j < col - 2 && board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2]) {
          return board[i][j];
        }
        //如果右斜线上连续的三个值相等就返回
        else if (i >= 2 && j <= i && board[i][j] == board[i - 1][j + 1] && board[i - 1][j + 1] == board[i - 2][j +2]) {
          return board[i][j];
        }
      }
    }
  }
  //平局
  if (IsFull(board, row, col) == 1)
  {
    return 'Q';
  }
  //继续
  return 'c';
}

以上的两个版本我更加喜欢第二个版本:

  • 当棋盘的大小改变的时候,也可以进行判断不需要再次修改代码
  • 版本一只适合3*3的棋盘

综上考虑个人觉得第二个版本更加的好

6.使用IsFull()函数判断棋盘是否下满

int IsFull(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++)
    {
      if (board[i][j]==' ')
      {
        return 0;
      }
    }
  }
  return 1;
}

下面是game.c完整的代码:

#define _CRT_SECURE_NO_WARNINGS 1
#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] = ' ';
    }
  }
}
//版本1
//void DispalyBoard(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]);
//    }
//    printf("\n");
//  }
//}
//版本二
//void DispalyBoard(char board[ROW][COL], int row, int col)
//{
//  int i = 0;
//  for (i = 0; i < row; i++)
//  {
//    打印数据
//    printf(" %c | %c | %c ", board[i][0], board[i][1], board[i][2]);
//    printf("\n"); 
//    打印分割行
//    if (i<row-1)
//    {
//      printf("---|---|---");
//      printf("\n");
//    }
//    
//  }
//}
//版本三
void DispalyBoard(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)
    {
      int j = 0;
      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;
  printf("请输入坐标:\n");
  while (1)
  {
    printf("玩家请输入,左边使用空格隔开:>");
    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 ComputerMove(char board[ROW][COL], int row, int col)
{
  int x = 0;
  int y = 0;
  x = rand() % row;
  y = rand() % col;
  printf("电脑下棋\n");
  while (1)
  {
    if (board[x][y]==' ')
    {
      board[x][y] = '#';
      break;
    }
  }
}
//判断棋盘是否下满
int IsFull(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++)
    {
      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++) {
    int j = 0;
    for (j = 0; j < col; j++) {
      //不为空字符进入判断
      if (board[i][j] != ' ') {
        //如果列上连续的三个值相等就返回,注意j+2不能超过列
        if (j < col - 2 && board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2]) {
          return board[i][j];
        }
        //如果行上连续的三个值相等就返回,注意i+2不能超过行
        else if (i < col - 2 && board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j]) {
          return board[i][j];
        }
        //如果左斜线上连续的三个值相等就返回
        else if (i < row - 2 && j < col - 2 && board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2]) {
          return board[i][j];
        }
        //如果右斜线上连续的三个值相等就返回
        else if (i >= 2 && j <= i && board[i][j] == board[i - 1][j + 1] && board[i - 1][j + 1] == board[i - 2][j +2]) {
          return board[i][j];
        }
      }
    }
  }
  //平局
  if (IsFull(board, row, col) == 1)
  {
    return 'Q';
  }
  //继续
  return 'c';
}


相关文章
|
2月前
|
算法 C语言
【C语言】三子棋游戏实现代码
【C语言】三子棋游戏实现代码
【C语言】三子棋游戏实现代码
|
4月前
|
C语言
C语言之详解数组【附三子棋和扫雷游戏实战】(二)
C语言之详解数组【附三子棋和扫雷游戏实战】(二)
|
7月前
|
C语言
|
7月前
|
C语言
C语言三子棋解析
C语言三子棋解析
24 0
|
7月前
|
算法 C语言
【C语言实现三子棋游戏】
【C语言实现三子棋游戏】
25 0
|
4月前
|
存储 编译器 C语言
C语言之详解数组【附三子棋和扫雷游戏实战】(一)
C语言之详解数组【附三子棋和扫雷游戏实战】(一)
|
9月前
|
C语言
C语言实现三子棋(详解版)(二)
C语言实现三子棋(详解版)
|
5月前
|
C语言
c语言之三子棋游戏
c语言之三子棋游戏
30 0
|
5月前
|
C语言
【三子棋】用C语言简单实现三子棋
【三子棋】用C语言简单实现三子棋
|
6月前
|
C语言
C语言之三子棋游戏实现篇
C语言之三子棋游戏实现篇
54 0