三子棋-支援N子棋-詳解(以及堵截玩家的方法設計)
我可能寫的有些囉嗦,見諒,但我會很詳細的講解每一個步驟。
分析步驟
遊戲框架的構造(遊戲結構的設計)
1,遊戲需要選單
2,需要選項(進入遊戲或退出)
3,三子棋需要一個3*3的棋盤
4,需要將棋盤表現(打印出來)
5,玩家要開始下棋(輸入座標)
6,每次落子後都要判斷輸贏或平局
7,列印目前棋盤的狀況8,電腦開始落子
9,每次落子後都要判斷輸贏或平局
10,列印目前棋盤的狀況
11.判斷遊戲目前的局面(輸或贏,繼續落子或者平局)
程式碼佈局設計
由於,程式碼量過大,並且各個函式的設計及作用。並且考慮N子棋的可能。我們需要分模組,分檔案來寫。
對遊戲佈局,初始選項的思考
遊戲選單-進入遊戲或者退出—分支語句(switch)
還要列印遊戲選單,使用函式。
為了多次play遊戲,也包括多次選項輸入,考慮do{}while();迴圈,可以至少進入一次迴圈。
void option(int input)
{
switch (input)//分支語句
{
case 1:
game(); //進入遊戲
break;
case 0:
printf("Logon out the game\n");
break;
default:
printf("Input error,please input again\n");
break;
}
}
void menu(void)
{
printf("Welcome to game\n");
printf("\n");
printf("****************\n");
printf("*----1.play----*\n" );
printf("*----0.exit----*\n");
printf("****************\n");
}
int main(void)
{
int input;
//srand((unsigned int)time(NULL));時間戳,為電腦落子設定隨機數
do
{
menu();//列印遊戲選單
printf("please input option(1/0):>");
scanf("%d", &input);
option(input);//選項判斷
} while (input);
return 0;
}
我們要求輸入數字1或0,如果輸入其他值,就會default結束,並進入while判斷,為,int型,再次迴圈。
game函式的實現
將上述遊戲設計實現
1,三子棋需要一個3*3的棋盤
2,需要將棋盤表現(打印出來)
3.玩家要開始下棋(輸入座標)
4.每次落子後都要判斷輸贏或平局
5,列印目前棋盤的狀況
6,電腦開始落子
7,每次落子後都要判斷輸贏或平局
8,列印目前棋盤的狀況
void game(void)
{
char ret;
char board[ROW][COL];//建立二維陣列
setboard(board, ROW, COL);//製作棋盤
while (1)
{
player(board);//玩家開始下棋
ret=judgewinner(board);//判斷輸贏
if (ret != 'C')
break;
computer(board);//電腦開始下棋
ret=judgewinner(board);//判斷輸贏
if (ret != 'C')
break;
}
if (ret == '*')
printf("The winner is player\n");
else if (ret == '#')
printf("The winner is computer\n");
else if (ret == 'D')
printf("Player and computer draw\n");
}
1,三子棋需要一個3*3的棋盤
畢竟是個3 * 3的棋盤,可以使用二維陣列。
char board[3][3]//這兩個行列可以使用巨集定義常量,方便延申N子棋。
#define ROW 3
#define COL 3
char board[ROW][COL]
2, 列印三子棋棋盤
大概是這樣的
二維陣列的元素也要被定義為空格。在後面玩家或電腦輸入後可以被重新定義為*號或#號。
void setboard(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] = ' ';//元素被定義為空格
}
}
showboard(board,ROW, COL);//列印棋盤的函式
}
void showboard(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)
printf("|");
}
if (i < row)
printf("\n---|---|---|\n");
}
}
3,玩家落子
就是輸入座標
void player(char board[ROW][COL])//玩家下棋
{
int x, y;
while (1)
{
printf("please input the coordinate:>");
scanf("%d %d", &x, &y);//輸入要落子的座標
if (x>=1&&x<=ROW&&y>=1&&y<=COL)//判斷該座標處,是否未被輸入過
{
if (board[x - 1][y - 1] != ' ')
printf("Coordinates occupied,please input again\n");
else
{
board[x - 1][y - 1] = '*';
break;
}
}
else
printf("Coordinate is illegal,please input again\n");//被使用過,重新輸入
}
//printf("*******************\n");
printf("Player\n");
showboard(board, ROW, COL);//列印每次下棋後的棋盤
}
由於玩家並不是程式設計師不認為,起點是0,所以賦值時要x-1,y-1.。
並且這是多次輸入,要保證輸入那個座標處不能已經輸入過,就是說要保證該陣列元素只能為空格。同時還要保證輸入座標要有效,必須在33的棋盤內,如果兩個問題有一個存在,必須要重新輸入,所以放入迴圈內,直到輸入正確,才會跳出迴圈。
4,先不考慮判斷輸贏,先列印當前棋盤,就是呼叫showboard(board, ROW, COL);函式,迴圈列印。
先保證電腦和玩家的棋盤輸入輸出正確再來判斷輸贏。
6,電腦開始落子,列印棋盤
暫時先使用隨機落子的演算法,下次我再寫堵截玩家落子的演算法
void computer(char board[ROW][COL])//電腦落子
{
while (1)
{
int x = rand() % ROW;
int y = rand() % COL;
if (board[x][y] == ' ')//判斷該座標處,是否未被輸入過
{
board[x][y] = '#';
break;
}
}
printf("Computer\n");
//printf("*******************\n");
showboard(board, ROW, COL);//列印每次下棋後的棋盤
}
前面已經使用srand();,保證了隨機數
int x = rand() % ROW;
int y = rand() % COL;
X y,為隨機數除以排或列的餘數,也就是說xy的值必定小於排,列的值,也就保證了xy,為 0,1,2
這也同樣保證了由三子棋走向N子棋的條件。
同樣得保證電腦落子的座標處不能已經使用過,必須得保證座標元素處為空格,才能輸入#。並且呼叫函式列印當前棋盤。
判斷棋盤的局面
呼叫char judgewinner(char board[ROW][COL])函式
char ifdraw(char board[ROW][COL])
{
int i;
for (i = 0; i < ROW; i++)
{
int j;
for (j = 0; j < COL; j++)
{
if (board[i][j] == ' ')
return 'C';
}
}
return 'D';
}
char judgewinner(char board[ROW][COL])
{
int count;
//判斷一行贏
for (int i = 0; i < ROW; i++)
{
int j,count=0;
for (j = 0; j < COL-1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
if ((count != COL - 1) && (i == ROW - 1))
return ifdraw(board);//平局
}
//判斷列贏
for (int i = 0; i < COL; i++)
{
int j, count = 0;
for (j = 0; j < ROW - 1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
if ((count != ROW - 1) && i == COL - 1)
return ifdraw(board);//平局
}
//判斷對角線\贏
count = 0;
int i = 0;
int j;
while ((count != COL - 1) && (i <ROW-1))
{
j = i;
if (board[i][j] == board[i + 1][j + 1])
count++;
else if (board[i][j] != board[i + 1][j + 1])
break;
i++;
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
}
return ifdraw(board);//平局}
//對角線/
count=0;
i = ROW - 1;
while (i>0)
{
j=ROW-i-1;
if (board[i][j] == board[i - 1][j + 1])
count++;
else if (board[i][j] = board[i - 1][j + 1])
break;
i--;
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
}
return ifdraw(board);//平局
}
判斷一行或者一列的棋子都相等的情況下,我們使用l兩個for迴圈,我們同時定義一個控制變數。外迴圈,保證每一個行或每列都能覆蓋。內迴圈來確定每一行或每一列上的元素,相鄰之間是否相等?如果相等,count加一,不相等就可以確定,不存在決定當前棋局的條件,直接跳出。同樣支援N子棋的判斷。
對於左斜線以及右斜線上的三指相的條件,這個就比較簡單,,不需要一遍遍的遍歷,只需要找到特定的三個元素去判斷是否相等即可得出條件。
用這些迴圈條件來判斷,只能得出是否是玩家贏還是電腦贏,但是還需要新增一個函式來判斷是否是平局或者棋局未滿,可以繼續落子。
char ifdraw(char board[ROW][COL])
判斷平局或繼續落子。
用兩個for迴圈去遍歷陣列只要判斷出有一個元素是空格隔那麼就返回c就可以直接得出可以繼續落子,就需要返回來D來決定已經平局無法再落子。
因為一旦進入這卡數就表明已經判斷出無法決定誰勝或者誰負,只能繼續走兩條路一就是平局,二就是繼續落子。
同時,設定了ret來接受judgewinner(char board[ROW][COL])函式的返回值,來判斷是否可以繼續迴圈落子。
計算機堵截玩家的演算法設計:思路
遊戲的規則是行列斜線,三種情況下,只要有一種情況,該線上都歸屬於三個同樣的旗子,即可判斷輸贏
我們可以考慮迴圈遍歷
依靠迴圈進入每行每列,每個斜線,進行每個元素的遍歷,如果該行該列或該斜線上有兩個相同的元素,立馬在第三個元素上進行,若無論是否與自己相同.
該思路目前只適用於三字棋,也可延伸到四子棋,4則是兩個起步,如果該列該行或該切線上有兩個以上的相同元素,就立馬在第三或第四個元素中進行落子
以下便是為拆開講解的全部程式碼。
三子棋
主函式介面
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "game.h"
#define ROW 3
#define COL 3
//返回值
//*
//#
//C-繼續
//D-平局
void game(void)
{
char ret;
char board[ROW][COL];//建立二維陣列
setboard(board, ROW, COL);//製作棋盤
while (1)
{
player(board);//玩家開始下棋
ret=judgewinner(board);//判斷輸贏
if (ret != 'C')
break;
computer(board);//電腦開始下棋
ret=judgewinner(board);//判斷輸贏
if (ret != 'C')
break;
}
if (ret == '*')
printf("The winner is player\n");
else if (ret == '#')
printf("The winner is computer\n");
else if (ret == 'D')
printf("Player and computer draw\n");
}
void option(int input)
{
switch (input)//分支語句
{
case 1:
game();
break;
case 0:
printf("Logon out the game\n");
break;
default:
printf("Input error,please input again\n");
break;
}
}
void menu(void)
{
printf("Welcome to game\n");
printf("\n");
printf("****************\n");
printf("*----1.play----*\n");
printf("*----0.exit----*\n");
printf("****************\n");
}
int main(void)
{
int input;
srand((unsigned int)time(NULL));
do
{
menu();//列印遊戲選單
printf("please input option(1/0):>");
scanf("%d", &input);
option(input);//選項判斷
} while (input);
}
game.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "game.h"
//void game(void)
//{
// char board[ROW][COL];//建立二維陣列
// setboard(board, ROW, COL);//製作棋盤
// player(board);//玩家開始下棋
//
// computer(board);//電腦開始下棋
//
//}
void setboard(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] = ' ';
}
}
showboard(board,ROW, COL);
}
void showboard(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)
printf("|");
}
if (i < row)
printf("\n---|---|---|\n");
}
}
void player(char board[ROW][COL])//玩家下棋
{
int x, y;
while (1)
{
printf("please input the coordinate:>");
scanf("%d %d", &x, &y);//輸入要落子的座標
if (x>=1&&x<=ROW&&y>=1&&y<=COL)//判斷該座標處,是否未被輸入過
{
if (board[x - 1][y - 1] != ' ')
printf("Coordinates occupied,please input again\n");
else
{
board[x - 1][y - 1] = '*';
break;
}
}
else
printf("Coordinate is illegal,please input again\n");//被使用過,重新輸入
}
//printf("*******************\n");
printf("Player\n");
showboard(board, ROW, COL);//列印每次下棋後的棋盤
}
void computer(char board[ROW][COL])//電腦落子
{
while (1)
{
int x = rand() % ROW;
int y = rand() % COL;
if (board[x][y] == ' ')//判斷該座標處,是否未被輸入過
{
board[x][y] = '#';
break;
}
}
printf("Computer\n");
//printf("*******************\n");
showboard(board, ROW, COL);//列印每次下棋後的棋盤
}
char ifdraw(char board[ROW][COL])
{
int i;
for (i = 0; i < ROW; i++)
{
int j;
for (j = 0; j < COL; j++)
{
if (board[i][j] == ' ')
return 'C';
}
}
return 'D';
}
char judgewinner(char board[ROW][COL])
{
int count;
//判斷一行贏
for (int i = 0; i < ROW; i++)
{
int j,count=0;
for (j = 0; j < COL-1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
if ((count != COL - 1) && (i == ROW - 1))
return ifdraw(board);//平局
}
//判斷列贏
for (int i = 0; i < COL; i++)
{
int j, count = 0;
for (j = 0; j < ROW - 1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
if ((count != ROW - 1) && i == COL - 1)
return ifdraw(board);//平局
}
//判斷對角線\贏
count = 0;
int i = 0;
int j;
while ((count != COL - 1) && (i <ROW-1))
{
j = i;
if (board[i][j] == board[i + 1][j + 1])
count++;
else if (board[i][j] != board[i + 1][j + 1])
break;
i++;
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
}
return ifdraw(board);//平局}
//對角線/
count=0;
i = ROW - 1;
while (i>0)
{
j=ROW-i-1;
if (board[i][j] == board[i - 1][j + 1])
count++;
else if (board[i][j] = board[i - 1][j + 1])
break;
i--;
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家贏
else if (board[i][j] == '#')
return '#';//電腦贏
}
}
return ifdraw(board);//平局
}
game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void game(void);//三子棋遊戲
void setboard(char board[ROW][COL], int row, int col);//建立棋盤
void showboard(char board[ROW][COL], int row, int col);//列印、展示棋盤
void player(char board[ROW][COL]);//玩家落子
void computer(char board[ROW][COL]);//電腦落子
char judgewinner(char board[ROW][COL]);//判斷輸贏
char ifdraw(char board[ROW][COL]);//判斷是否平局