C++2048

前言

大家都应该玩过这个风靡一时的游戏吧。至于这个游戏的一些技巧就不在给大家讲解了,我也是一个菜鸡的。但是这个游戏后面所包含的算法可以通过C++来进行实现。
在这里插入图片描述

原理

移动

这个原理就是向一个方向移动,遇到相同的元素就翻倍。
首先我们看一下怎么实现非零元素的移动(以向上移动为例):
在这里插入图片描述
上面这一个我们可以检查:

  1. 每一列第一个元素是否为0,如果为零就与第二个元素交换;
  2. 继续检查第一个元素是否为0,如果为零就与第三个元素交换;
  3. 继续检查第一个元素是否为0,如果为零就与第四个元素交换;
  4. 继续检查第二个元素是否为0,如果为零就与第三个元素交换;
  5. 继续检查第二个元素是否为0,如果为零就与第四个元素交换;
  6. 继续检查第三个元素是否为0,如果为零就与第四个元素交换。

以第一列为例:

  1. 第一个元素为0,所以和第二个元素交换;
  2. 第一个元素依然为0,所以和第三个元素交换;
  3. 第一个元素依然为0,所以和第四个元素交换;
    在这里插入图片描述
    以此类推,第二个位置第三个位置,这就实现了移动的功能。

消除

对于消除来说,和前面的移动的类似的,只不过在判断前面的为零元素的时候换成判断相等的情况。依然以向上移动作为例子。
在这里插入图片描述

  1. 检查第一列第一个元素是否和第二个元素相等,如果相等就将第一个元素翻倍,将第二个元素置为零;
  2. 检查第一个元素是否和第三个元素相等,如果相等就将第一个元素翻倍,将第三个元素置为零;
  3. 检查第一个元素是否和第四个元素相等,如果相等就将第一个元素翻倍,将第四个元素置为零;
  4. 检查第二个元素是否和第三个元素相等,如果相等就将第二个元素翻倍,将第三个元素置为零;
  5. 检查第二个元素是否和第四个元素相等,如果相等就将第二个元素翻倍,将第四个元素置为零;
  6. 检查第三个元素是否和第四个元素相等,如果相等就将第三个元素翻倍,将第四个元素置为零;

以第一列为例

  1. 第一个元素和第二个元素不相等;
  2. 第一个元素和第三个元素相等,第一个元素变为两倍,第三个元素置为零;
    在这里插入图片描述
  3. 后面的情况都是零,翻倍也不需要处理了。

**上面两种处理方式是不冲突的,如果是0那么就不会和另外一个元素相等。**下面我们对一个例子进行一个分析:
在这里插入图片描述

  1. 判断第一个元素是否为0(),判断是第一个元素是否和第二个元素相等();
  2. 判断第一个元素是否为0(),判断是第一个元素是否和第三个元素相等();
  3. 判断第一个元素是否为0(),判断是第一个元素是否和第四个元素相等();
  4. 判断第二个元素是否为0(),第三个元素和第二个元素交换;
    在这里插入图片描述
  5. 判断第二个元素是否为0(),判断是第二个元素是否和第四个元素相等(),第二个元素翻倍,第四个元素置为0;
    在这里插入图片描述
    6.判断第一个元素是否为0(),判断是第一个元素是否和第二个元素相等();
    最后的结果就是:在这里插入图片描述

细节讲解

总体结构

在这里插入图片描述
StartGame没有实现具体的功能,它的作用就是调用Game对象的功能,实现对外封装的效果。在main()里面直接调用StartGame即可。

Game

Game.h

#ifndef MYGAME_GAME_H
#define MYGAME_GAME_H
#include <iostream>
#include <iomanip>
#include "windows.h"
#include<fstream>
using namespace std;
class Game {
public:
	void setSize(const int size_);
	void Draw(ostream& os, std::string f);
	void Draw(ostream& os);//重载函数打印界面
	void move();
	bool generate();//生成新的数字,生成成功返回true,生成失败返回false
	void init();
	int getScore();
	void setMaxScore();//生成新的最高成绩
	Game();
private:
	int array1[10][10];
	int score;
	int x, y;
	int size;
	int max_score;
	bool isFully();//判断是否已满
	void addScore(int score_);//加成绩
	void moveUp();
	void moveDown();
	void moveRight();
	void moveLeft();
	void getControl(char& c);//获取输入字符,判断输入是否合法
	void clear();//清除历史最高成绩
};
#endif // MYGAME_GAME_H

Game.cpp

#include "Game.h"

void Game::moveUp() {//向上移动
	for (int k = 0; k < size; ++k) {
		for (int i = 0; i < size; ++i) {
			for (int j = i + 1; j < size; ++j) {
				if (array1[i][k] == 0 && array1[k][j] != 0) {
					array1[i][k] = array1[j][k];
					array1[j][k] = 0;
				}
				if (array1[i][k] == array1[j][k] && array1[k][i] != 0)
				{
					array1[i][k] *= 2;
					addScore(array1[i][k]);
					array1[j][k] = 0;
				}
			}
		}
	}
}


void Game::moveDown() {//向下移动
	for (int k = 0; k < size; ++k) {
		for (int i = size - 1; i >= 0; --i) {
			for (int j = i - 1; j >= 0; --j) {
				if (array1[i][k] == 0 && array1[k][j] != 0) {
					array1[i][k] = array1[j][k];
					array1[j][k] = 0;
				}
				if (array1[i][k] == array1[j][k] && array1[k][i] != 0)
				{
					array1[i][k] *= 2;
					addScore(array1[i][k]);
					array1[j][k] = 0;
				}
			}
		}
	}
}

void Game::moveRight() {//向右移动
	for (int k = 0; k < size; ++k) {
		for (int i = size - 1; i >= 0; --i) {
			for (int j = i - 1; j >= 0; --j) {
				if (array1[k][i] == 0 && array1[k][j] != 0)
				{
					array1[k][i] = array1[k][j];
					array1[k][j] = 0;
				}
				if (array1[k][i] == array1[k][j] && array1[k][i] != 0)
				{
					array1[k][i] *= 2;
					addScore(array1[k][i]);
					array1[k][j] = 0;
				}
			}
		}
	}
}

void Game::moveLeft() {//向左移动
	for (int k = 0; k < size; ++k) {
		for (int i = 0; i < size; ++i) {
			for (int j = i + 1; j < size; ++j) {
				if (array1[k][i] == 0 && array1[k][j] != 0) {
					array1[k][i] = array1[k][j];
					array1[k][j] = 0;
				}
				if (array1[k][i] == array1[k][j] && array1[k][i] != 0)
				{
					array1[k][i] *= 2;
					addScore(array1[k][i]);
					array1[k][j] = 0;
				}
			}
		}
	}
}

bool Game::generate() {//生成新的数字
	if (isFully())
		return false;
	x = rand() % size;
	y = rand() % size;
	while (array1[x][y] != 0) {
		x = rand() % size;
		y = rand() % size;
	}
	array1[x][y] = 2;
	return true;
}

void Game::move() {
	char c;
	getControl(c);
	switch (c)
	{//判断输入的字符
	case 'W':
		moveUp();
		break;
	case 'S':
		moveDown();
		break;
	case 'D':
		moveRight();
		break;
	case 'A':
		moveLeft();
		break;
	case '0':
		clear();
		break;
	}
}

void Game::getControl(char& c) {//获取输入字符,判断输入是否合法
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);
	cout << "Press the keys to start and continue." << endl;
	cout << "W => Up" << endl << "S => Down" << endl << "A => Left" << endl << "D => Right" << endl << "0 => clear max score" << endl;
	while (cin >> c && !(c == 'A' || c == 'S' || c == 'D' || c == 'W' || c == '0'))
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4);
		cout << "please input right instruction" << endl;
	};
}

void Game::Draw(ostream& os) {
	cout << endl;
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE | FOREGROUND_RED);
	cout << "===================================================================================" << endl;
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 9);
	cout << "your score:" << getScore() << endl;
	cout << "your max score : " << max_score << endl;
	for (int i = 0; i < size; ++i) {
		for (int j = 0; j < size; ++j) {
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);
			if (i == x && j == y)
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_RED);
			cout << setw(4) << array1[i][j];
		}
		cout << endl;
	}
}

void Game::Draw(ostream& os, std::string f) {
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE);
	os << f;
}

bool Game::isFully() {
	for (int i = 0; i < size; ++i) {
		for (int j = 0; j < size; ++j) {
			if (array1[i][j] == 0)
				return false;
		}
	}
	return true;
}

void Game::init() {
	for (int i = 0; i < size; ++i) {
		for (int j = 0; j < size; ++j) {
			array1[i][j] = 0;
		}
	}
	score = 0;
}

