N子棋(N一般大于等于3)是指在一个N*N的方格棋盘上,双方轮流落子,最先把N个棋子排列成一排,一列或者一条斜线的就获胜,平时我们玩的多的一般是五子棋。
游戏的实现逻辑并不复杂,但是需要细心一点,否则调试起来就头疼了,步骤如下:
- 打印游戏开始界面
void menu()
{
printf("***********************************\n");
printf("*** 1.开始游戏 0.结束游戏 ***\n");
printf("***********************************\n");
}
int main()
{
//设置随机数种子
srand((unsigned)time(NULL));
//根据输入,选择开始还是结束游戏
int input = 0;
do
{
//打印游戏开始界面
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入:");
break;
}
} while (input!=0);
return 0;
}
2. 实现里面的game函数里面的srand函数用来设置随机数种子,给后面电脑生成棋子坐标用。
- 棋子的数据我们用一个N行N列的二维数组来储存,初始化棋盘为全部空格
//棋盘内容初始化为空格
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
- 棋盘的分割线我们用 '-' 和 '|' 符号循环打印来实现
//打印棋盘
void print_board(char board[ROW][COL], int row, int col)
{
putchar('\n');
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
putchar('\n');
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
putchar('\n');
}
}
打印出来就是这个效果:
- 玩家和电脑依次给出坐标在棋盘落子,玩家棋子用*表示,电脑用#表示,其实就是二维数组里面数据由空格改为*或者#。每次下棋的坐标需要判定是否在有效范围内以及给出的坐标的地方是否已经有棋子。这里面用了两个全局变量储存每次玩家或者电脑落子后棋子的坐标。
//玩家走棋
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入落子的坐标:");
scanf("%d%d", &x, &y);
//判断坐标范围是否合法以及要落子处是否已有棋子
if (x >= 1 && x <= row && y >= 1 && y <= col && board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
chess_x = x - 1;
chess_y = y - 1;
break;
}
else
{
printf("输入坐标错误或已被落子,请重新输入!\n");
}
}
}
//电脑走棋
void computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
//随机走棋
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
chess_x = x;
chess_y = y;
break;
}
}
}
下的过程大概就像这样:
- 每次落子后很重要的一件事就是做判定,这里有四种情况:
- 玩家赢
- 电脑赢
- 棋盘已满,平局
- 棋盘未满,继续
//根据上次落子的坐标判断输赢
char is_win(char board[ROW][COL], int x, int y)
{
int count_star_hor = 0;
int count_star_ver = 0;
int count_star_dia1 = 0;
int count_star_dia2 = 0;
int count_sharp_hor = 0;
int count_sharp_ver = 0;
int count_sharp_dia1 = 0;
int count_sharp_dia2 = 0;
int count_blank = 0;
int i = 0;
int j = 0;
//遍历整个棋盘并记数跟目前落子有关的行,列,两条对角线的各方落子个数
for (i = 0; i < ROW; i++)
{
for (j = 0; j < COL; j++)
{
if ((i == x) && board[i][j] == '*')
count_star_hor++;
if ((i == x) && board[i][j] == '#')
count_sharp_hor++;
if ((j == y) && board[i][j] == '*')
count_star_ver++;
if ((j == y) && board[i][j] == '#')
count_sharp_ver++;
if ((i + j) == (x + y) && board[i][j] == '*')
count_star_dia1++;
if ((i + j) == (x + y) && board[i][j] == '#')
count_sharp_dia1++;
if ((i - j) == (x - y) && board[i][j] == '*')
count_star_dia2++;
if ((i - j) == (x - y) && board[i][j] == '#')
count_sharp_dia2++;
if (board[i][j] == ' ')
count_blank++;
}
}
if (count_blank == 0)
return ' ';
if (count_star_hor == COL || count_star_ver == ROW || count_star_dia1 == ROW || count_star_dia2 == ROW)
return '*';
if (count_sharp_hor == COL || count_sharp_ver == ROW || count_sharp_dia1 == ROW || count_sharp_dia2 == ROW)
return '#';
return 'c';
}
本来不想用全局变量的,无奈输入坐标数据传递起来太麻烦。
根据输入的棋子坐标,计算所在行,所在列,以及所在的两条对角线上双方的棋子数,如果达到N,说明其中一方赢,返回*或者#;如果棋盘上空格为0,说明棋盘满,返回空格;如果不是以上情况,就返回字符c。
- 拿到判定结果,就可以来判断。若某一方赢,或者平局,就退出循环;否则继续下。
void game(void)
{
int row = ROW;
int col = COL;
char result = 0;
char board[ROW][COL] = { 0 };
init_board(board, row, col);
print_board(board, row, col);
while (1)
{
player_move(board, row, col);
print_board(board, row, col);
result = is_win(board, chess_x, chess_y);
if (result != 'c')
break;
computer_move(board, row, col);
print_board(board, row, col);
result = is_win(board, chess_x, chess_y);
if (result != 'c')
break;
}
if (result == '*')
{
printf("玩家胜!\n");
}
else if (result == '#')
{
printf("电脑胜!\n");
}
else
{
printf("平局!\n");
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)