三子棋见证“编程思想“

今天这篇博客是通过编写一个小小三子棋游戏来阐述一下编程的思路
流程:

  1. 创建棋盘并且初始化
  2. 打印棋盘
  3. 玩家和电脑轮流落子,玩家先落子(玩家输入行列坐标的方式)
  4. 判断胜负
  5. 电脑也落子(电脑随机落子)
  6. 确认胜负关系
  7. 回到2继续执行,打印新的棋面

START

一.呈现给用户的是:游戏选择界面
三子棋见证“编程思想“代码如下:

//主函数中存放这些,用来进行选择判断,去调用一些函数,来达到最终的效果
while (1) {
		int choice = menu();
		if (choice == 1) {
			game();
		}
		else if (choice == 0) {
			printf("goodbye!");
			break;
		}
		else {
			printf("您的输入有误,请重新输入\n");
			continue;
		}
	}

//在外面定义函数,菜单函数,菜单函数与游戏函数一起在主函数下面进行被调用
int menu() {
	printf("================================\n");
	printf("========  1. 开始游戏  =========\n");
	printf("========  0. 退出游戏  =========\n");
	printf("================================\n");
	printf("请输入您的选择: \n");
	int choice = 0;
	scanf("%d", &choice);
	return choice;
}

二.选择以后进行游戏函数的调用,编写游戏函数
注意:在游戏函数中进行其他流程函数的编写

  1. 创建棋盘,其实就是用3*3的二维数组来展示,类型为字符类型
    (对于棋盘的"初始化",其实就是对整个数组进行赋"置空格",这里就要将整个二维数组作为参数,传给另一个函数进行初始化,这个思想是需要注意学习)
 void game() {
	 char winner = ' ';
	 //1.创建棋盘并且初始化
	 char chessBoard[ROW][COL] = { 0 };
	 //棋盘一开始是空格而不是0,所以要进行初始化
	 init(chessBoard);
	 
  1. 对于棋盘初始化函数的定义
void init(char chessBoard[ROW][COL]) {
	//初始化,全部设为空格
	for (int row = 0; row < ROW; row++) {
		for (int col = 0; col < COL; col++) {
			chessBoard[row][col] = ' ';
		}
	}
}
  1. 接着就是将初始化好的函数棋盘打印出来,编写打印函数
    (注意这里最可能好的去打印棋盘,于是进行美化)
void printBoard(char chessBoard[ROW][COL]) {
	//打印棋盘,循环
	printf("+---+---+---+\n");
	for (int row = 0; row < ROW; row++) {
		printf("| %c | %c | %c |\n", chessBoard[row][0], chessBoard[row][1], chessBoard[row][2]);
	printf("+---+---+---+\n");
	}
}

效果如下:
三子棋见证“编程思想“

  1. 打印好棋盘以后,就是玩家开始下子,当然也可以是电脑先下,这里我们采用的是玩家先下子的情况
    编写玩家下子函数,其中需要注意点已经在注释中指出,请认真琢磨注释分析情况
//让玩家落子,输入行列坐标的方式来实现
void playerMove(char chessBoard[ROW][COL]) {
	while (1) {
		printf("请玩家输入行列坐标(row col): ");
		int row = 0;
		int col = 0;
		scanf("%d %d", &row, &col);
		//判断玩家输入的坐标是否正确,一定要校验玩家输入是否合法
		if (row < 0 || row >= ROW || col < 0 || col >= COL) {
			printf("您的输入不合法,请重新输入\n");
			continue;
		}
		//校验玩家落子位置是否已经有子了
		if (chessBoard[row][col] != ' ') {
			printf("这个卫位置已经有子了,请重新输入\n");
			continue;
		}
		//真正落子
		chessBoard[row][col] = 'x';
		break;
	}
}
  1. 玩家落子以后就是判断胜负函数
    三子棋见证“编程思想“
//注意这里,就是空格说明没有分出胜负,就不会跳出循环,继续下面的电脑下子
winner = iswin(chessBoard);
if (winner != ' ') {
	break;
}


char iswin(char chessBoard[ROW][COL]) {//返回x表示玩家获胜,返回O表示电脑获胜,' '表示继续,q表示合棋
	//p判定左右的行列斜线
	for (int row = 0; row < ROW; row++) {
		if (chessBoard[row][0] != ' ' &&
			chessBoard[row][0] == chessBoard[row][1] &&
			chessBoard[row][0] == chessBoard[row][2])
			return chessBoard[row][0];
	}
	for (int col = 0; col < COL; col++) {
		if (chessBoard[0][col] != ' ' &&
			chessBoard[0][col] == chessBoard[1][col] &&
			chessBoard[0][col] == chessBoard[2][col])
			return chessBoard[0][col];
	}
	if (chessBoard[0][0] != ' ' &&
		chessBoard[0][0] == chessBoard[1][1]
		&& chessBoard[0][0] == chessBoard[2][2])
		return chessBoard[0][0];

	if (chessBoard[0][2] != ' ' &&
		chessBoard[1][1] == chessBoard[0][2]
		&& chessBoard[0][2] == chessBoard[2][0])
		return chessBoard[0][2];
	//判断是否合棋,看棋盘是否有剩余空间
	if (isFull(chessBoard)) {
		return 'q';
	}
	return ' ';
}


//函数判断平手情况,如果为平手就返回1,这个1返回给上面调用处
int isFull(char chessBoard[ROW][COL]) {
	for (int row = 0; row < ROW; row++) {
		for (int col = 0; col < COL; col++) {
			if (chessBoard[row][col] == ' ') {
				return 0;
			}
		}
	}
	return 1;
}

//这就是产生结果以后的打印
printBoard(chessBoard);
if (winner == 'x') {
	printf("恭喜你,你赢了\n");
}
else if (winner == 'o') {
	printf("您连人工智障下不过\n");
}
else {
	printf("您平手\n");
}
  1. 继续编写电脑下子
    (电脑下子就是瞎下,随机下,在没有子的地方下,这就又有了一定的判断就需要注意注释了)
void computerMove(char chessBoard[ROW][COL]) {
	//随机产生一组行列坐标
	srand(time(0));
	while (1) {
		int row = rand() % ROW;
		int col = rand() % COL;
		if (chessBoard[row][col] != ' ') {
			//不能是已经有子的位置
			continue;
		}
		chessBoard[row][col] = 'o';
		break;
	}
}
  1. 电脑下子以后进行判断,和第五步一样就不进行编写了,调用即可
  2. 如果走完依次还没有跳出,说明没有分出胜负,就需要在进行函数的循环执行,直到分出胜负就是

流程到这里就结束了,下面说几点注意的地方:

  1. 兵马未动,粮草先行,就是要先将函数的整个思路已经排好
  2. 在编写函数时,要注意哪里要重新定义一个函数,这就需要刚多的机会去编写练习
  3. 就是尽量少的使用字面常量,用宏定义去分析,好了解明白
  4. 其他就是二维数组进行操作和一维数组不一样,就是可以对二维数组直接进行使用,函数传参等

完整代码点击获取,感谢您的阅读,不足请多指教!!!

上一篇:【PAT】A1128 N Queens Puzzle (20point(s))


下一篇:OpenCV 相机标定 findChessboardCorners() 与 cornerSubPix() 函数