目录
1.头文件game.h
2.源文件
2.1主函数
2.2子函数
3.程序的不足
可取点:在头文件中,使用#define定义行和列类,在后续的程序中行和列没有具体数值,全部通过ROW和COL表示。这样以后想要对棋盘的大小进行修改的时候,直接在头文件中对#define进行修改即可。
#define ROW 3
#define COL 3
#pragma once #define ROW 3 #define COL 3 #include //菜单函数 void menu(); //是否继续游戏菜单 void ContinueMenu(); //游戏函数 void game(); //初始化棋盘 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); //判断胜、负或平局 char Judge(char Board[ROW][COL], int row, int col); //判断棋盘是否下满了 int Full(char Board[ROW][COL], int row, int col);
//井字棋游戏 #include"game.h" int main() { int input = 0; int con = 0; do { menu(); printf("请选择:"); scanf("%d", &input); switch (input) { case 1: printf("开始游戏\n"); game(); ContinueMenu(); printf("请选择:"); scanf("%d", &con); break; case 2: printf("退出游戏\n"); break; default: printf("输入无效,请重新选择\n"); break; } } while (con == 1 ||(input != 2 && input != 1)); return 0; }
要点
1. 子函数【2.2棋盘生成函数】,生成的棋盘样式如下图,不知道这样直观的展示出来,会方便理解该程序吗?
2.子函数【2.3玩家下棋函数】中
因为数组的起始位置为[0][0],但大众一般认为的起始位置为[1][1],所以要进行+1、-1调整,以符合大众的认知。
if ((i > 0 && i < row+1 && j > 0 && j < col+1) && (Board[i-1][j-1] == ' '))
{
Board[i-1][j-1] = 'O';
...
如果输入的坐标无效,就要重新输入,为此设置了一个标志flag。如果flog=0,说明输入的坐标无效(位置被占用或超出棋盘范围),需要重新输入。
3.生成随机数
利用时间戳生成随机数,需要的头文件为#include
#include #include int ran; srand((unsigned int)time(NULL)); ran = rand();
4.【2.5判断胜负函数】
如果是玩家胜利,就返回玩家使用的符号‘O’
如果是电脑胜利,就返回电脑使用的符号‘X’
如果是棋盘满了且未分出胜负,就返回‘E’
如果以上三种情况都不是,就返回'C',继续进行游戏
#define ROW 3 #define COL 3 #include #include #include //1.菜单函数 void menu() { printf("************************\n"); printf("*****1.Play 2.Exit*****\n"); printf("************************\n"); } //2.游戏函数 void game() { char result; //生成棋盘 char Board[ROW][COL] = { 0 }; //初始化棋盘 InitBoard(Board, ROW, COL); //展示棋盘 DisplayBoard(Board, ROW, COL); while (1) { //玩家下棋 PlayerMove(Board, ROW, COL); DisplayBoard(Board, ROW, COL); //判断胜负 result = Judge(Board, ROW, COL); if (result != 'C') { break; } //电脑下棋 ComputerMove(Board, ROW, COL); DisplayBoard(Board, ROW, COL); //判断胜负 result = Judge(Board, ROW, COL); if (result != 'C') { break; } } if (result == 'O') printf("玩家获胜\n"); else if (result == 'X') printf("电脑获胜\n"); else printf("平局\n"); } //2.1棋盘初始化函数 void InitBoard(char Board[ROW][COL],int row,int col) { int i, j; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { Board[i][j] = ' '; } } } //2.2棋盘生成函数 void DisplayBoard(char Board[ROW][COL], int row, int col) { int i, j; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { //1.打印一行数据 printf(" %c ", Board[i][j]); if (j < col - 1) printf("|"); } printf("\n"); //2.打印分割线 if (i < row - 1) { for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) printf("|"); } printf("\n"); } } } //2.3玩家下棋 void PlayerMove(char Board[ROW][COL], int row, int col) { int i, j; int flag = 1; printf("玩家回合\n"); do { printf("请输入坐标:"); scanf("%d%d", &i, &j); //因为数组的起始位置为[0][0],但大众一般认为的起始位置为[1][1],所以要进行+1、-1调整 if ((i > 0 && i < row+1 && j > 0 && j < col+1) && (Board[i-1][j-1] == ' ')) { Board[i-1][j-1] = 'O'; flag = 1; } else { //如果输入的坐标无效,就要重新输入,为此设置了一个标志flag printf("坐标无效,请重新输入\n"); flag = 0; } } while (flag == 0); } //2.4电脑下棋 void ComputerMove(char Board[ROW][COL], int row, int col) { int i, j; int flag = 1; printf("电脑回合\n"); do { //通过时间生成随机位置 srand((unsigned int)time(NULL)); //通过模row取余数,就能让i在0~row-1之间浮动;j同理 i = rand() % row; j = rand() % col; if (Board[i][j] == ' ') { Board[i][j] = 'X'; flag = 1; } else flag = 0; } while (flag == 0); } //2.5判断胜负函数 char Judge(char Board[ROW][COL], int row, int col) { int i, j; //判断行是否连成三个 for (i = 0; i < row; i++) { int count = 0; for (j = 0; j < col-1; j++) { if ((Board[i][0] != ' ') && (Board[i][j] == Board[i][j + 1])) { count++; } } if (col-1 == count) return Board[i][0]; } //判断列是否连成三个 for (j = 0; j < col; j++) { int count = 0; for (i = 0; i < row-1; i++) { if ((Board[0][j] != ' ') && (Board[i][j] == Board[i+1][j])) { count++; } } //三个元素相等,计数器的数字应该比行数少1。可以用两刀切三段理解。 if (row - 1 == count) return Board[0][j]; } //判断斜线是否连成三个 if (Board[0][0] == Board[1][1] && Board[2][2] == Board[1][1] && Board[0][0] != ' ') return Board[0][0]; if (Board[0][2] == Board[1][1] && Board[2][0] == Board[1][1] && Board[0][2] != ' ') return Board[0][2]; //判断是否平局 if (1 == Full(Board, ROW, COL)) { return 'E'; } return 'C'; } //2.5.1判断棋盘是否满了函数 int Full(char Board[ROW][COL], int row, int col) { int i, j; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { if (Board[i][j] == ' ') return 0; } } return 1; } //3.继续游戏函数 void ContinueMenu() { printf("************************\n"); printf("游戏已结束,是否继续游戏\n"); printf("***1.Continue 2.Exit***\n"); printf("************************\n"); }
程序的不足出现在子函数【2.4电脑下棋】函数中。在实际游玩的发现,在游戏的后期,电脑下棋的速度会变慢。我分析原因如下:
1.电脑下棋的位置完全靠随机数生成,这就导致在游玩的后期,当大多数格子被占用时,电脑往往需要进行多次循环,才能随机出新的位置,耗费计算资源。
2.完全随机的落子,也导致电脑下棋没什么策略性,导致玩家很容易胜利,游戏的趣味性降低。
如果大家有好的解决方案,欢迎留言!
//2.4电脑下棋 void ComputerMove(char Board[ROW][COL], int row, int col) { int i, j; int flag = 1; printf("电脑回合\n"); do { //通过时间生成随机位置 srand((unsigned int)time(NULL)); //通过模row取余数,就能让i在0~row-1之间浮动;j同理 i = rand() % row; j = rand() % col; if (Board[i][j] == ' ') { Board[i][j] = 'X'; flag = 1; } else flag = 0; } while (flag == 0); }