前言:
为了实现三子棋,首先我们应该将代码分模块编写,我们分为3个部分
1. test.c —测试游戏(主函数)2. game.c 实现游戏部分代码 3. game.h 函数的声明、宏定义等
1. 菜单的打印
菜单打印:
为了玩游戏方便,我们可以设置一个菜单,在每次玩游戏的时候都打印一下,方便玩家玩游戏体验,实现如下:
玩家选择 “1” -玩游戏
玩家选择 “0”-退出游戏
玩家选择其他数字—提示选择错误,重新选择
实现选择数字玩游戏:
1.如何做到玩完一把再玩一把,不想玩了还能退出游戏呢?
我们可以使用do-while循环,设置循环判断为输入的值,这样就实现了只有在输入为0时退出游戏
2. 如何做到选择1玩游戏、选择0退出游戏、选择其他数提示选择错误呢?
我们可以在do-while循环的里面使用switch-case语句
代码如下:
2. game函数的实现
2.1 初始化棋盘
我们这里写的是三子棋的代码,三子棋有三行三列,我们可以使用二维数组来打印
我们可以遍历这个二维数组,把里面的9个元素都初始化为空格
代码:
void InitBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = ' '; } } }
2.2 显示棋盘
由于我们将上面二维数组的每个元素都初始化为空格,如果我们就这样打印出来给玩家玩游戏,那体验感是非常差的,所以,我们将用以下方法优化我们的棋盘显示,方便玩家玩
面蓝色长方形框中:
我们可以将三个空格(中间是数据,两边是空格)和后面的竖线归为1组,这一行有三组
注意:我们最后1组没有竖线(|),所以要另外控制下
上面黄色长方形框中:
我们将三个横线和一条竖线归为1组,一行也是三组,最后一行同理
代码实现:
总结:通过上面的分析,我们可以看出,每打印一行棋盘,我们其实是有两行的棋盘格式控制,所以,我们可以将蓝色和黄色框看成一组,一共有三组,最后一组不打印横线
void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { //1. 打印数据 int j = 0; for (j = 0; j < col; j++) { printf(" %c ", board[i][j]); if(j<col-1) printf("|"); } printf("\n"); //2. 打印分割线 if (i < row - 1) { //printf("---|---|---\n"); int j = 0; for (j = 0; j < col; j++) { printf("---"); if(j<col-1) printf("|"); } printf("\n"); } } }
2.3 玩家下棋
三行三列的二维数组,行和列的下标范围都是0~2,玩家有可能不知道数组的性质,会出现数组下标越界的情况,这时我们需要将玩家输入的横竖坐标都进行减1处理
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"); } } }
2.4 电脑下棋
电脑下棋,我们可以使用生成随机数的函数,让生成的随机数%行、%列,就是一个随机的二维数组下标
生成随机数的函数用法,在我之前的博客有介绍,有兴趣可以去学习下哦!
void ComputerMove(char board[ROW][COL], int row, int col) { int x = 0;//0~row-1 int y = 0;//0~col-1 printf("电脑下棋:>\n"); while (1) { x = rand() % row; y = rand() % col; if (board[x][y] == ' ') { board[x][y] = '#'; break; } } }
2.5 判断输赢
该函数要实现以下4种情况
1. 玩家赢
2. 电脑赢
3. 平局
4. 上面情况都不符合,那就继续下
赢的三种情况
1. 每一行出现三个相同的符号 2. 每一列出现三个相同的符号 3. 对角线出现三个相同的
平局:
实现一个判断这把游戏是不是平局的函数,在判断输赢函数中来调用
char IsWin(char board[ROW][COL], int row, int col) { //赢 //行 int i = 0; for (i = 0; i < row; i++) { if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ') { return board[i][0]; } } //列 for (i = 0; i < col; i++) { if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') { return board[0][i]; } } //对角线 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ') return board[1][1]; if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ') return board[1][1]; //平局 if (IsFull(board, row, col) == 1) { return 'Q'; } //继续 return 'C'; }
2.6 判断棋盘是否满了
遍历数组,看是否有元素还是空格,如果有返回0,如果没有,那就表示棋盘满了,返回1
注意:这里返回的数字是返回到判断输赢函数的条件判断语句中
int IsFull(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { if (board[i][j] == ' ') { return 0; } } } return 1; }
3. 全部代码
3.1 game.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 3 #define COL 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); //电脑下棋 void ComputerMove(char board[ROW][COL], int row, int col); //判断输赢 //玩家赢 - '*' //电脑赢 - '#' //平局 - 'Q' //继续 - 'C' char IsWin(char board[ROW][COL], int row, int col);
3.2 game.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" //初始化棋盘为空格 void InitBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = ' '; } } } //打印棋盘 void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { //1. 打印数据 int j = 0; for (j = 0; j < col; j++) { printf(" %c ", board[i][j]); if(j<col-1) printf("|"); } printf("\n"); //2. 打印分割线 if (i < row - 1) { //printf("---|---|---\n"); int j = 0; for (j = 0; j < col; j++) { printf("---"); if(j<col-1) printf("|"); } printf("\n"); } } } 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"); } } } // //电脑随机下棋 // void ComputerMove(char board[ROW][COL], int row, int col) { int x = 0;//0~row-1 int y = 0;//0~col-1 printf("电脑下棋:>\n"); while (1) { x = rand() % row; y = rand() % col; if (board[x][y] == ' ') { board[x][y] = '#'; break; } } } //判断棋盘是否已满 int IsFull(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { if (board[i][j] == ' ') { return 0; } } } return 1; } //判断输赢 char IsWin(char board[ROW][COL], int row, int col) { //赢 //行 int i = 0; for (i = 0; i < row; i++) { if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ') { return board[i][0]; } } //列 for (i = 0; i < col; i++) { if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ') { return board[0][i]; } } //对角线 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ') return board[1][1]; if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ') return board[1][1]; //平局 if (IsFull(board, row, col) == 1) { return 'Q'; } //继续 return 'C'; }
3.3 test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void menu() { printf("*****************************\n"); printf("******** 1. play *********\n"); printf("******** 0. exit *********\n"); printf("*****************************\n"); } void game() { 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); //判断输赢 ret = IsWin(board, ROW, COL); if (ret != 'C') break; } if (ret == '*') printf("玩家赢\n"); else if (ret == '#') printf("电脑赢\n"); else printf("平局\n"); } int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("请选择:>"); scanf("%d", &input);//1 0 4 switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,重新选择!\n"); break; } } while (input); return 0; }