1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > C语言实现井字棋游戏(含算法优化)

C语言实现井字棋游戏(含算法优化)

时间:2020-09-29 12:00:56

相关推荐

C语言实现井字棋游戏(含算法优化)

目录

序言

代码1

小结

算法优化

代码2

总结

序言

井字棋

英文名叫Tic-Tac-Toe

想必大家对这个小游戏都不陌生了

无论是小时候课堂上被画的全是”井“字的草稿纸

还是长大后在”炼狱小镇“

那么,如何通过C语言来实现呢?

我们需要大量的自定义函数来满足游戏功能

需要函数来展示井字棋的棋盘

需要函数来实现玩家和机器下棋

那么

首先,我们先构思一个框架

头文件#include<stdio.h>…… 主函数中自定义函数int menu() 初始界面展示int Game() 游戏运行算法其他自定义函数(首先想到的是用3*3的数组来表达棋盘 并通过放入字符来表达落子)void Board(char board[ROW][COL], int row, int col) 棋盘void player_move(char board[ROW][COL], int row, int col) 玩家下棋void computer_move(char board[ROW][COL], int row, int col) 电脑下棋char win_lose(char board[ROW][COL], int row, int col) 判断胜负

由于这次代码有点小多 所以分类建立了三个文件来存储代码

代码1