int Game::getScore() {
	return score;
}

void Game::addScore(int score_) {
	score += score_;
}

void Game::setSize(const int size_) {
	size = size_;
}

Game::Game() {
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 10; j++)
			array1[i][j] = 0;
	}
	ifstream is("max_score.txt");
	is >> max_score;//从文件中读入最高成绩
}

void Game::setMaxScore() {
	if (score > max_score)
	{
		ofstream os("max_score.txt");
		os << score;//将新的最高成绩写入文件中
	}
}

void Game::clear() {
	ofstream os("max_score.txt");
	os << 0;
}

这里面最核心的内容就是那个四个move()函数,所以我们将这其中的一个move函数单独拿出来进行解释:

/*
	*k:表示一列
	*i:表示选定的标定位置
	*j:表示另一个移动的位置
*/
void Game::moveUp() {//向上移动
	for (int k = 0; k < size; ++k) {
		for (int i = 0; i < size; ++i) {
			for (int j = i + 1; j < size; ++j) {
				if (array1[i][k] == 0 && array1[k][j] != 0) {
					array1[i][k] = array1[j][k];
					array1[j][k] = 0;
				}
				/*	
					*当一列中的i元素为0,且j元素不为0时,二者交换,实现前面原理当中的向前移动
				*/
				if (array1[i][k] == array1[j][k] && array1[k][i] != 0)
				{
					array1[i][k] *= 2;
					addScore(array1[i][k]);
					array1[j][k] = 0;
				}
				/*
					*其中两个元素不为0且相等的时候其中一个翻倍,另一个置为0,实现消除功能。
				*/
			}
		}
	}
}

对于不同的移动方向,相应的i,j,k的移动方向的初始大小不同而已,其余原理均相同。

StartGame

StartGame.h

#ifndef MYGAME_STARTGAME_H
#define MYGAME_STARTGAME_H
#include "Game.h"
void StartGame();
#endif // MYGAME_STARTGAME_H

StartGame.cpp

#include "StartGame.h"
void StartGame() {
	Game game;
	game.init();
	string str = R"(
  /\\\\\\\\\          /\\\\\\\                /\\\         /\\\\\\\\\
  /\\\///////\\\      /\\\/////\\\            /\\\\\       /\\\///////\\\
  \///      \//\\\    /\\\    \//\\\         /\\\/\\\      \/\\\     \/\\\
             /\\\/    \/\\\     \/\\\       /\\\/\/\\\      \///\\\\\\\\\/
           /\\\//      \/\\\     \/\\\     /\\\/  \/\\\       /\\\///////\\\
         /\\\//         \/\\\     \/\\\   /\\\\\\\\\\\\\\\\   /\\\      \//\\\
        /\\\/            \//\\\    /\\\   \///////////\\\//   \//\\\      /\\\
       /\\\\\\\\\\\\\\\   \///\\\\\\\/              \/\\\      \///\\\\\\\\\/
       \///////////////      \///////                \///         \/////////
  )";
	int size;
	game.Draw(cout, str);//打印封面
	cout << "input your size(>3&&<11):" << endl;
	cin >> size;
	if (size < 3 || size > 10) {
		cout << "Game Over!" << endl;
		cout << "your score:" << game.getScore() << endl;
		return;
	}
	game.setSize(size);
	while (game.generate()) {
		system("cls");
		game.Draw(cout, str);
		game.Draw(cout);
		game.move();
	}//循环游戏
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);
	cout << "Game Over!" << endl;
	cout << "your score:" << game.getScore() << endl;
	game.setMaxScore();//设置新的记录
}

实现

main函数

#include <iostream>
#include <iomanip>
#include "windows.h"
#include "StartGame.h"
using namespace std;
int main() {
	StartGame();
	return 0;
}

开始界面
在这里插入图片描述
游戏过程中
在这里插入图片描述
在这里插入图片描述
游戏结束
在这里插入图片描述

总结

经过这一系列的写作练习,发现自己的写作能力在潜移默化中发生改表,希望自己能够继续坚持下去。这个2048还有可以优化的地方,比如我们可以直接读取上下左右键而不是WASD键等等,以后我还会继续优化的。希望这个能够对大家有帮助! 谢谢!

发布了16 篇原创文章 · 获赞 13 · 访问量 4285

猜你喜欢

转载自blog.csdn.net/deng821776892/article/details/104756635
今日推荐