三子棋游戏又叫井字棋游戏,是很多人小时候都玩过的一种小游戏,游戏的玩法是两名玩家在三行三列的九个格子子里依次下棋,若一方的棋子有三个在横、竖,斜线三种中的任何一种连成一条线就获得游戏胜利。接下来就让我们看看如何用c语言来实现这个简单的小游戏吧!
首先就是需要设计一个简单的菜单来供玩家选择,这个利用printf函数就可以简单的实现了:
void Show() {//打印选择界面
printf("--------------------------------\n");
printf("--------欢迎来到三子棋游戏------\n");
printf("--------1.PLAY 0.EXIT------\n");
printf("--------------------------------\n");
}
其次,可以选择利用switch语句来根据玩家的选择调用游戏函数或者退出程序:
void Tic_Tac_Toe() {
int choice = 0;
srand((int)time(NULL));//随机数种子
while (1) {
Show();//打印菜单
printf("请输入你的选择:");
scanf("%d", &choice);
switch (choice) {
case 0:
printf("再见!\n");
return;
case 1:
game();
break;
default:
printf("输入错误!请重新输入!\n");
}
}
}
那么接下来,就是对游戏函数的设计了。考虑到三子棋游戏的特点,我们可以利用一个3x3的二维数组来实现棋盘的打印和棋子的保存,为了方便后续可以对游戏进行扩展,这里我们可以把数组的行列用宏常量来代替:
#define ROW 3
#define COL 3
void Init_Board(int 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 Board(int board[ROW][COL], int row, int col) {//打印棋盘
system("cls");
for (int i = 0; i < row; i++) {
printf(" %c | %c | %c \n", board[i][0], board[i][1],board[i][2]);
if (i != row - 1) {
printf("---|---|---\n");
}
}
}
接下来,就是要实现下棋操作了,这里分为两种,玩家下棋和电脑AI下棋,首先我们来实现玩家下棋:
通过玩家输入的下棋位置,在对应位置保存并打印玩家的棋子 ,这里用O表示玩家棋子,当然前提是玩家输入的位置合法并且当前位置没有其他棋子,所以要先对玩家输入的下棋位置进行一个合法性和是否已经有棋子进行判断,代码实现如下:
void Player(int board[ROW][COL], int row, int col, int* x, int* y) {//玩家下棋
while (1) {
printf("请输入下棋位置:");
scanf("%d %d", x, y);
*x = *x - 1;
*y = *y - 1;
if (*x < 0 || *x>2 || *y < 0 || *y>2) {
printf("输入位置不合法!请重新输入!\n");
continue;
}
if (board[*x][*y] != ' ') {
printf("位置已被占用!请重新输入!\n");
continue;
}
board[*x][*y] = 'O';
break;
}
}
同理,电脑AI下棋的实现原理大致是相同的,唯一的区别就是需要电脑进行随机下棋,这里我们可以通过产生随机数的方式并对行列分别求余来得到电脑下棋位置,实现如下(电脑棋子为X):
void AI_Player(int board[ROW][COL], int row, int col, int* x, int* y) {//电脑下棋
while (1) {
*x = rand() % row;
*y = rand() % col;
if (board[*x][*y] != ' ') {
continue;
}
board[*x][*y] = 'X';
break;
}
}
下棋操作实现后,我们就需要写对应的函数来判断游戏是否结束了,结束的条件自然是玩家赢了、电脑AI赢了,和平局三种情况。如果某一方下棋后,产生了三子连线,则说明该玩家获胜了,若果棋子已经下满了棋盘,仍没有三子连线产生,则说明平局了,所以每一次下棋后,我们都需要对这两种情况进行判断。
首先我们来分析第一种情况,落棋者赢了,说明落棋位置行、正斜,或反斜至少其中一种成功三子连线,那么我们可以先设置一个标志count,通过判断对应位置的棋子与该棋子是否相同,相同则count加一,最后如果count大于等于三,则说明成功三子连线,该玩家获胜,若count小于三,则说明胜负为产生,然后判断棋盘是否满,决定游戏是否继续。其中行、正斜,反斜判断原理相同,判断棋盘是否满也比较简单,直接上代码:
int Is_Win(int board[ROW][COL], int row, int col, int x, int y) {//判断输赢 1赢 0平局 2游戏继续
//横向
int count = 1;
for (int temp = 1; (y - temp >= 0); temp++) {
if (board[x][y - temp] == board[x][y]) {
count++;
}
else {
break;
}
}
for (int temp = 1; (y + temp = 3) {
return 1;
}
//纵向
count = 1;
for (int temp = 1; (x - temp >= 0); temp++) {
if (board[x-temp][y] == board[x][y]) {
count++;
}
else {
break;
}
}
for (int temp = 1; (x + temp < col); temp++) {
if (board[x+temp][y] == board[x][y]) {
count++;
}
else {
break;
}
}
if (count >= 3) {
return 1;
}
//正斜
count = 1;
for (int tmp = 1; (x - tmp >= 0) && (y + tmp < col); tmp++) {
if (board[x - tmp][y + tmp] == board[x][y])
count++;
else
break;
}
for (int tmp = 1; (x + tmp < row) && (y - tmp >= 0); tmp++) {
if (board[x + tmp][y - tmp] == board[x][y])
count++;
else
break;
}
if (count >= 3) return 1;
//反斜
count = 1;
for (int tmp = 1; (x - tmp >= 0) && (y - tmp >= 0); tmp++) {
if (board[x - tmp][y - tmp] == board[x][y])
count++;
else
break;
}
for (int tmp = 1; (x + tmp < row) && (y + tmp < col); tmp++) {
if (board[x + tmp][y + tmp] == board[x][y])
count++;
else
break;
}
if (count >= 3) return 1;
return Is_Draw(board, row, col);//判断棋盘是否满
}
int Is_Draw(int board[ROW][COL], int row, int col) {//棋盘是否已满(平局)
int count = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (board[i][j] ==' ') {
count++;
}
}
}
if (count == 0) {
return 0;
}
return 2;
}
这样,游戏的主体就全部完成了,接下来就是对函数进行整合,通过循环来实现反复下棋和调用对应函数的操作。
完整代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#define ROW 3
#define COL 3
void Tic_Tac_Toe();//三子棋游戏
void game();
void Show();//打印选择界面
void Board(int board[ROW][COL], int row, int col);//打印棋盘
void Init_Board(int board[ROW][COL], int row, int col);//棋盘初始化
void Player(int board[ROW][COL], int row, int col, int* x, int* y);//玩家下棋
int main() {
Tic_Tac_Toe();
return 0;
}
void Tic_Tac_Toe() {
int choice = 0;
srand((int)time(NULL));//随机数种子
while (1) {
Show();//打印菜单
printf("请输入你的选择:");
scanf("%d", &choice);
switch (choice) {
case 0:
printf("再见!\n");
return;
case 1:
game();
break;
default:
printf("输入错误!请重新输入!\n");
}
}
}
void Show() {//打印选择界面
printf("--------------------------------\n");
printf("--------欢迎来到三子棋游戏------\n");
printf("--------1.PLAY 0.EXIT------\n");
printf("--------------------------------\n");
}
void Board(int board[ROW][COL], int row, int col) {//打印棋盘
system("cls");
for (int i = 0; i < row; i++) {
printf(" %c | %c | %c \n", board[i][0], board[i][1],board[i][2]);
if (i != row - 1) {
printf("---|---|---\n");
}
}
}
void Init_Board(int 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 Player(int board[ROW][COL], int row, int col, int* x, int* y) {//玩家下棋
while (1) {
printf("请输入下棋位置:");
scanf("%d %d", x, y);
*x = *x - 1;
*y = *y - 1;
if (*x < 0 || *x>2 || *y < 0 || *y>2) {
printf("输入位置不合法!请重新输入!\n");
continue;
}
if (board[*x][*y] != ' ') {
printf("位置已被占用!请重新输入!\n");
continue;
}
board[*x][*y] = 'O';
break;
}
}
void AI_Player(int board[ROW][COL], int row, int col, int* x, int* y) {//电脑下棋
while (1) {
*x = rand() % row;
*y = rand() % col;
if (board[*x][*y] != ' ') {
continue;
}
board[*x][*y] = 'X';
break;
}
}
int Is_Draw(int board[ROW][COL], int row, int col) {//棋盘是否已满(平局)
int count = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (board[i][j] ==' ') {
count++;
}
}
}
if (count == 0) {
return 0;
}
return 2;
}
int Is_Win(int board[ROW][COL], int row, int col, int x, int y) {//判断输赢 1赢 0平局 2游戏继续
//横向
int count = 1;
for (int temp = 1; (y - temp >= 0); temp++) {
if (board[x][y - temp] == board[x][y]) {
count++;
}
else {
break;
}
}
for (int temp = 1; (y + temp = 3) {
return 1;
}
//纵向
count = 1;
for (int temp = 1; (x - temp >= 0); temp++) {
if (board[x-temp][y] == board[x][y]) {
count++;
}
else {
break;
}
}
for (int temp = 1; (x + temp < col); temp++) {
if (board[x+temp][y] == board[x][y]) {
count++;
}
else {
break;
}
}
if (count >= 3) {
return 1;
}
//正斜
count = 1;
for (int tmp = 1; (x - tmp >= 0) && (y + tmp < col); tmp++) {
if (board[x - tmp][y + tmp] == board[x][y])
count++;
else
break;
}
for (int tmp = 1; (x + tmp < row) && (y - tmp >= 0); tmp++) {
if (board[x + tmp][y - tmp] == board[x][y])
count++;
else
break;
}
if (count >= 3) return 1;
//反斜
count = 1;
for (int tmp = 1; (x - tmp >= 0) && (y - tmp >= 0); tmp++) {
if (board[x - tmp][y - tmp] == board[x][y])
count++;
else
break;
}
for (int tmp = 1; (x + tmp < row) && (y + tmp < col); tmp++) {
if (board[x + tmp][y + tmp] == board[x][y])
count++;
else
break;
}
if (count >= 3) return 1;
return Is_Draw(board, row, col);//判断棋盘是否满
}
void game() {
int board[ROW][COL];
Init_Board(board, ROW, COL);//棋盘初始化
while (1) {
Board(board, ROW, COL);//打印棋盘
int x=0, y=0, ret=0;
Player(board,ROW,COL,&x,&y);//玩家下棋
ret = Is_Win(board, ROW, COL, x, y);
if (ret == 0) {
Board(board, ROW, COL);
printf("游戏平局!\n");
break;
}
else if (ret == 1) {
Board(board, ROW, COL);
printf("恭喜你赢了!\n");
break;
}
Board(board, ROW, COL);//打印棋盘
AI_Player(board, ROW, COL, &x, &y);//电脑下棋
ret = Is_Win(board, ROW, COL, x, y);
if (ret == 0) {
Board(board, ROW, COL);
printf("游戏平局!\n");
break;
}
else if (ret == 1) {
Board(board, ROW, COL);
printf("电脑玩家获胜!再接再厉!\n");
break;
}
}
}
效果展示: