C语言经典游戏——三子棋

简介: 平时我们在编写代码时只会创建一个.c文件,但是将代码编写在同一个.c文件中会显得没有任何条理。我们可以通过创建多个.c文件,使我们的代码更加有逻辑性和条理性。

问题描述

用c语言实现三子棋

基本思路

  1. 简简单单的菜单
  2. 菜单功能:a、玩游戏 b、退出游戏
  3. 进入游戏
  4. 创建并初始化棋盘
  5. 打印数组
  6. 玩家下棋(*表示玩家下棋)
  7. 判断玩家是否胜利
  8. 电脑下棋(#)
  9. 判断电脑是否胜利
  10. 判断是否平局

实现过程

平时我们在编写代码时只会创建一个.c文件,但是将代码编写在同一个.c文件中会显得没有任何条理。我们可以通过创建多个.c文件,使我们的代码更加有逻辑性和条理性。

因此我们在创建工程时创建两个.c文件,一个头文件。

test.c用于调试程序

game.c用于实现游戏过程

game.h用于函数头文件的引用以及函数的声明。

1、简简单单的一个菜单

void menu()
{
  printf("********************************\n");
  printf("*     经典小游戏——三子棋        *\n");
  printf("********************************\n");
  printf("*           1、Play            *\n");
  printf("*           0、Exit            *\n");
  printf("********************************\n");
}

选择1,进入三子棋游戏

2、棋盘初始化

玩游戏首先得要有棋盘,最简单的是3X3棋盘

void InitChessBoard()
{
  for (int i = 0; i < 3; ++i)
  {
    for (int j = 0; j < 3; ++j)
    {
      board[i][j] = ' ';
    }
  }
}

这样就可以得到一个3X3的空间,但是当我们需要更大 的棋盘时,我们需要将所有代码中的3进行修改,这是一个巨大的工程量。因此我们在头文件中定义两个宏变量,用于棋盘长宽的设置。

game.h
#define ROW 3  //ROW代表长
#define COL 3  //COL代表宽

因此代码可改为

void InitChessBoard()
{
  for (int i = 0; i < ROW; ++i)
  {
    for (int j = 0; j < COL; ++j)
    {
      board[i][j] = ' ';
    }
  }
}

因此代码可改为

void InitChessBoard()
{
  for (int i = 0; i < ROW; ++i)
  {
    for (int j = 0; j < COL; ++j)
    {
      board[i][j] = ' ';
    }
  }
}

在后面的代码中,我们就直接用这两个宏变量代表长宽。当我们需要修改时直接在头文件中进行修改。避免了在修改时出现不必要的麻烦。

3、打印棋盘

444e65a53829e1d8aff0cfab3a6e9aa.png

这个我们每个人都很熟悉,但是我们如何将其出现在程序中呢?

void PrintChessBoard()
{
  for (int i = 0; i < ROW; ++i)
  {
    for (int j = 0; j < COL; ++j)
    {
      printf("%c ", board[i][j]);
      if (j < ROW - 1)
      {
        printf(" |");
      }
    }
    printf("\n");
    if (i < ROW - 1)
    {
      for (int j = 0; j < COL; ++j)
      {
        printf("---");
        if (j < COL - 1)
        {
          printf("|");
        }
      }
      printf("\n");
    }
  }
}

0fc28908edea8d0887b0583ced2e793.png

为此,我们打印出这样的棋盘。

3、玩家下棋

玩家输入相应的坐标,首先判断所输入的坐标是否有效,有效后,输入的坐标是否被占用。最后再进行落子。

void PlayerMove()
{
  int x, y;
  printf("玩家下棋\n");
  while (1)
  {
    printf("玩家输入坐标:>");
    scanf("%d %d", &x, &y);
    //判断合法性
    if (x <= ROW + 1 && y <= COL + 1 && x >= 1 && y >= 1)
    {
      //判断输入的是否被占用
      if (board[x - 1][y - 1] == ' ')
      {
        board[x - 1][y - 1] = '*';
        break;
      }
      else
      {
        printf("坐标被占用,请重新输入\n");
      }
    }
    else
    {
      printf("输入无效,请重新输入...\n");
    }
  }
}

因为棋盘是个二维数组,数组的初始下标是0,但我们习惯性的会认为是1.因此在进行坐标的判断时将x、y坐标-1进行判断。

4电脑下棋

和玩家下棋一样,但是少去了坐标输入的过程。但是电脑下棋也需要坐标,如何生成呢?

game.h
#include<stdlib.h>
#include<time.h>
srand((unsigned)time(NULL));
int x = rand() % ROW;
int y = rand() % COL;
void ComputerMove()
{
  printf("电脑下棋\n");
  while (1)
  {
    int x = rand() % ROW;
    int y = rand() % COL;
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }
  }
}

