1. 程式人生 > >2048原始碼~~小遊戲。C++實現

2048原始碼~~小遊戲。C++實現

每一個學習軟體工程的人,都很想自己寫出遊戲的程式碼,我也不例外,但是,能寫出一些小遊戲的程式碼,並不能說明你很厲害,而只能說明你對於這門語言你比較熟悉了。

2048這個遊戲,是一兩年前很火的遊戲,不過現在也沒什麼人在玩了,閒來沒事,就寫了一下這個遊戲,控制檯上實現的,目前我還不會寫視窗,所以很多東西都只能在控制檯上來實現了。

2048這個小遊戲,主要的是上下左右移動後,相同的數合併,不相同的數原樣輸出,而你就是要判斷每一行或每一列有沒有相同的,還有一點就是,數字有移動,就產生新的數,沒有,什麼都不用做。

下面是標頭檔案的:

class New2048
{
public:
	New2048()                       //建構函式,初始話資料。
	{ 
		for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			a[i][j] = 0;
		num = 0;
	}
	void make_frame();             //列印框架函式。
	void display_num();            //列印數字函式。
	void creat_num();              //隨機產生數函式
	void RightMove();              //右移函式
	void LeftMove();               //左移函式
	void UpMove();		       //上移函式
	void DownMove();	       //下移函式
	int cheak();                   //檢查遊戲是否結束函式
	void clean();                  //清理顯示出來的數字
	~New2048(){}

private:
	int a[4][4];
	int num;
};


