程式設計師帶你回味童年,一起用C語言做一個「推箱子」玩!【文末原始碼】

2021-06-23 11:00:02

這篇文章是用C語言做了一個推箱子小遊戲,實現起來比較簡單,和大家一起回味一下童年捧著按鍵機玩推箱子的日子!文末附帶萬字原始碼!

目錄

一、寫在前面

二、設計思路

1.主介面函數介紹

2.選擇介面函數

3.選擇函數

4.遊戲步驟重播函數

5.鍵盤鍵位設定函數

6.遊戲介面函數

7.向左函數

8.向右函數

9.向下函數

10.向上函數

11.通關函數

12.最佳記錄函數

13.入佇列函數

14.出佇列函數

三、最後總結

四、完整原始碼


Hello,你好呀,我是灰小猿!一個超會寫bug的程式猿!

還記得我們曾經的那個推箱子嗎,記得小時候家裡只有按鍵的諾基亞的時候,推箱子、貪吃蛇都是我天天最經常玩的遊戲,然後最近正好有小夥伴問我有沒有做過相關的開發,所以今天在這裡跟大家一個用C語言實現的簡單推箱子的小遊戲,帶著大家一起回味一下童年呀!【點贊收藏,上車坐好!】

一、寫在前面

推箱子游戲程式的設計為分別設定各型別函數類,設定推箱子房子佈局的資料結構二維陣列,以及記錄最短步驟數目以及最好成績的二維陣列,通過函數對房子進行佈局,定義資料結構佇列類,並設定公有成員函數和私有成員函數。

與此同時,我運用C++中的派生類相關知識設定相同類名以及不同類名的物件,用於構造推箱子游戲的分佈函數,設定資料結構出隊和入隊函數,同時設計以箱子為物件,依據於人的橫縱座標位置的函數,設計基於遊戲資料介面的,開始介面通關提示、遊戲時選項提示、玩遊戲時介面顯示地圖左右上下方向通關提示以及排行榜等。

同時,根據遊戲要求設定輸出遊戲主介面和遊戲關卡選擇介面,用於我們的操作,構造將遊戲步驟進行重新播放的函數,根據以上以及各型別詳細函數設定主函數並進行操作執行遊戲,以此來達到使遊戲平穩執行的要求。除上述內容之外,在製作遊戲時,我還運用了多元分組的構造模式,使得程式內容簡單易懂,任何有程式基礎的人都可以進行交流學習。接下來我跟大家分享一下主要的模組設計,最後附上完整原始碼供大家參考!小夥伴們別忘了三連支援,收藏學習呀!

二、設計思路

在程式中我利用類與物件完成了對遊戲地圖的設計,以及對於關卡的選擇等眾多功能。並且利用資料結構中的理念,實現了對人與箱子的定位和時間步數等功能的實現。總體來說,該程式涵蓋了我們所學習的相關知識,雖然遊戲有點簡單,但是其中內容卻涉獵甚廣,

推箱子游戲的設計目的,在於合理有效運用資料結構棧與佇列,以及C++中的類與物件以及派生類的相關知識,將遊戲中的各個環節拆分開來,運用派生類將各個環節串聯起來,達到實現程式穩定執行的目的。以下是總體設計圖:

1.主介面函數介紹

在box下的begin派生類中,我們的主要功能是輸出遊戲介面,在該函數中,我們對遊戲內部功能進行了詳細介紹,其中包括遊戲玩法和操作指令,與此同時,對遊戲主介面進行了詳細優化,在該函數中,在遊戲功能的介紹上,我們分別使用星星,圓圈和特殊符號代表箱子,目標位置和推箱子的小人物,我們呼叫進行觀察,選擇的函數來完成遊戲,玩家對遊戲關卡的選擇,並且在操作指令上對進行復原選擇和退出遊戲進行了詳細介紹,方便玩家更好的遊戲體驗,

2.選擇介面函數

在遊戲選擇介面中,我們採用雙五角星的介面圖形動畫,在中間設定關卡選項,選擇選項中有1到4個關卡可供選擇,在使用者進行關卡選擇以後,可將選擇關卡的序號進行返回到函數之中,函數對玩家選擇的序號進行識別,一次對1到4個關卡進行選擇判斷,然後在程式中跳轉到相應的函數介面,供玩家進行遊戲,倘若玩家輸入的序號不在1到4之間,則系統會自動提示輸入錯誤,請重新輸入的字樣。

3.選擇函數

在派生類選擇函數中,我們設定了重播,主介面,最好記錄,退出四個選項,當玩家遊戲無法通關時,可按鍵盤上的c鍵來跳轉出選擇介面進行玩家的選擇,和選擇關卡的設定一樣,我們在玩家反饋過來的1到4四個序號進行判斷,然後依次作出重播放,返回主介面,跳轉出最好記錄,退出系統四個功能。