5、判断棋盘状态

玩家电脑下完棋后,我们的判断一下是否有获胜的一方。如果有则返回胜利者所下的棋子,没有判断一下棋盘空间是否有剩余,有剩余继续下棋,反之,平局。

//判断是否全满
int IsFull()
{
  for (int i = 0; i < ROW; ++i)
  {
    for (int j = 0; j < COL; ++j)
    {
      if (board[i][j] == ' ')
        return 0;
    }
  }
  return 1;
}
//判断状态
char IsWin()
{
  //判断三行
  for (int i = 0; i < ROW; ++i)
  {
    if (board[0][i]== board[1][i] && board[1][i]== board[2][i] && board[2][i]!=' ')
    {
      return board[1][i];
    }
  }
  //判断三列
  for (int j = 0; j < COL; ++j)
  {
    if (board[j][0] == board[j][1] && board[j][1]== board[j][2] && board[j][2]!=' ')
    {
      return board[j][1];
    }
  }
  //判断对角线
  if (board[0][0]== board[1][1] && board[1][1]== board[2][2] && board[2][2]!=' ')
  {
    return board[1][1];
  }
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
  {
    return board[0][2];
  }
  //判断棋盘是否全满
  int res = IsFull();
  if (res == 1)
  {
    return 'Q';
  }
  return 'C';
}

以上为游戏功能的实现。

游戏功能实现的全过程

void Play()
{
  //初始化棋盘
  InitChessBoard();
  //打印棋盘
  PrintChessBoard();
  char ret=0;
  while (1)
  {
    //玩家下棋
    PlayerMove();
    ret = IsWin();
    if (ret != 'C')
    {
      break;
    }
    //电脑下棋
    ComputerMove();
    PrintChessBoard();
    ret = IsWin();
    if (ret != 'C')
    {
      break;
    }
  }
  //状态判断
  if (ret == '*')
  {
    printf("玩家获胜\n");
  }
  else if (ret == '#')
  {
    printf("电脑获胜\n");
  }
  else
  {
    printf("平局\n");
  }
  PrintChessBoard();
}

好了,以上为整个游戏的全部功能以及实现过程。

由于没有给电脑下棋实现判断方法,电脑下棋是随机的。

以下为整个程序的完整代码:

game.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//
void InitChessBoard();
void PrintChessBoard();
void PlayerMove();
void ComputerMove();
char IsWin();

game.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
static board[ROW][COL];
//初始化棋盘
void InitChessBoard()
{
  for (int i = 0; i < ROW; ++i)
  {
    for (int j = 0; j < COL; ++j)
    {
      board[i][j] = ' ';
    }
  }
}
//打印棋盘
void PrintChessBoard()
{
  for (int i = 0; i < ROW; ++i)
  {
    for (int j = 0; j < COL; ++j)
    {
      printf("%c ", board[i][j]);
      if (j < ROW - 1)
      {
        printf(" |");
      }
    }
    printf("\n");
    if (i < ROW - 1)
    {
      for (int j = 0; j < COL; ++j)
      {
        printf("---");
        if (j < COL - 1)
        {
          printf("|");
        }
      }
      printf("\n");
    }
  }
}
//玩家下棋
void PlayerMove()
{
  int x, y;
  printf("玩家下棋\n");
  while (1)
  {
    printf("玩家输入坐标:>");
    scanf("%d %d", &x, &y);
    //判断合法性
    if (x <= ROW + 1 && y <= COL + 1 && x >= 1 && y >= 1)
    {
      //判断输入的是否被占用
      if (board[x - 1][y - 1] == ' ')
      {
        board[x - 1][y - 1] = '*';
        break;
      }
      else
      {
        printf("坐标被占用,请重新输入\n");
      }
    }
    else
    {
      printf("输入无效,请重新输入...\n");
    }
  }
}
//电脑下棋
void ComputerMove()
{
  printf("电脑下棋\n");
  while (1)
  {
    int x = rand() % ROW;
    int y = rand() % COL;
    if (board[x][y] == ' ')
    {
      board[x][y] = '#';
      break;
    }
  }
}
//判断是否全满
int IsFull()
{
  for (int i = 0; i < ROW; ++i)
  {
    for (int j = 0; j < COL; ++j)
    {
      if (board[i][j] == ' ')
        return 0;
    }
  }
  return 1;
}
//判断状态
char IsWin()
{
  //判断三行
  for (int i = 0; i < ROW; ++i)
  {
    if (board[0][i]== board[1][i] && board[1][i]== board[2][i] && board[2][i]!=' ')
    {
      return board[1][i];
    }
  }
  //判断三列
  for (int j = 0; j < COL; ++j)
  {
    if (board[j][0] == board[j][1] && board[j][1]== board[j][2] && board[j][2]!=' ')
    {
      return board[j][1];
    }
  }
  //判断对角线
  if (board[0][0]== board[1][1] && board[1][1]== board[2][2] && board[2][2]!=' ')
  {
    return board[1][1];
  }
  if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
  {
    return board[0][2];
  }
  //判断棋盘是否全满
  int res = IsFull();
  if (res == 1)
  {
    return 'Q';
  }
  return 'C';
}