下面是各個函式的cpp檔案:
# include <iostream>
# include <Windows.h>
# include <time.h>
# include <conio.h>
# include "2048.h"
using namespace std;

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);    //獲取控制代碼
void gotoxy(HANDLE hOut, int x, int y)            //輸出位置的函式
{
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(hOut, pos);
}
void New2048::make_frame()                       //列印框架
{
	gotoxy(hOut, 0, 0);
	cout << "         得分" << endl;
	cout << "┏━━┳━━┳━━┳━━┓" << endl;
	cout << "┃    ┃    ┃    ┃    ┃" << endl;
	cout << "┣━━╋━━╋━━╋━━┫" << endl;
	cout << "┃    ┃    ┃    ┃    ┃" << endl;
	cout << "┣━━╋━━╋━━╋━━┫" << endl;
	cout << "┃    ┃    ┃    ┃    ┃" << endl;
	cout << "┣━━╋━━╋━━╋━━┫" << endl;
	cout << "┃    ┃    ┃    ┃    ┃" << endl;
	cout << "┗━━┻━━┻━━┻━━┛" << endl;
}
void New2048::clean()
{
	int k = 0, l = 0;
	for (int i = 2; i < 21, k < 4; i = i + 6)    //找到對應的框,輸入空格
	{
		l = 0;
		for (int j = 2; j < 9; j = j + 2)
		{
			gotoxy(hOut, i, j);
			printf("    ");
			l++;
		}
		k++;
	}
}
void New2048::display_num()                          //列印數字
{
	int k = 0, l = 0;
	for (int i = 2; i < 21, k < 4; i = i + 6)    //找到對應的框,輸入數字,這個嘗試了好久,才搞定了。
	{
		l = 0;
		for (int j = 2; j < 9; j = j + 2)
		{
			gotoxy(hOut, i, j);          //找到各個位置並輸出數字
			a[l][k] == 0 ? printf(" ") : printf("%d", a[l][k]);
			l++;
		}
		k++;
	}
	gotoxy(hOut, 13, 0);
	cout << num * 100;
	gotoxy(hOut, 0, 10);
}
void New2048::creat_num()                     //隨機產生座標位置和該位置的數 2 或 4
{
	int i, j, num;
	srand((unsigned)time(NULL));             //隨機數產生初始化,不然產生的數一直相同        
	i = (rand() % (4)) + 0;
	j = (rand() % (4)) + 0;
	while (a[i][j])                           //該位置上的數不是0,重新產生
	{
		i = (rand() % (4)) + 0;
		j = (rand() % (4)) + 0;
	}
	num = (rand() % (4)) + 1;                //產生的是1就自增,是3便自減或自增,都可以的
	if (num == 1)
		++num;
	if (num == 3)
		--num;
	a[i][j] = num;
}
int New2048::cheak()
{
	int i, j, flag = 0, tag = 0;
	for (i = 0; i < 4; i++)                  //檢查是否還有位置,有,tag = 1。
	{
		for (j = 0; j < 4; j++)
		{
			if (a[i][j] == 0)
			{
				tag = 1;
				break;
			}
		}
		if (tag == 1)
			break;
	}
	if (tag)                               //有,返回1。
		return 1;
	for (i = 0; i < 4; i++)                //檢查左右的相鄰是否有相等,是,flag = 1,退出迴圈
	{
		for (j = 0; j < 3; j++)
		{
			if (a[i][j] == a[i][j + 1])
			{
				flag = 1;
				break;
			}
		}
		if (flag == 1)
			break;
	}
	for (j = 0; j < 4; j++)                //檢查上下的相鄰是否有想等,是,flag = 1,退出迴圈
	{
		for (i = 0; i < 3; i++)
		{
			if (a[i][j] == a[i + 1][j])
			{
				flag = 1;
				break;
			}
		}
		if (flag == 1)
			break;
	}
	if (tag == 0 && flag == 0)            //flag = 0 和 tag = 0,遊戲結束。
		return 0;
	else                                  //否則,繼續遊戲
		return 1;
}
void New2048::DownMove()                  //下移的情況
{
	int k, tag = 0;
	for (int i = 0; i < 4; i++)           //從每一列開始
	{
		int b[4] = { 0 };				 //定義一個臨時陣列來儲存相加之後的情況
		k = 3;
		for (int j = 3; j > 0; j--)
		{
			if (a[j][i] != 0)
			{
				int flag = 0;
				for (int l = j - 1; l >= 0; l--)    //找是否有相同的數
				{
					if (a[l][i] != 0)
					{
						flag = 1;
						if (a[l][i] == a[j][i])
						{
							b[k--] = 2 * a[j][i];
							num++;         
							a[l][i] = a[j][i] = 0;
							break;
						}
						else
						{
							b[k--] = a[j][i];
							break;
						}
					}
				}
				if (flag == 0)
					b[k--] = a[j][i];
			}
		}
		b[k] = a[0][i];                 //最後一個沒有檢查,賦值過去,不管是否為0,都無所謂的
		for (int j = 0; j < 4; j++)     //檢查是否有移動
		{
			if (a[j][i] != b[j])
			{
				tag = 1;
				break;
			}
		}
		for (int j = 0; j < 4; j++)    //將結果覆蓋回去
			a[j][i] = b[j];
	}
	if (tag)                          //存在移動,產生新的數
		creat_num();
}
void New2048::LeftMove()                 //同上
{
	int k, tag = 0;
	for (int i = 0; i < 4; i++)
	{
		int b[4] = { 0 };
		k = 0;
		for (int j = 0; j < 3; j++)
		{
			if (a[i][j] != 0)
			{
				int flag = 0;
				for (int l = j + 1; l < 4; l++)
				{
					if (a[i][l] != 0)
					{
						flag = 1;
						if (a[i][l] == a[i][j])
						{
							b[k++] = 2 * a[i][j];
							num++;
							a[i][j] = a[i][l] = 0;
							break;
						}
						else
						{
							b[k++] = a[i][j];
							break;
						}
					}
				}
				if (flag == 0)
					b[k++] = a[i][j];
			}
		}
		b[k] = a[i][3];
		for (int j = 0; j < 4; j++)
		{
			if (a[i][j] != b[j])
			{
				tag = 1;
				break;
			}
		}
		for (int j = 0; j < 4; j++)
			a[i][j] = b[j];
	}
	if (tag)
		creat_num();
}
void New2048::RightMove()              //同上
{
	int k, tag = 0;
	for (int i = 0; i < 4; i++)
	{
		int b[4] = { 0 };
		k = 3;
		for (int j = 3; j > 0; j--)
		{
			if (a[i][j] != 0)
			{
				int flag = 0;
				for (int l = j - 1; l >= 0; l--)
				{
					if (a[i][l] != 0)
					{
						flag = 1;
						if (a[i][l] == a[i][j])
						{
							b[k--] = 2 * a[i][j];
							num++;
							a[i][j] = a[i][l] = 0;
							break;
						}
						else
						{
							b[k--] = a[i][j];
							break;
						}
					}
				}
				if (flag == 0)
					b[k--] = a[i][j];
			}
		}
		b[k] = a[i][0];
		for (int j = 0; j < 4; j++)
		{
			if (a[i][j] != b[j])
			{
				tag = 1;
				break;
			}
		}
		for (int j = 0; j < 4; j++)
			a[i][j] = b[j];
	}
	if (tag)
		creat_num();
}
void New2048::UpMove()
{
	int k, tag = 0;
	for (int i = 0; i < 4; i++)
	{
		int b[4] = { 0 };                 //定義一個臨時陣列來儲存相加之後的情況
		k = 0;
		for (int j = 0; j < 3; j++)
		{
			if (a[j][i] != 0)
			{
				int flag = 0;
				for (int l = j + 1; l < 4; l++)    //找是否有相同的數
				{
					if (a[l][i] != 0)
					{
						flag = 1;
						if (a[l][i] == a[j][i])
						{
							b[k++] = 2 * a[j][i];
							num++;
							a[l][i] = a[j][i] = 0;
							break;
						}
						else
						{
							b[k++] = a[j][i];
							break;
						}
					}
				}
				if (flag == 0)
					b[k++] = a[j][i];
			}
		}
		b[k] = a[3][i];
		for (int j = 0; j < 4; j++)
		{
			if (a[j][i] != b[j])
			{
				tag = 1;
				break;
			}
		}
		for (int j = 0; j < 4; j++)      //將結果覆蓋回去
			a[j][i] = b[j];
	}
	if (tag)
		creat_num();
}