4.遊戲步驟重播函數

在遊戲玩一下通關以後,我們會設定一個遊戲步驟重播函數,在該函數執行以後,玩家可以觀看由程式對玩家步驟進行記錄而設定好的遊戲步驟重播,在該函數中,我們主要是依據玩家進行上下左右方向鍵操作,對其方向的使用進行儲存到陣列之中,當玩家選擇進行遊戲步驟重播時,我們可將該二維陣列中的資料釋放出來,達到將遊戲步驟進行重新播放的效果。

5.鍵盤鍵位設定函數

在遊戲開始以後,有玩家可通過上下左右方向鍵來進行遊戲中小人的控制操作,而遊戲中小人控制操作的方向鍵,我們所依據的是Ascii碼鍵盤鍵位,其中左鍵為75號,右鍵為77號上鍵為72號,下鍵為80號,在開始遊戲以後,玩家對按鍵進行操作,與此同時,我們在內部函數中會對75,77,72,84個數進行記憶,當返回值為四個數中的其中之一時,我們會將該記錄存入函數之中,並且在遊戲步驟上加1,其中我們還設定鍵盤上的c鍵為26,當選擇c鍵時可進行重新選擇操作,在該重新選擇以後,我們設定返回主介面和退出遊戲兩個選項,可供玩家進行選擇。

6.遊戲介面函數

在遊戲介面函數中,我們設定了遊戲的各種形狀來代表我們遊戲內部的不同內容,分別以‘■’代表牆體,‘○’代表目標位置,‘★’代表箱子,‘♀’代表人,和‘㊣’代表箱子在目標位置上的效果展示,與此同時,在介面的最下邊,我們增加有復原(Ctrl+z),選擇(c)和遊戲步數記錄選項,可實時記錄玩家進行的遊戲步驟,效果圖如下:


7.向左函數

在遊戲按鍵中的向左函數中,我們有進行多項判斷,我們所依據的是小人向左位置的地址進行返回值,如果我們檢測到該陣列內部的值為零時進行判斷,我們將記錄小人左側函數的陣列賦值給4,然後進行判斷,同時,如果該陣列上元數等於2,我們要使人員移動到目標位置上,同時恢復目標位置的函數,使其恢復到原來位置,同時對該位置進行標記,記錄人員經過該位置,方便我們進行重播函數的操作,

如果說我們檢測到該函數內的值為零,或者是3的話,我們可以執行將箱子推到空白位置上的函數操作,如果該函數為5或者為1的話,我們要執行的是將箱子從目標位置上推出的函數操作,如果該函數值為3且為2,我們要執行的是將箱子推到目標位置上的函數操作,且人在目標位置上用來抵消仍不動的情況。

8.向右函數

我們在執行向右函數時,所依據的原理和向左函數類似,我們對右鍵的地址來進行判斷且返回值,如果說函數值等於零,我們則進行以下操作,如果說返回值等於2,我們要將人員移到目標位置之上,同時恢復目標位置及原來的狀態標誌,該位置記錄仍在該位置上的地址,方便我們進行重播操作,否則如果說該函數值為3且為0的話,我們將箱子推到空白位置上,如果按函數值為5或者不等於1的話,我們要將箱子從目標位置上推出,移動到下一個目標位置,且還是目標位置,如果該函數值為3且為2的話,要將箱子推到目標位置上。

9.向下函數

在向下函數中,我們對向下按鍵的地址進行返回,並且讀取判斷,如果說陣列記錄中為2,要將人要移到目標位置上,同時恢復目標位置的原來狀態標誌,該位置記錄仍在目標位置上的地址,方便我們進行重播操作,如果該陣列的值為3且等於0,將箱子推到空白位置之上,將箱子從標位置上推出,如果下一個位置還是目標位置,我們將該值為5或4,如果下一個位置是空白,之後我們將該陣列值賦為3且為4,如果該陣列的值為3且為2,我們要將箱子推到目標位置上,並且如果說該陣列值為5的話,將箱子推到目標位置之上,仍在目標位置上,否則如果人不在目標位置之上的話,我們將該函數值賦值為0,同時抵消人不動的情況。

10.向上函數

在執行向上函數時,我們對應函數值返回的地址值進行判斷,如果該陣列值為0,則我們將該陣列值賦值為4,否則如果說該函數值為2,我們要說明人在目標位置之上,同時恢復目標位置的原來狀態標誌,該位置記錄人在目標位置上的地址,方便進行重播操作,如果該陣列位置為3且為0,我們將箱子推到空白位置之上,否則如果陣列值為5或不等於1,要將箱子從目標位置上推出,如果下一個位置還是目標位置,我們則將輸出值賦值為5,將另一個陣列賦值為4,如果該陣列賦值為3,且另一個陣列數值為2,要將箱子推到目標位置上,並且將該值賦值為5,將箱子在目標位置上,仍在目標位置之上,若人在目標位直之上,則抵調整波動的情況。

11.通關函數

在玩家進行通關以後,我們系統會自動識別,並且返回一個通關介面,該介面我們會對玩家進行詢問的操作,該操作分為四步,繼續,觀看通關視訊過程,檢視最好記錄,退出介面,返回主介面,當玩家進行1到4的選擇以後,我們會返回相應的操作,並且可以在按任意鍵回到主頁面。

12.最佳記錄函數

在最佳記錄函數中,我們設定一個值來記錄遊戲玩家的步數,每當遊戲玩家對按鍵進行操作一次,則該函數定義的變數則加一次,當我們讀取到該玩家通關以後,將應該資料進行儲存,當我們檢測到有最好記錄時,即該步數為最小值時,確定為最佳記錄。

13.入佇列函數

在入佇列函數中,主要運用資料結構的佇列知識,設定入佇列函數,並定義指標變數指向頭結點,相關數值在入佇列以後,會自動的將數值賦值到隊頭位置,並且迴圈使searchp節點不為空,然後按照次序,將數值依次從隊頭向對尾進行賦值運算,

14.出佇列函數

在出佇列操作中,主要依據佇列相關規則,設定指標變數,將隊頭元素賦值給指標,同時在進行if語句的判斷,將for迴圈之中如i的數值小於正方形的邊長,則使用隊頭接收searchp的數值,與此同時,讓count的數值不斷的進行減減操作,

三、最後總結

截止到這裡,推箱子游戲的基本功能就完成了,最後把它總結一下,我們設計的推箱子小遊戲,合理的使用了資料結構中佇列的知識點,在使用這些知識點的時候,我們也對遊戲過程進行了詳細的優化,通過這次推箱子游戲的設計,大家應該能學到佇列在實際應用中的操作,同時這也很好地讓大家對資料結構的知識點進行了一個鞏固和複習,也從中學到了遊戲介面,佈局的構造思想和構造方法,以及鍵盤與程式碼之間的有效聯絡,所以這個設計能夠學習到的東西還是很多的了。

我把完整原始碼放在了最後,小夥伴們可以自己修改地圖介面、設定關卡。

 

四、完整原始碼

//推箱子小遊戲
#include<iostream>
#include<windows.h>
#include<stdlib.h>
#include<conio.h>
#include<fstream>
#include<iomanip>
using namespace std;
const int roomsize = 9;//設計房子內部為正方形,邊長為9
int map[roomsize + 2][roomsize + 2]; //推箱子房子佈局的資料結構:二維陣列
int followmap[1000];
int data;//記錄最短步驟數目
int times = 0;
int array[2] = { 100, 100 }; //記錄最好成績
char String[30] = "開始比賽...........";
//以下為前幾輪遊戲房子中細節佈局的資料結構:二維陣列的實際內容
int map1[roomsize + 2][roomsize + 2] =
{   //0,1,2,3,4,5,6,7,8,9,10
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, //0
	{ -1, 0, 0, 0, 0, 1, 1, 1, 1, 1, -1 },          //1
	{ -1, 0, 0, 0, 0, 1, 2, 0, 0, 1, -1 },          //2
	{ -1, 1, 1, 1, 0, 1, 0, 3, 0, 1, -1 },          //3
	{ -1, 1, 2, 1, 0, 1, 0, 0, 0, 1, -1 },          //4
	{ -1, 1, 2, 1, 0, 1, 0, 3, 0, 1, -1 },          //5
	{ -1, 1, 2, 1, 1, 1, 0, 3, 0, 1, -1 },          //6
	{ -1, 1, 0, 0, 0, 0, 3, 4, 0, 1, -1 },          //7
	{ -1, 1, 0, 0, 1, 0, 0, 0, 0, 1, -1 },          //8
	{ -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1 },          //9
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } //10
};
int map2[roomsize + 2][roomsize + 2] =
{   //0,1,2,3,4,5,6,7,8,9,10
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },//0
	{ -1, 0, 1, 1, 1, 1, 1, 0, 0, -1, -1 },        //1
	{ -1, 0, 1, 4, 0, 0, 1, 1, 0, -1, -1 },        //2
	{ -1, 0, 1, 0, 3, 0, 0, 1, 0, -1, -1 },        //3
	{ -1, 1, 1, 1, 0, 1, 0, 1, 1, -1, -1 },        //4
	{ -1, 1, 2, 1, 0, 1, 0, 0, 1, -1, -1 },        //5
	{ -1, 1, 2, 3, 0, 0, 1, 0, 1, -1, -1 },        //6
	{ -1, 1, 2, 0, 0, 0, 3, 0, 1, -1, -1 },        //7
	{ -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1 },        //8
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },//9
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } //10
};
int map3[roomsize + 2][roomsize + 2] =
{   //0,1,2,3,4,5,6,7,8,9,10
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },//0
	{ -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1 },        //1
	{ -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1 },        //2
	{ -1, 1, 1, 0, 0, 0, 0, 1, 1, -1, -1 },        //36
	{ -1, 1, 0, 3, 0, 3, 3, 0, 1, -1, -1 },        //4
	{ -1, 1, 2, 2, 2, 2, 2, 2, 1, -1, -1 },        //5
	{ -1, 1, 0, 3, 3, 0, 3, 0, 1, -1, -1 },        //6
	{ -1, 1, 1, 1, 0, 1, 1, 1, 1, -1, -1 },        //7
	{ -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1 },        //8
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },//9
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } //10
};
int map4[roomsize + 2][roomsize + 2] =
{   //0,1,2,3,4,5,6,7,8,9,10
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },//0
	{ -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1 },        //1
	{ -1, 1, 0, 0, 0, 0, 0, 0, 1, -1, -1 },        //2
	{ -1, 1, 0, 3, 0, 1, 1, 1, 1, -1, -1 },        //3
	{ -1, 1, 0, 0, 0, 2, 2, 1, 1, -1, -1 },        //4
	{ -1, 1, 0, 0, 1, 2, 1, 1, 1, -1, -1 },        //5
	{ -1, 1, 0, 3, 0, 4, 3, 0, 1, -1, -1 },        //6
	{ -1, 1, 0, 0, 0, 0, 0, 0, 1, -1, -1 },        //7
	{ -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1 },        //8
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },//9
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } //10
};



