三子棋
在這個程序裏面總共包含了5個子函數,和一個main函數。接下來逐個分析一下每個函數的構建思路。
1.初始化函數。
該部分函數主要對棋盤內的9個空格進行賦值,一般情況下我們把它們設爲空格,這裏我把它設爲‘0’,不是空格也無大礙。這是很簡單的一部分,只需要些兩個for循環就可以把初始化完成。
對於傳參這部分,需要把數組board傳進去,因爲我們要用數組對棋盤進行初始化,還需要row和col兩個參數,來控制棋盤的大小。
void InitBoard(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++)
{
board[i][j]='0';
}
}
}`
2.顯示棋盤
這裏也是比較簡單的一部分,只需要一個for循環就可以完成。對於格子裏的橫線豎線,我們可以自己調整到自己喜歡的樣子,我這裏沒有畫出外面的一圈線,因爲我發現不太好畫,畫出來不美觀。
傳參同樣需要數組board和row、col,和初始化函數一致。
void PrintBoard(char board[ROW][COL],int row,int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
if(i != row-1)
printf("---|---|---\n");
}
}
3.電腦走
這裏是玩家先走還是電腦先走,是我們自己定的,我這裏定的電腦先走,畢竟電腦下這個三子棋不會思考,所以讓它先走吧,不要欺負它嘛!
先說傳參的部分,與上面的部分一致,需要一個數組,還需要知道行和列。
要想電腦走到任意一個位置,這裏我們就用到了一個生成隨機數的關鍵字rand,但是事先我們要在測試文件中定義srand((unsigned int)time(NULL)),這樣子纔可以使用rand()。然後我們用rand模上行和列,就得到了電腦要下的位置,行和列是3,所以我們模3的結果就是0-2,就是棋盤數組的下標,這就是我們爲什麼要模3的原因。
還需要注意的一點就是,電腦在下的時候,需要判斷該位置是否已經被佔了,如果被佔了,肯定是不能下這個地方的,所以這個地方用一個if,判斷一下,就OK了,因爲我的初始化是設爲0,所以如果該位置不爲0,那就可以下。
void ComMove(char board[ROW][COL],int row,int col)
{
int x = 0;
int y = 0;
printf("電腦走!\n");
while(1)
{
x = rand()%row;//因爲下標是0-2,所以這裏模3
y = rand()%col;
if(board[x][y] =='0')
{
board[x][y] ='2';
break;
}
}
}
4.玩家走
玩家走的時候,也需要考慮和電腦走的時候同樣的問題,一個是該位置是否被佔,一個是玩家輸入座標是否合法。
## 判斷是否被佔 ##
假如玩家輸入x和y,x和y就要在1-3之間,這樣子才能匹配棋盤位置,然後數組裏面的部分就要寫成x-1和y-1,因爲數組下標從0開始,下標與順序差1。
其實也可以規定輸入x和y要在0-2之間,這樣子數組裏面就不用改了,只是玩家要清楚位置與下標之間的關係。
## 判斷輸入是否合法 ##
這裏與電腦輸入一樣,判斷要下的位置是否爲0,不是0纔可以下到該位置。否則輸出“座標非法!重新輸入”,我們可以看見把printf(“玩家走!\n”)放在while(1)外面,就是爲了不重複顯示“玩家走”,重複顯示“請輸入座標”就可以了!
void PlayerMove(char board[ROW][COL],int row,int col)
{
int x = 0;
int y = 0;
printf("玩家走!\n");
while(1)
{
printf("請輸入座標(x,y):");
scanf("%d%d",&x,&y);
if(((x>=1) && (x<=row)) &&((y>=1) &&( y<=col)))
{
if(board[x-1][y-1] == '0')
{
board[x-1][y-1] ='1';
break;
}
else
{
printf("該位置被佔用!");
}
}
else
{
printf("座標錯誤!");
}
}
}
5.判斷輸贏
這裏我們知道有8種贏的局面,橫着3個相同的相連有3種,豎着也有3種,還有斜着的有2種。
所以只要我們判斷出是否有上述8種情況出現,就可以判斷出輸贏。不過我們還不知道誰輸誰贏,所以我們要判斷出現“贏”的情況時,那一步是誰下的。所以我們的思路是,電腦或者玩家走,判斷輸贏,打印棋盤,打印誰輸誰贏。
`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][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(is_full(board,row,col))
{
return 'q';
}
return ' ';
}`
static 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;
}
}
}
5個函數就寫好了,我們把它們放在game.c裏面
接下來,還需要一個測試文件test.c,把我們寫的game.c運行起來。
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//測試的代碼都放到test文件裏面,遊戲的代碼都放到game文件裏面
void menu()
{
printf("*****1.play 0.exit*****\n");
}
//1.打印棋盤 玩家走;請輸入座標;判斷輸贏;電腦走;判斷輸贏
void game()
{
char arr[ROW][COL]={0};
InitBoard(arr,ROW,COL);
PrintBoard(arr,ROW,COL);
while(1)
{
ComMove(arr,ROW,COL);
PrintBoard(arr,ROW,COL);
CheckWin();
PlayerMove(arr,ROW,COL);
PrintBoard(arr,ROW,COL);
CheckWin();
}
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請選擇:");
scanf("%d",&input);
switch(input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("選擇錯誤\n");
break;
}
}while(input);
}
int main()
{
test();
system("pause");
return 0;
}
最後我們還需要一個頭文件,來聲明這些函數,我們設置頭文件可以防止裏面的函數被重複調用。
#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define COL 3
#define ROW 3
void InitBoard(char board[ROW][COL],int row,int col);
void PrintBoard(char board[ROW][COL],int row,int col);
void ComMove(char board[ROW][COL],int row,int col);
void PlayerMove(char board[ROW][COL],int row,int col);
char CheckWin(char board[ROW][COL], int row, int col);
#endif //__GAME_H__
!運行實例