【项目】—— 三子棋(C语言)
三子棋就是三颗棋子连成一线就赢的棋,非常简单,我们使用C语言来实现一个人机对战的三子棋。虽然实现的是三子棋,但是咱们的三子棋具有多子棋的逻辑,只要修改头文件的常量就能实现任意子棋。
三子棋的功能
- 游戏开始界面有一个 R × C R\times C R×C的棋盘
- 玩家可以输入坐标落子
- 电脑在玩家落子后自动落子
- 每次落子后判断输赢,三颗棋子连成一线则赢
*
#
game.h
:头文件,用于引入头文件,声明常量和声明函数game.c
:源文件,用于实现游戏的功能test.c
:测试文件,用于测试游戏代码的逻辑,并写有main
函数启动程序修改该文件中的ROW
和COL
常量就可以修改棋盘的大小,修改WIN
常量可改变胜利的条件,完成WIN
子棋的改变
#pragma once
#include
#include
#include
#include
#define ROW 5 //棋盘行数
#define COL 5 //棋盘宽度
#define WIN 3 //胜利条件
void menu(); //菜单
void Init(char board[ROW][COL], int row, int col); //初始化棋盘
void DisplayBoard(char board[ROW][COL], int row, int col); //打印棋盘
void PlayMove(char board[ROW][COL], int row, int col); //玩家落子
void ComputerMoveAndPrint(char board[ROW][COL], int row, int col); //电脑落子
char IsWin(char board[ROW][COL], int row, int col); //判断输赢
将棋盘的所有字符初始化为空格
void Init(char board[ROW][COL], const int row, const int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
打印一个 r o w × c o l row\times col row×col的棋盘,并输出棋盘中的字符
void DisplayBoard(char board[ROW][COL], const int row, const int col)
{
//打印列坐标
printf(" ");
for (int j = 0; j < col; j++)
{
printf(" %d ", j + 1);
}
printf("\n");
int i = 0;
for (i = 0; i < row; i++)
{
printf("%d- ", i + 1); //打印行坐标
int j = 0;
for (j = 0; j < col; j++)
{
if (j < col - 1)
{
printf(" %c |", board[i][j]);
}
else
{
printf(" %c \n", board[i][j]);
}
}
if (i < row - 1)
{
printf(" ");
for (j = 0; j < col; j++)
{
if (j < col - 1)
{
printf("---|");
}
else
{
printf("---\n");
}
}
}
}
}
玩家输入坐标,判断坐标的正确性和是否被占用,若是没有将该位置赋值为*
void PlayMove(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:>\n");
int x = 0, y = 0;
while (1)
{
printf("请输入坐标(用空格隔开):>");
scanf("%d %d", &x, &y);
if ((x >= 1) && (x <= row) && (y >= 1) && (y <= col))
{
x--;
y--;
if (board[x][y] != ' ')
{
printf("坐标被占用\n");
}
else
{
board[x][y] = '*';
break;
}
}
else
{
printf("坐标输入有误,请重新输入");
}
}
}
电脑随机生成一个坐标,将该位置赋值为#
,并打印棋盘,并打印电脑下棋坐标
void ComputerMoveAndPrint(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (' ' == board[x][y])
{
board[x][y] = '#';
DisplayBoard(board, ROW, COL);
printf("电脑下棋>%d %d\n", x + 1, y + 1);
break;
}
}
}
遍历每一行,使用conut
记录每一行指定棋子c
的个数,边记录边判断连续的个数是否达到胜利条件WIN
的个数,若是中途遇到其他棋子则将count
置为0
_Bool XofV(char board[ROW][COL], int row, int col, char c)
{
int i = 0;
for (i = 0; i < row; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < col; j++)
{
if (c == board[i][j])
{
count++;
if (count >= WIN) //判断是否赢
{
return 1;
}
}
else
{
count = 0;
}
}
}
return 0;
}
根判断行赢的逻辑一样,所以我们直接将行列交换完成实现
_Bool YofV(char board[ROW][COL], int row, int col, char c)
{
int i = 0;
for (i = 0; i < col; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < row; j++)
{
if (c == board[j][i])
{
count++;
if (count >= WIN)
{
return 1;
}
}
else
{
count = 0;
}
}
}
return 0;
}
正对角和斜对角都要遍历,每个遍历分为2个步骤,分别是上三角和下三角
_Bool XandYofV(char board[ROW][COL], int row, int col, char c)
{
//正对角
int i = 0;
for (i = 0; i < row; i++)
{
int count = 0;
int j = 0;
int x = i;
for (j = 0; j < col && x < row; j++, x++)
{
if (board[x][j] == c)
{
count++;
if (count >= WIN)
{
return 1;
}
}
else
{
count = 0;
}
}
}
int j = 0;
for (j = 1; j < col; j++) //上三角已经把对角线遍历过了,所以下三角不用遍历0对角线
{
int count = 0;
int i = 0;
int y = j;
for (i = 0; i < row && y < col; i++, y++)
{
if (board[i][y] == c)
{
count++;
if (count >= WIN)
{
return 1;
}
}
else
{
count = 0;
}
}
}
//斜对角
for (j = col-1; j >= 0; j--)
{
int count = 0;
int y = j;
int i = 0;
for (i = 0; y >= 0 && i < row; y--, i++)
{
if (board[i][y] == c)
{
count++;
if (count >= WIN)
{
return 1;
}
}
else
{
count = 0;
}
}
}
for (i = 1; i < row; i++)
{
int count = 0;
int x = i;
int j = col - 1;
for (j = col - 1; j >= 0 && x < row; x++, j--)
{
if (board[x][j] == c)
{
count++;
if (count >= WIN)
{
return 1;
}
}
else
{
count = 0;
}
}
}
return 0;
}
遍历棋盘,若是没有空格则棋盘满了
_Bool 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;
break;
}
}
}
return 1;
}
将玩家或电脑棋子表示的字符作为参数,比较行、列、对角线,若是都没有赢的,判断棋盘满了,则为平局
*
#
q
c
char IsWin(char board[ROW][COL], int row, int col)
{
//玩家赢
if (XofV(board, row, col, '*') || YofV(board, row, col, '*') || XandYofV(board, row, col, '*'))
{
return '*';
}
//电脑赢
else if (XofV(board, row, col, '#') || YofV(board, row, col, '#') || XandYofV(board, row, col, '#'))
{
return '#';
}
//棋盘满
else if(IsFull(board, row, col))
{
return 'q';
}
//对局继续
else
{
return 'c';
}
}
让用户选择的界面
void menu()
{
printf("******************************\n");
printf("******** 1. play *******\n");
printf("******** 0. exit *******\n");
printf("******************************\n");
}
void game()
{
//创建棋盘
char board[ROW][COL] = { 0 };
char win = ' ';
Init(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//双方对局
while (1)
{
PlayMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
win = IsWin(board, ROW, COL);
if (win != 'c')
{
break;
}
system("cls");
ComputerMoveAndPrint(board, ROW, COL);
win = IsWin(board, ROW, COL);
if (win != 'c')
{
break;
}
}
//判定结果
system("cls");
DisplayBoard(board, ROW, COL);
if ('*' == win)
{
printf("玩家胜利\n");
}
else if ('#' == win)
{
printf("电脑胜利\n");
}
else
{
printf("平局\n");
}
}
启动游戏,并调用菜单供用户选择参考
int main(void)
{
int input = 0;
srand(time(NULL));
do
{
menu();
printf("请操作>");
scanf("%d", &input);
switch (input)
{
case 1:
system("cls");
game();
break;
case 0:
printf("欢迎下次光临~\n");
break;
default:
printf("数字输入错误\n");
break;
}
} while (0 != input);
return 0;
}
代码存储于gitee中:点击查看完整代码