目錄
一、三子棋簡介
二、游戲規則
三、C語言實作三子棋的基本邏輯
四、代碼實作
0.創建專案
1.創建選單
2.創建棋盤并初始化
3.列印棋盤
4.玩家落子
5.判斷勝/負/平/繼續
6.電腦落子
7.同樣判斷勝/負/平/繼續
8.整合函式,回圈步驟4~7
9.尾聲
一、三子棋簡介
三子棋又稱井字棋、九宮棋,是可以隨時隨地想玩就玩的休閑益智小游戲,你可以通過三子棋消愁解悶、轉移意念、振奮精神、開發智力、增進友誼、聯絡感情、驅除孤獨,必要時更是可以哄哄不省人事的弟弟妹妹,用C語言寫個三子棋程式,在弟弟妹妹眼中,你就是帶給他們快樂的天使;在長輩眼中,你就是武能制服四腳吞金獸文可編程的斜杠青年,如此何樂而不為?那快來搞起來吧~

二、游戲規則
相同三子一條線(橫、豎、對角線)
三、C語言實作三子棋的基本邏輯
- 創建選單選擇‘開始游戲’或‘結束游戲’(畢竟下棋之前也需要征詢弟弟妹妹同不同意嘛)
- 創建棋盤并初始化(買個棋盤)
- 列印棋盤(擺出棋盤)
- 玩家落子(這里一切操作都是在鍵盤上進行= =)
- 判斷勝/負/平/繼續
- 電腦落子
- 判斷勝/負/平/繼續
- 回圈步驟4~7

四、代碼實作
0.創建專案
這里為了顯得有條理一些,我們共創建三個專案,分別是頭檔案game.h、源檔案game.c和三子棋.c,其中game.h用于宏定義、函式宣告;game.c用于game.h中函式的定義;而三子棋.c則用于實作三子棋的邏輯,

