【C语言】三子棋小游戏实现

1.三子棋实现步骤讲解

首先先想一想实现三子棋的必须物件
1.棋盘 2.两种棋子
棋盘可以使用 – 和 | 符号进行构建,玩家的棋子就用* 电脑的棋子就用@代替,建一个3*3的数组用来存储棋子
那么数组中的数据就是棋子,下棋的过程就是填充数组的过程

1.1游戏菜单

void Menu()                                                                                                 
{                                                                                                 
  printf("\n");                                                                                                 
  printf("welcome to the three chess game\n");                                                                                                 
  printf("-------------------------------\n");                                                                                                 
  printf("----1.Start         2.out------\n");                                                                                                                                          
  printf("-------------------------------\n");                                                                                                 
  printf("\n");                                                                                                 
}                     

先做一个简单的菜单

1.2初识化棋盘

void InitBoard(char board[ROW][COL], size_t row, size_t col)                                                                                                 
{                                                                                                 
  for (size_t i = 0; i < row; i++)                                                                                                 
  {                                                                                                 
    for (size_t j = 0; j < col; j++)                                                                                                 
    {                                                                                                 
      board[i][j] = ' ';                                                                                                 
    }                                                                                                 
  }                                                                                                 
}                  

初识化棋盘的原理就是清空数组中的数据,将其设置为看不见的 ’ ‘,便于之后填充数据

1.3打印棋盘

void DisplayBoard(char board[ROW][COL], size_t row, size_t col)
{
  for (size_t i = 0; i < row; i++)
  {
    printf("          ");//调整棋盘位置,处于整个游戏的中心
    for (size_t j = 0; j < col; j++)
    {                                                                                                 
      printf(" %c ", board[i][j]);                                                                                                 
      if (j < col -1)    //需要加上(列数-1)的|
      {                                                                                                 
        printf("|");                                                                                                 
      }                                                                                                                                                                                 
    }                                                                                                 
    printf("\n");                                                                                                 
    if (i < row -1)                                                                                                 
    {                                                                                                 
      printf("          ");                                                                                                 
      printf("-----------\n");                                                                                                 
    }                                                                                                 
  }                                                                                                 
  printf("\n\n");                                                                                                 
}                                                  

在这里插入图片描述

写完这两步就可以写一个小测试验证一下代码的正确性,可以对代码进行微调棋盘更美观

1.4玩家落子

调用的函数
size_t Celebrate(char board[ROW][COL], size_t row, size_t col);    //庆祝胜利
size_t IsFull(char board[ROW][COL], size_t row, size_t col)        //判断格子是否有子
void PlayerMove(char board[ROW][COL], size_t row, size_t col)
 56 {
 57   size_t my_row, my_col;
 58   printf("请先输入行再输入列:>");
 59   scanf("%lu%lu", &my_row, &my_col);
 60   while (my_row > row || my_col > col || !IsFull(board, my_row, my_col)) //检验坐标合法
 61   {
 62     printf("错误位置或位置已满,请重新输入\n");
 63     printf("请先输入行再输入列:>");
 64     scanf("%lu%lu", &my_row, &my_col);  //落子
 65   }
 66   board[my_row][my_col] = '*';
 67   DisplayBoard(board, row, col);  //打印棋盘
 68   Celebrate(board, row, col);    //检验输赢
 69 }

这里需要想一想玩家下棋会出现的几个现象。
检验坐标:首先输入坐标就可能产生越界,所以要判断坐标合法性,并且坐标中可能已经有棋。
打印棋盘:玩家下完棋对方(电脑)肯定想看对手下了那一步,所以要打印棋盘
判断对局情况:玩家落子后可能已经有三子连着,所以应该判断对局是否分出胜负、

1.5电脑落子

size_t IsFull(char board[ROW][COL], size_t row, size_t col)        //判断格子是否有子
void ComputerMove(char board[ROW][COL], size_t row, size_t col)
 72 {
 73   size_t c_row, c_col;
 74   c_row = rand() % 3;
 75   c_col = rand() % 3;
 76   while (!IsFull(board, c_row, c_col)) //检验坐标是否有棋
 77   {
 78     c_row = rand() % 3;
 79     c_col = rand() % 3;
 80   }
 81   board[c_row][c_col] = '@';
 82   DisplayBoard(board, row, col);
 83 }

我们可以使用随机数来帮电脑落子,rand()函数返回随机值
坐标合法:虽然随机数%3保证了坐标不会越界,但是可能随机的坐标位置已经有棋了所以还需检验
注意:使用rand()函数需要提前调用strand()函数,并用时间戳来充当strand函数的参数
这里我们没有使用Celebrate函数是因为游戏中我们将其放在while判断语句中

1.6判断获胜

三子棋有结局有三种,加上继续对局就是有四种状态。玩家获胜,电脑获胜,平局,对局继续
状态有点多通过两个函数来实现
函数一:

char IsWin(char board[ROW][COL], size_t row, size_t col)
{
  for (size_t i = 0; i < row; i++)  //三点成行获胜判断
  {
    size_t count_p = 0;         //计数器。判断每个玩家每一行有几个棋子
    size_t count_c = 0;
    for (size_t j = 0; j < col; j++)
    {
      if (board[i][j] == '*')    //玩家获胜返回 p 字符
      {
        count_p++;
      }
      if (board[i][j] == '@')
      {
        count_c++;               //电脑成行返回 c 字符
      }
    }
    if (count_p == 3)
    {
      return 'p';
    }
    if (count_c == 3)
    {
      return 'c';
    }

  }

  for (size_t i = 0; i < row; i++)   //三点成列判断
  {
    size_t count_p = 0;
    size_t count_c = 0;
    for (size_t j = 0; j < col; j++)
    {
      if (board[j][i] == '*')
      {
        count_p++;
      }
      if (board[j][i] == '@')
      {
        count_c++;
      }
    }
    if (count_p == 3)
    {
      return 'p';
    }
    if (count_c == 3)
    {
      return 'c';
    }

  }

  if (board[0][0] == '*' && board[1][1] == '*' && board[2][2] == '*') //三点成对角线判断
    return 'p';
  if (board[0][2] == '*' && board[1][1] == '*' && board[2][0] == '*')
    return 'p';
  if (board[0][0] == '@' && board[1][1] == '@' && board[2][2] == '@')
    return 'c';
  if (board[0][2] == '*' && board[1][1] == '*' && board[2][0] == '*')
    return 'c';
  size_t count = 0;                  //此时没有任何一方三子连线,可能棋盘格子已经下完,进行平局判断
  for (size_t i = 0; i < row; i++)
  {
    for(size_t j = 0; j < col; j++)
    {
      if (board[i][j] != ' ')
      {
        count++;
      }
    }
  }
  if (count == (row * col))
  {
    return 'o';                     //平局返回o字符
  }
  return 'v';                       //对局并未结束,继续对局返回v字符
}

IsWin函数通过返回四种不同的字符来表现对局状态,我们接下来会使用函数二接收函数一的返回值来进行庆祝判断

函数二:

size_t Celebrate(char board[ROW][COL], size_t row, size_t col)
{
  char ch = IsWin(board, row, col);  //接收IsWin返回值,产生获胜方或者平局对局都不需要继续
  if (ch == 'p')                     //返回0可以交给判断语句判断,结束游戏
  { 
    printf("Player win\n");
    return 0;
  }
  if (ch == 'c')
  {
    printf("Computer win\n");
    return 0;
  }
  if (ch == 'o')                    
  {
    printf("if ends in a draw\n");
    return 0;
  }
    return 1;                         //上面结束状态都没有进去,说明对局继续,返回1
}

接收函数一返回值进行对局状态判断,返回0和1判断结束游戏还是继续游戏

1.7游戏实现

void game()
{
  char board[ROW][COL];
  InitBoard(board, ROW, COL);
  DisplayBoard(board, ROW, COL);
  while (Celebrate(board, ROW, COL)) //我们电脑获胜条件放在这里,就不需要在电脑落子里判断了
  {
    PlayerMove(board, ROW, COL);
    ComputerMove(board, ROW, COL);
  }

}
void game_test()
{
  
  size_t chess = 0;
  do 
  {
    Menu();
    printf("请选择是否开始游戏:>");
    scanf("%lu", &chess);
    if (chess == 0)
    {
      break;    //退出循环
    }
    else if (chess == 1)
    {
      printf("game start\n");
      game();
    }
    else 
    {
      printf("输入错误请重新输入\n");
    }
    
  }while(1);
  
}

int main()
{
  srand((unsigned int)time(NULL));  //使用rand()函数的前提条件
  game_test();
  return 0;

}

这里基本没什么问题,有一些需要注意的地方已经在代码中标注出来了。

2.三子棋源代码

2.1Makefile

test:test.o game.o
		gcc -o $@ $^ -std=c99
test.o:test.c
		gcc -c $< -std=c99 
game.o:game.c
		gcc -c $< -std=c99
