C語言實(shí)現(xiàn)三子棋程序
本文實(shí)例為大家分享了C語言實(shí)現(xiàn)三子棋的具體代碼,供大家參考,具體內(nèi)容如下
先直接上代碼:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> //2.實(shí)現(xiàn)三子棋游戲。 #include<Windows.h> //Sleep() RAND_MAX 的頭文件 void menu() //打印菜單 { printf("****************************\n"); printf("**** 歡迎來到三子棋游戲 ****\n"); printf("**** 1、 進(jìn)入游戲 ****\n"); printf("**** 0、 退出游戲 ****\n"); printf("****************************\n"); printf("請輸入:->"); } void print_chessboard(char coord[][3]) //打印棋盤函數(shù) { //多維數(shù)組在傳參時(shí),接收數(shù)組的形參最多只能是第一個(gè)方括號(hào)里沒有數(shù)字(下標(biāo)范圍) //否則就會(huì)出錯(cuò)(因?yàn)榇藭r(shí)編譯器不知道你要把傳過來的數(shù)組的元素劃分成幾行幾列, //但是當(dāng)除第一個(gè)方括號(hào)的其他方括號(hào)都有值時(shí),就可以經(jīng)過計(jì)算知道第一個(gè)方括號(hào)的值是多少 int i = 0; int index_x = 0; int index_y = 0; for (i = 1; i <= 153; i++) { char out_ch = ' '; if ((i % 51 == 20) || (i % 51 == 26) || (i % 51 == 32) ) { out_ch = coord[index_x][index_y]; index_x++; if (index_x < 3) { index_x = 0; index_y++; } } else if ((i % 17 == 6) || (i % 17 == 12)) { out_ch = '|'; } else if( (i >= 35 && i <= 51 && i != 40 && i != 46) || \ (i >= 86 && i <= 102 && i != 91 && i != 97)) { out_ch = '_'; } putchar(out_ch); if (i % 17 == 0) //每輸出 17 個(gè)字符換下一行輸出 { printf("\n"); } } } void winer(char coord[][3], int *flag); //贏家判斷函數(shù)的聲明 int computer(char coord[][3]) //電腦下棋 { int flag = 0; int index_x2 = 0; int index_y2 = 0; srand((unsigned)time(NULL)); while (1) { index_x2 = 2 * rand() / RAND_MAX; //產(chǎn)生 0--2 的隨機(jī)數(shù) index_y2 = 2 * rand() / RAND_MAX; if ((coord[index_x2][index_y2] != '*') && (coord[index_x2][index_y2] != 'o')) { //判斷該位置是否已有落子 coord[index_x2][index_y2] = 'o'; winer(coord, &flag); if (flag == 1) { return 1; } return 0; } } } int player(char coord[][3], int index_x1, int index_y1) //玩家下棋 { int flag = 0; int ret = 0; if ((coord[index_x1][index_y1] == '*') || (coord[index_x1][index_y1] == 'o')) { //判斷該位置是否已有落子 printf("此位置已有棋子,請重下!\n"); return 0; } else { coord[index_x1][index_y1] = '*'; winer(coord, &flag); if (flag == 1) { return 1; } ret = computer(coord); if (ret == 1) { return 1; } print_chessboard(coord); //把打印棋盤放在是因?yàn)橄朐趦扇硕甲咄暌淮魏笤俅蛴‘?dāng)前棋盤狀態(tài) } return 0; } void winer(char coord[][3],int *flag) //判斷是否產(chǎn)生贏家,贏家是誰 { char line_ch[8][4] = { { coord[0][0], coord[1][1], coord[2][2] }, { coord[0][0], coord[0][1], coord[0][2] }, \ { coord[0][0], coord[1][0], coord[2][0] }, { coord[0][1], coord[1][1], coord[2][1] }, \ { coord[0][2], coord[1][2], coord[2][2] }, { coord[1][0], coord[1][1], coord[1][2] }, \ { coord[2][0], coord[2][1], coord[2][2] }, { coord[0][2], coord[1][1], coord[2][0] } }; //把所有能贏的情況定義成一個(gè)字符串?dāng)?shù)組 int i = 0; for (i = 0; i < 8; i++) { if (strcmp(line_ch[i],"***") == 0) //判斷此時(shí)玩家已輸入的落子能不能組成一個(gè)使玩家能贏的字符串 { print_chessboard(coord); //先打印棋盤,再判斷誰勝誰負(fù) printf("\n恭喜您贏了!\n"); *flag = 1; //玩家贏,使最開始設(shè)置的贏的標(biāo)志位為1,結(jié)束此次游戲 return; } else if (strcmp(line_ch[i],"ooo") == 0) { print_chessboard(coord); printf("\n很遺憾,您輸了!\n"); *flag = 1; return; } else { ; } } } int main() { while (1) { int num = 0; //決定開始或退出游戲 int x = 0; int y = 0; int i = 4; //一次游戲最多的內(nèi)層while循環(huán)可循環(huán)的次數(shù) int ret = 0; //是否結(jié)束此次游戲的標(biāo)志位 int is_play = 0; //是否再次玩游戲的標(biāo)志位 char coordinate[3][3] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; //為了拓展游戲比較方便,可以把行和列定義成宏定義 menu(); scanf("%d", &num); if (num == 0) { printf("5秒后退出程序!\n"); Sleep(5000); exit(0); } computer(coordinate); //因?yàn)樵O(shè)計(jì)電腦智商低,所以游戲開始前先讓電腦落一子 print_chessboard(coordinate); while ((i)) //因?yàn)榭偣灿芯艂€(gè)位置可以落子,已用一個(gè),還剩八個(gè),每次循環(huán)不結(jié)束的話會(huì)用掉兩個(gè) //所以最多循環(huán)四次 { printf("請輸入 X、Y 的坐標(biāo)(0--2)來確定你下棋的位置:"); //也可以加一個(gè)判斷輸入是否合法 scanf("%d %d", &x, &y); ret = player(coordinate, x, y); if (ret == 1) { break; } i--; } printf("\n"); printf("請選擇接下來的操作:\n"); printf("1、 再玩一次游戲 0、退出游戲系統(tǒng)\n"); scanf("%d", &is_play); if(is_play == 0) { printf("5秒后退出程序!\n"); Sleep(5000); exit(0); } else { system("cls"); } } system("pause"); return 0; }
程序一共設(shè)計(jì)了六個(gè)函數(shù),一個(gè)主函數(shù),五個(gè)自定義函數(shù)— 菜單打印函數(shù)、棋盤打印函數(shù)、電腦下棋函數(shù)、玩家下棋函數(shù)、贏家判斷函數(shù)。
其中最難設(shè)計(jì)的就是棋盤打印函數(shù)和贏家判斷函數(shù)。這兩個(gè)函數(shù)需要完成的任務(wù)多,計(jì)算量大,邏輯設(shè)計(jì)麻煩。
下面來分析一下幾個(gè)函數(shù)的設(shè)計(jì)思路:
1.菜單打印函數(shù)
這個(gè)函數(shù)很簡單,一看就能明白,這兒就不多說了。
2.棋盤打印函數(shù)
首先得構(gòu)思一下三子棋的棋盤應(yīng)該是什么樣
簡單點(diǎn),上圖就可以作為三子棋棋盤(其實(shí)就是利用 putchar() 函數(shù)和 printf() 把顯示在屏幕上的字符一個(gè)個(gè),一行行打印上去)。設(shè)計(jì)時(shí)可把其分成四部分來看,(1) 短豎杠 ; (2) 短橫杠 ; (3) 棋子(用一個(gè)二維字符數(shù)組來定義每一個(gè)棋子,用二維是因?yàn)榉奖爿斎氲?X 和 Y 值與數(shù)組下標(biāo)對應(yīng)) ; (4) 空格(一開始打印的時(shí)候,因?yàn)檫€沒有落子,所以把棋子也設(shè)計(jì)成空格)。 先確定要輸入幾行幾列字符,以確定循環(huán)輸出的次數(shù),還有確定每個(gè)位置該輸出的字符,這樣就可以依靠循環(huán)和判斷打印出棋盤了。
3 . 贏家判斷函數(shù)
在每次落子后都要先進(jìn)行一次判斷,看是否已經(jīng)產(chǎn)生贏家了。
因?yàn)闀?huì)出現(xiàn)贏家的情況就八種———–
{ coord[0][0], coord[1][1], coord[2][2] }, { coord[0][0], coord[0][1], coord[0][2] },
{ coord[0][0], coord[1][0], coord[2][0] }, { coord[0][1], coord[1][1], coord[2][1] },
{ coord[2][0], coord[2][1], coord[2][2] }, { coord[1][0], coord[1][1], coord[1][2] },
{ coord[2][0], coord[2][1], coord[2][2] }, { coord[0][2], coord[1][1], coord[2][0] }
定義一個(gè)字符串?dāng)?shù)組,里面共有八個(gè)字符串,每一個(gè)字符串就是上面的一個(gè)花括弧里的內(nèi)容,當(dāng)某個(gè)字符串的內(nèi)容與 * 或 ooo 相等,那么說明產(chǎn)生贏家了,否則不會(huì)產(chǎn)生贏家,那么就用一個(gè)循環(huán),遍歷字符串?dāng)?shù)組里的每一個(gè)字符串,判斷是否會(huì)產(chǎn)生贏家。
4. 玩家下棋函數(shù)
玩家通過輸入 x,y 坐標(biāo)來確定落子的位置, x,y 對應(yīng)的就是 定義的棋子二維字符數(shù)組的下標(biāo),每次先判斷輸入的 x,y 值對應(yīng)數(shù)組下標(biāo)的元素是否是 * 或 o ,是的話就說明此處已有落子,得重新輸入,不是的話就落下該棋子,接著判斷是否產(chǎn)生贏家,是的話就結(jié)束此次游戲,不是的話就判斷棋盤上是否還有空位置沒落子,有的話就輪到電腦繼續(xù)落子,沒有的話就結(jié)束此次游戲。
5. 電腦下棋函數(shù)
因?yàn)殡娔X是自動(dòng)落子,所以得為電腦產(chǎn)生一個(gè)隨機(jī)的 棋子二維數(shù)組下標(biāo)值,使電腦隨機(jī)落子,這個(gè)用srand((unsigned)time(NULL)); index_x2 = 2 * rand() / RAND_MAX; index_y2= 2 * rand() / RAND_MAX;來實(shí)現(xiàn)把它們放在一個(gè)while 死循環(huán)里,因?yàn)榭赡墚a(chǎn)生的兩個(gè)隨機(jī)下標(biāo)那兒已經(jīng)有棋子了,需要重新產(chǎn)生一次隨機(jī)下標(biāo),當(dāng)下標(biāo)值與已落棋子不沖突時(shí),就落下該棋子,接著判斷是否產(chǎn)生贏家,是的話,就結(jié)束此次游戲,不是的話就判斷棋盤上是否還有空位置沒落子,有的話就輪到玩家繼續(xù)落子,沒有的話就結(jié)束此次游戲。
6. 主函數(shù)
在主函數(shù)里適當(dāng)調(diào)用以上定義的幾個(gè)函數(shù),實(shí)現(xiàn)正確的邏輯功能。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語言實(shí)現(xiàn)清空指定文件夾中所有文件的方法
這篇文章主要介紹了C語言實(shí)現(xiàn)清空指定文件夾中所有文件的方法,實(shí)例分析了C語言實(shí)現(xiàn)文件刪除的相關(guān)技巧,需要的朋友可以參考下2015-06-06c++ 單線程實(shí)現(xiàn)同時(shí)監(jiān)聽多個(gè)端口
這篇文章主要介紹了c++ 單線程實(shí)現(xiàn)同時(shí)監(jiān)聽多個(gè)端口的方法,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下2021-03-03C語言中求字符串長度的函數(shù)的幾種實(shí)現(xiàn)方法
這篇文章主要介紹了C語言中求字符串長度的函數(shù)的幾種實(shí)現(xiàn)方法,需要的朋友可以參考下2018-08-08一篇文章帶你了解C++Primer學(xué)習(xí)日記--處理數(shù)據(jù)
今天小編就為大家分享一篇關(guān)于C++對數(shù)器的使用講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2021-08-08C語言判斷一個(gè)數(shù)是否為素?cái)?shù)方法解析
這篇文章主要介紹了C語言判斷一個(gè)數(shù)是否為素?cái)?shù)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07C++超詳細(xì)講解函數(shù)參數(shù)的默認(rèn)值
在C++中,定義函數(shù)時(shí)可以給形參指定一個(gè)默認(rèn)的值,這樣調(diào)用函數(shù)時(shí)如果沒有給這個(gè)形參賦值(沒有對應(yīng)的實(shí)參),那么就使用這個(gè)默認(rèn)的值。也就是說,調(diào)用函數(shù)時(shí)可以省略有默認(rèn)值的參數(shù)2022-05-05