1. 程式人生 > >c++實現2048遊戲(控制檯)

c++實現2048遊戲(控制檯)

#ifndef CGAME_H
#define CGAME_H

#include <windows.h>
#include <String>

#define ROW 4   //格子總行數
#define COLUMN 4    //格子總列數

class cGame
{
public:
	cGame();
	~cGame();
	void play();
	void moveUp();
	void moveDown();
	void moveLeft();
	void moveRight();
	void newLattice();
	bool canMove();
	void show();
	void buf_show();

private:
	int(*matrix)[COLUMN];	//儲存格子資訊
	int max;	//格子最大的數字的值
	bool gameWin;	//遊戲是否取勝
	bool gameOver;	//遊戲是否結束
	
};

#endif // CGAME_H

#include <iostream>
#include <conio.h>
#include <cstdlib>
#include "cgame.h"
#include "Point.h"

using namespace std;

//cGame::cGame(QObject *parent) : QObject(parent)
//{
//    memset(matrix,0,ROW*COLUMN);

//}

cGame::cGame()
{
	matrix = new int[ROW][COLUMN];
	for (int row = 0;row < ROW;row++)
		for(int column=0;column<COLUMN;column++)
			matrix[row][column] = 0;
	gameWin = false;
	gameOver = false;
	max = 0;
	newLattice();
}

cGame::~cGame()
{
	delete[] matrix;
}

void cGame::moveUp()
{
	bool flag = false;	//能否上移
	//先往上移動
	for (int column = 0;column<COLUMN;column++)
		for (int row = 1;row<ROW;row++)
		{
			if (matrix[row][column] != 0)
			{
				for (int i = 0;i<row;i++)
					if (matrix[i][column] == 0)    //是空格,移動到該處
					{
						matrix[i][column] = matrix[row][column];
						matrix[row][column] = 0;
						flag = true;
						break;
					}
			}
		}
	//再合併相同的數字
	for (int column = 0;column<COLUMN;column++)
		for (int row = 0;row<ROW - 1;row++)
		{
			if (matrix[row][column] == 0)
				break;
			if (matrix[row][column] == matrix[row + 1][column])
			{
				//合併數字
				matrix[row][column] *= 2;
				matrix[row + 1][column] = 0;
				flag = true;
				//更新最大格子數值
				if (matrix[row][column] > max)
					max = matrix[row][column];
				//判斷是否贏////////////////
				if (matrix[row][column] == 2048)
				{
					gameWin = true;
					return;
				}
				//往上移動格子
				for (int i = row + 1;i<ROW - 1;i++)
					matrix[i][column] = matrix[i + 1][column];
				matrix[ROW - 1][column] = 0;
			}
		}
	//是可以移動狀態,建立新的格子
	if(flag)
		newLattice();
}

void cGame::moveDown()
{
	bool flag = false;	//能否下移
	//先往下移動
	for (int column = 0;column<COLUMN;column++)
		for (int row = ROW - 2;row >= 0;row--)
		{
			if (matrix[row][column] != 0)
			{
				for (int i = ROW - 1;i>row;i--)
					if (matrix[i][column] == 0)    //是空格,移動到該處
					{
						matrix[i][column] = matrix[row][column];
						matrix[row][column] = 0;
						flag = true;
						break;
					}
			}
		}
	//再合併相同的數字
	for (int column = 0;column<COLUMN;column++)
		for (int row = ROW - 1;row>0;row--)
		{
			if (matrix[row][column] == 0)
				break;
			if (matrix[row][column] == matrix[row - 1][column])
			{
				//合併數字
				matrix[row][column] *= 2;
				matrix[row - 1][column] = 0;
				flag = true;
				//更新最大格子數值
				if (matrix[row][column] > max)
					max = matrix[row][column];
				//判斷是否贏////////////////
				if (matrix[row][column] == 2048)
				{
					gameWin = true;
					return;
				}
				//往下移動格子
				for (int i = row - 1;i>0;i--)
					matrix[i][column] = matrix[i - 1][column];
				matrix[0][column] = 0;
			}
		}
	//是可以移動狀態,建立新的格子
	if (flag)
		newLattice();
}

void cGame::moveLeft()
{
	bool flag = false;	//能否左移
	//先向左移動
	for (int row = 0;row<ROW;row++)
		for (int column = 1;column<COLUMN;column++)
		{
			if (matrix[row][column] != 0)
			{
				for (int j = 0;j<column;j++)
					if (matrix[row][j] == 0)   //是空格,移動到該處
					{
						matrix[row][j] = matrix[row][column];
						matrix[row][column] = 0;
						flag = true;
						break;
					}
			}
		}
	//再合併相同數字
	for (int row = 0;row<ROW;row++)
		for (int column = 0;column<COLUMN - 1;column++)
		{
			if (matrix[row][column] == 0)
				break;
			if (matrix[row][column] == matrix[row][column + 1])
			{
				//合併數字
				matrix[row][column] *= 2;
				matrix[row][column + 1] = 0;
				flag = true;
				//更新最大格子數值
				if (matrix[row][column] > max)
					max = matrix[row][column];
				//判斷是否贏////////////////
				if (matrix[row][column] == 2048)
				{
					gameWin = true;
					return;
				}
				//向左移動格子
				for (int j = column + 1;j<COLUMN - 1;j++)
					matrix[row][j] = matrix[row][j + 1];
				matrix[row][COLUMN - 1] = 0;
			}
		}
	//是可以移動狀態,建立新的格子
	if (flag)
		newLattice();
}

