完成三子棋的構思
1,列印選單,是否進入游戲
2,生成二維陣列儲存下棋棋盤,而且棋盤要易改變
3,將棋盤初始化成空格
4,列印棋盤
5,玩家下棋
6,判斷輸贏
7,電腦下棋
8,判斷輸贏
9,列印看電腦下棋的資訊
10,在判斷輸贏后列印誰獲勝了
11,列印選單,選擇是否再次進行游戲
這里生成game.h頭檔案放函式宣告 , game.c檔案放函式的實作 , test.c檔案放工程的main函式

這里實作每一步
1,列印選單,是否進入游戲 11,完成游戲后,選擇是否再次進行游戲
這里我們規定當玩家選擇1時玩游戲并執行game函式之后再列印一次選單讓玩家選擇,當選擇0時退出游戲,當選擇1,0以外的數字時提醒選擇錯誤并再一次列印選單,
通過上面的分析發現,這個程序是我們玩游戲的總流程,所以在main函式中可以通過do{…}while();回圈來進行,
進入游戲先列印選單,用input來接受玩家選擇的數字,
當玩家選擇0時為假跳出主函式,
當玩家選擇1時為真進行game()函式,再列印選單
當玩家選擇非1,0時也為真,這時提醒玩家選擇錯誤,在列印一次選單
(用switch case來實作) (do{…}while(input))
(注意接收玩家選擇的數字應該在回圈內,每一次列印選單都要接受一次玩家的選擇)
代碼實作
//在test.c檔案中實作
#include<game.h>//引我們的函式宣告頭檔案
void menu()
{
printf("***********************\n");
printf("****** 1.進入 ******\n");
printf("****** 0.退出 ******\n");
printf("***********************\n");
}
void game()
{
printf("三子棋游戲\n");//這里先進行測驗看一看主邏輯有沒有寫對
}
int main()
{
srand((unsigned int)time(NULL))//通過時間戳設定亂數生成起點
int input = 0;
do
{
menu();
printf("請選擇\n");
scanf("%d",&input);
switch (input)
{
case 1:
{
game();//負責完成游戲邏輯
break;
}
case 0:
{
printf("退出游戲\n");
break;
}
default:
{
printf("輸入錯誤請重新選擇\n");
break;
}
}
} while (input);//判斷input只要input不是0就要進行回圈
return 0;
}
輸出樣例

從2到11步我們這里全部放到game()里去實作
2到11步要回圈進行下棋直到判斷出輸贏,
這里我們用字符ret來接受判斷輸贏函式的回傳值,
如果回傳 ‘ #’則電腦贏 break
如果回傳 ‘ * ’ 則玩家贏 break
如果回傳 ‘ q ’則是平局 break
如果回傳 ‘ c ’ 則還沒有分出高下,棋盤也沒有滿,
//在test.c檔案中實作
#include"game.h"
void menu()
{
printf("***********************\n");
printf("****** 1.進入 ******\n");
printf("****** 0.退出 ******\n");
printf("***********************\n");
}
void game()
{
char board[ROW][COL];//實作第二步生成二維陣列
//,為了方便改變棋盤大小這里行ROW列COL的值放到game.h去定義
InitBoard(board, ROW, COL);//實作第三步初始化棋盤
DisplayBoard(board, ROW, COL);//列印棋盤實作第四步
while(1)//回圈下棋直到分出勝負或平局
{
PlayerMove(board, ROW, COL);//玩家輸入坐標實作下棋操作實作第五步
ret = CheckWin(board, ROW, COL);//玩家下棋后,判斷當前輸贏實作第六步
if(ret !='C')//如果回傳是c說明游戲繼續,回傳不是c先出回圈在列印誰贏了或平局
{
break;
}
ComputerMove(board, ROW, COL);//電腦下棋實作第七步
ret = CheckWin(board, ROW, COL);//電腦下棋后,判斷當前輸贏實作第八步
if(ret !='C')//如果回傳是c說明游戲繼續,回傳不是c先出回圈在列印誰贏了或平局
{
break;
}
DisplayBoard(board, ROW, COL);//列印電腦下棋后棋盤資訊實作第九步
}
//出了回圈可能是玩家勝利或者電腦勝利,或者平局
//列印獲勝資訊實作第十步
if(ret =='*')
{
printf("玩家勝利");
}
if(ret=='#')
{
printf("電腦勝利");
}
if(ret=='q')
{
printf("平局沒有贏家");
}
DisplayBoard(board, ROW, COL);//再列印一次棋盤顯示獲勝棋盤資訊
}
int main()
{
int input = 0;
do
{
menu();
printf("請選擇\n");
scanf("%d",&input);
switch (input)
{
case 1:
{
game();//負責完成游戲邏輯
break;
}
case 0:
{
printf("退出游戲\n");
break;
}
default:
{
printf("輸入錯誤請重新選擇\n");
break;
}
}
} while (input);//判斷input只要input不是0就要進行回圈
return 0;
}
到這里我們把tese.c檔案中游戲主程式寫完
之后要實作在game()中函式的作用
先在game.h中進行函式宣告
每一個函式實作功能的時候都需要給函式陣列資訊,整形row(行),整形col(列)的資訊
在CheckWin()中函式有字符回傳值char
在 IsFull()中函式有數字回傳值int
在Computer_AI() 中函式有數字回傳值int
#include <stdio.h>
#include<time.h>
#include<stdlib.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 PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char CheckWin(char board[ROW][COL], int row, int col);
int IsFull(char board[ROW][COL], int row, int col);
//IsFull函式將在判斷棋盤是否被填滿中來使用(后面解釋)只要知到有這個功能,
int Computer_AI(char board[ROW][COL], int row, int col);
//這個函式是來實作電腦的智能下棋的(后面會解釋)只要知道有這個功能,
到這里game.h檔案已經寫完
(包括函式宣告,要引的頭檔案,行列數字的定義)
在game.c檔案中實作我們自己定義的函式
InitBoard函式的實作
//InitBoard函式初始化棋盤
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]=' ';//陣列所有元素被初始化成空格
}
}
}
DisplayBoard函式的實作

