联博开奖_C语言小项目--《三子棋》实战训练
发表时间:2021-01-03 浏览量:85
C语言小项目--《三子棋》实战训练
写在开头:本案例代码接纳win10系统下 Visual Studio 2019 编译器举行誊写编译的。对于该编译器“scanf()”编译时无法通过,解决方案在每个需要该函数的文件的第一行加入如下代码:
#define _CRT_SECURE_NO_WARNINGS 1
首先确立主程序文件main.c,函数文件game.c,头文件game.h。其中函数文件用于存放对游戏中各个部门功效实现的函数代码;头文件用于举行函数声明。
对于任何程序,都需要一个主体部门,在三子棋游戏中也不破例。对于一个游戏,基本包罗游戏界面和游戏选项。游戏运行,首先举行游戏菜单打印,守候用户输入,凭据用户输入内容举行下一步的操作。其中菜单部门可以使用menu()函数举行实现,用户输入则用scanf()函数来吸收。划定:菜单打印两个选项,当用户键入1时,则最先举行游戏(游戏部门由game()函数实现);当用户键入0时,则退出程序;若用户键入其他字符,则提醒用户输入有误,需重新收支。因此可以使用switch()函数来实现此部门功效。详细实现代码如下:
int main(void) { int input; srand((unsigned int)time(NULL)); printf("****三子棋游戏****\n"); printf("玩家执子:*;电脑执子:#\n"); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("游戏竣事。\n"); break; default: printf("输入错误,请重新输入!!!\n\n"); break; } } while (input); return 0; }
其中menu()函数的代码如下:
//打印菜单 void menu(void) { printf("*************************\n"); printf("**1.play*********0.exit**\n"); printf("*************************\n"); }
对于游戏部门,首先是要天生棋盘,每次进入游戏初始都要对棋盘内容举行初始化,然后对棋盘举行可视化。天生棋盘可以使用一个2维数组举行,只需对玩家和电脑每次输入的坐标举行存放。初始化棋盘使用InitBoard()函数举行,可视化用DisplayBoard()函数举行。
其次是游戏的主要部门,天生棋盘后,玩家和电脑划分落子,当有一方赢或者平手则退出游戏。玩家落子使用PlayerMove()函数实现,电脑落子使用ComMove()函数实现,判断输赢则用Winner()函数实现。下边则对上述的各个函数功效的逻辑举行剖析并实现。
棋盘部门
为了保证程序的健壮性,即可以利便改变棋盘的巨细,在头文件中界说三个常量来存放棋盘的巨细和玩的巨细(如可以玩4子棋,5子棋等)。注重界说常量时最后不要加“;”,否则后边代码会失足。
#define COL 5 //棋盘有5列 #define ROW 5 //棋盘有5行 #define COUNT 3 //三子棋
建立棋盘:
//建立一个棋盘 char board[ROW][COL] = { 0 };
对棋盘举行初始化:每开一次新的游戏后都需要对棋盘举行初始化。对棋盘举行初始化即遍历棋盘,把棋盘每个位置元素都置空。因此该函数需要能够吸收棋盘而且知道棋盘的巨细。其代码对应如下:
//初始化棋盘 void InitBoard(char board[ROW][COL],int row, int col) { int i; int j; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { board[i][j] = ' '; } } }
棋盘可视化:在屏幕上打印棋盘;棋盘上应该包罗位置坐标,以便于用户输入。棋盘如下图所示:
可以看出,首先在屏幕上打印出横坐标(或者最后打印出来),然后每一行都可以看成是由以下两部门字符组成“(空格)(数组内容)(空格)|”,每一行的最后一列没有“|”,紧接着是“---|”,同理最后一列没有“|”。代码实现如下:
//显示棋盘 void DisplayBoard(char board[ROW][COL], int row, int col) { int i; int j; //首先打印出横坐标 printf(" "); for (j = 0; j < col; j++) { printf("%2d ",j+1); } printf("\n\n"); //打印棋盘 for (i = 0; i < row; i++) { //棋盘的每一列最先打印纵坐标 printf("%3d ",i+1); //打印棋盘每一行的第一部门内容 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("---"); if (j < col - 1) { printf("|"); } } } printf("\n"); } }
游戏部门
天生棋盘后则玩家最先落子:
玩家落子:要求函数可以吸收玩家输入的坐标,而且每次对玩家输入的坐标举行判断,若是玩家输入的位置上已经有棋子,则提醒玩家已经有棋子,而且重新输入,同理若是玩家输入的坐标局限超出了棋盘局限,应该提醒玩家输入坐标不在棋盘局限内,重新输入坐标,此外,棋盘显示的坐标位置是从1最先,而二维数组下标是从0最先,函数内部还要对坐标举行转换。
电脑落子:电脑使用随机数举行落子,同玩家落子一样,需要举行同样判断,但不需要举行提醒。此外,电脑举行落子后,需要对其坐标举行纪录并输出,提醒玩家电脑落子的位置(若是棋盘过大,落子过多,不提醒则不清晰电脑的落子位置),同理,函数也需对坐标举行转化。C语言中函数无法返回两个值,以是需要用一个长度为2的整型数组对坐标举行存放,以便后续屏幕输出和判断输赢使用。
玩家落子函数代码如下:
//玩家落子,函数形参中arr用于吸收落子坐标 void PlayerMove(char board[ROW][COL], int row, int col, int arr[]) { int i; int j; printf("该玩家落子\n"); printf("请输入位置:"); printf("例如:1 1(该位置对应棋盘左上角第一格,输入完毕按enter键竣事)\n"); while (1) { //吸收坐标 scanf("%d %d", &i, &j); //将坐标转换为棋盘对应的数组下标并对输入坐标的合法性举行判断 //坐标局限判断 if ((i - 1) >= 0 && (i - 1) < row && (j - 1) >= 0 && (j - 1) < row ) { //输入坐标内容判断,若是没有棋子则落子 if (board[i - 1][j - 1] == ' ') { board[i - 1][j - 1] = '*'; arr[0] = i-1; //存放落子横坐标对应的数组下标 arr[1] = j-1; //存放落子纵坐标对应的数组下标 return arr; //将下标举行返回 } else { printf("该位置已有棋子,请重新输入!!\n"); } } else { printf("输入坐标不在棋盘局限内,请重新输入!!\n"); } } }
电脑落子代码如下:
,,www.9cx.net采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。
//电脑落子 void ComMove(char board[ROW][COL], int row, int col,int arr[]) { printf("该电脑落子:\n"); int i; int j; while (1) { i = rand() % row; //在0-棋盘横向长度的局限内天生随机数 j = rand() % col; //在0-棋盘纵向长度的局限内天生随机数 if (board[i][j ] == ' ') { board[i][j] = '#'; arr[0] = i; arr[1] = j; return arr; //将电脑该步的位置返回 } } }
输赢判断
每次玩家或电脑举行落子后,都需要举行判断输赢。以三子棋(头文件中COUNT 设为3)为例,落子后以该子为起点,在其横向、纵向、斜向举行搜索,若是有三个延续相同的子,则提醒本轮落子的获胜,同时退出游戏。若是棋盘最后一个位置落子后仍未有赢家,则提醒平手,并退出游戏。
由上边落子代码看出,落子时返回了落子时的坐标,该坐标在此处举行传参。
以横向搜索为例:先向右举行搜索,使用一个计数器吸收相同棋子的个数,若是碰着相同的棋子则计数器加一,碰着差别的棋子(棋盘为空也算差别的棋子)则直接退出搜索;然后向左举行同样的步骤。搜索时要注重不要超出棋盘局限,可以看出,横向搜索时只有横坐标发生变化,而纵坐标没有发生变化。
其他三个偏向搜索同理(斜向有两个)。总共有四个偏向,以是使用一个长度为4的一维数组来吸收四个偏向的计数器值。
若是随便一个偏向的棋子数大于或者即是COUNT,则该函数返回落子位置对应的子(这里就是字符:*或#)。
若是该次落子后还没有赢家,则判断棋盘是否下满,若是没有下满,则函数返回“C”(Continue,示意继续下一回合),若是棋盘下满,则函数返回“E”(End,示意游戏竣事)。
判断输赢代码如下:
//判断输赢 char Winner(char board[ROW][COL], int row, int col,int arr[]) { int i; int j; int x = arr[0]; //落子横坐标对应棋盘数组的下标 int y = arr[1]; //落子纵坐标对应棋盘数组的下标 int count[4] = {1,1,1,1}; //用于吸收四个偏向延续子长度的数组 //向左检查 //纵坐标稳定,横坐标增添 for (i = x+1; i < row; i++) { if (board[i][y] == board[x][y] && board[x][y] != ' ') { (count[0])++; } else { break; } } //向右检查 for (i = x-1; i >= 0; i--) { if (board[i][y] == board[x][y] && board[x][y] != ' ') { (count[0])++; } else { break; } } //向上检查 for (j = y+1; j < col; j++) { if (board[x][j] == board[x][y] && board[x][y] != ' ') { (count[1])++; } else { break; } } //向下检查 for (j = y-1; j >= 0; j--) { if (board[x][j] == board[x][y] && board[x][y] != ' ') { (count[1])++; } else { break; } } //向右上检查 i = x + 1; j = y + 1; while (i < row && j < col) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[2])++; i++; j++; } else { break; } } //向左下检查 i = x - 1; j = y - 1; while (i >= 0 && j >= 0) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[2])++; i--; j--; } else { break; } } //向左上检查 i = x - 1; j = y + 1; while (i >= 0 && j < col) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[3])++; i--; j++; } else { break; } } //向右下检查 i = x + 1; j = y - 1; while (i < row && j >= 0) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[3])++; i++; j--; } else { break; } } //随便偏向的计数器跨越COUNT,就返回落子时对应的子 for (i = 0; i < 4; i++) { if (count[i] >= COUNT) { return board[x][y]; } } //判断棋盘是否下满 int ret = IsFull(board, ROW, COL); if (ret) { return 'E'; } return 'C'; }
判断棋盘是否下满的函数:对棋盘举行遍历,若是每个位置都不为空,就返回1;否则返回0.
//判断棋盘是否落满子 int IsFull(char board[ROW][COL], int row, int col) { int i; int j; for (i = 0; i < row; i++) { for (j = 0; j< row; j++) { if (board[i][j] == ' ') { return 0; } } } return 1; }
game()实现
上边对该游戏形貌的每个功效都举行了实现,下边在game()函数里对这些函数举行组装
//游戏主体 void game(void) { char ret; //用于吸收落子坐标 int arr[2]; //游戏界面部门 //建立一个棋盘 char board[ROW][COL] = { 0 }; //初始化棋盘 InitBoard(board, ROW, COL); //打印棋盘 DisplayBoard(board, ROW, COL); //游戏功效部门 while (1) { //玩家落子 PlayerMove(board, ROW, COL,arr); DisplayBoard(board, ROW, COL); \\落子后举行判断,由Winner()函数返回值可以看出,只要返回值是C就继续举行游戏 ret = Winner(board, ROW, COL,arr); if (ret !='C') { break; } //电脑落子 ComMove(board, ROW, COL,arr); printf("电脑落子位置是:(%d,%d)\n",arr[0]+1,arr[1]+1); DisplayBoard(board, ROW, COL,arr); ret = Winner(board, ROW, COL,arr); if (ret != 'C') { break; } } if (ret == '*') { printf("恭喜你,胜利!\n"); } else if (ret == '#') { printf("很遗憾,失败了!\n"); } else { printf("旗鼓相当,打成平手\n"); } }
总结
main.c文件的代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" int main(void) { int input; srand((unsigned int)time(NULL)); printf("****三子棋游戏****\n"); printf("玩家执子:*;电脑执子:#\n"); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("游戏竣事。\n"); break; default: printf("输入错误,请重新输入!!!\n\n"); break; } } while (input); return 0; }
game.c文件的代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" //打印菜单 void menu(void) { printf("*************************\n"); printf("**1.play*********0.exit**\n"); printf("*************************\n"); } //初始化棋盘 void InitBoard(char board[ROW][COL],int row, int col) { int i; int j; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { board[i][j] = ' '; } } } //显示棋盘 void DisplayBoard(char board[ROW][COL], int row, int col) { int i; int j; printf(" "); for (j = 0; j < col; j++) { printf("%2d ",j+1); } printf("\n\n"); for (i = 0; i < row; i++) { printf("%3d ",i+1); 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("---"); if (j < col - 1) { printf("|"); } } } printf("\n"); } } //玩家落子 void PlayerMove(char board[ROW][COL], int row, int col, int arr[]) { int i; int j; printf("该玩家落子\n"); printf("请输入位置:"); printf("例如:1 1(该位置对应棋盘左上角第一格,输入完毕按enter键竣事)\n"); while (1) { scanf("%d %d", &i, &j); if ((i - 1) >= 0 && (i - 1) < row && (j - 1) >= 0 && (j - 1) < row ) { if (board[i - 1][j - 1] == ' ') { board[i - 1][j - 1] = '*'; arr[0] = i-1; arr[1] = j-1; return arr; } else { printf("该位置已有棋子,请重新输入!!\n"); } } else { printf("输入坐标不在棋盘局限内,请重新输入!!\n"); } } } //电脑落子 void ComMove(char board[ROW][COL], int row, int col,int arr[]) { printf("该电脑落子:\n"); int i; int j; while (1) { i = rand() % row; j = rand() % col; if (board[i][j ] == ' ') { board[i][j] = '#'; arr[0] = i; arr[1] = j; return arr; } } } //判断输赢 char Winner(char board[ROW][COL], int row, int col,int arr[]) { int i; int j; int x = arr[0]; int y = arr[1]; int count[4] = {1,1,1,1}; //向左检查 for (i = x+1; i < row; i++) { if (board[i][y] == board[x][y] && board[x][y] != ' ') { (count[0])++; } else { break; } } //向右检查 for (i = x-1; i >= 0; i--) { if (board[i][y] == board[x][y] && board[x][y] != ' ') { (count[0])++; } else { break; } } //向上检查 for (j = y+1; j < col; j++) { if (board[x][j] == board[x][y] && board[x][y] != ' ') { (count[1])++; } else { break; } } //向下检查 for (j = y-1; j >= 0; j--) { if (board[x][j] == board[x][y] && board[x][y] != ' ') { (count[1])++; } else { break; } } //向右上检查 i = x + 1; j = y + 1; while (i < row && j < col) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[2])++; i++; j++; } else { break; } } //向左下检查 i = x - 1; j = y - 1; while (i >= 0 && j >= 0) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[2])++; i--; j--; } else { break; } } //向左上检查 i = x - 1; j = y + 1; while (i >= 0 && j < col) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[3])++; i--; j++; } else { break; } } //向右下检查 i = x + 1; j = y - 1; while (i < row && j >= 0) { if (board[i][j] == board[x][y] && board[x][y] != ' ') { (count[3])++; i++; j--; } else { break; } } for (i = 0; i < 4; i++) { if (count[i] >= COUNT) { return board[x][y]; } } //棋盘是否满? int ret = IsFull(board, ROW, COL); if (ret) { return 'E'; } return 'C'; } //判断棋盘是否落满子 int IsFull(char board[ROW][COL], int row, int col) { int i; int j; for (i = 0; i < row; i++) { for (j = 0; j< row; j++) { if (board[i][j] == ' ') { return 0; } } } return 1; } //游戏主体 void game(void) { char ret; //用于吸收落子坐标 int arr[2]; //游戏界面部门 //建立一个棋盘 char board[ROW][COL] = { 0 }; //初始化棋盘 InitBoard(board, ROW, COL); //打印棋盘 DisplayBoard(board, ROW, COL); //游戏功效部门 while (1) { //玩家落子 PlayerMove(board, ROW, COL,arr); DisplayBoard(board, ROW, COL); ret = Winner(board, ROW, COL,arr); if (ret !='C') { break; } //电脑落子 ComMove(board, ROW, COL,arr); printf("电脑落子位置是:(%d,%d)\n",arr[0]+1,arr[1]+1); DisplayBoard(board, ROW, COL,arr); ret = Winner(board, ROW, COL,arr); if (ret != 'C') { break; } } if (ret == '*') { printf("恭喜你,胜利!\n"); } else if (ret == '#') { printf("很遗憾,失败了!\n"); } else { printf("旗鼓相当,打成平手\n"); } }
game.h头文件代码如下:
#include <stdio.h> #include <stdlib.h> #include <time.h> #ifndef __GAME_H__ #define __GAME_H__ #define COL 5 #define ROW 5 #define COUNT 3 void menu(void); void game(void); 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,int arr[]); void ComMove(char board[ROW][COL], int row, int col,int arr[]); char Winner(char board[ROW][COL], int row, int col,int arr[]); int IsFull(char board[ROW][COL], int row, int col); #endif
0
珍藏