test.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void Play()
{
  //初始化棋盘
  InitChessBoard();
  //打印棋盘
  PrintChessBoard();
  char ret=0;
  while (1)
  {
    //玩家下棋
    PlayerMove();
    ret = IsWin();
    if (ret != 'C')
    {
      break;
    }
    //电脑下棋
    ComputerMove();
    PrintChessBoard();
    ret = IsWin();
    if (ret != 'C')
    {
      break;
    }
  }
  //状态判断
  if (ret == '*')
  {
    printf("玩家获胜\n");
  }
  else if (ret == '#')
  {
    printf("电脑获胜\n");
  }
  else
  {
    printf("平局\n");
  }
  PrintChessBoard();
}
void menu()
{
  printf("********************************\n");
  printf("*     经典小游戏——三子棋     *\n");
  printf("********************************\n");
  printf("*           1、Play            *\n");
  printf("*           0、Exit            *\n");
  printf("********************************\n");
}
int main()
{
  srand((unsigned)time(NULL));
  int input;
  do
  {
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      Play();
      break;
    case 0:
      printf("退出游戏...\n");
      break;
    default:
      printf("选择错误,请重新选择....\n");
      break;
    }
  }
  while (input);
}


目录
相关文章
|
1月前
|
C语言
扫雷游戏(用C语言实现)
扫雷游戏(用C语言实现)
100 0
|
3月前
|
机器学习/深度学习 C语言
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
【8月更文挑战第5天】本篇文章用C语言采用多文件编写实现了一个基础的扫雷游戏(附源码),并讲解了关于函数递归的基础概念及其相对应的习题练习(附源码)
42 1
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
|
15天前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
27 1
|
4月前
|
存储 C语言 开发者
C语言实战 | Flappy Bird游戏
【7月更文挑战第4天】Flappy Bird是由越南开发者制作的简单却极具挑战性的游戏,玩家需控制小鸟穿越水管障碍。游戏涉及角色初始化、显示和更新。小鸟和水管结构体存储数据,使用变量和数组。初始化小鸟和水管,显示背景、小鸟和水管,更新小鸟位置及碰撞检测。代码示例展示了小鸟和水管的状态管理,当小鸟与管道碰撞或触地时,游戏结束。游戏的成功在于其独特的虐心体验。
79 0
C语言实战 | Flappy Bird游戏
|
1月前
|
编译器 C语言
猜数字游戏实现#C语言
猜数字游戏实现#C语言
84 1
|
1月前
|
存储 C语言
揭秘C语言:泊舟的猜数字游戏
揭秘C语言:泊舟的猜数字游戏
|
1月前
|
存储 算法 安全
C语言实现扫雷游戏
C语言实现扫雷游戏
|
1月前
|
算法 编译器 C语言
【C语言】实现猜数字游戏(分支语句与循环语句的运用)
【C语言】实现猜数字游戏(分支语句与循环语句的运用)
|
1月前
|
C语言
初学者指南:使用C语言实现简易版扫雷游戏
初学者指南:使用C语言实现简易版扫雷游戏
37 0
|
1月前
|
C语言
C语言扫雷游戏(详解)
C语言扫雷游戏(详解)
40 0