觀察第一行先列印了空格,再列印陣列內容,再列印空格,再列印 |
發現空格+陣列內容+空格是一組列印次數和列相同
‘ | ’在最后一次不列印
再看第一行下面_ _ _是一組列印完后列印 ‘ | ’
’ | ‘在最后一次不會列印,
一共列印了三行且最后一行沒有_ _ _
實作代碼如下
//DisplayBoard函式列印棋盤
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");//換行開始第二行的列印
}
}
}
列印的棋盤如下

當改變ROW COL 的值時棋盤也會正常列印,為我們五子棋設計打基礎,
當ROW COL 的值為5時列印棋盤為

PlayerMove()函式的實作
玩家下棋是通過坐標的形式來下棋的
玩家不知道陣列下標為0,所以玩家輸入坐標的x y值要減1才是他想下的陣列位置
當玩家下棋輸入坐標時首先判斷輸入坐標的合法性(行坐標要大于1小于ROW)
(列坐標要大于1小于COL)
其次坐標所在的陣列位置不能被占用
玩家一直輸入坐標直到坐標合法后,將該坐標下陣列的空格換成玩家下的’ * ‘
所以這個程序是一個回圈
//PlayerMove()函式是玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:>\n");
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");
}
printf("輸入你要下的坐標\n");
}
}
輸出結果

