前言:
该篇文章是用C语言来实现三子棋的,是对之前的知识灵活运用加以巩固,如何合理的分块来写一个工程性的代码,大家仔细看看,哪里要有不对的地方请一定要指出来。
1、游戏规则
我们在玩三子棋的时候,用户先落子再是电脑落子,用户或者电脑玩家在3*3的棋盘上最终落子为行或列是三子连成,或者两个对角线是三子连成的,就认定哪一玩家胜出。如若棋盘下满都没出现三子连成认定为平局。
2、创建文件
我们需要分块来写不同用途的文件,在实现三子棋我们需要分三个文件,分别是:
game.h //头文件(包含所有需要的用到的头文件,define定义的常量,函数声明)
注:我们将2.1,2.2,2.3全部写在此文件中目的在于,game.c和test.c中调用这些内容时,只需要对我们自己写的game.h声明一次便可直接使用里面的内容。
game.c //游戏文件(里面分别写入所要用到功能函数)
test.c //测试文件(代码的整合)
2.1 头文件
#include <stdio.h> #include <stdlib.h> #include <time.h>
2.2 用define定义行列
优点:如果我们后期需要改棋盘大小的时候只需要在这里改,一劳永逸,不用在整个程序中修改。
#define ROW 3 #define COL 3
2.3 函数声明
//初始化棋盘 void InitBoard(char board[ROW][COL], int row, int col); //显示棋盘 void DisplayBoard(char board[ROW][COL], int row, int col); //玩家下棋 void PlayerMove(char board[ROW][COL], int row, int col); //判断输赢 //玩家赢 -- '*' //电脑赢 -- '#' //平局 -- 'Q' //继续 -- 'C' char IsWin(char board[ROW][COL], int row, int col); //电脑下棋 void ComputerMove(char board[ROW][COL], int row, int col);
3、游戏测试部分
3.1 主函数
这部分先写出玩游戏的逻辑
int main() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }
对主函数内容的分析:
3.1.1 menu()函数(菜单函数)
void menu() { printf("***********************\n"); printf("\t1.play\n"); printf("\t0.exit\n"); printf("***********************\n"); }
效果展示:
3.1.2 switch语句
switch语句实现了用户在选择不同菜单的实现
效果展示:
3.1.3 do while语句
这里使用dowhile语句是实现先运行主函数,然后再进行选择,主函数会根据用户的选择进行实现不同的功能。
3.1.4 game()函数
在玩家选择数字 1 便会调用game()函数,实现以下功能。
void game() { srand((unsigned int)time(NULL)); //存放数据需要一个3*3的二维数组 char board[ROW][COL] = { 0 }; //初始化棋盘 InitBoard(board, ROW, COL); //显示棋盘 DisplayBoard(board, ROW, COL); char ret = 0; while (1) { //玩家下棋 - * PlayerMove(board, ROW, COL); //打印棋盘 DisplayBoard(board, ROW, COL); //判断输赢 ret = IsWin(board, ROW, COL); if (ret != 'C') { break; } //电脑下棋 - # ComputerMove(board, ROW, COL); //打印棋盘 DisplayBoard(board, ROW, COL); //判断输赢 if (ret != 'C') { break; } } if ('*' == ret) printf("玩家赢\n"); else if ('#' == ret) printf("电脑赢\n"); else printf("平局\n"); }
game()函数中包含了初始化棋盘函数、显示棋盘函数、玩家下棋函数、电脑下棋函数、判断输赢函数的调用,这些函数在下面我们展开来分析。
game()函数我们在最后进行逻辑的解析。
4、游戏功能实现部分
游戏的实现逻辑
4.1 打印棋盘函数
首先我们需要打印出棋盘,棋盘是 3*3 的样式
头文件里面包含了行、列
定义DisplayBoard()函数打印棋盘,棋盘打印时包含了数据和分割行,代码实现:
void DisplayBoard(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++) { printf(" %c ",board[i][j]); if (j<col-1) printf("|"); } printf("\n"); //分割行 if (i < row - 1)//---只打印两行 { for (j = 0; j < col; j++) { printf("---");//每行需要3个--- if(j<col-1) printf("|"); } } printf("\n"); } }
效果展示:
4.2 初始化棋盘函数
定义InitBoard()函数,代码实现:
void InitBoard(char board[ROW][COL], int row, int col) { int i = 0; int j = 0; for (i = 0; i < row; i++)//3行 { for (j = 0; j < col; j++)//3列 { board[i][j] = ' '; } } }
将棋盘初始化为空格。
4.3 玩家下棋
定义PlayerMove()函数,代码实现:
void PlayerMove(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("玩家下棋:>\n"); while (1) { printf("请选择你要下棋的坐标:>"); scanf("%d %d", &x, &y); if ((x>=1 && x<=row) && (y >= 1 && y <= col)) { if (board[x - 1][y - 1] == ' ') { board[x - 1][y - 1] = '*'; break; } else { printf("位置已被占用,请重新输入\n"); } } else { printf("坐标非法,请重现输入坐标\n"); } } }
这里存在一个小细节,以及一些问题,相应的解决办法如下:
我们在写代码的时候知道第一个位置的坐标是(0,0),但是在玩家眼里第一个位置的坐标是(1,1),所以玩家输入的数字(x,y)是程序的(x-1,y-1)位置。
1.用户输入的坐标棋盘上没有怎么处理?
答:这里我们使用了if-else语句,如果坐标合法,那么玩家的棋子正常落子;如果坐标非法,程序会提醒"坐标非法,请重现输入坐标"的字样,利用while循环使玩家输入合法的坐标正确落子后在跳出循环。
2.用户输入的坐标已被占用怎么处理?
答:这里还是使用if-else语句,我们在初始化棋盘的时候用空格将每个位置占着,如果这个位置是空格,这个位置便会正常落子*;如果这个位置是非空格符号(本文中只会是*或者#),那么这个位置就是被占用了,程序会提醒"位置已被占用,请重新输入"的字样,利用while循环使玩家输入没有被占用且合法的坐标正确落子后在跳出循环。