主函式的cpp檔案:
# include <iostream>
# include <conio.h>
# include "2048.h"
using namespace std;

int main()
{
	while (1)
	{
		char ch;
		system("cls");                        //清屏
		system("color 3B");                   //改變背景和字型顏色
		New2048 s;
		s.make_frame();                       //列印框架
		s.creat_num();
		s.creat_num();                        //產生兩個隨機數
		s.display_num();                      //顯示數字
		while (1)
		{
			ch = _getch();                   //如果不是VS的,_getch應該改成getch
			if (ch == 'a' || ch == 's' || ch == 'd' || ch == 'w' || ch == ' ' || 
				ch == 'A' || ch == 'S' || ch == 'D' || ch == 'W')
				break;
		}
p:		switch (ch)
		{
		case 's':
		case 'S':
		{
					while (s.cheak())
					{
						s.DownMove();             //下移
						s.clean();                //清理
						s.display_num();          //顯示數字
						while (1)
						{
							ch = _getch();
							if (ch == 'a' || ch == 's' || ch == 'd' || ch == 'w' || ch == ' ' ||
								ch == 'A' || ch == 'S' || ch == 'D' || ch == 'W')
								break;
						}
						goto p;
					}
		}break;
		case 'd':
		case 'D':
		{
					while (s.cheak())
					{
						s.RightMove();                //右移
						s.clean();                    //清理
						s.display_num();              //顯示數字
						while (1)
						{
							ch = _getch();
							if (ch == 'a' || ch == 's' || ch == 'd' || ch == 'w' || ch == ' ' || 
								ch == 'A' || ch == 'S' || ch == 'D' || ch == 'W')
								break;
						}
						goto p;
					}
		}break;
		case 'a':
		case 'A':
		{
					while (s.cheak())
					{
						s.LeftMove();              //左移
						s.clean();                 //清理
						s.display_num();           //顯示數字
						while (1)
						{
							ch = _getch();
							if (ch == 'a' || ch == 's' || ch == 'd' || ch == 'w' || ch == ' ' || 
								ch == 'A' || ch == 'S' || ch == 'D' || ch == 'W')
								break;
						}
						goto p;
					}
		}break;
		case 'w':
		case 'W':
		{
					while (s.cheak())
					{
						s.UpMove();               //上移
						s.clean();                //清理
						s.display_num();          //顯示數字
						while (1)
						{
							ch = _getch();
							if (ch == 'a' || ch == 's' || ch == 'd' || ch == 'w' || ch == ' ' || 
								ch == 'A' || ch == 'S' || ch == 'D' || ch == 'W')
								break;
						}
						goto p;
					}
		}break;
		default:
			break;
		}                            //退出switch,遊戲結束
		system("cls");               //清屏
		cout << "               PLAY AGAIN ? YES(Y) : NO(N)" << endl;
		while (1)
		{
			ch = _getch();
			if (ch == 'y' || ch == 'n' || ch == 'Y' || ch == 'N')
				break;
		}
		if (ch == 'y' || ch == 'Y')          //Y繼續
			continue;
		else                                 //否則退出
			break;
	}
	return 0;
}

遊戲開始圖片:



遊戲過程中的圖片:



遊戲結束圖片:


這個或多或少的存在bug,如果發現了,歡迎來告訴我,好讓我改正!~~