class node
{
public:
	int data[1000];
	int positionL;//位置左
	int positionH;//位置
	node *next;

};
/*
*佇列
*/
class linkqueue//定義佇列類
{
private://定義私有資料成員
	node *front;
	int count;
public://定義公有資料成員
	linkqueue();
	~linkqueue();
	void insert(int item[]);//定義公有成員函數
	void out(int item[]);
	void clearqueue(void);
	int getcount();
};
linkqueue::linkqueue()//定義相同類名的派生類
{
	front = new node;//將定義的變數賦值給隊頭
	front->next = NULL;//隊頭指向空節點
	count = 0;
}
linkqueue::~linkqueue()
{
	clearqueue();
	count = 0;
}

void linkqueue::out(int item[])//出佇列
{
	node *searchp;
	searchp = front->next;//將隊頭元素賦值給指標
	for (int i = 0; i<(roomsize + 2)*(roomsize + 2); i++)//使i的值小於正方形滴邊長
		item[i] = searchp->data[i];
	front->next = searchp->next;//隊頭接收searchp
	delete searchp;
	count--;
}

void linkqueue::insert(int item[])//進隊
{
	node *newnodep = new node, *searchp = front; 
	while (searchp->next != NULL)//迴圈使searchp節點不為空
		searchp = searchp->next;
	for (int i = 0; i<121; i++)
		newnodep->data[i] = item[i];
	newnodep->next = searchp->next;
	searchp->next = newnodep;
	count++;
}
void linkqueue::clearqueue(void)//定義依據於linkequeue的派生類
{

	if (front->next == NULL)//若頭結點為空。則返回
		return;
	while (front->next != NULL)//若隊頭結點不為空,則將頭結點賦值給指標
	{
		node *searchp;
		searchp = front->next;
		front->next = searchp->next;
		delete searchp;
	}
	count = 0;
}
int linkqueue::getcount()//定義依據於linkequeue的派生類用來返回count滴值
{
	return count;
}
/*
*棧
*/
class  seqstack//定義類
{
public://設定公有成員函數
	seqstack();
	~seqstack();
	void clearseqstack(void);
	void push(int item[], int &line, int &lie);//括號內為只接收變數滴地址
	void pop(int item[], int &line, int &lie);
private:
	node *top;
};
seqstack::seqstack()
{
	top = new node;
	top->next = NULL;
}
seqstack::~seqstack()
{}

void seqstack::push(int item[], int &line, int &lie)//定義以seqtack類滴push(推)的類,用來記錄推動箱子的地址和位置
{
	node *newnodep, *searchp = top;
	newnodep = new node;
	for (int i = 0; i<(roomsize + 2)*(roomsize + 2); i++)
		newnodep->data[i] = item[i];
	newnodep->positionH = line;//將地址進行返回
	newnodep->positionL = lie;//將地址進行返回
	newnodep->next = searchp->next;
	searchp->next = newnodep;

}

