C语言实现《三子棋》小游戏
1-需求分析
1️⃣ 游戏规则介绍: 双方轮流下子,直到三个子连成一条线,横、竖、斜线都可以,谁先达到这个要求就获胜,或者说棋盘满了,则游戏平局结束[1]。
2️⃣ 需求分析:
-
菜单界面必不可少,用户可以手动选择进行游戏或退出游戏
-
如果用户选择进行游戏,则需要打印出棋盘
-
玩家先下,下完打印出来方便观察
-
电脑后下,下完也得打印棋盘
-
要保证每一方下在可以下子的地方,需要对应的控制机制
-
每一方下完需要判断目前棋局状态,玩家赢了?电脑赢了?平局?还是应该游戏继续?
-
除非用户选择退出游戏,否则游戏应该可以一直玩。
通过上述模拟游戏的过程,可以总结出以下需求:
- 控制游戏可循环直到用户选择退出
- 菜单界面
- 接收用户输入,控制走向(进入游戏/退出游戏)
- 实时打印棋盘
- 接收用户输入转换为棋盘落子
- 电脑自动落子
- 判断棋局状态(谁赢?平局?继续)
2-准备工作
- test.c 执行主函数
- game.h 头文件,用于定义函数和常量
- game.c 用来完成各个函数功能
3-功能实现
- 进入游戏首先需要打印菜单
void menu()
{
printf("*********************\n");
printf("***** 1.play ****\n");
printf("***** 0.exit ****\n");
printf("*********************\n");
}
- do-while循环控制游戏可循环地玩,直到用户选择退出
do
{
//打印菜单
menu();
printf("Please enter your choice(1/0):>");
scanf("%d", &input);
switch(input)
{
case 1:
printf("Welcome!\n");
game();
break;
case 0:
printf("Exit.\n");
break;
default:
printf("Unvalidated input, please input again.\n");
break;
}
}while(input);
- 进入游戏之后,首先应该初始化一个棋盘,棋盘可以用二维数组表示,为了程序泛化性,可以在头文件game.h里指定棋盘地行数和列数,以防需要修改:
//定义符号
#define ROW 3
#define COL 3
//定义函数
//初始化棋盘
void Initboard(char board[ROW][COL], int row, int col);
初始化棋盘就是将数组值置为空格,在game.c里实现:
void Initboard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
- 接下来打印出棋盘
game.h 里定义:
//打印棋盘
void Printboard(char board[ROW][COL], int row, int col);
game.c里实现:
void Printboard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
- 用户玩:可以输入坐标,转化为数组下标,判断合法即打印出新棋盘,如果位置已经被占或者输入位置超出棋盘范围,需要提示并可以重新输入
game.h 里定义:
//玩家下
void Player(char board[ROW][COL], int row, int col);
game.c里实现:
void Player(char board[ROW][COL], int row, int col)
{
int x,y;
while(1)
{
printf("Please enter the coordinates:>");
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("The location is occupied, please re-enter.\n");
}
}else
{
printf("Invalid input, please enter again.\n");
}
}
}
- 电脑下:简单起见,直接随机生成坐标,判断合法即打印出新棋盘
game.h 里定义:
//电脑下
void Computer(char board[ROW][COL], int row, int col);
game.c里实现:
void Computer(char board[ROW][COL], int row, int col)
{
printf("Computer input:\n");
while(1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
有关生成随机数的rand函数需要搭配srand()一起用,方可实现真正的随机,详细内容可参考官方文件关于rand()函数的解释,也可以参考网上博客
使用随机数需要用到的标准库,在game.h里声明
#include <stdlib.h>
#include <time.h>
- 判断输赢的函数应该返回此时棋局状态,不妨进行如下设计:
game.h 里定义:
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
/*
返回值含义:
'*' -> 玩家赢
'#' -> 电脑赢
'Q' -> 平局
'C' -> 游戏继续
*/
game.c里实现:分情况逐一判断:
逐行判断有没有一行值相同且值不是空格,如果有则返回改行的值,该值即代表赢家(玩家下子用,电脑用#,所以如果返回则玩家赢)。
逐列判断,逻辑和上述行判断一样;
主对角线判断,同上述逻辑;
次对角线判断,同上述逻辑;
如果上述过程都没有返回值,再判断是否平局:此时棋盘被占满则返回Q(平局);
否则,返回C(继续游戏)。
char IsWin(char board[ROW][COL], int row, int col)
{
//判断行
int i = 0;
for (i = 0; i < row; i++)
{
int flag = 1;
int j = 0;
for (j = 0; j < col -1; j++)
{
if (board[i][j] != board[i][j+1])
{
flag = 0;
break;
}
}
if (flag == 1 && board[i][0] != ' ')
{
return board[i][0];
}
}
//判断列
for (i = 0; i < col; i++)
{
int flag = 1;
int j = 0;
for (j = 0; j < row -1; j++)
{
if (board[j][i] != board[j+1][i])
{
flag = 0;
break;
}
}
if (flag == 1 && board[0][i] != ' ')
{
return board[0][i];
}
}
//判断对角线
int flag = 1;
for (i = 0; i < row-1; i++)
{
if (board[i][i] != board[i+1][i+1])
{
flag = 0;
break;
}
}
if (flag == 1 && board[0][0] != ' ')
{
return board[0][0];
}
//对角线2
flag = 1;
int j = col - 1;
for (i = 0; i < row-1; i++, j--)
{
if (board[i][j] != board[i+1][j-1])
{
flag = 0;
break;
}
}
if (flag == 1 && board[0][col-1] != ' ')
{
return board[0][col-1];
}
//平局
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 'C'; //游戏继续
}
}
}
return 'Q'; //平局
}
- 主函数根据上述过程返回的棋局状态做出反应,继续游戏则继续进行下子-判断棋局-下子的循环过程,否则需要终止本局并打印最终棋盘:
void game()
{
//初始化棋盘
char board[ROW][COL];
Initboard(board,ROW,COL);
//打印棋盘
Printboard(board,ROW,COL);
char ret = 'C'; //记录棋局状态
while(1)
{
//玩家下
Player(board,ROW,COL);
Printboard(board,ROW,COL);
//判断赢家
ret = IsWin(board,ROW,COL);
if (ret != 'C')
{
break;
}
//电脑下
Computer(board,ROW,COL);
Printboard(board,ROW,COL);
//判断赢家
ret = IsWin(board,ROW,COL);
if (ret != 'C')
{
break;
}
//游戏继续
}
if (ret == '*') //玩家赢了
{
printf("======Player win!======\n");
Printboard(board,ROW,COL);
}else if (ret == '#') //电脑赢了
{
printf("======Computer win!======\n");
Printboard(board,ROW,COL);
}else if (ret == 'Q')//平局
{
printf("======Tie game.======\n");
Printboard(board,ROW,COL);
}
}
- 整合各个项目代码:
1-test.c
#include "game.h"
int main(int argc, char **argv)
{
srand((unsigned int)time(NULL));
void menu();
void game();
int input;
do
{
//打印菜单
menu();
printf("Please enter your choice(1/0):>");
scanf("%d", &input);
switch(input)
{
case 1:
printf("Welcome!\n");
game();
break;
case 0:
printf("Exit.\n");
break;
default:
printf("Unvalidated input, please input again.\n");
break;
}
}while(input);
return 0;
}
void menu()
{
printf("*********************\n");
printf("***** 1.play ****\n");
printf("***** 0.exit ****\n");
printf("*********************\n");
}
void game()
{
//初始化棋盘
char board[ROW][COL];
Initboard(board,ROW,COL);
//打印棋盘
Printboard(board,ROW,COL);
char ret = 'C'; //记录棋局状态
while(1)
{
//玩家下
Player(board,ROW,COL);
Printboard(board,ROW,COL);
//判断赢家
ret = IsWin(board,ROW,COL);
if (ret != 'C')
{
break;
}
//电脑下
Computer(board,ROW,COL);
Printboard(board,ROW,COL);
//判断赢家
ret = IsWin(board,ROW,COL);
if (ret != 'C')
{
break;
}
//游戏继续
}
if (ret == '*') //玩家赢了
{
printf("======Player win!======\n");
Printboard(board,ROW,COL);
}else if (ret == '#') //电脑赢了
{
printf("======Computer win!======\n");
Printboard(board,ROW,COL);
}else if (ret == 'Q')//平局
{
printf("======Tie game.======\n");
Printboard(board,ROW,COL);
}
}
2-game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义符号
#define ROW 3
#define COL 3
//定义函数
//初始化棋盘
void Initboard(char board[ROW][COL], int row, int col);
//打印棋盘
void Printboard(char board[ROW][COL], int row, int col);
//玩家下
void Player(char board[ROW][COL], int row, int col);
//电脑下
void Computer(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
/*
返回值含义:
'*' -> 玩家赢
'#' -> 电脑赢
'Q' -> 平局
'C' -> 游戏继续
*/
3-game.c
#include "game.h"
void Initboard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void Printboard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
void Player(char board[ROW][COL], int row, int col)
{
int x,y;
while(1)
{
printf("Please enter the coordinates:>");
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("The location is occupied, please re-enter.\n");
}
}else
{
printf("Invalid input, please enter again.\n");
}
}
}
void Computer(char board[ROW][COL], int row, int col)
{
printf("Computer input:\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++)
{
int flag = 1;
int j = 0;
for (j = 0; j < col -1; j++)
{
if (board[i][j] != board[i][j+1])
{
flag = 0;
break;
}
}
if (flag == 1 && board[i][0] != ' ')
{
return board[i][0];
}
}
//判断列
for (i = 0; i < col; i++)
{
int flag = 1;
int j = 0;
for (j = 0; j < row -1; j++)
{
if (board[j][i] != board[j+1][i])
{
flag = 0;
break;
}
}
if (flag == 1 && board[0][i] != ' ')
{
return board[0][i];
}
}
//判断对角线
int flag = 1;
for (i = 0; i < row-1; i++)
{
if (board[i][i] != board[i+1][i+1])
{
flag = 0;
break;
}
}
if (flag == 1 && board[0][0] != ' ')
{
return board[0][0];
}
//对角线2
flag = 1;
int j = col - 1;
for (i = 0; i < row-1; i++, j--)
{
if (board[i][j] != board[i+1][j-1])
{
flag = 0;
break;
}
}
if (flag == 1 && board[0][col-1] != ' ')
{
return board[0][col-1];
}
//平局
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 'C'; //游戏继续
}
}
}
return 'Q'; //平局
}
4-功能测试
点击即可查看
*********************
***** 1.play ****
***** 0.exit ****
*********************
Please enter your choice(1/0):>1
Welcome!
| |
---|---|---
| |
---|---|---
| |
Please enter the coordinates:>2 3
| |
---|---|---
| | *
---|---|---
| |
Computer input:
| |
---|---|---
| # | *
---|---|---
| |
Please enter the coordinates:>1 3
| | *
---|---|---
| # | *
---|---|---
| |
Computer input:
| | *
---|---|---
| # | *
---|---|---
| | #
Please enter the coordinates:>1 1
* | | *
---|---|---
| # | *
---|---|---
| | #
Computer input:
* | | *
---|---|---
# | # | *
---|---|---
| | #
Please enter the coordinates:>1 2
* | * | *
---|---|---
# | # | *
---|---|---
| | #
======Player win!======
* | * | *
---|---|---
# | # | *
---|---|---
| | #
*********************
***** 1.play ****
***** 0.exit ****
*********************
Please enter your choice(1/0):>1
Welcome!
| |
---|---|---
| |
---|---|---
| |
Please enter the coordinates:>3
3
| |
---|---|---
| |
---|---|---
| | *
Computer input:
| |
---|---|---
| | #
---|---|---
| | *
Please enter the coordinates:>2 2
| |
---|---|---
| * | #
---|---|---
| | *
Computer input:
| # |
---|---|---
| * | #
---|---|---
| | *
Please enter the coordinates:>1 1
* | # |
---|---|---
| * | #
---|---|---
| | *
======Player win!======
* | # |
---|---|---
| * | #
---|---|---
| | *
*********************
***** 1.play ****
***** 0.exit ****
*********************
Please enter your choice(1/0):>1
Welcome!
| |
---|---|---
| |
---|---|---
| |
Please enter the coordinates:>1 3
| | *
---|---|---
| |
---|---|---
| |
Computer input:
# | | *
---|---|---
| |
---|---|---
| |
Please enter the coordinates:>2 3
# | | *
---|---|---
| | *
---|---|---
| |
Computer input:
# | | *
---|---|---
# | | *
---|---|---
| |
Please enter the coordinates:>3 3
# | | *
---|---|---
# | | *
---|---|---
| | *
======Player win!======
# | | *
---|---|---
# | | *
---|---|---
| | *
*********************
***** 1.play ****
***** 0.exit ****
*********************
Please enter your choice(1/0):>1
Welcome!
| |
---|---|---
| |
---|---|---
| |
Please enter the coordinates:>2 2
| |
---|---|---
| * |
---|---|---
| |
Computer input:
| |
---|---|---
| * |
---|---|---
# | |
Please enter the coordinates:>1 2
| * |
---|---|---
| * |
---|---|---
# | |
Computer input:
| * | #
---|---|---
| * |
---|---|---
# | |
Please enter the coordinates:>2 3
| * | #
---|---|---
| * | *
---|---|---
# | |
Computer input:
| * | #
---|---|---
| * | *
---|---|---
# | | #
Please enter the coordinates:>2 1
| * | #
---|---|---
* | * | *
---|---|---
# | | #
======Player win!======
| * | #
---|---|---
* | * | *
---|---|---
# | | #
*********************
***** 1.play ****
***** 0.exit ****
*********************
Please enter your choice(1/0):>0
Exit.