寫之前首先感謝各位博客大神分享了自己的代碼和自己的思路
最近在學習C++的一些基本語法,一直想找個小的項目練一下,後來在網上找到了很多的開源項目,發現2048比較簡單也比較容易入門,就選擇了做個命令窗口式的2048。
總體思路就是設計一個44的數組模型,然後對這個44的數組模型進行移動合併等操作。
做這個項目主要就是分爲以下幾步:
第一步:輸出合適的2048窗口,話不多說這部分直接看代碼,可以加強對C++輸出輸入的理解。
void show( )
{
cout << "**************2048***************" << endl;
for (int i = 0; i < 4; ++i)
{
cout << "---------------------------------" << endl;
for (int j = 0; j < 4; ++j)
{ if(game_num[i][j]==0)
cout <<" "<<'\t' << '|';
else
cout<<game_num[i][j]<< '\t' << '|';
if (j ==3)
cout << endl;
}
}
cout << "---------------------------------" << endl;
}
第二步就是產生隨機數了,在這裏我們使用的是rand()函數,通過rand()函數使得2和4出現的概率都爲50%,並且出現數字的地方也是隨機。
void generate_number()
{
int k = 1;
while(k==1)
{
int x = rand() % 4;
int y = rand() % 4;
if ((game_num[x][y] == 0))
{
game_num[x][y] = rand_number();
k = 0;
}
else
{
k = 1;
}
}
}
第三步就是通過一個getch()函數來讀取當前的鍵盤的輸入方向,來確定如何移動;
int get_direction()
{
char c1, c2;
c1 = getch();
if (!isascii(c1))
{
c2 = getch();
switch (c2)
{
case 72: direction = 1; break;
case 80: direction = 2; break;
case 75: direction = 3; break;
case 77: direction = 4; break;
default: break;
}
}
return direction;
}
第四步也是最關鍵的一步,就是2048移動的算法問題,這裏最初自己的想法比較蠢,就是把涉及到的情況儘可能的都羅列出來,用if語句,但是這樣不僅代碼複雜而且容易出現bug和錯誤。看了很多網上大神的一些思路後,確定2048的算法分爲兩步,第一步移動,第二步計算這裏以往上操作爲例,結合程序簡單講解一下,第一部分的程序是移動,2048這個小遊戲在移動的過程中都是將有數字的格子往無數字的格子中移動,所以這裏我就是先把所有的數字往上移動,把前面的無數字的空格先填滿:
void up()
{
for (int j = 0; j < 4; ++j)
{
for (int k = 0; k <3; ++k)
{
for (int i = 0; i < 3; ++i)
{
if (game_num[i][j] == 0)
{
game_num[i][j] = game_num[i + 1][j];
game_num[i + 1][j] = 0;
}
}
}
for (int i = 0; i < 3; ++i)
{
if (game_num[i][j] == game_num[i + 1][j])
{
game_num[i][j] += game_num[i + 1][j];
game_num[i + 1][j] = 0;
}
}
}
}
最下面的數字移動到上面也只需要3次,因此,定義了一個變量K值,便可以將最下面的數字循環一直移動到最上面。
移動之後就是判斷是否能夠合併,若是能夠合併就可以直接合並,合併後將下方格子中的數字置0;其餘三種情況一樣,這裏便不一一列舉。
第五步也就是判斷遊戲何時結束,這個主要分爲兩個條件,第一個是判斷是否還能有可以合併的,即遍歷判斷一下是否能夠合併,第二個是遍歷所有數判斷是否還有0;
void game_over()
{
int times=0;
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (game_num[i][j] == game_num[i][j + 1])
{
++times;
}
}
}
for (int j = 0; j < 4; ++j)
{
for (int i = 0; i < 3; ++i)
{
if (game_num[i][j] == game_num[i+1][j] )
{
++times;
}
}
}
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (game_num[i][j] == 0)
++times;
}
}
if (times == 0)
{
cout << "Game over" << endl;
}
}
總的來說就是分爲這幾個部分,但這裏我的代碼到最後存在一個非常嚴重的bug就是判斷結束時會出現這樣一種情況,就是16個數全部填滿,並且還存在相鄰的數可以消除,但是無法消除,也不會提示GAME OVER這個bug我還在改,可能是哪裏的函數調用存在問題。如果有大神發現了,麻煩說一下,不甚感激。最後附上所有的代碼:
#include<iostream>
#include<string>
#include<vector>
#include<ctime>
#include<windows.h>
#include<conio.h>
#pragma comment(lib,"User32.lib")
#pragma warning(disable:4996)
#include"practice.h"
using namespace std;
int game_num[4][4] = { 0 };
int direction = -1;
void show( )
{
cout << "**************2048***************" << endl;
for (int i = 0; i < 4; ++i)
{
cout << "---------------------------------" << endl;
for (int j = 0; j < 4; ++j)
{ if(game_num[i][j]==0)
cout <<" "<<'\t' << '|';
else
cout<<game_num[i][j]<< '\t' << '|';
if (j ==3)
cout << endl;
}
}
cout << "---------------------------------" << endl;
}
int rand_number()
{
int rand_num = rand() % 10;
int num = 0;
if (rand_num <= 4)
return num = 2;
else
return num = 4;
}
void generate_number()
{
int k = 1;
while(k==1)
{
int x = rand() % 4;
int y = rand() % 4;
if ((game_num[x][y] == 0))
{
game_num[x][y] = rand_number();
k = 0;
}
else
{
k = 1;
}
}
}
void up()
{
for (int j = 0; j < 4; ++j)
{
for (int k = 0; k <3; ++k)
{
for (int i = 0; i < 3; ++i)
{
if (game_num[i][j] == 0)
{
game_num[i][j] = game_num[i + 1][j];
game_num[i + 1][j] = 0;
}
}
}
for (int i = 0; i < 3; ++i)
{
if (game_num[i][j] == game_num[i + 1][j])
{
game_num[i][j] += game_num[i + 1][j];
game_num[i + 1][j] = 0;
}
}
}
}
void down()
{
for (int j = 0; j < 4; ++j)
{
for (int k = 3; k>0; --k)
{
for (int i = 3; i > 0; --i)
{
if (game_num[i][j] == 0)
{
game_num[i][j] = game_num[i - 1][j];
game_num[i - 1][j] = 0;
}
}
}
for (int i = 3; i > 0; --i)
{
if (game_num[i][j] == game_num[i - 1][j])
{
game_num[i][j] += game_num[i - 1][j];
game_num[i - 1][j] = 0;
}
}
}
}
void left()
{
for (int i = 0; i < 4; ++i)
{
for (int k = 0; k < 3; ++k)
{
for (int j = 0; j < 3; ++j)
{
if (game_num[i][j] == 0)
{
game_num[i][j] = game_num[i][j+1];
game_num[i][j+1] = 0;
}
}
}
for (int j = 0; j < 3; ++j)
{
if (game_num[i][j] == game_num[i][j+1])
{
game_num[i][j] += game_num[i][j+1];
game_num[i][j+1] = 0;
}
}
}
}
void right()
{
for (int i = 0; i < 4; ++i)
{
for (int k = 3; k > 0; --k)
{
for (int j = 3; j > 0; --j)
{
if (game_num[i][j] == 0)
{
game_num[i][j] = game_num[i][j-1];
game_num[i][j-1] = 0;
}
}
}
for (int j = 3; j > 0; --j)
{
if (game_num[i][j] == game_num[i][j-1])
{
game_num[i][j] += game_num[i ][j-1];
game_num[i][j-1] = 0;
}
}
}
}
int get_direction()
{
char c1, c2;
c1 = getch();
if (!isascii(c1))
{
c2 = getch();
switch (c2)
{
case 72: direction = 1; break;
case 80: direction = 2; break;
case 75: direction = 3; break;
case 77: direction = 4; break;
default: break;
}
}
return direction;
}
void game_over()
{
int times=0;
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (game_num[i][j] == game_num[i][j + 1])
{
++times;
}
}
}
for (int j = 0; j < 4; ++j)
{
for (int i = 0; i < 3; ++i)
{
if (game_num[i][j] == game_num[i+1][j] )
{
++times;
}
}
}
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (game_num[i][j] == 0)
++times;
}
}
if (times == 0)
{
cout << "Game over" << endl;
}
}
int main()
{
srand((unsigned)time(NULL));
int i = rand()%4;
int j = rand()%4;
game_num[i][j ]= rand_number();
generate_number();
show( );
while (1)
{
get_direction();
if (direction == 1)
{
up();
generate_number();
system("cls");
show();
game_over();
}
if(direction==2)
{
down();
generate_number();
system("cls");
show();
game_over();
}
if (direction == 3)
{
left();
generate_number();
system("cls");
show();
game_over();
}
if (direction == 4)
{
right();
generate_number();
system("cls");
show();
game_over();
}
}
}