.PHONY:clean
clean:
		rm -f ./*.o test

2.2game.h

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

void Menu();
void InitBoard(char board[ROW][COL], size_t row, size_t col);      //初始化棋盘
void DisplayBoard(char board[ROW][COL], size_t row, size_t col);   //打印棋盘
size_t IsFull(char board[ROW][COL], size_t row, size_t col)        //判断格子是否有子
void PlayerMove(char board[ROW][COL], size_t row, size_t col);     //玩家落子
void ComputerMove(char board[ROW][COL], size_t row, size_t col);   //电脑落子
char IsWin(char board[ROW][COL], size_t row, size_t col);          //判断对局情况
size_t Celebrate(char board[ROW][COL], size_t row, size_t col);    //庆祝胜利

2.3game.c

#include "game.h"

void Menu()
{
  printf("\n");
  printf("welcome to the three chess game\n");
  printf("-------------------------------\n");
  printf("----1.Start         2.out------\n");
  printf("-------------------------------\n");
  printf("\n");
}
void InitBoard(char board[ROW][COL], size_t row, size_t col)
{
  for (size_t i = 0; i < row; i++)
  {
    for (size_t j = 0; j < col; j++)
    {
      board[i][j] = ' ';
    }
  }
}
void DisplayBoard(char board[ROW][COL], size_t row, size_t col)
{
  for (size_t i = 0; i < row; i++)
  {
    printf("          ");
    for (size_t j = 0; j < col; j++)
    {
      printf(" %c ", board[i][j]);
      if (j < col -1)
      {
        printf("|");
      }
    }
    printf("\n");
    if (i < row -1)
    {
      printf("          ");
      printf("-----------\n");
    }
  }
  printf("\n\n");
}
size_t IsFull(char board[ROW][COL], size_t row, size_t col)
{
  if (board[row][col] == ' ')
  {
    return 1;
  }
  else 
  {
    return 0;
  }
}
void PlayerMove(char board[ROW][COL], size_t row, size_t col)
{
  size_t my_row, my_col;
  printf("请先输入行再输入列:>");
  scanf("%lu%lu", &my_row, &my_col);
  while (my_row > row || my_col > col || !IsFull(board, my_row, my_col))
  {
    printf("错误位置或位置已满,请重新输入\n");
    printf("请先输入行再输入列:>");
    scanf("%lu%lu", &my_row, &my_col);
  }
  board[my_row][my_col] = '*';
  DisplayBoard(board, row, col);
  Celebrate(board, row, col);
}

void ComputerMove(char board[ROW][COL], size_t row, size_t col)
{
  size_t c_row, c_col;
  c_row = rand() % 3;
  c_col = rand() % 3;
  while (!IsFull(board, c_row, c_col))
  {
    c_row = rand() % 3;
    c_col = rand() % 3;
  }
  board[c_row][c_col] = '@';
  DisplayBoard(board, row, col);
}
char IsWin(char board[ROW][COL], size_t row, size_t col)
{
  for (size_t i = 0; i < row; i++)
  {
    size_t count_p = 0;
    size_t count_c = 0;
    for (size_t j = 0; j < col; j++)
    {
      if (board[i][j] == '*')
      {
        count_p++;
      }
      if (board[i][j] == '@')
      {
        count_c++;
      }
    }
    if (count_p == 3)
    {
      return 'p';
    }
    if (count_c == 3)
    {
      return 'c';
    }

  }

  for (size_t i = 0; i < row; i++)
  {
    size_t count_p = 0;
    size_t count_c = 0;
    for (size_t j = 0; j < col; j++)
    {
      if (board[j][i] == '*')
      {
        count_p++;
      }
      if (board[j][i] == '@')
      {
        count_c++;
      }
    }
    if (count_p == 3)
    {
      return 'p';
    }
    if (count_c == 3)
    {
      return 'c';
    }

  }

  if (board[0][0] == '*' && board[1][1] == '*' && board[2][2] == '*')
    return 'p';
  if (board[0][2] == '*' && board[1][1] == '*' && board[2][0] == '*')
    return 'p';
  if (board[0][0] == '@' && board[1][1] == '@' && board[2][2] == '@')
    return 'c';
  if (board[0][2] == '*' && board[1][1] == '*' && board[2][0] == '*')
    return 'c';
  size_t count = 0;
  for (size_t i = 0; i < row; i++)
  {
    for(size_t j = 0; j < col; j++)
    {
      if (board[i][j] != ' ')
      {
        count++;
      }
    }
  }
  if (count == (row * col))
  {
    return 'o';
  }
  return 'v';
}


size_t Celebrate(char board[ROW][COL], size_t row, size_t col)
{
  char ch = IsWin(board, row, col);
  if (ch == 'p')
  {
    printf("Player win\n");
    return 0;
  }
  if (ch == 'c')
  {
    printf("Computer win\n");
    return 0;
  }
  if (ch == 'o')
  {
    printf("if ends in a draw\n");
    return 0;
  }
    return 1;
}

2.4test.c

void test_1()
{
  char board[ROW][COL]; 
  Menu();
  InitBoard(board, ROW, COL);
  DisplayBoard(board, ROW, COL);
  PlayerMove(board, ROW, COL);
  ComputerMove(board, ROW, COL);
  PlayerMove(board, ROW, COL);
  PlayerMove(board, ROW, COL);
  PlayerMove(board, ROW, COL);
}
void game()
{
  char board[ROW][COL];
  InitBoard(board, ROW, COL);
  DisplayBoard(board, ROW, COL);
  while (Celebrate(board, ROW, COL))
  {
    PlayerMove(board, ROW, COL);
    ComputerMove(board, ROW, COL);
  }

}
void game_test()
{
  
  size_t chess = 0;
  do 
  {
    Menu();
    printf("请选择是否开始游戏:>");
    scanf("%lu", &chess);
    if (chess == 0)
    {
      break;
    }
    else if (chess == 1)
    {
      printf("game start\n");
      game();
    }
    else 
    {
      printf("输入错误请重新输入\n");
    }
    
  }while(1);
  
}

int main()
{
  srand((unsigned int)time(NULL));
  game_test();
  return 0;

}

以上即是【C语言】三子棋小游戏实现的全部内容,感谢观看。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白在进击

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值