void seqstack::pop(int item[], int &line, int &lie)
{
	node *newnodep, *searchp = top;
	if (searchp->next != NULL)
	{
		newnodep = top->next;
		for (int i = 0; i<(roomsize + 2)*(roomsize + 2); i++)
			item[i] = newnodep->data[i];
		line = newnodep->positionH;
		lie = newnodep->positionL;
		top->next = newnodep->next;
		delete newnodep;
	}
}
void seqstack::clearseqstack(void)
{
	if (top->next == NULL)
		return;
	while (top->next != NULL)
	{
		node *searchp;
		searchp = top->next;
		top->next = searchp->next;
		delete searchp;
	}
}

//物件:箱子
class box//記錄人位置滴函數
{
	int positionh;//人的位置縱座標
	int positionl;//人的位置橫座標
	int flag;//標誌位,記錄人在目標位置上
	int gate;//這個變數是記錄關數
	int count;//這個變數是記錄步數
	seqstack st;
	linkqueue linkqu;
public:
	box();
	void begin();//開始介面
	void choose_gate();//選關提示
	void choose();//遊戲時c選項的提示
	void replay();//重玩
	void playing();//玩遊戲時介面
	void display();//顯示地圖
	void left();//左方向
	void right();//右方向
	void down();//下方向
	void up();//上方向
	void test_flag();//過關提示
	void record();//這段函數為排行榜
	void travers();
	void returnpush();
	void returninseart();
	//void random();//這段函數為隨機生成室內佈局,暫時沒有提供
};

box::box()
{
	positionh = 0;
	positionl = 0;
	flag = 0;
	count = 0;
	gate = 0;
}
void box::begin()
{
	system("color 17");

	/*******************************輸出遊戲主介面***********************************/
	cout << "   ╭────────────-─────────────────-──╮" << endl <<//1                                                                       "<<endl<<//1
		"  │                                                                  │" << endl <<//2
		"  │              ★☆★       推箱子游戲        ★☆★               │" << endl <<//3
		"  │★☆★★☆★★☆★★☆★★☆★★☆★★☆★★☆★★☆★★☆★★☆★│" << endl <<//4
		"  │                            遊戲介紹                              │" << endl <<//5
		"  │                                                                  │" << endl <<//6
		"  │怎麼玩這個遊戲呢?我來介紹一下:這是小人人(♀)小星星就是箱子啦(★)│" << endl <<//7
		"  │你要把星星放在這個地方喔(○),等到有了㊣.你就贏咯!快來挑戰吧!!   │" << endl <<//8
		"  │                                                                  │" << endl <<//9
		"  │                           操作指令                               │" << endl <<//10
		"  │                                                                  │" << endl <<//11
		"  │使用方向鍵控制哦!'Ctrl+z' 用來複原,'c'用來選擇 'Esc'退出遊戲!  │" << endl <<//12
		"  │                                                                  │" << endl <<//13
		"  │                                                                  │" << endl <<//14
		"  ╰─────────────────────────────────╯" << endl; //15
	choose_gate();//選擇關數
	cout << String << endl;
	Sleep(1000);
	system("cls");
	linkqu.clearqueue();
	st.clearseqstack();
	playing();
}
void box::choose_gate()
{
	//system("color 10");
	int j, k;

		/*******************************輸出遊戲關卡選擇介面***********************************/
	cout << "              ★               ╭────╮            ★      " << endl
		<< "             ★★             │ 關卡選擇 │          ★★      " << endl
		<< "            ★  ★            │ 1.first  │         ★  ★        " << endl
		<< "       ★★★    ★★★       │ 2.scend  │    ★★★    ★★★     " <<endl
		<< "        ★          ★        │ 3.third  │     ★          ★        " << endl
		<< "         ★        ★         │ 4.forth  │      ★        ★          " << endl
		<< "          ★  ★  ★          │★★★★  │       ★  ★  ★            " << endl
		<< "          ★★  ★★          │  ★★★★│       ★★  ★★         " << endl
		<< "          ★      ★          ╰─────╯       ★      ★         " << endl<<endl<<endl;
	cout << "請選擇關卡喲:";
	cin >> gate;
	do
	{
		switch (gate)
		{
		case 1:
			for (j = 0; j<roomsize + 2; j++)//此處 j控制行,k控制列
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map1[j][k];
			positionh = 7; positionl = 7;
			break;
		case 2:
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map2[j][k];
			positionh = 2; positionl = 3;
			break;
		case 3:
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map3[j][k];
			positionh =7, positionl = 5;
			break;
		case 4:
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map4[j][k];
			positionh = 6, positionl = 5;
			break;
		default:
			cout << "輸入錯誤啦^_^請重新輸入喲@v@!";
			cin >> gate;
		}
	} while (gate>4);
}
void box::choose()//選項
{
	int choice;
	cout << " ╭────────╮" << endl
		<< " │1. 重播         │" << endl
		<< " │2. 主介面       │" << endl
		<< " │3. 最好的記錄   │" << endl
		<< " │4. 退出         │" << endl
		<< " ╰────────╯" << endl;
	cin >> choice;
	switch (choice)
	{
	case 1:
		system("cls");
		replay();
		break;
	case 2:
		system("cls");
		begin();
		break;
	case 3:
		record();
		system("cls");
		playing();
		break;
	case 4:
		exit(0);
	}
}
void box::replay()//將遊戲步驟進行重播
{
	int j, k;
	count = 0;
	flag = 0;
	st.clearseqstack();
	linkqu.clearqueue();
	do
	{
		switch (gate)
		{
		case 1:
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map1[j][k];
			positionh = 7; positionl = 7;
			break;
		case 2:
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map2[j][k];
			positionh = 2; positionl = 3;
			break;
		case 3:
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map3[j][k];
			positionh = positionl = 4;
			break;
		case 4:
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
				map[j][k] = map4[j][k];
			positionh = 6, positionl = 5;
			break;
		
		}
	} while (gate>4);
	playing();
}
void box::playing()//Ascii碼鍵盤鍵位:左為75 右為77 上為72 下為80
{
	int choice, i, l, r, item[1000],j,k;
	count = 0;
	cout << "遊戲開始";
	while (1)
	{
		display();
		switch (_getch())
		{
		case 72:
			returninseart();
			returnpush();
			up();
			count++;
			break;
		case 80:
			returninseart();
			returnpush();
			down();
			count++;
			break;
		case 75:
			returninseart();
			returnpush();
			left();
			count++;
			break;
		case 77:
			returninseart();
			returnpush();
			right();
			count++;
			break;
		//case 'x':
		case 26:
			i = 0;
			system("cls");
			st.pop(item, l, r);
			for (j = 0; j<roomsize + 2; j++)
			for (k = 0; k<roomsize + 2; k++)
			{
				map[j][k] = item[i];
				i++;
			}
			positionl = r; positionh = l;
			display();
			break;
		case 'c':
		case 'C':
			choose();
			break;
		//case 'q':
		case 27:
			cout << " ╭──────────────╮" << endl
				<< " │請給你選擇喔:              │" << endl
				<< " │   1. 我要返回主介面        │" << endl
				<< " │   2. 我不玩了退出遊戲      │" << endl
				<< " ╰──────────────╯" << endl;
			cin >> choice;
			switch (choice)
			{
			case 1:
				count = 0;
				Sleep(500);
				system("cls");
				begin();
				break;
			case 2:
				exit(0);
			}
		default:
			break;
		}
		system("cls");
	}
}
void box::display()
{
	cout << endl << endl << endl << endl << endl << endl;
	for (int i = 1; i <= roomsize; i++)
	{
		cout << setw(30);
		for (int j = 1; j <= roomsize; j++)
		{
			if (map[i][j] == 0) cout << "  ";
			if (map[i][j] == 1) cout << "■";//牆
			if (map[i][j] == 2) cout << "○";//目標位置
			if (map[i][j] == 3) cout << "★";//箱子
			if (map[i][j] == 4) cout << "♀";//人
			if (map[i][j] == 5) cout << "㊣";//箱子在目標位置上
		}
		cout << endl;
	}
	cout << endl << endl;
	cout << "復原(Ctrl+z)★★★" << "選擇(c)★★★" << "遊戲步數:" << count << endl;
}
void box::left()//向左函數
{
	if (map[positionh][positionl - 1] == 0)
	{
		map[positionh][positionl - 1] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2;  flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionl--;
	}
	else if (map[positionh][positionl - 1] == 2)//人要到目標位置上
	{
		map[positionh][positionl - 1] = 4;
		if (flag == 1)
			map[positionh][positionl] = 2;//恢復目標位置
		else
		{
			map[positionh][positionl] = 0;//恢復原來的狀態
			flag = 1;//標誌位,記錄人在目標位置上
		}
		positionl--;
	}
	else if (map[positionh][positionl - 1] == 3 && map[positionh][positionl - 2] == 0)//將箱子推到空白位置上
	{
		map[positionh][positionl - 2] = 3;
		map[positionh][positionl - 1] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionl--;
	}
	else if (map[positionh][positionl - 1] == 5 && map[positionh][positionl - 2] != 1)//要將箱子從目標位置上推出
	{
		if (map[positionh][positionl - 2] == 2)//下一個位置還是目標位置
		{
			map[positionh][positionl - 2] = 5;
			map[positionh][positionl - 1] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		else if (map[positionh][positionl - 2] == 0)//下一個位置是空白
		{
			map[positionh][positionl - 2] = 3;
			map[positionh][positionl - 1] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		positionl--;
	}
	else if (map[positionh][positionl - 1] == 3 && map[positionh][positionl - 2] == 2)//要將箱子推到目標位置上
	{
		map[positionh][positionl - 2] = 5;//箱子在目標位置上
		map[positionh][positionl - 1] = 4;
		if (flag == 1)//人在目標位置上
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else //人不在目標位置上
			map[positionh][positionl] = 0;
		positionl--;
	}
	else count--;//抵消人不動的情況
	test_flag();

}
void box::right()//向右函數
{
	if (map[positionh][positionl + 1] == 0)
	{
		map[positionh][positionl + 1] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2;  flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionl++;
	}
	else if (map[positionh][positionl + 1] == 2)//人要到目標位置上
	{
		map[positionh][positionl + 1] = 4;
		if (flag == 1)
			map[positionh][positionl] = 2;//恢復目標位置
		else
		{
			map[positionh][positionl] = 0;//恢復原來的狀態
			flag = 1;//標誌位,記錄人在目標位置上
		}
		positionl++;
	}
	else if (map[positionh][positionl + 1] == 3 && map[positionh][positionl + 2] == 0)//將箱子推到空白位置上
	{
		map[positionh][positionl + 2] = 3;
		map[positionh][positionl + 1] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionl++;
	}
	else if (map[positionh][positionl + 1] == 5 && map[positionh][positionl + 2] != 1)//要將箱子從目標位置上推出
	{
		if (map[positionh][positionl + 2] == 2)//下一個位置還是目標位置
		{
			map[positionh][positionl + 2] = 5;
			map[positionh][positionl + 1] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		else if (map[positionh][positionl + 2] == 0)//下一個位置是空白
		{
			map[positionh][positionl + 2] = 3;
			map[positionh][positionl + 1] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		positionl++;
	}
	else if (map[positionh][positionl + 1] == 3 && map[positionh][positionl + 2] == 2)//要將箱子推到目標位置上
	{
		map[positionh][positionl + 2] = 5;//箱子在目標位置上
		map[positionh][positionl + 1] = 4;
		if (flag == 1)//人在目標位置上
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else //人不在目標位置上
			map[positionh][positionl] = 0;
		positionl++;
	}
	else count--;//抵消人不動的情況
	test_flag();
}
void box::down()//向下函數
{
	if (map[positionh + 1][positionl] == 0)
	{
		map[positionh + 1][positionl] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionh++;
	}
	else if (map[positionh + 1][positionl] == 2)//人要到目標位置上
	{
		map[positionh + 1][positionl] = 4;
		if (flag == 1)
			map[positionh][positionl] = 2;//恢復目標位置
		else
		{
			map[positionh][positionl] = 0;//恢復原來的狀態
			flag = 1;//標誌位,記錄人在目標位置上
		}
		positionh++;
	}
	else if (map[positionh + 1][positionl] == 3 && map[positionh + 2][positionl] == 0)//將箱子推到空白位置上
	{
		map[positionh + 2][positionl] = 3;
		map[positionh + 1][positionl] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionh++;
	}
	else if (map[positionh + 1][positionl] == 5 && map[positionh + 2][positionl] != 1)//要將箱子從目標位置上推出
	{
		if (map[positionh + 2][positionl] == 2)//下一個位置還是目標位置
		{
			map[positionh + 2][positionl] = 5;
			map[positionh + 1][positionl] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		else if (map[positionh + 2][positionl] == 0)//下一個位置是空白
		{
			map[positionh + 2][positionl] = 3;
			map[positionh + 1][positionl] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		positionh++;
	}
	else if (map[positionh + 1][positionl] == 3 && map[positionh + 2][positionl] == 2)//要將箱子推到目標位置上
	{
		map[positionh + 2][positionl] = 5;//箱子在目標位置上
		map[positionh + 1][positionl] = 4;
		if (flag == 1)//人在目標位置上
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else //人不在目標位置上
			map[positionh][positionl] = 0;
		positionh++;
	}
	else count--;//抵消人不動的情況
	test_flag();
}
void box::up()//向上函數
{
	if (map[positionh - 1][positionl] == 0)
	{
		map[positionh - 1][positionl] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionh--;
	}
	else if (map[positionh - 1][positionl] == 2)//人要到目標位置上
	{
		map[positionh - 1][positionl] = 4;
		if (flag == 1)
			map[positionh][positionl] = 2;//恢復目標位置
		else
		{
			map[positionh][positionl] = 0;//恢復原來的狀態
			flag = 1;//標誌位,記錄人在目標位置上
		}
		positionh--;
	}
	else if (map[positionh - 1][positionl] == 3 && map[positionh - 2][positionl] == 0)//將箱子推到空白位置上
	{
		map[positionh - 2][positionl] = 3;
		map[positionh - 1][positionl] = 4;
		if (flag == 1)
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else
			map[positionh][positionl] = 0;
		positionh--;
	}
	else if (map[positionh - 1][positionl] == 5 && map[positionh - 2][positionl] != 1)//要將箱子從目標位置上推出
	{
		if (map[positionh - 2][positionl] == 2)//下一個位置還是目標位置
		{
			map[positionh - 2][positionl] = 5;
			map[positionh - 1][positionl] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		else if (map[positionh - 2][positionl] == 0)//下一個位置是空白
		{
			map[positionh - 2][positionl] = 3;
			map[positionh - 1][positionl] = 4;
			if (flag == 1)
				map[positionh][positionl] = 2;
			else
			{
				map[positionh][positionl] = 0; flag = 1;
			}
		}
		positionh--;
	}
	else if (map[positionh - 1][positionl] == 3 && map[positionh - 2][positionl] == 2)//要將箱子推到目標位置上
	{
		map[positionh - 2][positionl] = 5;//箱子在目標位置上
		map[positionh - 1][positionl] = 4;
		if (flag == 1)//人在目標位置上
		{
			map[positionh][positionl] = 2; flag = 0;
		}
		else //人不在目標位置上
			map[positionh][positionl] = 0;
		positionh--;
	}
	else count--;//抵消人不動的情況
	test_flag();

}
void box::test_flag()
{
	int choice;
	int item[1000];
	for (int i = 1; i <= roomsize; i++)
	for (int j = 1; j <= roomsize; j++)
	{
		if (map[i][j] == 3)
			return;
	}
	system("cls");
	count++;
	data = count;
	times++;
	display();
	returninseart();
	cout << "╭──────────────╮" << endl
		<< "│恭喜小可愛呀!你通關啦喲!  │" << endl
		<< "│★★★ 再來一局不?★★★   │" << endl
		<< "│1. 繼續                     │" << endl
		<< "│2. 觀看通關過程             │" << endl
		<< "│3. 最好滴記錄               │" << endl
		<< "│4. 退出呀                   │" << endl
		<< "╰──────────────╯" << endl;
	cin >> choice;
	switch (choice)
	{
	case 1:
		count = 0;
		Sleep(500);
		system("cls");
		begin();
		break;
	case 2:
		travers();
		cout << "按任意鍵回到主介面喲..." << endl;
		_getch();
		system("cls");
		begin();
		break;
	case 3:
		record();
		system("cls");
		cout << "按任意鍵回到主介面喲..." << endl;
		begin();
		break;
	case 4:
		cout << "★★★嘻嘻!歡迎再次遊戲★★★" << endl;
		cout << "★★★按任意鍵退出喔★★★" << endl;
		_getch();
		exit(0);
	}
}
void box::record()//最佳記錄
{
	int rhigh;
	if (times % 2)
		array[0] = data;
	else
		array[1] = data;
	if (array[0]>array[1])
		rhigh = array[1];
	else
		rhigh = array[0];
	if (times % 2)
		array[0] = rhigh;
	else
		array[1] = rhigh;
	cout << "最優秀滴記錄:" << rhigh << endl;
	_getch();
}
void box::travers()
{
	int i, l = linkqu.getcount(), item[1000];
	while (l)
	{
		i = 0;
		linkqu.out(item);
		for (int j = 0; j<roomsize + 2; j++)
		for (int k = 0; k<roomsize + 2; k++)
		{
			map[j][k] = item[i];
			i++;
		}
		system("cls");
		display();
		Sleep(50);
		l--;
	}
}
void box::returnpush()
{
	int i = 0, l, r;
	for (int j = 0; j<roomsize + 2; j++)
	for (int k = 0; k<roomsize + 2; k++)
	{
		if (map[j][k] == 4)
		{
			l = j;
			r = k;
		}
		followmap[i] = map[j][k];
		i++;
	}
	st.push(followmap, l, r);
}
void box::returninseart()
{
	int i = 0;
	for (int j = 0; j<roomsize + 2; j++)
	for (int k = 0; k<roomsize + 2; k++)
	{
		followmap[i] = map[j][k];
		i++;
	}
	linkqu.insert(followmap);
}

//主程式
int main()
{
	box Mybox;
	system("color B0");
	Mybox.begin();
	return 0; 
}

覺得有用的小夥伴可以點贊關注喲!

有問題的小夥伴可以在評論區留言提出!

我是灰小猿!我們下期見!