void cGame::moveRight()
{
	bool flag = false;	//能否右移
	//先向右移動
	for (int row = 0;row<ROW;row++)
		for (int column = COLUMN - 2;column >= 0;column--)
		{
			if (matrix[row][column] != 0)
			{
				for (int j = COLUMN - 1;j>column;j--)
					if (matrix[row][j] == 0)   //是空格,移動到該處
					{
						matrix[row][j] = matrix[row][column];
						matrix[row][column] = 0;
						flag = true;
						break;
					}
			}
		}
	//再合併相同數字
	for (int row = 0;row<ROW;row++)
		for (int column = COLUMN - 1;column>0;column--)
		{
			if (matrix[row][column] == 0)
				break;
			if (matrix[row][column] == matrix[row][column - 1])
			{
				//合併數字
				matrix[row][column] *= 2;
				matrix[row][column - 1] = 0;
				flag = true;
				//更新最大格子數值
				if (matrix[row][column] > max)
					max = matrix[row][column];
				//判斷是否贏////////////////
				if (matrix[row][column] == 2048)
				{
					gameWin = true;
					return;
				}
				//向右移動格子
				for (int j = column - 1;j>0;j--)
					matrix[row][j] = matrix[row][j - 1];
				matrix[row][0] = 0;
			}
		}
	//是可以移動狀態,建立新的格子
	if (flag)
		newLattice();
}

void cGame::play()
{
	//遊戲結束時,不做任何事情
	if (gameOver)
		return;
	//沒有按鍵按下時,不做任何事情
	if (!_kbhit())
		return;

	switch (_getch())
	{
	case 'a':
	case 'A':
		moveLeft();
		break;
	case 'd':
	case 'D':
		moveRight();
		break;
	case 'w':
	case 'W':
		moveUp();
		break;
	case 's':
	case 'S':
		moveDown();
		break;
	default:
		break;
	}
	//buf_show();
}

void cGame::newLattice()
{
	//儲存空格資訊
	Point posArray[ROW*COLUMN];
	int num = 0;
	for(int row=0;row<ROW;row++)
		for(int column=0;column<COLUMN;column++)
			if (matrix[row][column] == 0)
			{
				posArray[num].setPos(row, column);
				num++;
			}

	//有空位置,隨機選擇一個空位置放2或者4
	if (num)
	{
		int index = rand() % num;
		int x = posArray[index].x();
		int y = posArray[index].y();
		int number=(rand()%20==0)?4:2;	//出現2和4的概率比為19:1
		matrix[x][y] = number;
		if (max == 0)
			max = number;
	}

	//檢測是否能繼續移動
	if (canMove())
	{
		gameOver = false;
	}
	else
	{
		gameOver = true;
	}
}

bool cGame::canMove()
{
	//判斷是否有空格,有則返回true
	for (int row = 0;row < ROW;row++)
		for (int column = 0;column < COLUMN;column++)
			if (matrix[row][column] == 0)
				return true;
	
	//判斷同一行中是否有相鄰格子的值相等,有則返回true
	for (int row = 0;row < ROW;row++)
		for (int column = 0;column < COLUMN-1;column++)
			if (matrix[row][column] == matrix[row][column+1])
				return true;

	//判斷同一列中是否有相鄰格子的值相等,有則返回true
	for (int row = 0;row < ROW;row++)
		for (int column = 0;column < COLUMN;column++)
			if (matrix[row][column] == matrix[row+1][column])
				return true;

	return false;
}

void cGame::show()
{
	system("cls");
	//提示資訊
	if (gameWin)
		cout << "You win!" << endl;
	else if (gameOver)
		cout << "You lose!" << endl;
	else
		cout << "Fighting!" << endl;
	//列印格子
	for (int row = 0;row < ROW;row++)
	{
		for (int column = 0;column < COLUMN;column++)
		{
			cout << matrix[row][column] << "\t";
		}
		cout << endl;
	}
}

void cGame::buf_show()
{
	//建立螢幕緩衝區
	HANDLE hNewConsole = CreateConsoleScreenBuffer(GENERIC_WRITE | GENERIC_READ,
		0,
		NULL,
		CONSOLE_TEXTMODE_BUFFER,
		NULL);

	//隱藏游標
	CONSOLE_CURSOR_INFO cci = { 1,0 };
	SetConsoleCursorInfo(hNewConsole, &cci);

	//設定標題欄
	SetConsoleTitle("2048小遊戲");

	//設定視窗緩衝區大小
	COORD cdBufferSize = { 320,480 };// 80, 25};
	SetConsoleScreenBufferSize(hNewConsole, cdBufferSize);

	//提示資訊
	if (gameWin)
		cout << "You win!" << endl;
	else if (gameOver)
		cout << "You lose!" << endl;
	else
		cout << "Fighting!" << endl;
	//列印格子
	for (int row = 0; row < ROW; row++)
	{
		for (int column = 0; column < COLUMN; column++)
		{
			COORD cdCursorPos = { column,row };
			//cout << matrix[row][column] << '\t';
			int *p = &matrix[row][column];
			SetConsoleCursorPosition(hNewConsole, cdCursorPos);
			WriteConsole(hNewConsole, p, sizeof(int), NULL, NULL);
		}
		cout << endl; cout << "row";
	}
	//顯示繪製好的東西
	SetConsoleActiveScreenBuffer(hNewConsole);

	//遊戲結束,返回正常模式
	if (gameOver)
		SetConsoleActiveScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE));

}

Point 類是用來記錄點座標的,c++裡面是有處理平面點座標的方法的,不過我懶得找了就簡單寫了一個類,程式碼如下: