C語言開發(fā)實(shí)現(xiàn)井字棋及電腦落子優(yōu)化示例詳解
總體思路
井字棋棋盤我們總體可以當(dāng)成一個(gè)二維數(shù)組來操作,我們分別需要實(shí)現(xiàn)初始化二維數(shù)組,打印棋盤,玩家下棋,電腦下棋,判斷輸贏等代碼
項(xiàng)目的創(chuàng)建
我們創(chuàng)建了頭文件用于放函數(shù)的聲明,game.c文件放置函數(shù)的實(shí)現(xiàn),test.c文件用于測試。
測試結(jié)果
電腦獲勝
玩家獲勝
平局
各函數(shù)代碼的實(shí)現(xiàn)
我們在game.c文件中實(shí)現(xiàn)函數(shù)功能的代碼
初始化二維數(shù)組
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) { for (int i = 0; i < row; i++) { for (int 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"); } }
這里的棋盤我們只打印了井字的形狀,如果為了美觀,還可以進(jìn)行封邊,這里就留給朋友們自行實(shí)現(xiàn)啦。
玩家下棋
void PlayMove(char Board[ROW][COL], int row, int col) { while (1) { int x = 0, y = 0; printf("請輸入坐標(biāo):\n"); 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("輸入錯(cuò)誤,請重新輸入:\n"); } } }
電腦下棋
在電腦落子之前,先檢測有沒有下一步可以直接贏的,若有,則落子在此處,電腦獲勝,若沒有,再檢測玩家下一步是否有機(jī)會獲勝,若玩家下一步可以直接獲勝,那么電腦將搶占這一步。
如果上述兩種情況均不存在,當(dāng)發(fā)現(xiàn)(1,1)位置是空時(shí),電腦先下這一步。
其他情況均隨意落子。
void ComputerMove(char Board[ROW][COL], int row, int col) { int x = 0, y = 0; while (1) { if (JudgeComputer(Board, ROW, COL)) { for (int i = 0; i < row; i++) { if (Board[i][0] == Board[i][1] && Board[i][0] == '*' && Board[i][2] == ' ') { Board[i][2] = '*'; return; } else if (Board[i][0] == Board[i][2] && Board[i][0] == '*' && Board[i][1] == ' ') { Board[i][1] = '*'; return; } else if (Board[i][1] == Board[i][2] && Board[i][1] == '*' && Board[i][0] == ' ') { Board[i][0] = '*'; return; } } for (int j = 0; j < col; j++) { if (Board[0][j] == Board[1][j] && Board[0][j] == '*' && Board[2][j] == ' ') { Board[2][j] = '*'; return; } else if (Board[0][j] == Board[2][j] && Board[0][j] == '*' && Board[1][j] == ' ') { Board[1][j] = '*'; return; } else if (Board[1][j] == Board[2][j] && Board[1][j] == '*' && Board[0][j] == ' ') { Board[0][j] = '*'; return; } } if (Board[0][0] == Board[1][1] && Board[0][0] == '*' && Board[2][2] == ' ') { Board[2][2] = '*'; return; } else if (Board[0][0] == Board[2][2] && Board[0][0] == '*' && Board[1][1] == ' ') { Board[1][1] = '*'; return; } else if (Board[1][1] == Board[2][2] && Board[1][1] == '*' && Board[0][0] == ' ') { Board[0][0] = '*'; return; } else if (Board[0][2] == Board[1][1] && Board[0][2] == '*' && Board[2][0] == ' ') { Board[2][0] = '*'; return; } else if (Board[0][2] == Board[2][0] && Board[0][2] == '*' && Board[1][1] == ' ') { Board[1][1] = '*'; return; } else if (Board[2][0] == Board[1][1] && Board[2][0] == '*' && Board[0][2] == ' ') { Board[0][2] = '*'; return; } } else if (JudgePlayer(Board, ROW, COL)) { for (int i = 0; i < row; i++) { if (Board[i][0] == Board[i][1] && Board[i][0] == '#' && Board[i][2] == ' ') { Board[i][2] = '*'; return; } else if (Board[i][0] == Board[i][2] && Board[i][0] == '#' && Board[i][1] == ' ') { Board[i][1] = '*'; return; } else if (Board[i][1] == Board[i][2] && Board[i][1] == '#' && Board[i][0] == ' ') { Board[i][0] = '*'; return; } } for (int j = 0; j < col; j++) { if (Board[0][j] == Board[1][j] && Board[0][j] == '#' && Board[2][j] == ' ') { Board[2][j] = '*'; return; } else if (Board[0][j] == Board[2][j] && Board[0][j] == '#' && Board[1][j] == ' ') { Board[1][j] = '*'; return; } else if (Board[1][j] == Board[2][j] && Board[1][j] == '#' && Board[0][j] == ' ') { Board[0][j] = '*'; return; } } if (Board[0][0] == Board[1][1] && Board[0][0] == '#' && Board[2][2] == ' ') { Board[2][2] = '*'; return; } else if (Board[0][0] == Board[2][2] && Board[0][0] == '#' && Board[1][1] == ' ') { Board[1][1] = '*'; return; } else if (Board[1][1] == Board[2][2] && Board[1][1] == '#' && Board[0][0] == ' ') { Board[0][0] = '*'; return; } else if (Board[0][2] == Board[1][1] && Board[0][2] == '#' && Board[2][0] == ' ') { Board[2][0] = '*'; return; } else if (Board[0][2] == Board[2][0] && Board[0][2] == '#' && Board[1][1] == ' ') { Board[1][1] = '*'; return; } else if (Board[2][0] == Board[1][1] && Board[2][0] == '#' && Board[0][2] == ' ') { Board[0][2] = '*'; return; } } else { if (Board[1][1] == ' ') { Board[1][1] = '*'; return; } else { x = rand() % row; y = rand() % col; if (Board[x][y] == ' ') { Board[x][y] = '*'; break; } } } } }
判斷電腦是否有位置可以獲勝
static int JudgeComputer(char Board[ROW][COL], int row, int col) { for (int i = 0; i < row; i++) { if (Board[i][0] == Board[i][1] && Board[i][0] == '*' && Board[i][2] == ' ') return 1; else if (Board[i][0] == Board[i][2] && Board[i][0] == '*' && Board[i][1] == ' ') return 1; else if (Board[i][1] == Board[i][2] && Board[i][1] == '*' && Board[i][0] == ' ') return 1; } for (int j = 0; j < col; j++) { if (Board[0][j] == Board[1][j] && Board[0][j] == '*' && Board[2][j] == ' ') return 1; else if (Board[0][j] == Board[2][j] && Board[0][j] == '*' && Board[1][j] == ' ') return 1; else if (Board[1][j] == Board[2][j] && Board[1][j] == '*' && Board[0][j] == ' ') return 1; } if (Board[0][0] == Board[1][1] && Board[0][0] == '*' && Board[2][2] == ' ') return 1; else if (Board[0][0] == Board[2][2] && Board[0][0] == '*' && Board[1][1] == ' ') return 1; else if (Board[1][1] == Board[2][2] && Board[1][1] == '*' && Board[0][0] == ' ') return 1; else if (Board[0][2] == Board[1][1] && Board[0][2] == '*' && Board[2][0] == ' ') return 1; else if (Board[0][2] == Board[2][0] && Board[0][2] == '*' && Board[1][1] == ' ') return 1; else if (Board[2][0] == Board[1][1] && Board[2][0] == '*' && Board[0][2] == ' ') return 1; else return 0; }
判斷玩家是否有位置獲勝
static int JudgePlayer(char Board[ROW][COL], int row, int col) { for (int i = 0; i < row; i++) { if (Board[i][0] == Board[i][1] && Board[i][0] == '#' && Board[i][2] == ' ') return 1; else if (Board[i][0] == Board[i][2] && Board[i][0] == '#' && Board[i][1] == ' ') return 1; else if (Board[i][1] == Board[i][2] && Board[i][1] == '#' && Board[i][0] == ' ') return 1; } for (int j = 0; j < col; j++) { if (Board[0][j] == Board[1][j] && Board[0][j] == '#' && Board[2][j] == ' ') return 1; else if (Board[0][j] == Board[2][j] && Board[0][j] == '#' && Board[1][j] == ' ') return 1; else if (Board[1][j] == Board[2][j] && Board[1][j] == '#' && Board[0][j] == ' ') return 1; } if (Board[0][0] == Board[1][1] && Board[0][0] == '#' && Board[2][2] == ' ') return 1; else if (Board[0][0] == Board[2][2] && Board[0][0] == '#' && Board[1][1] == ' ') return 1; else if (Board[1][1] == Board[2][2] && Board[1][1] == '#' && Board[0][0] == ' ') return 1; else if (Board[0][2] == Board[1][1] && Board[0][2] == '#' && Board[2][0] == ' ') return 1; else if (Board[0][2] == Board[2][0] && Board[0][2] == '#' && Board[1][1] == ' ') return 1; else if (Board[2][0] == Board[1][1] && Board[2][0] == '#' && Board[0][2] == ' ') return 1; else return 0; }
判斷輸贏
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][2] == Board[i][1] && Board[i][1] != ' ') { return Board[i][0]; } } for (int j = 0; j < col; j++) { if (Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j] && Board[j][1] != ' ') { return Board[0][j]; } } if (Board[0][0] == Board[1][1] && Board[2][2] == Board[1][1] && Board[2][2] != ' ') return Board[0][0]; if (Board[0][2] == Board[1][1] && Board[2][0] == Board[1][1] && Board[1][1] != ' ') return Board[1][1]; if (IsFull(Board, ROW, COL)) { return 'o'; } return 'C'; }
判斷和棋
static int IsFull(char Board[ROW][COL], int row, int col) { for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { if (Board[i][j] == ' ') return 0; } } return 1; }
聲明代碼
我們在game.h頭文件中進(jìn)行函數(shù)的聲明。
void meun(); #define ROW 3 #define COL 3 //游戲主函數(shù) void game(); //初始化二維數(shù)組 void InitBoard(char Board[ROW][COL], int row, int col); //打印棋盤 void DisplayBoard(char Board[ROW][COL], int row, int col); //玩家下棋 void PlayMove(char Board[ROW][COL], int row, int col); //電腦下棋 void ComputerMove(char Board[ROW][COL], int row, int col); //判斷贏否 char IsWin(char Board[ROW][COL], int row, int col); //判斷棋盤滿了嗎 //int IsFull(char Board[ROW][COL], int row, int col); //判斷電腦下一部是否可以直接贏 //int JudgeComputer(char Board[ROW][COL], int row, int col); //判斷玩家下一步是否會贏 //int JudgePlayer(char Board[ROW][COL], int row, int col);
測試代碼
我們在test.c文件中測試該游戲。
#include "game.h" void game() { char ret = 0; char Board[ROW][COL] = { 0 }; //初始化數(shù)組 InitBoard(Board, ROW, COL); //打印棋盤 printf("棋盤如下:\n"); DisplayBoard(Board, ROW, COL); while (1) { //玩家下棋 printf("玩家落子:\n"); PlayMove(Board, ROW, COL); //每下一步打印一次棋盤 DisplayBoard(Board, ROW, COL); //每下一步判斷一次勝負(fù) ret = IsWin(Board, ROW, COL); if (ret != 'C') { break; } //電腦下棋 printf("電腦落子:\n"); 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 if (ret == 'o') printf("臥龍鳳雛\n"); } void test() { int input = 0; srand((size_t)time(NULL)); do { meun(); printf("請選擇:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("游戲結(jié)束\n"); break; default: printf("輸入錯(cuò)誤,請重新輸入:\n"); break; } } while (input); } int main() { test(); return 0; }
總結(jié)
此次代碼的實(shí)現(xiàn)總體來說雖然能夠?qū)崿F(xiàn)井字棋功能,但是不得不承認(rèn)代碼確實(shí)不夠精簡,還有我們可以思考是否可以使電腦更加聰明,落子的每一步都有自己的‘想法',這里也是博主需要不斷思考的問題,博主也要不斷的學(xué)習(xí)看能否實(shí)現(xiàn)該功能,如果朋友們有好的想法,歡迎與我進(jìn)行交流,不勝感激,希望大家以后多多支持腳本之家!
相關(guān)文章
C語言雙向鏈表實(shí)現(xiàn)根據(jù)使用頻率安排元素位置的功能實(shí)例代碼
這篇文章主要介紹了C語言雙向鏈表實(shí)現(xiàn)根據(jù)使用頻率安排元素位置的功能實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03基于C語言掃雷游戲的設(shè)計(jì)與實(shí)現(xiàn)
大家好,本篇文章主要講的是基于C語言掃雷游戲的設(shè)計(jì)與實(shí)現(xiàn),感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12C++中constexpr與函數(shù)參數(shù)轉(zhuǎn)發(fā)的操作方法
constexpr是c++11引入的關(guān)鍵字,c++11的constexpr的函數(shù)中只是支持單句代碼,c++14限制放寬,可以在里邊寫循環(huán)及邏輯判斷等語句,本文探討關(guān)于constexpr的函數(shù)中參數(shù)的現(xiàn)象,以及如果參數(shù)是constexpr如何做轉(zhuǎn)發(fā),感興趣的朋友一起看看吧2024-02-02Opencv二幀差法檢測運(yùn)動目標(biāo)與提取輪廓
這篇文章主要為大家詳細(xì)介紹了Opencv使用二幀差法檢測運(yùn)動目標(biāo)與提取輪廓,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03詳解C語言中strcpy()函數(shù)與strncpy()函數(shù)的使用
這篇文章主要介紹了詳解C語言中strcpy()函數(shù)與strncpy()函數(shù)的使用,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-08-08C基礎(chǔ) 尋找隨機(jī)函數(shù)的G點(diǎn)詳解
下面小編就為大家?guī)硪黄狢基礎(chǔ) 尋找隨機(jī)函數(shù)的G點(diǎn)詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06VC++中HTControl控制類使用之CHTDlgBase對話框基類實(shí)例
這篇文章主要介紹了VC++中HTControl控制類使用之CHTDlgBase對話框基類,是比較豐富而實(shí)用的功能,需要的朋友可以參考下2014-08-08