根据咱们设想的框架来逐步完善程序

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++){//打印数据int j = 0;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 player_move(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 computer_move(char board[ROW][COL], int row, int col){int x = 0;int y = 0;printf("电脑下棋:>\n");while (1){x = rand() % row;//0~2y = rand() % col;//0~2if (board[x][y] == ' '){board[x][y] = '#';break;}}}//判断棋盘是否被下满static int if_full(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 is_win(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][1] != ' '){return board[i][1];}}//判断列for (i = 0; i < col; i++){if (board[0][i] == board[1][i]&&board[1][i] == board[2][i] && board[1][i] != ' '){return board[1][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 (if_full(board, row, col) == 1){return 'Q';}//继续return 'C';}

game.h

函数的声明

#define _CRT_SECURE_NO_WARNINGS 1#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 player_move(char board[ROW][COL], int row, int col);//电脑下棋void computer_move(char board[ROW][COL], int row, int col);//判断输赢char is_win(char board[ROW][COL], int row, int col);//1. 玩家赢了 - hr//2. 电脑赢了 - cw//3. 平局 - d//4. 游戏继续 - c

test.c

测试游戏

#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"void menu(){system("cls");printf("Tic-Tac-Toe");printf("**************************************\n");printf("***********1.PLAY***********\n");printf("**************************************\n");printf("***********0.QUET***********\n");printf("**************************************\n");printf("\n");}void Game(){char ret = 0;char board[ROW][COL] = { 0 };InitBoard(board,ROW,COL);DisplayBoard(board, ROW, COL);while (1){player_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = win_lose(board, ROW, COL);if (ret != 'c'){break;}computer_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = win_lose(board, ROW, COL);if (ret != 'c'){break;}}if (ret == '*'){printf("\n\n");printf("\t\t\t You Win!\n");}else if (ret == '#'){printf("\n\n");printf("\t\t\t You Lose!\n");}else if (ret =='d'){printf("\n\n");printf("\t\t\t 和局\n");}}int main(){int input = 0;srand((unsigned int)time(NULL));do {menu();printf("\t\t\t 请选择-->");scanf("%d", &input);switch (input){case 1:Game();system("pause");break;case 0:printf("退出游戏\n");system("pause");break;default:printf("输入错误,请重新选择");system("pause");break;}} while (input);return 0;}

小结

整个“井字棋”程序算是初步完成了

但是有亿点点小问题——电脑宛如人工智障

因为我们是通过<time.h>头文件获得的时间(秒数)数字,调用srand()来初始化它的随机值,最后通过rand() % rowrand() % col 随机生成行、列范围在1到3的坐标,从而达成电脑下棋。

BUT!问题在于这样完全没有人机交互性 人工智能?人工智障!

电脑只会在3*3的棋盘中剩余的格子内落子,不会追三字连线去赢,也不会阻碍玩家三子连线

所以我们要对其算法进行优化 让电脑变得更聪明一些

算法优化

我想到的方法是通过设一个变量 当作电脑落子优先级变量

例如int k=0; 当k=0的时候 电脑暂时没有优先级更高的事要做 所以这时候还是随机落子

但是当遇到特别的情况 例如电脑自己将要三子连线 又或是 玩家将要三子连线,将变量k赋值为1,优先执行连子获胜或者围堵玩家妨碍玩家获胜的指令

具体操作如下:

void computer_move(char board[ROW][COL], int row, int col) {int i = 0;int j = 0;int k = 0;k = priority_board_com(board, row, col);while (0 == k){i = rand() % row;j = rand() % col;if (board[i][j] == ' '){Sleep(400);board[i][j] = '#';break;}}}

在执行指令前另定义一个函数,用于判断当前棋盘局势是否满足特殊情况。若是满足则赋值k=1 执行针对性落子操作;若是不满足,则返回k=0;继续进行computer_move(board, row, col) 中剩余指令,当k==0 随机落子

对于判断优先级函数priority_board_com(board, row, col)没有什么难度高的编写,单纯是列举出所有特殊情况,包括电脑自己将要赢或者玩家将要赢,进行针对性落子,并返回k=1,不执行computer_move()中后续代码

例:当电脑在同一列上有两个己方的子 且剩余的那个格为空

if ((board[i][0] == board[i][1]) && (board[i][0] == '#' || board[i][1] == '#') && board[i][2] == ' '){board[i][2] = '#';k = 1;break;}

同一行从两个子连成三个子的情况有三种

那么对于行 有以下的代码

for (i = 0; i < row; i++){if ((board[i][0] == board[i][1]) && (board[i][0] == '#' || board[i][1] == '#') && board[i][2] == ' '){board[i][2] = '#';k = 1;break;}if ((board[i][0] == board[i][2]) && (board[i][0] == '#' || board[i][2] == '#') && board[i][1] == ' '){board[i][1] = '#';k = 1;break;}if ((board[i][1] == board[i][2]) && (board[i][1] == '#' || board[i][2] == '#') && board[i][0] == ' '){board[i][0] = '#';k = 1;break;}}if (k != 0)break;

举一反三 我们又可以对列 对角线(需注意 对角线分左右两条)条件继续编写 方法一致

编写完电脑判断自己能否获胜的程序,咱们再举再反,编写电脑判断玩家能否获胜的程序

代码与上诉相类似

代码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){system("cls");printf("\n\n\n\n\n\n");printf("\t\t\t\tTic-Tac-Toe");printf("\n\n\n");int i = 0;for (i = 0; i < row; i++){int j = 0;printf("\t\t\t\t");for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1) printf("|");}printf("\n");if (i < row - 1){printf("\t\t\t\t");for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}}//玩家下棋void player_move(char board[ROW][COL], int row, int col){int x = 0;int y = 0;printf("\n");printf("\t\t\t(玩家)轮到你了!:\n");while (1){printf("\t\t\t请输入坐标:");fflush(stdin);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("\t\t\t棋位已占!\n");}}else{printf("\t\t\t非法坐标!\n");}}}//电脑下棋int priority_board_com(char board[ROW][COL], int row, int col);int priority_board_hum(char board[ROW][COL], int row, int col, int k);void computer_move(char board[ROW][COL], int row, int col) {printf("\t\t\t(电脑)电脑在思考中~:\n");int i = 0;int j = 0;int k = 0;k = priority_board_com(board, row, col);while (0 == k){i = rand() % row;j = rand() % col;if (board[i][j] == ' '){Sleep(400);board[i][j] = '#';break;}}}//电脑算法优化 判断优先级 //电脑判断自己能否赢 并去连线int priority_board_com(char board[ROW][COL], int row, int col){int i = 0;int j = 0;//k用于返回值int k = 0;while (k == 0){//电脑判断自己在三行上是否会赢for (i = 0; i < row; i++){if ((board[i][0] == board[i][1]) && (board[i][0] == '#' || board[i][1] == '#') && board[i][2] == ' '){board[i][2] = '#';k = 1;break;}if ((board[i][0] == board[i][2]) && (board[i][0] == '#' || board[i][2] == '#') && board[i][1] == ' '){board[i][1] = '#';k = 1;break;}if ((board[i][1] == board[i][2]) && (board[i][1] == '#' || board[i][2] == '#') && board[i][0] == ' '){board[i][0] = '#';k = 1;break;}}if (k != 0)break;//电脑判断自己在三列上是否会赢for (j = 0; j < col; j++){if ((board[0][j] == board[1][j]) && (board[0][j] == '#' || board[1][j] == '#') && board[2][j] == ' '){board[2][j] = '#';k = 1;break;}if ((board[0][j] == board[2][j]) && (board[0][j] == '#' || board[2][j] == '#') && board[1][j] == ' '){board[1][j] = '#';k = 1;break;}if ((board[1][j] == board[2][j]) && (board[1][j] == '#' || board[2][j] == '#') && board[0][j] == ' '){board[0][j] = '#';k = 1;break;}}if (k != 0)break;//对角线是否会赢while (0 == k){//左边对角线if ((board[0][0] == board[1][1]) && (board[0][0] == '#' || board[1][1] == '#') && board[2][2] == ' '){board[2][2] = '#';k = 1;break;}if ((board[0][0] == board[2][2]) && (board[0][0] == '#' || board[2][2] == '#') && board[1][1] == ' '){board[1][1] = '#';k = 1;break;}if ((board[1][1] == board[2][2]) && (board[1][1] == '#' || board[2][2] == '#') && board[0][0] == ' '){board[0][0] = '#';k = 1;break;}//右边对角线if ((board[0][2] == board[1][1]) && (board[0][2] == '#' || board[1][1] == '#') && board[2][0] == ' '){board[2][0] = '#';k = 1;break;}if ((board[0][2] == board[2][0]) && (board[0][2] == '#' || board[2][0] == '#') && board[1][1] == ' '){board[1][1] = '#';k = 1;break;}if ((board[1][1] == board[2][0]) && (board[1][1] == '#' || board[2][0] == '#') && board[0][2] == ' '){board[0][2] = '#';k = 1;break;}break;}k = priority_board_hum(board, row, col, k);return k;}}//电脑判断玩家能否赢 并去堵截int priority_board_hum(char board[ROW][COL],int row,int col,int k){int i = 0;int j = 0;while (k == 0){//判断玩家在三行上是否会赢for (i = 0; i < row; i++){if ((board[i][0] == board[i][1]) && (board[i][0] == '*' || board[i][1] == '*') && board[i][2] == ' '){board[i][2] = '#';k = 1;break;}if ((board[i][0] == board[i][2]) && (board[i][0] == '*' || board[i][2] == '*') && board[i][1] == ' '){board[i][1] = '#';k = 1;break;}if ((board[i][2] == board[i][1]) && (board[i][2] == '*' || board[i][1] == '*') && board[i][0] == ' '){board[i][0] = '#';k = 1;break;}}if (k != 0)break;//判断玩家在三列上是否会赢for (j = 0; j < col; j++){if ((board[0][j] == board[1][j]) && (board[1][j] == '*' || board[0][j] == '*') && board[2][j] == ' '){board[2][j] = '#';k = 1;break;}if ((board[0][j] == board[2][j]) && (board[2][j] == '*' || board[0][j] == '*') && board[1][j] == ' '){board[1][j] = '#';k = 1;break;}if ((board[1][j] == board[2][j]) && (board[2][j] == '*' || board[1][j] == '*') && board[0][j] == ' '){board[0][j] = '#';k = 1;break;}}break;}//判断玩家在对角线上是否会赢while (k == 0){//左边对角线if ((board[0][0] == board[1][1]) && (board[1][1] == '*' || board[0][0] == '*') && board[2][2] == ' '){board[2][2] = '#';k = 1;break;}if ((board[0][0] == board[2][2]) && (board[2][2] == '*' || board[0][0] == '*') && board[1][1] == ' '){board[1][1] = '#';k = 1;break;}if ((board[1][1] == board[2][2]) && (board[1][1] == '*' || board[2][2] == '*') && board[0][0] == ' '){board[0][0] = '#';k = 1;break;}//右边对角线if ((board[0][2] == board[1][1]) && (board[0][2] == '*' || board[1][1] == '*') && board[2][0] == ' '){board[2][0] = '#';k = 1;break;}if ((board[0][2] == board[2][0]) && (board[2][0] == '*' || board[0][2] == '*') && board[1][1] == ' '){board[1][1] = '#';k = 1;break;}if ((board[1][1] == board[2][0]) && (board[2][0] == '*' || board[1][1] == '*') && board[0][2] == ' '){board[0][2] = '#';k = 1;break;}break;}return k;}//判断胜负char win_lose(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][1] != ' '){return board[i][1];}}//判断列for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '){return board[1][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 (if_full(board, row, col) == 1){return 'd';}//继续return 'c';}//判断是否和局static int if_full(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;//满了}

