由于n子棋代码较复杂,编辑时可当成三子棋理解。我们还需要分成三个文件来写。请耐心看完,保证你能学会。定义test.c为源文件,用于编写游戏的主体,定义game.c为源文件,用于编写程序用到的函数,定义game.h为头文件,用于使用的函数的声明。
在这里添加这些文件。
再看一下棋盘吧,方便后面理解。
接着上一串代码,这个就是游戏的主体,其他需要写的基本都是函数
int main()
{
srand((unsigned int)time(NULL));
int put=0;
do
{
menu();
printf("\n");
printf("请选择\n");
scanf("%d", &put);
switch (put)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:
printf("请重新输入");
break;
}
} while (put);
getchar();
getchar();
return 0;
}
代码第一行有关时间戳,需要和后面用到的rand()一起用,具体请自行查阅,或者先记住就行。
下面我们需要写一个为玩家提供选择功能的代码,首先我们写一个打印选项菜单的函数
menu()
void menu()
{
printf("******1 play,0 quit*****");
}
需要写在主函数上面。
剩下的主干照着写就行了,自己写代码时会发现,这种do~while形的循环适合这个菜单判断。
而那个game函数就是我们要啃的硬骨头。
下面是test.c文件的剩余部分
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("******1 play,0 quit*****");
}
void game()
{
char board[row][col] = { 0 };
initboard(board, row, col);
displayboard(board, row, col);
while (1)
{
playmove(board, row, col);
displayboard(board, row, col);
if (isfull(board, row, col)!='q')
{
computer(board, row, col);
displayboard(board, row, col);
}
char ret;
ret = iswin(board, row, col);
if (ret == '*')
{
printf("玩家赢\n");
break;
}
if (ret == '#')
{
printf("电脑赢\n");
break;
}
if (ret == 'q')
{
printf("平局\n");
break;
}
}
}
由于函数声明都在game.h中,所以直接引用game.h就行了。但要注意game.h里是然后引头文件的。
menu菜单函数上面有写过.
接着写的是game函数的主体,首先定义一个字符数组,玩家和电脑通过输入字符,在这个数组里面下棋,至于这个row,col是在game.h里面定义的,要玩几子棋,就改变define后面的数就可以了,但这个简易n子棋程序,这俩个数要一样。
#pragma once是什么请自行查找。简单说就是下边的代码只包含一次。
接着是初始化数组的函数,要把每个数组元素赋值为空格,方便下一步打印棋盘。
接着在game.h中声明函数,在game.c中定义函数,这里注意一下game.c文件的开头怎么写,从第二行开始看,第一行懂的都懂,不知道的可以先不管。
注意形参实参的变化。
接着会到test.c文件,是一个打印棋盘的函数,下面需要和上面初始化棋盘的函数一样,先在game.h中声明这个函数,然后在game.c中编写打印棋盘的函数displayboard()。
这是game.h中全部代码,下面会有可复制的代码段。
下面需编写打印棋盘的函数
void displayboard(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
for (int k = 0;k < co;k++)
{
if (k < co - 1)
{
printf(" %c |", board[i][k]);
}
else if (k == co - 1)
{
printf("%c", board[i][k]);
printf("\n");
}
}if (i < ro - 1)
{
for (int i = 0;i < col;i++)
printf("--- ");
printf("\n");
}
}
}
下面进入编写下棋的代码,需要一个while(1)循环,进入循环后首先需要写一个玩家下棋的函数,声明同上,在game.c定义编写函数代码如下。因为玩家不知道数组减一的情况,所以-1需编写出来。注意两个重新输入的不同情况。
void playmove(char board[row][col], int ro, int co)
{
while (1)
{
printf("请输入");
scanf("%d %d", &ro, &co);
if (ro-1 >= 0 && ro-1 < row && co-1 >= 0 && co-1 < col)
{
if (board[ro-1][co-1] == ' ')
{
board[ro-1][co-1] = '*';
break;
}
else {
printf("输入错误,重新输入");
}
}
else {
printf("输入错误,重新输入");
}
}
}
接着回到test.c写入一个打印棋盘的函数,这回不用再次定义。然后if判断中的函数在这里用到,也在后面定义判断输赢的函数中用到。用来判断棋盘是否输入满了,并用来判断是否平局,此处为前一种情况。声明方法同上,下面是函数代码。
char isfull(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
for (int k = 0;k < co;k++)
{
if (board[i][k] == ' ')
{
return 'c';
}
}
}
return 'q';
}
用return ‘q’,是因为test.c里判断平局时要用到,return ‘c’可以用任意字母。
if语句里第一个是电脑下棋的函数,声明方法同上,定义代码如下。
void computer(char board[row][col], int ro, int co)
{
while (1)
{
int x = rand() % ro;
int y = rand() % co;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
这里面用到了rand()函数,具体请自行查阅,和上面主函数说到的时间戳都要写,就是能够随机生成一个数,而为了生成的数在数组范围里,需要%上ro或co(请看代码)。回到test.c下面同样是一个打印棋盘的函数,因为电脑输入完的棋盘需要打印出来。出if语句,就到判断棋盘状况的地方了。首先定义一个字符变量ret,用来接收iswin函数的值,iswin函数用来判断棋盘状态,并返回一个值。需要和isfull函数一起看。
char isfull(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
for (int k = 0;k < co;k++)
{
if (board[i][k] == ' ')
{
return 'c';
}
}
}
return 'q';
}
char iswin(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
int count = 0;
for (int k = 0;k < co-1;k++)
{
if (board[i][k] == board[i][k + 1])
{
count++;
}
}
if (board[i][0] != ' ')
{
count++;
}
if (count == ro)
{
return board[i][0];
}
}
for (int i = 0;i < co;i++)
{
int count = 0;
for (int k = 0;k < ro - 1;k++)
{
if (board[k][i] == board[k+1][i])
{
count++;
}
}
if (board[0][i] != ' ')
{
count++;
}
if (count == co)
{
return board[0][i];
}
}
int count = 0;
for (int i = 0;i < co-1;i++)
{
if (board[i][i] == board[i + 1][i + 1])
{
count ++ ;
}
if (count == ro - 1 && board[0][0] != ' ')
{
return board[0][0];
}
}
count = 0;
for (int i = 0;i < co - 1;i++)
{
if (board[ro-i-1][i] == board[ro-i-2][i + 1])
{
count++;
}
if (count == ro - 1 && board[ro-1][0] != ' ')
{
return board[ro-1][0];
}
}
char k;
k=isfull(board, row, col);
return k;
}
iswin函数用来判断输赢状态,返回值给ret,如果没有满足一方赢的条件,就让主函数继续执行下棋的语句(和主函数一起看)。iswin如何判断是否满足赢的条件?因为是简易n子棋,所以棋盘是n*n的,简单说就是如果哪一行或哪一列,或左右对脚线是一个字符相同,那么就是这一方赢棋。为了实现n子棋,我们需用到for循环,循环里面用count计数,在上面四种条件下,两个相邻的元素如果相等,这count++,如果这里面元素都不是空格,则count再加1,如果赢,满足条件,那么count的值正好等于n。函数代码在上面,应该能分析明白。因为iswin函数用来判断棋盘状态,所以需要和isfull函数连在一起看,并且iswin函数在最后调用了isfull函数。因为棋盘状态都需要iswin函数传一个值给ret(联系test.c一起看).
现在硬骨头基本啃完,回到test.c文件(下面有).如果ret为'*',那么打印玩家赢,并结束本次while(1)循环,重新进入do~while循环语句,重新进行判断。剩下代码你应该能分析明白,下面分别吧text.c,game.h,game.c文件完整版重新复制到下面。
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("******1 play,0 quit*****");
}
void game()
{
char board[row][col] = { 0 };
initboard(board, row, col);
displayboard(board, row, col);
while (1)
{
playmove(board, row, col);
displayboard(board, row, col);
if (isfull(board, row, col)!='q')
{
computer(board, row, col);
displayboard(board, row, col);
}
char ret;
ret = iswin(board, row, col);
if (ret == '*')
{
printf("玩家赢\n");
break;
}
if (ret == '#')
{
printf("电脑赢\n");
break;
}
if (ret == 'q')
{
printf("平局\n");
break;
}
}
}
int main()
{
srand((unsigned int)time(NULL));
int put = 0;
do
{
menu();
printf("\n");
printf("请选择\n");
scanf("%d", &put);
switch (put)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:
printf("请重新输入");
break;
}
} while (put);
getchar();
getchar();
return 0;
}
#pragma once
#include
#include
#include
#define row 3
#define col 3
void initboard(char board[row][col], int ro, int co);
void displayboard(char board[row][col], int ro, int co);
void playmove(char board[row][col], int ro, int co);
void computer(char board[row][col], int ro, int co);
char iswin(char board[row][col], int ro, int co);
char isfull(char board[row][col], int ro, int co);
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void initboard(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
for (int k = 0;k < co;k++)
{
board[i][k] = ' ';
}
}
}
void displayboard(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
for (int k = 0;k < co;k++)
{
if (k < co - 1)
{
printf(" %c |", board[i][k]);
}
else if (k == co - 1)
{
printf("%c", board[i][k]);
printf("\n");
}
}if (i < ro - 1)
{
for (int i = 0;i < col;i++)
printf("--- ");
printf("\n");
}
}
}
void playmove(char board[row][col], int ro, int co)
{
while (1)
{
printf("请输入");
scanf("%d %d", &ro, &co);
if (ro-1 >= 0 && ro-1 < row && co-1 >= 0 && co-1 < col)
{
if (board[ro-1][co-1] == ' ')
{
board[ro-1][co-1] = '*';
break;
}
else {
printf("输入错误,重新输入");
}
}
else {
printf("输入错误,重新输入");
}
}
}
void computer(char board[row][col], int ro, int co)
{
while (1)
{
int x = rand() % ro;
int y = rand() % co;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
char isfull(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
for (int k = 0;k < co;k++)
{
if (board[i][k] == ' ')
{
return 'c';
}
}
}
return 'q';
}
char iswin(char board[row][col], int ro, int co)
{
for (int i = 0;i < ro;i++)
{
int count = 0;
for (int k = 0;k < co-1;k++)
{
if (board[i][k] == board[i][k + 1])
{
count++;
}
}
if (board[i][0] != ' ')
{
count++;
}
if (count == ro)
{
return board[i][0];
}
}
for (int i = 0;i < co;i++)
{
int count = 0;
for (int k = 0;k < ro - 1;k++)
{
if (board[k][i] == board[k+1][i])
{
count++;
}
}
if (board[0][i] != ' ')
{
count++;
}
if (count == co)
{
return board[0][i];
}
}
int count = 0;
for (int i = 0;i < co-1;i++)
{
if (board[i][i] == board[i + 1][i + 1])
{
count ++ ;
}
if (count == ro - 1 && board[0][0] != ' ')
{
return board[0][0];
}
}
count = 0;
for (int i = 0;i < co - 1;i++)
{
if (board[ro-i-1][i] == board[ro-i-2][i + 1])
{
count++;
}
if (count == ro - 1 && board[ro-1][0] != ' ')
{
return board[ro-1][0];
}
}
char k;
k=isfull(board, row, col);
return k;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)