三子棋之VS人工智能/人工智障,你能赢吗?
文章目錄
- 一.前言🚀
- 二.游戲邏輯?🚀
- 三.代碼實(shí)現(xiàn)🚀
- 1.test.c🚗
- 2.game.h🚓
- 3.game.c🚕
- 四.游戲功能具體分析🚀
- 1.棋盤的初始化🚙
- 2.棋盤的打印🚑
- 3.玩家下棋🚒
- 4.電腦下棋🚍
- 4.1簡單模式🚘
- 4.2困難模式🚖
- 5.判斷棋盤滿沒滿🚅
- 6.判斷游戲輸贏🚃
- 五.總結(jié)🚀
一.前言🚀
大家好,首先祝大家五一快樂🎈🎈🎈🎈🎈🎈,當(dāng)然有很多大學(xué)生像作者一樣五一并沒有放假,說多了都是淚啊😭,不過沒事,我們還有周末!廢話不多說了,今天我們一起來研究一下三子棋,雖然在c站三子棋已經(jīng)爛大街了,但是每個(gè)人都有自己與眾不同的地方,值得我們學(xué)習(xí)。所以我們可以博采眾長,吸收別人優(yōu)秀的地方,提高自己的水平。
二.游戲邏輯?🚀
我們在寫一個(gè)項(xiàng)目的時(shí)候,如果這個(gè)項(xiàng)目非常復(fù)雜,不建議大家上來就干代碼的,因?yàn)槟阌泻艽蟮目赡軙?huì)出錯(cuò)。我們應(yīng)該仔細(xì)思考游戲的邏輯,如何實(shí)現(xiàn)這個(gè)項(xiàng)目。
1.我們需要一個(gè)菜單控制游戲,讓玩家做出選擇
2.游戲最好可以讓玩家一直玩,除非玩家退出游戲
3.三子棋需要一個(gè)棋盤,我們打印一個(gè)棋盤(通過二維數(shù)組)
4.玩家下棋,輸入坐標(biāo)(也可以電腦先下棋)
5.打印棋盤,觀察坐標(biāo),(是否有錯(cuò)誤)
6.電腦下棋,打印棋盤,這部分我們可以優(yōu)化一下,讓我們很難贏電腦
7.判斷輸贏,打印棋盤,觀察坐標(biāo)
三.代碼實(shí)現(xiàn)🚀
當(dāng)我們寫的代碼比較多的時(shí)候,建議大家使用模塊化的設(shè)計(jì),我們這里分成三個(gè)部分:
test.c
主函數(shù)部分,對游戲的邏輯進(jìn)行測試運(yùn)行
game.h
庫函數(shù)頭文件的包含
行列的自定義設(shè)置
函數(shù)的定義
game.c
游戲邏輯的具體實(shí)現(xiàn)
1.test.c🚗
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h" void menu() {printf("**************************************\n");printf("******** 1. play(智能模式) *********\n");printf("******** 2. play(智障模式) *********\n");printf("******** 0. exit(退出游戲) *********\n");printf("**************************************\n");} void game1() { //存儲(chǔ)數(shù)據(jù) - 二維數(shù)組char board[ROW][COL] = { 0 };//初始化棋盤 - 初始化空格initBoard(board, ROW, COL);//打印棋盤 - 本質(zhì)是打印數(shù)組的內(nèi)容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;}}switch (ret){case 'O':printf("你贏了,也就一般般吧\n");break;case 'X':printf("你竟然輸給了人工智障,哈哈\n");break;case 'p':printf("平局,好好反思一下你自己\n");break;displayBoard(board, ROW, COL);}//效果差不多/*if (ret == 'o'){printf("玩家贏了\n");}else if (ret == 'x'){printf("電腦贏了\n");}else{printf("平局\n");}*/ } void game2() { //存儲(chǔ)數(shù)據(jù) - 二維數(shù)組char board[ROW][COL] = { 0 };//初始化棋盤 - 初始化空格initBoard(board, ROW, COL);//打印棋盤 - 本質(zhì)是打印數(shù)組的內(nèi)容displayBoard(board, ROW, COL);//下棋char ret = 0;while (1){ SmartComputerMove(board, ROW, COL);displayBoard(board, ROW, COL);ret = isWin(board, ROW, COL);//判斷電腦是否贏得游戲if (ret != 'c'){break;}playerMove(board, ROW, COL);displayBoard(board, ROW, COL);//判斷玩家是否贏得游戲ret = isWin(board, ROW, COL);if (ret != 'c'){break;}}switch (ret){case 'O':printf("您贏了,就算是阿爾法狗也不是您的對手\n");break;case 'X':printf("你輸了,沒事,等于你已經(jīng)和大神過過手了\n");break;case 'p':printf("平局,小伙子,你非常有前途\n");break;displayBoard(board, ROW, COL);} }int main() {int input = 0;srand((unsigned int)time(NULL));do{menu();printf("請選擇模式:>");printf("\n人工智障:1 | 人工智能:2 | 退出游戲:0\n");scanf("%d", &input);switch (input){case 1:game1();break;case 2:game2();break;case 0:printf("退出游戲\n");break;default:printf("輸入錯(cuò)誤,請重新輸入\n");break;}} while (input);return 0; }2.game.h🚓
//防止頭文件被重復(fù)包含 #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); //打印棋盤的函數(shù) 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); //困難模式 void SmartComputerMove(char board[ROW][COL], int row, int col); //判斷棋盤滿沒滿 int isFull(char board[ROW][COL], int row, int col); //1.玩家贏 - O //2.電腦贏 - X //3.平局 - p //4.游戲繼續(xù) - c //判斷輸贏 char isWin(char board[ROW][COL], int row, int col);3.game.c🚕
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"void initBoard(char board[ROW][COL], int row, int col) {for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){board[i][j] = ' ';}} } void displayBoard(char board[ROW][COL], int row, int col) {int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){for(int 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("請輸入下棋坐標(biāo):>");scanf("%d %d", &x, &y);if (x > 0 && x <= row && y > 0 && y <= col){//判斷坐標(biāo)是否被占用if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = 'O';break;}else{printf("坐標(biāo)已被占用,請重新輸入\n");break;}}else{printf("坐標(biāo)錯(cuò)誤,請重新輸入\n");}} }void computerMove(char board[ROW][COL], int row, int col) {int x = 0;int y = 0;printf("電腦走:>\n");while (1){x = rand() % row;y = rand() % col;//不用判斷合法性if(board[x][y] == ' '){board[x][y] = 'X';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) {//判斷三行for (int 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 (int j = 0; j < col; j++){if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' '){return board[0][j];}}//判斷對角線if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[0][0];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[0][2];}//判斷平局int ret = isFull(board, row, col);if (ret == 1){return 'p';}return 'c'; }void SmartComputerMove(char board[ROW][COL], int row, int col) {int i = 0;int j = 0;//判斷每一行是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則落棋for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][0] == 'X' && board[i][2] == ' '){board[i][2] = 'X';}if (board[i][0] == board[i][2] && board[i][0] == 'X' && board[i][1] == ' '){board[i][1] = 'X';}if (board[i][1] == board[i][2] && board[i][1] == 'X' && board[i][0] == ' '){board[i][0] = 'X';}}//判斷每一列是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則落棋for (j = 0; j < col; j++){if (board[0][j] == board[1][j] && board[0][j] == 'X' && board[2][j] == ' '){board[2][j] = 'X';}if (board[0][j] == board[2][j] && board[0][j] == 'X' && board[1][j] == ' '){board[1][j] = 'X';}if (board[1][j] == board[2][j] && board[1][j] == 'X' && board[0][j] == ' '){board[0][j] = 'X';}}//判斷兩條對角線是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則落棋{//第一條if (board[0][0] == board[1][1] && board[0][0] == 'X' && board[2][2] == ' '){board[2][2] = 'X';}if (board[0][0] == board[2][2] && board[0][0] == 'X' && board[1][1] == ' '){board[1][1] = 'X';}if (board[1][1] == board[2][2] && board[1][1] == 'X' && board[0][0] == ' '){board[0][0] = 'X';}//第二條if (board[0][2] == board[1][1] && board[0][2] == 'X' && board[2][0] == ' '){board[2][0] = 'X';}if (board[0][2] == board[2][0] && board[0][2] == 'X' && board[1][1] == ' '){board[1][1] = 'X';}if (board[1][1] == board[2][0] && board[1][1] == 'X' && board[0][2] == ' '){board[0][2] = 'X'; }//如果上面都沒落子,說明不符合贏的條件int i = 0;int j = 0;//判斷每一行是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則堵棋for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][0] == 'O' && board[i][2] == ' '){board[i][2] = 'X';goto end;}if (board[i][0] == board[i][2] && board[i][0] == 'O' && board[i][1] == ' '){board[i][1] = 'X';goto end;}if (board[i][1] == board[i][2] && board[i][1] == 'O' && board[i][0] == ' '){board[i][0] = 'X';goto end;}}//判斷每一列是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則堵棋for (j = 0; j < col; j++){if (board[0][j] == board[1][j] && board[0][j] == 'O' && board[2][j] == ' '){board[2][j] = 'X';goto end;}if (board[0][j] == board[2][j] && board[0][j] == 'O' && board[1][j] == ' '){board[1][j] = 'X';goto end;}if (board[1][j] == board[2][j] && board[1][j] == 'O' && board[0][j] == ' '){board[0][j] = 'X';goto end;}}//判斷兩條對角線是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則堵棋{//第一條if (board[0][0] == board[1][1] && board[0][0] == 'O' && board[2][2] == ' '){board[2][2] = 'X';goto end;}if (board[0][0] == board[2][2] && board[0][0] == 'O' && board[1][1] == ' '){board[1][1] = 'X';goto end;}if (board[1][1] == board[2][2] && board[1][1] == 'O' && board[0][0] == ' '){board[0][0] = 'X';goto end;}//第二條if (board[0][2] == board[1][1] && board[0][2] == 'O' && board[2][0] == ' '){board[2][0] = 'X';goto end;}if (board[0][2] == board[2][0] && board[0][2] == 'O' && board[1][1] == ' '){board[1][1] = 'X';goto end;}if (board[1][1] == board[2][0] && board[1][1] == 'O' && board[0][2] == ' '){board[0][2] = 'X';goto end;}//如果上面都沒返回,說明不符合堵棋,下棋的條件else{computerMove(board, ROW, COL);}}}int ret = 0;end://判斷平局ret = isFull(board, row, col);if (ret == 1){return 'p';}return 'c'; }四.游戲功能具體分析🚀
1.棋盤的初始化🚙
void initBoard(char board[ROW][COL], int row, int col) {for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){board[i][j] = ' ';}} }2.棋盤的打印🚑
void displayBoard(char board[ROW][COL], int row, int col) {int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){for(int j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}} }printf("\n");} }3.玩家下棋🚒
void playerMove(char board[ROW][COL], int row, int col) {int x = 0;int y = 0;printf("玩家走:>\n");while(1){ printf("請輸入下棋坐標(biāo):>");scanf("%d %d", &x, &y);if (x > 0 && x <= row && y > 0 && y <= col){//判斷坐標(biāo)是否被占用if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = 'O';break;}else{printf("坐標(biāo)已被占用,請重新輸入\n");break;}}else{printf("坐標(biāo)錯(cuò)誤,請重新輸入\n");}} }4.電腦下棋🚍
4.1簡單模式🚘
void computerMove(char board[ROW][COL], int row, int col) {int x = 0;int y = 0;printf("電腦走:>\n");while (1){x = rand() % row;y = rand() % col;//不用判斷合法性if(board[x][y] == ' '){board[x][y] = 'X';break;}} }4.2困難模式🚖
void SmartComputerMove(char board[ROW][COL], int row, int col) {int i = 0;int j = 0;//判斷每一行是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則落棋for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][0] == 'X' && board[i][2] == ' '){board[i][2] = 'X';}if (board[i][0] == board[i][2] && board[i][0] == 'X' && board[i][1] == ' '){board[i][1] = 'X';}if (board[i][1] == board[i][2] && board[i][1] == 'X' && board[i][0] == ' '){board[i][0] = 'X';}}//判斷每一列是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則落棋for (j = 0; j < col; j++){if (board[0][j] == board[1][j] && board[0][j] == 'X' && board[2][j] == ' '){board[2][j] = 'X';}if (board[0][j] == board[2][j] && board[0][j] == 'X' && board[1][j] == ' '){board[1][j] = 'X';}if (board[1][j] == board[2][j] && board[1][j] == 'X' && board[0][j] == ' '){board[0][j] = 'X';}}//判斷兩條對角線是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則落棋{//第一條if (board[0][0] == board[1][1] && board[0][0] == 'X' && board[2][2] == ' '){board[2][2] = 'X';}if (board[0][0] == board[2][2] && board[0][0] == 'X' && board[1][1] == ' '){board[1][1] = 'X';}if (board[1][1] == board[2][2] && board[1][1] == 'X' && board[0][0] == ' '){board[0][0] = 'X';}//第二條if (board[0][2] == board[1][1] && board[0][2] == 'X' && board[2][0] == ' '){board[2][0] = 'X';}if (board[0][2] == board[2][0] && board[0][2] == 'X' && board[1][1] == ' '){board[1][1] = 'X';}if (board[1][1] == board[2][0] && board[1][1] == 'X' && board[0][2] == ' '){board[0][2] = 'X'; }//如果上面都沒落子,說明不符合贏的條件int i = 0;int j = 0;//判斷每一行是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則堵棋for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][0] == 'O' && board[i][2] == ' '){board[i][2] = 'X';goto end;//防止多次落子的問題}if (board[i][0] == board[i][2] && board[i][0] == 'O' && board[i][1] == ' '){board[i][1] = 'X';goto end;}if (board[i][1] == board[i][2] && board[i][1] == 'O' && board[i][0] == ' '){board[i][0] = 'X';goto end;}}//判斷每一列是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則堵棋for (j = 0; j < col; j++){if (board[0][j] == board[1][j] && board[0][j] == 'O' && board[2][j] == ' '){board[2][j] = 'X';goto end;}if (board[0][j] == board[2][j] && board[0][j] == 'O' && board[1][j] == ' '){board[1][j] = 'X';goto end;}if (board[1][j] == board[2][j] && board[1][j] == 'O' && board[0][j] == ' '){board[0][j] = 'X';goto end;}}//判斷兩條對角線是否有兩個(gè)相連的棋子,如果有,且第三個(gè)棋格為空,則堵棋{//第一條if (board[0][0] == board[1][1] && board[0][0] == 'O' && board[2][2] == ' '){board[2][2] = 'X';goto end;}if (board[0][0] == board[2][2] && board[0][0] == 'O' && board[1][1] == ' '){board[1][1] = 'X';goto end;}if (board[1][1] == board[2][2] && board[1][1] == 'O' && board[0][0] == ' '){board[0][0] = 'X';goto end;}//第二條if (board[0][2] == board[1][1] && board[0][2] == 'O' && board[2][0] == ' '){board[2][0] = 'X';goto end;}if (board[0][2] == board[2][0] && board[0][2] == 'O' && board[1][1] == ' '){board[1][1] = 'X';goto end;}if (board[1][1] == board[2][0] && board[1][1] == 'O' && board[0][2] == ' '){board[0][2] = 'X';goto end;}//如果上面都沒返回,說明不符合堵棋,下棋的條件else{computerMove(board, ROW, COL);}}}int ret = 0;end://判斷平局ret = isFull(board, row, col);if (ret == 1){return 'p';}return 'c'; }5.判斷棋盤滿沒滿🚅
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;//棋盤滿了 }6.判斷游戲輸贏🚃
char isWin(char board[ROW][COL], int row, int col) {//判斷三行for (int 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 (int j = 0; j < col; j++){if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' '){return board[0][j];}}//判斷對角線if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[0][0];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[0][2];}//判斷平局int ret = isFull(board, row, col);if (ret == 1){return 'p';}return 'c'; }五.總結(jié)🚀
我們可以發(fā)現(xiàn)簡單模式下,電腦的下法是非常笨拙的,因?yàn)槭请S機(jī)的坐標(biāo)。我們可以改一下,比如困難模式,用窮舉的方法,判斷我方是否有兩顆棋子在一條線上,如果有則堵死;并且判斷電腦的棋子是否有兩顆在一條線上,如果有則落子。一定程度上增加了難度,不太容易贏,平局比較多。因?yàn)殡娔X前兩顆棋子是隨機(jī)的,所以也就是看運(yùn)氣。感興趣的小伙伴可以復(fù)制過去體驗(yàn)一下,可能會(huì)有BUG,我暫時(shí)還沒有發(fā)現(xiàn)!!!如果你發(fā)現(xiàn)了,請一定聯(lián)系我改正。另外,這個(gè)程序只適用于三子棋,其實(shí)也可以改,不過我懶寫的了,你可以搜一下,等以后閑了再說吧,孩子要好好學(xué)習(xí)了,不然要掛科了!!!😭😭😭
總結(jié)
以上是生活随笔為你收集整理的三子棋之VS人工智能/人工智障,你能赢吗?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BGP概述及基础配置
- 下一篇: 酒店客房管理系统之系统实施--数据库