文章目錄
- 0.思路簡介
- 1.準備作業
- 1.1 簡易的用戶互動界面
- 1.2 構建大體框架
- 2.棋盤相關函式
- 2.1 初始化棋盤
- 2.2 畫出簡易棋盤
- 2.3 玩家輸入函式
- 2.4 電腦輸入函式(簡易)
- 2.5 判斷游戲結果函式
- 2.6 完善game()函式
- 3.源代碼
- 3.1 頭檔案game.h
- 3.2 源檔案 game.c
- 3.3 源檔案 test.c
0.思路簡介
源代碼放在最后,
大致分為分為3部分
- 構建三子棋環境,即棋盤的樣子,如何贏等等
- 讓用戶可以進行輸入
- 讓電腦可以輸入
源代碼放在最后,
1.準備作業
創建兩個源檔案,一個叫test.c,一個叫game.c
再創建一個頭檔案,叫game.h
test.c用于寫主函式和程式的大體框架
game.c用于實作不同的函式
game.h用于對函式宣告和對庫的參考,
這樣的好處是使代碼獨立而且比較清晰,
1.1 簡易的用戶互動界面
可以寫一個menu函式,用于繪制選單,
void menu()
{
printf("****************************\n");
printf("******** 1. play *******\n");
printf("******** 0. exit *******\n");
printf("****************************\n");
}
用戶輸入1則開始游戲,0則退出游戲,
1.2 構建大體框架
常用的方式是使用switch陳述句和do…while陳述句(可以讓程式看起來更加清晰)
int input;
do
{
scanf("%d", &input);
switch (input)
{
case 1:
printf("開始游戲\n");
game(board, ROW, COL);
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤\n");
printf("請重新輸入:");
break;
}
} while (input);
若輸入1,則開始游戲,game函式負責游戲的開始,程序和結束,之后再慢慢實作,
注:game函式傳入了三個引數,一個是棋盤(二維陣列),另外兩個是行和列,行和列用宏的方式定義了,
#define ROW 3
#define COL 3
若輸入0,則退出游戲,
若輸入其他無關的東西,就重新輸入,
這樣宏觀的框架就完成了,可以去實作game函式的細節了,
2.棋盤相關函式
基礎的功能可以寫出4個函式
- 初始化棋盤,
- 列印棋盤
- 玩家輸入函式
- 電腦輸入函式
2.1 初始化棋盤
由于棋盤是正方型的,可以用二維陣串列示,
初始化的方法就是把二維陣列全部放進空格,這樣在沒有任何輸入的時候棋盤就是空的了,
代碼很簡單,就是遍歷二維陣列然后賦值就可以了,
void init_board(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] = ' ';
}
}
}
2.2 畫出簡易棋盤
棋盤可以由兩部分構成,一個部分是放棋子的地方,一個部分是分割行,
長這樣:

分割行由-------構成,放棋子的地方由空格和豎杠|構成,
本質還是兩個for回圈,第一個回圈控制列印多少行,第二個回圈控制列印多少列,只不過回圈體里面列印的東西換成空格和豎杠即可,
void display(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-1)//最后一列不列印豎杠了,
printf("|");
if (j >= col - 1)
{
printf("\n");
for (int k = 0; k < col; k++)
{
if(i<row-1)//最后一行不列印分割行了,
printf("----");
}
}
}
printf("\n");
}
printf("列印成功\n");
}
2.3 玩家輸入函式
玩家可以通過輸入坐標來給二維陣列賦值,然后實作下棋的功能,(這里用*來代表玩家下的棋子)
要注意的是:
1.如果棋盤里面本來已經下有棋子的地方是不能重復下子的,不注意這個點容易出bug,
2.由于陣串列示行和列的方式和日常生活中不一樣,所以在賦值的時候記得把下標減1.
void player_move(char board[ROW][COL], int row, int col)
{
int x, y;
printf("請玩家輸入坐標:");
scanf("%d%d", &x, &y);
if (board[x-1][y-1] == ' ')
{
board[x-1][y-1] = '*';
}
else
{
while (board[x-1][y-1] != ' ')
{
printf("這里已經有棋子了,請重新輸入:");
scanf("%d%d", &x, &y);
}
board[x-1][y-1] = '*';
}
}
2.4 電腦輸入函式(簡易)
電腦輸入用時間戳生成亂數即可,
要注意的幾個點:
1.rand()函式要取到固定區間的數值的方法是取模,
例如:如果想要生成0-2的亂數,模3即可,因為模數不可能大于3.
如果要生成0-100的亂數,模101即可,
如果要生成1-100的亂數,模100+1即可,因為模100可以生成0-99的亂數,加1就是1-100.
2.rand()函式使用前要記得在開始時使用srand作起點,里面加上時間戳time函式,這個函式在庫time.h里面,
srand((unsigned int)time(NULL));
void computer_move(char board[ROW][COL], int row, int col)
{
int x, y;
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
}
else
{
while (board[x][y] != ' ')
{
x = rand() % 3;
y = rand() % 3;
}
board[x][y] = '#';
}
}
2.5 判斷游戲結果函式
可以寫一個is_win函式,
- 玩家贏時—回傳W (WIN)
- 電腦贏時—回傳L (LOSE)
- 平局時—回傳D (DRAW)
- 其他時—回傳C (CONTINUE)
char is_win(char board[ROW][COL], int row, int col)
由于判斷贏和輸的情況都是需要找到棋盤上是否有三個連在一起的棋子,所以可以獨立寫一個find函式,
find函式加多了一個引數,就是棋子的種類kind,
int find(char board[ROW][COL], int row, int col, char kind)
實作方法很暴力,就是看每一行或每一列或者對角線是否有三個連在一起的棋子,
注:&& 和 ||的優先級時不一樣的,如果在判斷里面兩個都用了,務必要加上括號來區分優先級,否則會出bug,還難以預測,在對角線的判斷中就需要,
//找是否有三個連起來的棋子
int find(char board[ROW][COL], int row, int col, char kind)
{
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] == kind && board[i][1] == kind && board[i][2] == kind)
{
return 1;
}
}
for (int j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] == kind && board[1][j] == kind && board[2][j] == kind)
{
return 1;
}
}
//對角線
//&& 和 ||的優先級時不一樣的,如果在判斷里面兩個都用了,務必要加上括號來區分優先級,否則會出bug,還難以預測,在對角線的判斷中就需要,
if (((board[0][0] == board[1][1] && board[1][1] == board[2][2]) || (board[0][2] == board[1][1] && board[1][1] == board[2][0])) && (board[1][1] == kind))
{
return 1;
}
return 0;
}
現在可以來完善is_win函式了,
在判斷是否繼續的時候可以看棋盤是否有空位,在沒有產生勝負的時候有空位,就不會出現平局(在這個假設下容易實作),在沒有空位的時候且沒有產生勝負的時候就是平局,
//判斷是否贏棋
//玩家贏時---回傳W
//電腦贏時---回傳L
//平局時---回傳D
//其他時---回傳C
char is_win(char board[ROW][COL], int row, int col)
{
//玩家贏
char kind1 = '*';
int ret1 = find(board, row, col,kind1);
if (ret1 == 1)
{
printf("玩家勝利\n");
return 'W';
}
//電腦贏
char kind2 = '#';
int ret2 = find(board, row, col,kind2);
if (ret2 == 1)
{
printf("電腦勝利\n");
return 'L';
}
//有空位就繼續
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 'C';
}
}
}
//沒有空位且還沒有產生勝負時
if (ret1 == 0 && ret2 == 0)
{
printf("平局\n");
return 'D';
}
}
2.6 完善game()函式
所有基礎功能都實作了,可以來把game函式來完善了,
注:
每次玩家或者電腦下完棋都要進行是否結束的判斷,
且下棋是一個回圈的程序,所以可以寫成while(1),在結束后再break這個回圈,
void game(char board[ROW][COL], int row, int col)
{
init_board(board, ROW, COL);
display(board, ROW, COL);
while (1)
{
player_move(board, ROW, COL);
display(board, ROW, COL);
char ret1 = is_win(board, ROW, COL);
if (ret1 == 'W')
break;
else if (ret1 == 'L')
break;
else if (ret1 == 'D')
break;
computer_move(board, ROW, COL);
display(board, ROW, COL);
char ret2 = is_win(board, ROW, COL);
if (ret2 == 'W')
break;
else if (ret2 == 'L')
break;
else if (ret2 == 'D')
break;
}
}
3.源代碼
3.1 頭檔案game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
//列印選單
void menu();
void game(char board[ROW][COL], int row, int col);
//初始化棋盤
void init_board(char board[ROW][COL], int row, int col);
//列印棋盤
void display(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);
//判斷是否贏棋
//玩家贏時---回傳W
//電腦贏時---回傳L
//平局時---回傳D
//其他時---回傳C
char is_win(char board[ROW][COL], int row, int col);
int find(char board[ROW][COL], int row, int col, char kind);
3.2 源檔案 game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("****************************\n");
printf("******** 1. play *******\n");
printf("******** 0. exit *******\n");
printf("****************************\n");
}
void game(char board[ROW][COL], int row, int col)
{
init_board(board, ROW, COL);
display(board, ROW, COL);
while (1)
{
player_move(board, ROW, COL);
display(board, ROW, COL);
char ret1 = is_win(board, ROW, COL);
if (ret1 == 'W')
break;
else if (ret1 == 'L')
break;
else if (ret1 == 'D')
break;
computer_move(board, ROW, COL);
display(board, ROW, COL);
char ret2 = is_win(board, ROW, COL);
if (ret2 == 'W')
break;
else if (ret2 == 'L')
break;
else if (ret2 == 'D')
break;
}
}
//用空格來初始化棋盤
void init_board(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] = ' ';
}
}
}
//列印棋盤
void display(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-1)
printf("|");
if (j >= col - 1)
{
printf("\n");
for (int k = 0; k < col; k++)
{
if(i<row-1)
printf("----");
}
}
}
printf("\n");
}
printf("列印成功\n");
}
void player_move(char board[ROW][COL], int row, int col)
{
int x, y;
printf("請玩家輸入坐標:");
scanf("%d%d", &x, &y);
if (board[x-1][y-1] == ' ')
{
board[x-1][y-1] = '*';
}
else
{
while (board[x-1][y-1] != ' ')
{
printf("這里已經有棋子了,請重新輸入:");
scanf("%d%d", &x, &y);
}
board[x-1][y-1] = '*';
}
}
void computer_move(char board[ROW][COL], int row, int col)
{
int x, y;
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
}
else
{
while (board[x][y] != ' ')
{
x = rand() % 3;
y = rand() % 3;
}
board[x][y] = '#';
}
}
//判斷是否贏棋
//玩家贏時---回傳W
//電腦贏時---回傳L
//平局時---回傳D
//其他時---回傳C
char is_win(char board[ROW][COL], int row, int col)
{
//玩家贏
char kind1 = '*';
int ret1 = find(board, row, col,kind1);
if (ret1 == 1)
{
printf("玩家勝利\n");
return 'W';
}
//電腦贏
char kind2 = '#';
int ret2 = find(board, row, col,kind2);
if (ret2 == 1)
{
printf("電腦勝利\n");
return 'L';
}
//有空位時繼續比賽
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 'C';
}
}
}
//沒有空位且還沒有產生勝負時
if (ret1 == 0 && ret2 == 0)
{
printf("平局\n");
return 'D';
}
}
//找是否有三個連起來的棋子
int find(char board[ROW][COL], int row, int col, char kind)
{
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] == kind && board[i][1] == kind && board[i][2] == kind)
{
return 1;
}
}
for (int j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] == kind && board[1][j] == kind && board[2][j] == kind)
{
return 1;
}
}
if (((board[0][0] == board[1][1] && board[1][1] == board[2][2]) || (board[0][2] == board[1][1] && board[1][1] == board[2][0])) && (board[1][1] == kind))
{
return 1;
}
return 0;
}
3.3 源檔案 test.c
#include "game.h"
int main()
{
srand((unsigned int)time(NULL));
char board[ROW][COL];
menu();
int input;
do
{
scanf("%d", &input);
switch (input)
{
case 1:
printf("開始游戲\n");
game(board, ROW, COL);
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤\n");
printf("請重新輸入:");
break;
}
} while (input);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290750.html
標籤:其他
上一篇:Java實作三子棋小游戲