ComputerMove()函式的實作
電腦和人一樣我們在我們的棋子有兩個的時候會盡可能的連成三個
在敵方棋子有兩個的時候會堵截敵方
這兩種情況共同點是當有相同的棋子(不論是玩家的還是電腦的而且不能是空格)電腦在下一個位置下棋就可以起到攻擊或防御的目的
在沒有兩個連起來的棋子時就隨機下棋,
這里我們設計Computer_AI()函式當符合有兩個相同的棋子時回傳1結束下棋,當沒有兩個相同的棋子時回傳0;這是隨機下棋,
(要注意有兩個相同棋子時必須還有一個空格給電腦下棋,否則電腦可能就始終無法生成一個未被占用的棋子)
除此之外電腦隨機下棋直到符合有效范圍而且沒有被占用,這個是一個回圈
//
//ComputerMove()是電腦下棋
//Computer_AI()是我們設計的電腦的下棋方法
int Computer_AI(char board[ROW][COL], int row, int col)
{
int i=0;
int j=0;
for(i=0;i<row;i++)//看每一行是不是有兩個相同元素
{
if(board[i][0]==board[i][1] && board[i][0]!=' '&& board[i][2]==' ')
{
board[i][2] = '#';
//這種情況是搜索是否有每一行的第一二列有相同的棋子且第三列可以下棋
return 1;//搜索到就回傳值防止多下
}
else if(board[i][1]==board[i][2] && board[i][1]!=' '&& board[i][0]==' ')
{
board[i][0] = '#';
//這種情況是搜索是否有第二三列相同的棋子而且可以下棋
return 1;
}
else if(board[i][2]==board[i][0] && board[i][0]!=' '&& board[i][1]==' ')
{
board[i][1]='#';
//這種情況是搜索是否有第一三列相同的棋子而且可以下棋
return 1;
}
}
for(i=0;i<col;i++)//看每一列是不是有相同的棋子
{
if(board[0][i]==board[1][i] && board[1][i]!=' ' && board[2][i]==' ')
{
board[2][i]='#';
//這種情況是搜索是否有第一二行形同而且可以下棋的地方
retuen 1;
}
if(board[1][i]==board[2][i] && board[1][i]!=' '&& board[0][i]==' ')
{
board[0][i]='#';
//這種情況是搜索是否有第二三相同的棋子且可以下棋的地方
return 1;
}
if(board[0][i]==board[2][i] && board[0][i]!=' '&& board[1][i]==' ')
{
board[1][i]='#';
//這種情況是搜索是否有第一三相同的棋子且可以下棋的地方
return 1;
}
}
//以下是在搜索對角線上是否有相同的棋子且可以下棋的地方
if(board[0][0]==board[1][1] && board[1][1]!=' '&& board[2][2]==' ')
{
board[2][2] = '#';
return 1;
}
if(board[2][2]==board[1][1] && board[1][1]!=' '&& board[0][0]==' ')
{
board[0][0] = '#';
return 1;
}
if(board[0][0]==board[2][2] && board[0][0]!=' '&& board[1][1]==' ')
{
board[1][1] = '#';
return 1;
}
if(board[0][2]==board[1][1] && board[1][1]!=' '&& board[2][0]==' ')
{
board[2][0] = '#';
return 1;
}
if(board[2][0]==board[1][1] && board[1][1]!=' '&& board[0][2]==' ')
{
board[0][2] = '#';
return 1;
}
if(board[2][0]==board[0][2] && board[2][0]!=' '&& board[1][1]==' ')
{
board[1][1] = '#';
return 1;
}
return 0;//沒有相同的棋子時通過隨機值來下棋
}
// ComputerMove電腦下棋,
void ComputerMove(char board[ROW][COL], int row, int col)
{
while(1)//回圈生成在范圍內而且沒有被占用的棋子
{
int output=Computer_AI(char board, int row, int col)==1
if(output==1)
//回傳值為1時用我們的寫的下棋方式
{
break;
}
else//否則隨機生成合法坐標
{
int x=rand()%row;//x的范圍是0到row-1
int y=rand()%col;//y的范圍是0到col-1
if(board[x][y] == ' ')//未被占用
{
board[x][y]=='#';
break;//防止電腦多次下棋
}
}
}
}
CheckWin()函式的實作
在判斷輸贏函式中我們還需要一個判斷棋盤是否被裝滿函式
當棋盤被裝滿的時候回傳1,在CheckWin()函式中接受到1時回傳 ’ q ‘代表平局
//CheckWin()函式判斷輸贏
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;//到這里說明棋盤已滿回傳1
}
char CheckWin(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][0] != ' ')
{
return board[i][0];//回傳值正好可以判斷誰勝利(*代表人 #代表電腦)
}
}
for (i = 0; i < col;i++)//列
{
if(board[0][i]== board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//之后判斷兩條對角線
if(board[0][0]==board[1][1] && board[1][1] == board[2][2] && board[0][0]!= ' ')
{
return board[0][0];
}
if(board[0][2]==board[1][1] && board[1][1]==board[2][0] && board[0][2] !=' ')
{
return board[0][2];
}
if(IsFull(board,row,col)==1)
{
return ' q';
}
return 'C';//代表還要繼續進行
}
將這些函式連接起來,至此我們game.c檔案已經寫完
運行代碼就可以玩游戲了,
從三子棋到五子棋的拓展
從三子棋到五子棋大部分函式不需要動
要改的點
1,ROW,COL在頭檔案的值改變棋盤的大小
2,判斷輸贏的條件需要改動
3,電腦下棋的Computer_AI函式
這里只寫出判斷輸贏的改動,電腦Computer_AI種類太多不易一一列出
CheckWin函式在五子棋下的實作
從三子棋類比到五子棋發現一一列舉情況太過復雜
這里通過for回圈的方式來進行相同字符的比較
這里的兩個for回圈可以看成掃描
這里寫出對角線上的掃描






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;//到這里說明棋盤已滿回傳1
}
char CheckWin(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-4;j++)//一次就要檢查5個元素的值最后一次檢查就是陣列倒數第五個元素
{
if (board[i][j] == board[i][j+1] && board[i][j+1] == board[i][j+2] && board[i][j+2] == board[i][j+3] && board[i][j+3] == board[i][j+4] && board[i][j] != ' '
return board[i][j];//原理與三子棋的相似
}
}
for(i=0;i<col;i++)//判斷列
{
int j=0;
for(j=0;j<row-4;j++)
{
if(board[j][i]==board[j+1][i]&&board[j+1][i]==board[j+2][i]&&board[j+2][i]==board[j+3][i]&&board[j+3][i]==board[j+4][i]&&board[j][i]!=' ')
{
return board[j][i];
}
}
}
//判斷對角線元素是否相同(有兩種對角線)
//這里對角線上的元素不一定正好是棋盤的對角線所以用for回圈的嵌套
//有兩種情況
//1.從第一條對角線開始每一次檢測完后向下平移1,行不變繼續檢測,
//2.從第一條對角線開始每一次檢測完后向右平移1,列不變繼續檢測
for(i=0;i<row-4;i++)
{
for(j=0;j<col-4;j++)
{
if (board[i+j][j] == board[i + j + 1][j + 1] && board[i + j + 1][j + 1] == board[i +j+ 2][j+ 2] && board[i + j+ 2][j + 2] == board[i +j+ 3][j + 3] && board[i +j+ 3][j+ 3] == board[i +j+ 4][j + 4] && board[i+j][j] != ' ')
//從第一條對角線開始每一次檢測完后向下平移1,列不變繼續檢測
{
return board[i+j][j];
}
if (board[i][i+j] == board[i + 1][i + j + 1] && board[i + 1][i + j + 1] == board[i+ 2][i +j+ 2] && board[i + 2][i + j+ 2]== board[i + 3][i +j+ 3] && board[i + 3][i +j+ 3] == board[i + 4][i +j+ 4] && board[i][i+j] != ' ')
//從第一條對角線開始每一次檢測完后向右平移1,行不變繼續檢測
{
return board[i][i+j];
}
}
}
//第二種對角線思路類似
for(i=0;i<row-4;i++)
{
int j=0;
for(j=0;j<row-4;j++)
{
if (board[i][row - i - 1-j] == board[i+ 1][row - i - 2-j] && board[i + 1][row - i - 2-j] == board[i + 2][row - i - 3-j] && board[i + 2][row - i - 3-j] == board[i + 3][row - i - 4-j] && board[i + 3][row - i - 4-j] == board[i + 4][row - i - 5-j] && board[i][row - i - 1-j] != ' ')
{
//左平移來掃描
return board[i][row-i-j-1];
}
if (board[i+j][row - i - 1-j] == board[i + 1+j][row - i - 2-j] && board[i + 1+j][row - i - 2-j] == board[i + 2+j][row - i - 3-j] && board[i + j+2][row - i - 3-j] == board[i +j+ 3][row - i - 4-j] && board[i +j+ 3][row - i - 4-j] == board[i + j+4][row - i - 5-j] && board[i+j][row - i - 1-j] != ' ')
//下平移來掃描
{
return board[i+j][row - i - 1-j];
}
}
}
if (IsFull(board, row, col) == 1)
{
return 'q';
}
return 'C';//原理與三子棋相同
}
這篇文章是我總結來的,或許有一些問題,還麻煩大家斧正
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/253008.html
標籤:其他
上一篇:設定div背景透明的方法
下一篇:條件控制陳述句以及案例
