摘要:前言本篇文章記錄了用語言實現三子棋小游戲,主要目的是對之前語言知識學習的鞏固,聯系各個知識,以及怎么樣實際使用各個知識。效果顯示函數當玩家輸入時,跳入到游戲的實現代碼之中。這里調用了函數,實現代碼如下由于在這里強制轉化為正整數。
本篇文章記錄了用C語言實現三子棋小游戲,主要目的是對之前C語言知識學習的鞏固,聯系各個知識,以及怎么樣實際使用各個知識。
一、三子棋的游戲規則
玩家將會看到一個3X3的網格棋盤,默認玩家先下棋,電腦后下棋。
規定:先連成一條直線(3個棋子)的玩家獲勝,行,列,對角線均可。若在棋盤下滿時仍未分出勝負,則為平局
二、使用到的頭文件
#include #include #include
#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);
//玩家贏 - "*"http://電腦贏 - "#"http://平局 - "Q"http://繼續 - "C"char is_win(char board[ROW][COL],int row,int col);
三、游戲的測試
int main() { test();//調用test測試函數 return 0;}
void test() { int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("請選擇:>"); scanf("%d",&input); switch (input) { case 1: game(); break; case 0: printf("退出游戲/n"); break; default: printf("選擇錯誤/n"); break; } } while (input);}
解析test函數主要構成:
i>菜單menu()函數:
void menu() { printf("******************************/n"); printf("***** 1. play ********/n"); printf("***** 0. exit ********/n"); printf("******************************/n");}
實現效果:
?ii>switch case 語句:實現了玩家通過不同輸入選擇實現不同的功能。
效果顯示:
iii>game()函數:當玩家輸入1時,跳入到游戲的實現代碼之中。
void game() { // 數據存儲,玩家下棋"*",電腦下棋是"#" char board[ROW][COL] = {0};//數組的內容 應該是全部空格 InitBoard(board,ROW,COL);// 初始化棋盤 // 打印棋盤 DisplayBoard(board,ROW,COL); //下棋 char ret = 0; while (1) { player_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } computer_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } } if (ret == "*") { printf("玩家贏/n"); } else if (ret == "#") { printf("電腦贏/n"); } else{ printf("平局/n"); } }
game()函數里面包括了:打印棋盤函數,初始化棋盤函數,玩家下棋函數,電腦下棋函數,判斷輸贏函數的調用,已經規定輸贏的條件,具體每個函數的實現代碼和問題如下。
注:最后有game()函數的邏輯順序。
四、游戲的實現
我們首先實現對棋盤的打印:
我們在頭文件中規定了 3行3列
#define ROW 3 #define COL 3
自定義函數DisplayBoard實現對棋盤的打印:
預期實現的棋盤模樣:
?我們發現里面包含了數據和分割行,實現代碼:
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 (j = 0; j < col; j++) { printf("---"); if (j < col - 1) { printf("|"); } } } printf("/n"); }}
定義InitBoard()函數,主要實現代碼如下:
void InitBoard(char board[ROW][COL], int row, int col){ int i = 0; int j = 0; for (i = 0; i < row; i++) { //3行 for (j = 0; j < col; j++) { // 3列 board[i][j] = " "; } }}
初始化棋盤全為空格
自定義函數 player_move 實現,代碼如下:
void player_move(char board[ROW][COL], int row, int col) { printf("玩家下棋:>"); int x = 0; int y = 0; while (1) { 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"); } }}
這里面包含了很多小問題和解決方案:
1:輸入的坐標不在棋盤的范圍內怎么辦?
答:使用if else 選擇語句,如果輸入的坐標合法,則輸入成功,如果輸入的坐標不合法則會提醒“坐標非法,請重新輸入!”字樣。
if (x >= 1 && x <= row && y >= 1 && y <= col)
2:輸入的坐標在棋盤上已被占用怎么辦?
這個問題我們需要轉化成這個問題解決:
i>怎么判斷輸入坐標被占用?
答:我們通過對選擇語句if else 對改坐標進行判斷,由于我們在初始化棋盤時,初始化棋盤全部為空格,如果輸入坐標所對應的格子是空格,則說明未被占用,如果輸入坐標所對應的格子不是空格,則說明該格子已經被占用。
if (board[x - 1][y - 1] == " ")
ii>如何正確輸入棋子?
如果輸入坐標所對應的格子是空格,則可以成功輸入,如果不是空格,則會else提醒玩家“該坐標被占用,請重新輸入!”字樣。利用while循環語句可再次輸入正確的未被占用的坐標。
自定義函數 computer_move 實現,代碼如下:
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 ~ 2 y = rand() % COL; // 0 ~ 2 if (board[x][y] == " ") { board[x][y] = "#"; break; } }}
這里也包含了幾個小問題和解決方案:
1:這里電腦的輸入是隨機輸入,如何實現?
答:這里我們并非是真的隨機值,只是利用了時間戳,由于時間在每時每刻的改變,所以在不同的時間,經過處理后的時間我們也無法知道,可當做隨機值使用。這里調用了time函數,實現代碼如下:
#include srand((unsigned int)time(NULL));
由于在這里強制轉化為正整數。
2:如何控制電腦隨機輸入的值合法?
答:這個問題的意思是,如果不對這個隨機值進行處理,那么這個值很可能超出棋盤,所以要對這個值進行控制,由于棋盤規定3行3列,數組下標由0開始,所以隨機值只要在0~2之內即可。所以我們對這個隨機值進行取模(取余數)處理即可解決此問題:
x = rand() % ROW; // 0 ~ 2y = rand() % COL; // 0 ~ 2
為了區分玩家和電腦的棋子不同,在此規定
玩家使用 " * " , 電腦使用 " #?"
因為這里電腦輸入坐標均為隨機值,所以不具有判斷的能力,讀者可以思考一種優化算法,寫出一種最快贏下比賽的算法。而不至于出現可能都已經一行出現2個棋子了,隨機值可能再下到別處的情況(哈哈 人工“智障”)。
實現代碼:
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 (1 == is_full(board, row, col)) { return "Q"; } //繼續 return "C";}
游戲規定,首先完成一行或者一列或者對角線的玩家獲勝,在此我們只需要進行三行,三列,對角線的判斷以及平局的判斷,游戲繼續判斷。具體是玩家贏還是電腦贏,我們在測試函數test中有規定,不同的玩家對應不同的字符,在此規定:
三行的判斷:
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]; }
平局的判斷:
游戲規定,當棋盤下滿時,還未分出勝負時,則為平局。
因此首先我們思考如何判斷棋盤是否下滿?
答:在這里我們通過返回值的數字來判斷是否下滿
自定義函數 is_full函數,具體代碼:
int is_full(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++) { if (board[i][j] == " ") { return 0; } } } return 1;}
代碼邏輯:我們通過返回值來判斷棋盤是否下滿,
如果未被下滿,則返回值是0(return 0 )
如果下滿我們將返回1(return 1)
小問題:我們如何判斷是否下滿?
我們遍歷數組的過程中,如果發現還有空格存在,說明棋盤還沒有被下滿,我們立刻返回0,否則說明棋盤沒有空格存在,說明已經下滿,返回1.
所以我們就可以通過返回值判斷平局,代碼如下:
if (1 == is_full(board, row, col)) { return "Q"; }
如果返回值 == 1 說明 棋盤被下滿 我們返回字符? " Q " (我們剛剛已經規定Q為平局)
五、game()函數
我們再次將game()函數調出進行詳解:
void game() { // 數據存儲,玩家下棋"*",電腦下棋是"#" char board[ROW][COL] = {0};//數組的內容 應該是全部空格 InitBoard(board,ROW,COL);// 初始化棋盤 // 打印棋盤 DisplayBoard(board,ROW,COL); //下棋 char ret = 0; while (1) { player_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } computer_move(board, ROW, COL); DisplayBoard(board, ROW, COL); ret = is_win(board, ROW, COL); if (ret != "C") { break; } } if (ret == "*") { printf("玩家贏/n"); } else if (ret == "#") { printf("電腦贏/n"); } else{ printf("平局/n"); } }
根據代碼發現主要邏輯順序:
?這是game()函數內部的主要邏輯順序,每一步所對應的函數調用和判斷也均在圖中顯示。
六、演示
完整代碼: 完整代碼我放在我的Gitee倉庫內,鏈接如下:
https://gitee.com/Yaulixingyu/c-language/tree/master/三子棋/三子棋
游戲演示:
?
以上就是我對三棋子小游戲的實現,有興趣的小伙伴可以對代碼進行優化,可實現五子棋等,也可以對電腦下棋記性優化,使電腦不再人工“智障”。
哈哈哈~由于文章較長,感謝各位小伙伴的觀看,由于本人的技術水平有待提高,如果遇到錯誤也請及時指正。如果各位小伙伴覺得不錯的話,可以點贊關注一波~多謝多謝
下期預告:掃雷? 小游戲
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/123187.html
摘要:簡單介紹了三子棋原理后接下來為大家講解分步目標及代碼如何實現。電腦下棋我們實現了玩家和電腦的下棋后,我們需要編寫一個函數來判斷雙方的輸贏。我們使用函數來實現這一目標。 目錄 1.三子棋原理 2.分塊代碼實現 3.總結 1.首先向大家介紹一下三子棋的原理 首先我們需要有一個棋盤,初始時棋...
摘要:三子棋目錄一問題介紹三子棋,在民間又叫井字棋。因為人們在游玩時常常不畫棋盤的邊框,正如漢字中的井字,多稱為井字棋。 三子棋 目錄 一、問題介紹 ? ? ? ? 三子棋,在民間又叫井字棋。因為人們在游玩時常常不畫棋盤的邊框,正如漢字中的井字,多稱為井字棋。 三子棋的游戲規則十分的簡單: ...
摘要:今天博主將為大家帶來語言入門級小游戲三子棋井字棋的詳細介紹,希望這篇文章對大家能有幫助。在這里,我們使用函數來實現這一功能。 ?? ? ??今天博主將為大家帶來C語言入門級小游戲——三子棋(井字棋)的詳細介紹,希望這篇文章對大家能有幫助?。?? ? ? 在編程的學習過程中,編寫一些中這樣...
閱讀 3572·2023-04-25 19:56
閱讀 1679·2021-11-12 10:36
閱讀 1798·2021-11-08 13:19
閱讀 1552·2019-08-30 14:06
閱讀 3044·2019-08-30 11:01
閱讀 1750·2019-08-29 13:23
閱讀 2751·2019-08-29 11:18
閱讀 3436·2019-08-26 13:35