最近自己动手写了一个1024小游戏的控制代码,没有界面,但是比起原始版本多了对角线方向可以滑动,设计思路如下:
[0]:控制数字滑动的模块,我将它写成一个类的成员函数.实现数字的滑动以及相同数字的合并.因为数字有8个方向滑动,因此我们需要将不同方向的数字比较的方向,开始的位置都记录下来,然后写出一个通用的框架来处理四个方向的滑动.
bool Game:: slide(string ms)
{
auto &data = *matrix.get();
auto de_i = get<0>(direction[ms]),de_j = get<1>(direction[ms]);
auto beg_row = get<2>(direction[ms]),beg_col = get<3>(direction[ms]);
auto de_row = (beg_row==N-2) ? -1 : 1,de_col = (beg_col==N-2) ? -1 : 1;
MyType isnewvalue(N);
for (auto &it : isnewvalue) it.resize(N);
bool valuechanged = false;
for (size_t i = beg_row; isgood(i);i+=de_row)
for (size_t j = beg_col; isgood(j); j+=de_col)
{
if (!data[i][j])
continue;
int temp_i = i, temp_j = j;
if (!data[i + de_i][j + de_j])
{
valuechanged = true;
while (isgood(i + de_i) && isgood(j + de_j)&&!data[i + de_i][j + de_j] )
i += de_i,j += de_j;
data[i ][j] = data[temp_i][temp_j];
data[temp_i][temp_j] = 0;
}
if (isgood(i+de_i)&&isgood(j+de_j)&&(data[i][j] == data[i + de_i][j + de_j])&&
!isnewvalue[i+de_i][j+de_j])
{
data[i][j] = 0;
data[i + de_i][j + de_j] *= 2;
isnewvalue[i + de_i][j + de_j] = 1;
--count;
valuechanged = true;
}
i = temp_i, j = temp_j;
}
return valuechanged;
}
[1]数字生成模块:每次滑动后都应该生成新的数字,需要判断能生成几个(0,1或2),以及相应位置必须是空的.
void Game:: generate()
{
auto &data = *matrix.get();
int x, y;
srand(time(0));
int n = 0;
while (count != N*N&&n != 2)
{
do{
x = rand() % N;
y = rand() % N;
} while (data[x][y]);
data[x][y] = (count % 2) ? 2 : 4;
++count;
++n;
}
}
[2]判断游戏是否结束:当竖直方向以及水平方向和对角线与反对角线方向都不会产生数字矩阵状态变化的可能,则游戏结束.所以这里需要slide函数的配合,在slide函数中记录状态是否变化.
bool Game::isfailed()
{
Game temp = *this;
bool ans = (count == N*N&&!temp.slide("up") && !temp.slide("right")
&&!temp.slide("leftup")&&!temp.slide("rightup"));
if (ans)
cout << "game over";
return ans;
}
[3]:游戏类的设计
class Game
{
#define isgood(x) ((x!=N&&x!=-1)?true:false)
using MyType = vector<vector<int>>;
using change = tuple<int, int, int, int>;
public:
Game(int n) : matrix(make_shared<MyType>(n)),N(n){
for (auto &it : *matrix) it.resize(N);
direction.insert({ "up", change(-1, 0, 1, 0) });
direction.insert({ "down", change(1, 0, N - 2, 0) });
direction.insert({ "left", change(0,-1 , 0, 1) });
direction.insert({ "right", change(0, 1, 0, N-2) });
direction.insert({ "leftup", change(-1, -1, 1, 1) });
direction.insert({ "rightdown", change(1, 1, N-2, N-2) });
direction.insert({ "leftdown", change(1, -1, N-2, 1) });
direction.insert({ "rightup", change(-1, 1, 1, N-2) });});
}
Game(const Game& g) :N(g.N), count(g.count), direction(g.direction) {
matrix = make_shared<MyType>(*g.matrix.get());
}
void print();
bool slide(string ms);
void generate();
bool isfailed();
private:
const size_t N;
size_t count;
map<string, change>direction;
shared_ptr<MyType> matrix;
};
[4]:print()函数
void Game:: print()
{
auto &data = *matrix.get();
cout << std::endl;
for (auto row : data)
{
cout << std::endl;
for (auto it : row)
cout << it << "\t";
}
}
[5]:主函数:设计了简单/困难两种模式,简单模式在游戏失败前每一次滑动都会产生新的数字,而困难模式则要求数字矩阵状态改变才会产生新数字.
int main()
{
cout << "请选择简单/困难模式\n";
string mode;
cin >> mode;
Game game(4);
game.generate();
game.print();
string ms;
while (cin>>ms&&!game.isfailed())
{
auto changed = game.slide(ms);
if (mode == "easy"||changed)
game.generate();
game.print();
}
return 0;
}