1.創建選單
首先寫一個選單函式放在三子棋.c中,這里創建選單的目的是讓玩家進行選擇,弟弟妹妹玩上癮了可以一直玩下去,玩夠了也可以選擇退出游戲,這里創建的選單比較簡略,你可以通過庫函式printf實作各種花里胡哨的選單,
void Menu()
{
printf("************************\n");
printf("****** 1.開始游戲 ******\n");
printf("****** 0.結束游戲 ******\n");
printf("************************\n");
}
(小tip:可以把庫函式的宣告也放在game.h中,這樣在各個源檔案中只需宣告#include “game”就可以啦~是不是方便很多)

(這是完成之后頭檔案game.h中的所有函式宣告↑)


2.創建棋盤并初始化
在創建棋盤之前,我們先在源檔案三子棋.c中架構一下main函式的邏輯
2.1
首先,我們創建一個變數choice,用來接受玩家瀏覽選單時進行的選擇,然后用分支陳述句switch進行各種選擇的執行,如果輸入‘1’則進入游戲函式Game();如果輸入‘0’則跳出程式;如果輸入其它數字則需要提醒玩家重新選擇,然后進入到初始的輸入步驟,因此我們還要把switch陳述句放入回圈陳述句do...while中,
#include "game.h"
void Menu()
{
printf("************************\n");
printf("****** 1.開始游戲 ******\n");
printf("****** 0.結束游戲 ******\n");
printf("************************\n");
}
int main()
{
int choice = 0;
do
{
Menu();
printf("請輸入:>");
scanf("%d", &choice);
switch (choice)
{
case 1:
Game();
case 0:
break;
default:
printf("非法輸入,請重新選擇\n");
}
} while (choice);
return 0;
}
(由于scanf函式不安全,編譯器會報錯,所以我們先在game.h中貼個
#define _CRT_SECURE_NO_WARNINGS 1,這樣編譯器就不會報錯啦)
2.2
接下來,我們就正式開始創建棋盤啦~
我們在Game函式中實作玩三子棋的邏輯,下三子棋我們需要一個3×3的棋盤,即創建一個三行三列的二維陣列:char arr[3][3],由于arr[3][3]靈活度不高,為了方便日后修改,我們在頭檔案game.h中用#define定義兩個常量,即

這樣我們創建的陣列用arr[ROW][COL]表示即可,
然后我們寫一個函式Format用于初始化,即把九個小格子都初始化為空格,代碼如下:
void Format(char arr[ROW][COL], int row, int col)//初始化
{
int i = 0;
for (i = 0; i < row; i++)//用for回圈嵌套對九個小格子初始化
{
int j = 0;
for (j = 0; j < col; j++)
{
arr[i][j] = ' ';
}
}
}
(Format函式的宣告放頭檔案game.h中,定義放在源檔案game.c中)
然后在Game函式中用Format對陣列arr初始化
完成之后就是醬紫

3.列印棋盤
接下來我們就要把棋盤擺出來,準備下棋咯,
用電腦列印棋盤當然要先寫一個列印棋盤的函式Display啦,
我們先來康康棋盤的樣紙

兩條橫的兩條豎的...
用筆劃拉四下就能搞定,可是用編程呢?
我們拆開來看,其實整個棋盤我們可以這樣劃分三行三列


而每一行我們又可以分為兩行先后進行列印

為了美觀,我們在落子位置的左右旁邊留有空格,所以我們要列印的字符有‘ %c ’、‘---’和‘|’,由于在陣列第2行和第2列的末尾均不列印線條,因此我們用if陳述句控制一下即可,
因此我們在源檔案game.c中進行函式Display定義,頭檔案game.h中宣告一下,源檔案game.c中實作函式Display的代碼如下:
void Display(char arr[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 ", arr[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
int k = 0;
if (i == row-1)
break;
else
{
for (k = 0; k < col; k++)
{
printf("---");
if (k < col - 1)
printf("|");
}
printf("\n");
}
}
}
至此,我們的Game函式就進展到醬紫

4.玩家落子
走到這里,恭喜你已經完成三分之一遼,距離成功只有五步之遙,那我們馬不停蹄地進行接下來的打造吧~
首先我們要先寫一個玩家落子的函式Player,函式的實作同樣在源檔案game.c中,記得在頭檔案game.h中進行宣告,
玩家需要通過輸入坐標來控制落子的位置,因此我們要創建兩個變數用于接收坐標,由于玩家輸入的坐標可能不在棋盤范圍內,對于非法坐標我們應讓玩家重新輸入,合法的坐標進行落子(當然落子之前先要檢查一下該位置是否已經有子),因此我們把整個分支的討論放入while回圈中,
出于游戲人性化的考慮,在程式員眼中二維陣列的行和列都是從0開始的,而在不了解編程的玩家眼里行和列是從1開始的,因此我們有必要在寫程式的時候考慮一下玩家的情況,玩家落子我們用‘*’表示,電腦落子用‘#’表示,實作代碼如下:
void Player(char arr[ROW][COL], int row, int col)//玩家落子
{
int i = 0;
int j = 0;
while (1)
{
printf("請輸入(row col):>");
scanf("%d%d", &i, &j);
if (i >= 1 && i <= row&&j >= 1 && j <= col)
{
if (arr[i - 1][j - 1] == ' ')
{
arr[i - 1][j - 1] = '*';
break;
}
else
{
printf("坐標被占用,請重新輸入\n");
continue;
}
}
else
{
printf("非法坐標,請重新輸入\n");
continue;
}
}
}
玩家落子之后,別忘了列印一下棋盤呈現一下效果
到了這里,我們的Game函式就進行到這啦

5.判斷勝/負/平/繼續
在每一次落子之后,都需要系統來判斷一下本局的情況,誰勝誰負,是平局還是游戲繼續,于是我們要寫一個函式IsWin來實作這項功能,同樣在源檔案game.c中實作,頭檔案game.h里宣告,
我們先構思一下判斷的邏輯:如果IsWin函式的回傳值為'*'則判斷玩家勝利,回傳值為'#'則判斷電腦勝利;如果棋盤已滿還未分出勝負則為平局,設定IsWin此時的回傳值為'Q';其它情況則游戲繼續,設定IsWin此時的回傳值為'C',
5.1
判斷某方勝利比較簡單,只要通過兩個for回圈判斷三行三列上是否有相同的棋子連成一線,并且需要判斷兩條對角線上是否有相同的棋子連成一線,由于三子棋對角線的情況比較簡單,所以我們就硬寫這種情況好了,
(小tip:我們只需回傳已經連成線的棋子中的某一個即可,就可以直接區分玩家和電腦,這樣就不需要畫蛇添足遼)
到這里代碼實作如下:
char IsWin(char arr[ROW][COL], int row, int col)//判斷
{
int i = 0;
int j = 0;
for (i = 0; i < ROW; i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
{
return arr[i][0];
}
else
break;
}
for (j = 0; j < COL; j++)
{
if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[0][j] != ' ')
{
return arr[0][j];
}
else
break;
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')
{
return arr[0][0];
}
else if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' ')
{
return arr[1][1];
}
}
5.2
判斷平局是基于未分出勝負時棋盤是否已滿,于是我們要寫一個判斷棋盤是否已滿的函式Full,同樣在game.c中定義,game.h中宣告,
基本邏輯:對棋盤上的九個落子位置進行檢索,如果都不為' '(空格),則棋盤已滿,我們將判斷棋盤已滿的回傳值設為1,其它情況則不滿,回傳值設為0,由于要對陣列的九個位置進行檢索,我們用for回圈嵌套來實作,代碼如下:
int Full(char arr[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 (arr[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
這樣我們就可以整個實作IsWin函式惹,代碼如下:
char IsWin(char arr[ROW][COL], int row, int col)//判斷
{
int i = 0;
int j = 0;
for (i = 0; i < ROW; i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
{
return arr[i][0];
}
else
break;
}
for (j = 0; j < COL; j++)
{
if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[0][j] != ' ')
{
return arr[0][j];
}
else
break;
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')
{
return arr[0][0];
}
else if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' ')
{
return arr[1][1];
}
else if (Full(arr, ROW, COL))
{
return 'Q';
}
else
return 'C';
}
由于Full函式的回傳值只有1或0,而1恒為真,0為假,所以我們直接放在else if的判斷中,
當既沒分出勝負也沒有平局,那只有游戲繼續~
6.電腦落子
電腦落子的邏輯和玩家落子類似,但電腦落子的坐標是隨機值,因此我們用時間戳來實作,由于電腦隨機生成的坐標要在合法范圍內,因此我們只要讓產生的隨機值模3取余數即可,這樣生成的余數就是0~2之間的隨機整數了,
我們來寫一個電腦落子的函式Computer,在此之前先在main函式里貼個時間戳:
srand((unsigned int)time(NULL));
就是這樣

電腦落子函式Computer與之前的玩家落子函式Player函式邏輯基本一致,只需要創建0~2的隨機值即可,電腦落子函式Computer也是在game.c中實作,game.h里宣告,這里直接貼上代碼:
void Computer(char arr[ROW][COL], int row, int col)//電腦落子
{
int i = 0;
int j = 0;
printf("電腦走:\n");
while (1)
{
i = rand() % row;
j = rand() % col;
if (arr[i][j] == ' ')
{
arr[i][j] = '#';
break;
}
}
}
7.同樣判斷勝/負/平/繼續
與之前玩家落子之后需要判斷一樣,這里直接使用函式IsWin即可,
8.整合函式,回圈步驟4~7
到這里,我們需要整合我們之前寫過的函式,同時要回圈步驟4~7,并且在勝利方產生或者平局時電腦能夠顯示出來,這里我們創建一個變數ret,用來接收函式IsWin的回傳值,
基于以上整合,就產生了能實作三子棋的程式,
整合后的Game函式就變成了這樣:
void Game()
{
char arr[ROW][COL];
Format(arr, ROW, COL);
Display(arr, ROW, COL);
int ret = 0;
while (1)
{
Player(arr, ROW, COL);
Display(arr, ROW, COL);
ret = IsWin(arr, ROW, COL);
if (ret != 'C')
{
break;
}
Computer(arr, ROW, COL);
Display(arr, ROW, COL);
ret = IsWin(arr, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家勝\n");
}
else if (ret == '#')
{
printf("電腦勝\n");
}
else
{
printf("平局\n");
}
}
9.尾聲
OK,到了這里,我們的三子棋程式就已經大功告成了,
跑起來看看咋樣QwQ

嘿嘿,還不錯喔
最后貼一下整個工程的代碼:
三子棋.c
#include "game.h"
void Game()
{
char arr[ROW][COL];
Format(arr, ROW, COL);
Display(arr, ROW, COL);
int ret = 0;
while (1)
{
Player(arr, ROW, COL);
Display(arr, ROW, COL);
ret = IsWin(arr, ROW, COL);
if (ret != 'C')
{
break;
}
Computer(arr, ROW, COL);
Display(arr, ROW, COL);
ret = IsWin(arr, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家勝\n");
}
else if (ret == '#')
{
printf("電腦勝\n");
}
else
{
printf("平局\n");
}
}
void Menu()
{
printf("************************\n");
printf("****** 1.開始游戲 ******\n");
printf("****** 0.結束游戲 ******\n");
printf("************************\n");
}
int main()
{
int choice = 0;
srand((unsigned int)time(NULL));
do{
Menu();
printf("請選擇:>");
scanf("%d", &choice);
switch (choice)
{
case 1:
Game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("請重新選擇\n");
break;
}
} while (choice);
return 0;
}
game.c
void Player(char arr[ROW][COL], int row, int col)//玩家落子
{
int i = 0;
int j = 0;
while (1)
{
printf("請輸入(row col):>");
scanf("%d%d", &i, &j);
if (i >= 1 && i <= row&&j >= 1 && j <= col)
{
if (arr[i - 1][j - 1] == ' ')
{
arr[i - 1][j - 1] = '*';
break;
}
else
{
printf("坐標被占用,請重新輸入\n");
continue;
}
}
else
{
printf("非法坐標,請重新輸入\n");
continue;
}
}
}
void Computer(char arr[ROW][COL], int row, int col)//電腦落子
{
int i = 0;
int j = 0;
printf("電腦走:\n");
while (1)
{
i = rand() % row;
j = rand() % col;
if (arr[i][j] == ' ')
{
arr[i][j] = '#';
break;
}
}
}
int Full(char arr[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 (arr[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char IsWin(char arr[ROW][COL], int row, int col)//判斷
{
int i = 0;
int j = 0;
for (i = 0; i < ROW; i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
{
return arr[i][0];
}
else
break;
}
for (j = 0; j < COL; j++)
{
if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[0][j] != ' ')
{
return arr[0][j];
}
else
break;
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')
{
return arr[0][0];
}
else if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' ')
{
return arr[1][1];
}
else if (Full(arr, ROW, COL))
{
return 'Q';
}
else
return 'C';
}
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 3
#define COL 3
void Format(char arr[ROW][COL], int row, int col);
void Display(char arr[ROW][COL], int row, int col);
void Player(char arr[ROW][COL], int row, int col);
char IsWin(char arr[ROW][COL], int row, int col);
int Full(char arr[ROW][COL], int row, int col);
void Computer(char arr[ROW][COL], int row, int col);
好啦,快跑起你的程式,讓弟弟妹妹們過來玩吧~
(小tip:玩家有永遠不會輸的小訣竅喔~)
喜歡的話請點贊并關注一下喔,喜上加喜那可是再好不過啦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/293259.html
標籤:其他
下一篇:C++迷宮小游戲
