> 文档中心 > C语言实现:从入门的三子棋到N子棋

C语言实现:从入门的三子棋到N子棋

文章目录

  • 外部架构代码
  • 游戏内核代码实现

今天介绍的内容是关于从三子棋到N子棋的代码实现与优化。
话不多说直入正题

外部架构代码

首先,我们要将游戏的外部框架设计好。即为游戏的测试程序和游戏菜单的设计。由于夜已较深我们直接上代码。

void menu()      //菜单{printf("    #####################\n");printf("######  1.Play 0.Exit  ######\n");  //这里将 1 设为进入游戏,0 设为退出游戏在下面的条件语句中有妙用printf("    #####################\n");}void test()      //这里是游戏的测试程序{srand((unsigned int)time(NULL)); //在用srand()生成随机数种子时不需要进行循环,所以直接放这。并且srand()要用time()函数来获取时间戳来生成随机数种子。time函数声明头文件int input = 0;do//以do while 循环作为外部框架先执行一次程序再进行循环。{menu();      //这里是游戏菜单的函数printf("请输入:> ");scanf("%d", &input);  printf("\n");switch (input){case 1:game();break;case 0:printf("退出成功\n");break;default:printf("请重新输入:> \n");break;}} while (input); //上面菜单的设定使得这里巧妙的用input的值来做判断条件}int main() {test();return 0;}

第二步就是将game()函数里的内部逻辑(三子棋的内部逻辑)进行相关的编写了。还是直接上代码

void game()//游戏的主要框架{char arr[Row][Col] = { 0 };     //创建数组存储下棋信息InitBoard(arr, Row, Col);//初始化棋盘,即将数组内容全部初始化为空格DisplayBoard(arr, Row, Col);    //打印棋盘char ret = 0;     //声明变量待会用来接受判断输赢函数的返回值while (1){PlayerMove(arr, Row, Col);    //玩家下棋 DisplayBoard(arr, Row, Col);  //打印棋盘ret = Is_Win(arr, Row, Col);  //对游戏过程可能出现的四种情况进行判断,玩家赢返回 '*',电脑赢返回'#',平局返回'p',继续返回'c'(注意这里将玩家、电脑赢的返回值和对应落子形状设定相同将有妙用)if (ret != 'c') //每一次玩家下完棋都要判断一次对局情况{      break;}ComputerMove(arr, Row, Col);  //电脑下棋DisplayBoard(arr, Row, Col);  //打印棋盘ret = Is_Win(arr, Row, Col);  if (ret != 'c') //同理每次电脑落完子也要判断一次对局情况{break;}}if (ret == '*')    {printf("玩家赢\n");}else if (ret == '#'){printf("电脑赢\n");}else if (ret == 'p'){printf("平局\n");}}

游戏内核代码实现

第三步就是对游戏内部需要调用的所有函数进行实现

void InitBoard(char arr[Row][Col], int row, int col){int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){arr[i][j] = ' ';}}}void DisplayBoard(char arr[Row][Col], int row, int col){int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf(" %c ", arr[i][j]);   //将棋盘的每一行每一列都分开来打印,使得棋盘的大小可以随便改变。if (j < col - 1)      //这里要判断是因为当打印到最后一列时就不需要打印'|'{printf("|");}}printf("\n");if (i < row - 1)   //这里的判断作用同上,当打印到最后一行时就不需要打印'---'了。{for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}}printf("\n");}}void PlayerMove(char arr[Row][Col], int row, int col){int a, b;while (1){printf("请输入:> ");scanf("%d%d", &a, &b);if (a <= row && a >= 1 && b <= col && b >= 1) //注意此处玩家输入的坐标值可能超出了棋盘大小,或者是这个位置已经有棋子了。所以这里要对这两种情况进行判断。    {if (arr[a - 1][b - 1] == ' ')      {arr[a - 1][b - 1] = '*';break;}elseprintf("此坐标已被占用,请重新输入!\n");}elseprintf("请重新输入!\n");}}void ComputerMove(char arr[Row][Col], int row, int col){printf("电脑走:> \n");while (1){  //在用rand()之前要先调用srand()函数,生成随机数的种子。rand函数要声明头文件int a = rand() % row;      //此处用生成随机值的方式使得电脑随机落子,并且巧妙的用随机值模上棋盘行列信息使得这个落子范围在棋盘内。    int b = rand() % col;if (arr[a][b] == ' '){arr[a][b] = '#';break;}}}char Is_Win(char arr[Row][Col], int row, int col){int count = 0;      int i = 0;int j = 0;for (i = 0; i < row; i++)   //控制行      //横排是否相等的判断    {for (j = 0; j < col - 2; j++)  //控制列 if (arr[i][j] == arr[i][j + 1] && arr[i][j + 1] == arr[i][j + 2] && arr[i][j] != ' '){return arr[i][0];     //这里就是刚刚提到的妙用了,因为玩家下的棋与玩家赢的返回值一致,所以当三个数相等的时候直接返回棋盘信息即可,不需要再对棋盘信息进行判断来判断谁赢}}for (j = 0; j < col; j++)  //控制列//数列是否相等的判断{for (i = 0; i < row - 2; i++) //控制行{if (arr[i][j] == arr[i+1][j] && arr[i+1][j ] == arr[i+2][j] && arr[i][j] != ' ')return arr[i][j];     } }for (i = 0; i < col - 2; i++)     //控制列     //从左上至右下的斜列的判断{for (j = 0; j < row - 2; j++) //控制行{if (arr[j][i] == arr[j + 1][i + 1] && arr[j + 1][i + 1] == arr[j + 2][i + 2] && arr[j][i] != ' '){return arr[j][i]; //   |   |}//---|---|---}    //---|---|---} //   |   |for (i = 0; i < row - 2; i++)     //控制行    //从左下至右上的斜列的判断  {for (j = 2; j <= col; j++)    //控制列{if (arr[i][j] == arr[i+1][j-1] && arr[i+1][j-1] == arr[i+2][j-2] && arr[i][j] != ' '){return arr[i][j];}}}for (i = 0; i < row; i++)     //这里判断平局和继续游戏的情况  {     for (j = 0; j < col; j++)   {if (arr[i][j] == ' ') //这里引入一个初始化值为0的外界变量count,只要有一个元素为空格,就将他赋值为 1count = 1;}}if (count == 1)//如果count为1,则证明该棋盘还有空格可以落子,则游戏继续return 'c';elsereturn 'p';//当没人赢且棋盘满了,就代表双方平局,所以这里如果count为0,即代表上面的判断语句不成立,棋盘中没有空格,此时平局。}

emmm因为实在是比较晚了今天就弄得粗糙一点,都是一大坨一大坨的代码与注释。噢噢噢差点忘了还有个自定义函数的点。这里就直接在这做解释了。

#define Row 5     //这里采用宏定义的方式来设置行数与列数,可以通过改变宏定义设置的常量值直接控制棋盘大小。这样的话就能更方便使得棋盘信息可以得到扩充,而不是直接设为常量固定了行数与列数#define Col 5  

xdm慢慢看哈,阿西吧俺真的要溜去睡觉觉了。如果代码方面有相关问题欢迎评论区进行指正。