game.h

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>#include<Windows.h>#define MIN(x,y) ((x)<(y)?(x):(y))#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 player_move(char board[ROW][COL], int row, int col);//电脑下棋void computer_move(char board[ROW][COL], int row, int col);//1. 玩家赢了 - hr//2. 电脑赢了 - cw//3. 平局 - d//4. 游戏继续 - c//判断游戏是否有输赢char win_lose(char board[ROW][COL], int row, int col);

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"void menu(){system("cls");printf("\n\n\n\n\n\n");printf("\t\t\t\tTic-Tac-Toe");printf("\n\n\n");printf("\t\t\t **************************************\n");printf("\t\t\t ***********1.PLAY***********\n");printf("\t\t\t **************************************\n");printf("\t\t\t ***********0.QUET***********\n");printf("\t\t\t **************************************\n");printf("\n");}void Game();void menu_intro(){system("cls");printf("\n\n\n\n\n\n");printf("\t\t\t\tTic-Tac-Toe");printf("\n\n\n");printf("\t\t\t ****************************************\n");printf("\t\t\t *玩法介绍: *\n");printf("\t\t\t * 玩家的棋子为<*> 电脑的棋子为<#> *\n");printf("\t\t\t * 通过输入棋盘中的坐标落子*\n");printf("\t\t\t * 例:输入1 3 为第一行第三列 *\n");printf("\t\t\t ****************************************\n");printf("\t\t\t ***********1.continue **********\n");printf("\t\t\t ***********0.back **********\n");printf("\t\t\t ****************************************\n");printf("\n");int input2 = 0;printf("\t\t\t 请选择-->");scanf("%d", &input2);switch (input2){case 1:Game();break;case 0:printf("\t\t\t 返回菜单\n");system("pause");break;default:printf("\t\t\t 输入错误,请重新选择");system("pause");break;}}void Game(){char ret = 0;char board[ROW][COL] = { 0 };InitBoard(board,ROW,COL);DisplayBoard(board, ROW, COL);while (1){player_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = win_lose(board, ROW, COL);if (ret != 'c'){break;}computer_move(board, ROW, COL);DisplayBoard(board, ROW, COL);ret = win_lose(board, ROW, COL);if (ret != 'c'){break;}}if (ret == '*'){printf("\n\n");printf("\t\t\t You Win!\n");}else if (ret == '#'){printf("\n\n");printf("\t\t\t You Lose!\n");}else if (ret =='d'){printf("\n\n");printf("\t\t\t 和局\n");}}int main(){int input1 = 0;do {menu();printf("\t\t\t 请选择-->");scanf("%d", &input1);switch (input1){case 1:menu_intro();system("pause");break;case 0:printf("\t\t\t退出游戏\n");system("pause");break;default:printf("\t\t\t输入错误,请重新选择");system("pause");break;}} while (input1);return 0;}

总结

最后代码呈现出来是这样的

通过这次对井字棋的程序编写,学到了更多新知识,较上次的“猜数字游戏”,这次的代码更多,工作量更大,程序更复杂。学会了针对算法的进一步优化,能让程序运行起来看起来“更聪明”。(by th way 升级后的电脑可没那么好赢哦 快去玩玩吧)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。