2048-控制檯版本
/最近修改2017/6/26/
/修改2017/7/4,修改之前各自填滿之後無法移動的錯誤,暫時未發現大的錯誤/
/最後修改2017/7/5,新增前景色,新增模式選擇,改善介面/
一.實現目標:
2048遊戲
二.要求:
1、在螢幕上顯示4*4的表格
2、隨機生成2、4數字及位置
3、顏色設定
三.執行環境和工具:
VC++6.0
四.實現步驟
0.遊戲邏輯:
把遊戲畫面想象成4*4的陣列,其中數值為0的位置表示空的格子,
有數值的位置代表對應的格子。然後對於每一行按列來遍歷,或者每一列按行來遍歷,實現每一行每一列的對應數字合併,直到出現2048的格子就勝利,否則就失敗.
1.編寫用於實現數字移動的方向函式
以向左移動為例:
把遊戲畫面想象成4*4的陣列,其中數值為0的位置表示空的格子,
先看其中一行,有四列,用一個變數k=0,從第一列開始,另一個變數j=1開始,代表k之後的列,開始遍歷。
如果第j列這個位置不為0的話,那麼之後可以分為3種情況:
第一種情況:第k列和第j列相同,這個時候就將第k列的數字加倍,第j列重置為0.
第二種情況:第k列為0,那麼就交換第k列和第j列的數字。
第三種情況:第k列和第j列都不為0,但是兩者不相等,這個時候,就把兩個數緊挨在一起,如果j和k原本就緊挨在一起,那麼什麼也不做。
而如果第j列為,也什麼也不做。
在向左移動的時候,每一行都向左移動,所以逐行相加,然後按列遍歷。
同理,向右移動,區別在於,向右是反向的按列遍歷,向上是逐列相加,按行遍歷,向右於向左移動是行列相反的遍歷。
每次移動,步數就+1,每次合併,就會加上當前合併的格子的數值。
2.編寫用於實現隨機數字和隨機位置的函式,以及遊戲結束函式,顯示格子函式,初始化函式,退出函式等
#define TARGET 2048
標記最終的目標,同時也是判斷遊戲是否結束的標誌之一,如果在格子中出現了2048的格子,玩家勝利,遊戲結束。另一種結束方式是,當所有的格子都被填滿的時候,同時不存在可以相互合併的格子,並且沒有2048的格子,遊戲結束,玩家失敗。
3.困難模式下隨機函式用來隨機出現數字2和4,使得出現的概率之比為1:10,保證遊戲時間不至於過短。
正常模式下隨機函式2和4出現概率之比為1:4
4.Begin()函式用來將陣列初始化為0,包括分數和步數的清零
但是這個只在遊戲開始的時候執行一次。
5.顯示格子函式:設定好列印顏色,以及格子間距
五.程式執行:
六.以下為完整程式碼
#include<conio.h>
#include<time.h>
#include<Windows.h>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define TARGET 2048 //最終目標
HANDLE myHandle; //控制控制代碼,物件
const WORD FORE_BLUE =FOREGROUND_BLUE; //藍色文字
const WORD FORE_GREEN =FOREGROUND_GREEN; //綠色文字
const WORD FORE_RED =FOREGROUND_RED; //紅色文字
const WORD FORE_YELLOW =FORE_RED|FORE_GREEN; //黃色文字,其他顏色用三原色搭配
const WORD FORE_GRAY =FORE_BLUE|FORE_GREEN; //紫色文字
const WORD BACK_BLUE =BACKGROUND_BLUE; //藍色背景
const WORD BACK_GREEN =BACKGROUND_GREEN; //綠色背景
const WORD BACK_RED =BACKGROUND_RED; //紅色背景
const WORD BACK_YELLOW =BACK_RED|BACK_GREEN; //黃色背景,其他顏色用三原色搭配
const WORD BACK_GRAY =BACK_BLUE|BACK_GREEN; //紫色背景
int pass=0; //用來判斷是否需要返回
int Game; //標記遊戲是否結束
int ax[4][4]; //控制的二維陣列
int score=0; //記錄分數
int step=0; //記錄所花費的步數
void Up(); //向上移動數字,使其相同的合成,不同的緊湊
void Down(); //向下
void Right(); //向右
void Left(); //向左
void Movement(); //正常移動
void Movement_2(); //困難移動
void GAME_OVER(); //標記遊戲是否結束
void Exit(); //退出函式
void Begin(); //初始化陣列
void Run(); //將隨機出現的數字放入隨機的座標當中,概率修改
void Run_2(); //概率之比為1:10
void Show(); //顯示格子
void Mode1(); //正常模式
void Mode2(); //困難模式
void Help(); //幫助手冊
void choice(); //選擇
void Menu(); //選單
void Help()
{
system("cls");
HANDLE handle_out=GetStdHandle(STD_OUTPUT_HANDLE); //獲取標準輸入裝置控制代碼
CONSOLE_SCREEN_BUFFER_INFO csbi; //定義視窗緩衝區資訊結構體
GetConsoleScreenBufferInfo(handle_out,&csbi); //獲得視窗緩衝區資訊
SetConsoleTextAttribute(handle_out,FORE_YELLOW); //設定列印顏色為綠色
printf(" --------------------------------------------\n");
printf(" ********************************************\n\n");
printf(" 操作說明:\n↓:下 ←:左 ↑:上 →:右 ESC鍵:退出\n\n");
printf(" 遊戲介紹:每次選擇一個方向滑動,每次滑動,除了數字向該方向靠攏之外,系統會在空格處生成隨機數字2或者4,\n");
printf(" 相同數字可以相加。如果拼湊出“2048”這個數字,則遊戲勝利!\n");
system("pause");
system("cls");
}
void Left()
{
int i,j,k;
for(i=0;i<4;i++) //行數
{
for(j=1,k=0;j<4;j++) //每一行按列來遍歷
{
if(ax[i][j]!=0)
{
if(ax[i][k]==ax[i][j])
{
ax[i][k]<<=1;
score+=ax[i][k];
ax[i][j]=0;
k++;
}
else if(ax[i][k]==0)
{
ax[i][k]=ax[i][j];
ax[i][j]=0;
k++;
}
else
{
k++;
ax[i][k]=ax[i][j];
if(k!=j)
{
ax[i][j]=0;
}
}
}
}
}
step++;
}
void Right()
{
int i,j,k;
for(i=0;i<4;i++)
{
for(j=2,k=3;j>=0;j--)
{
if(ax[i][j]!=0)
{
if(ax[i][j]==ax[i][k])
{
ax[i][k]<<=1;
score+=ax[i][k];
ax[i][j]=0;
k--;
}
else if(ax[i][k]==0)
{
ax[i][k]=ax[i][j];
ax[i][j]=0;
k--;
}
else
{
k--;
ax[i][k]=ax[i][j];
if(j!=k)
{
ax[i][j]=0;
}
}
}
}
}
step++;
}
void Up()
{
int n,i,j,k;
for(n=0;n<4;n++)
{
k=0;
for(i=0;i<4;i++)
{
if(ax[i][n]!=0)
{
for(j=i;j>k;j--)
{
if(ax[j-1][n]==0) //上一行沒有數字
{
ax[j-1][n]=ax[j][n];
ax[j][n]=0;
}
else if(ax[j-1][n]==ax[j][n])
{
ax[j-1][n]=2*ax[j-1][n];
score+=ax[j-1][n];
ax[j][n]=0;
k=j;
Sleep(1);
break;
}
else
break;
}
}
}
}
step++;
}
void Down()
{
int i,j,k;
for(j=0;j<4;j++)
{
for(i=2,k=3;i>=0;i--)
{
if(ax[i][j]!=0)
{
if(ax[i][j]==ax[k][j])
{
ax[k][j]<<=1;
score+=ax[k][j];
ax[i][j]=0;
k--;
}
else if(ax[k][j]==0)
{
ax[k][j]=ax[i][j];
ax[i][j]=0;
k--;
}
else
{
k--;
ax[k][j]=ax[i][j];
if(k!=i)
{
ax[i][j]=0;
}
}
}
}
}
step++;
}
void Movement()
{
if(kbhit())
{
switch(getch())
{
case 27:
Exit();
break;
case 75: //向左
Left();
Run();
Show();
break;
case 72: //向上
Up();
Run();
Show();
break;
case 77: //向右
Right();
Run();
Show();
break;
case 80: //向下
Down();
Run();
Show();
break;
default:
break;
}
}
}
void Movement_2()
{
if(kbhit())
{
switch(getch())
{
case 27:
Exit();
break;
case 75: //向左
Left();
Run_2();
Show();
break;
case 72: //向上
Up();
Run_2();
Show();
break;
case 77: //向右
Right();
Run_2();
Show();
break;
case 80: //向下
Down();
Run_2();
Show();
break;
default:
break;
}
}
}
void Exit()
{
int i=0;
printf("\n退出中");
for(i=4;i>0;--i)
{
Sleep(200);
printf(".");
}
exit(0);
}
void Begin()
{
int i=0,j=0;
score=0; //分數清零
Game=0; //初始遊戲
step=0; //步數清零
SetConsoleTitleA("遊戲:2048");
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
ax[i][j]=0;
}
}
}
void Run()
{
int x,y,temp,num;
srand((int)time(0));
while(1)
{
x=rand()%4;
y=rand()%4;
temp=rand()%5; //概率之比為1:4
if(temp==1)
num=4;
else
num=2;
if(ax[x][y]==0)
{
ax[x][y]=num;
break;
}
}
}
void Run_2()
{
int x,y,temp,num;
srand((int)time(0));
while(1)
{
x=rand()%4;
y=rand()%4;
temp=rand()%10; //概率之比為1:10
if(temp==1)
num=4;
else
num=2;
if(ax[x][y]==0)
{
ax[x][y]=num;
break;
}
}
}
void GAME_OVER()
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<3;j++)
{
if(ax[i][j]==ax[i][j+1]||ax[j][i]==ax[j+1][i])
{
Game=0;//同列中的存在刻意繼續合併的數字,遊戲繼續
return ;
}
else if(ax[i][j]==0||ax[i][j+1]==0||ax[j][i]==0||ax[j+1][i]==0)
{
Game=0;
return ;
}
else if(ax[i][j]==TARGET||ax[i][j+1]==TARGET||ax[j][i]==TARGET||ax[j+1][i]==TARGET)
{
Game=2;
return; //存在2048,遊戲結束
}
}
}
Game =1; //不存在2048,但是同行同列中沒有能夠合併的數字,並且沒有空位置,遊戲結束
}
void Show()
{
int i,j;
HANDLE handle_out=GetStdHandle(STD_OUTPUT_HANDLE); //獲取標準輸入裝置控制代碼
CONSOLE_SCREEN_BUFFER_INFO csbi; //定義視窗緩衝區資訊結構體
GetConsoleScreenBufferInfo(handle_out,&csbi); //獲得視窗緩衝區資訊
system("cls");
SetConsoleTextAttribute(handle_out,FORE_GREEN); //設定列印顏色為綠色
printf(" --------------------------------------------\n");
printf(" ********************************************\n");
//上界
SetConsoleTextAttribute(handle_out,FORE_RED); //設定列印顏色為紅色
printf(" |----|----|----|----|\n");
//格子上半部分
for(i=0;i<4;i++)
{
SetConsoleTextAttribute(handle_out,FORE_RED); //設定列印顏色為紅色
printf(" |");
for(j=0;j<4;j++)
{
if(ax[i][j]!=0)
{
SetConsoleTextAttribute(handle_out,FORE_YELLOW); //設定列印顏色為黃色
printf("%4d|",ax[i][j]);
}
else
{
SetConsoleTextAttribute(handle_out,FORE_YELLOW); //設定列印顏色為黃色
printf(" |");
}
}
printf("\n");
SetConsoleTextAttribute(handle_out,FORE_RED); //設定列印顏色為紅色
printf(" |----|----|----|----|\n");
}
//格子下半部分
SetConsoleTextAttribute(handle_out,FORE_GREEN); //設定列印顏色為綠色
printf(" --------------------------------------------\n");
printf(" ********************************************\n");
printf(" ↓:下 ←:左 ↑:上 →:右 ESC鍵:退出\n\n");
SetConsoleTextAttribute(handle_out,FORE_RED); //設定列印顏色為紅色
printf(" ■▲□■○□■○□ ■○□■○□■○□\n");
printf(" ▲▲");
SetConsoleTextAttribute(handle_out,FORE_YELLOW); //設定答應顏色為黃色
printf("分數:%-3d ",score);
SetConsoleTextAttribute(handle_out,FORE_RED);
printf("▲□ ■○");
SetConsoleTextAttribute(handle_out,FORE_YELLOW);
printf("步數:%-3d ",step);
SetConsoleTextAttribute(handle_out,FORE_RED);
printf("○□\n");
printf(" ■▲ ○□ ■○ ○□\n");
printf(" ■▲▲■▲□■○□ ■○□■○□■○□\n");
//下界
if(Game==1) //遊戲結束,失敗
{ printf("\n Sorry,you losed!!!!!!!!!!!!!!!!!!!!!!\n");
system("pause");
Exit();
}
if(Game==2) //遊戲成功,勝利
{
printf("\n Good!YOU WIN!!!!!!!!!!!!!!!!!!!!!!!!\n");
system("pause");
Exit();
}
}
void Mode1()
{
Begin(); //遊戲初始化
Run(); //隨機一個數字
Run();
Show();
while(1)
{
GAME_OVER(); //每次都判斷一次遊戲是否結束
if(Game==1||Game==2)
{
break;
}
Movement();
}
Show();
return ;
}
void Mode2()
{
Begin();
Run_2();
Run_2();
Show();
while(1)
{
GAME_OVER();
if(Game==1||Game==2)
{
break;
}
Movement_2();
}
Show();
return ;
}
void Menu()
{
SetConsoleTitleA("遊戲:2048");
HANDLE handle_out=GetStdHandle(STD_OUTPUT_HANDLE); //獲取標準輸入裝置控制代碼
SetConsoleTextAttribute(handle_out,FORE_GREEN); //設定列印顏色為綠色
printf(" --------------------------------------------\n");
printf(" ********************************************\n");
SetConsoleTextAttribute(handle_out,FORE_YELLOW); //設定列印顏色為綠色
printf(" 選單\n");
SetConsoleTextAttribute(handle_out,FORE_GREEN|FORE_YELLOW); //設定列印顏色為青色
printf(" a.正常模式\n");
printf(" b.困難模式\n");
printf(" c.幫助手冊\n");
printf(" d.遊戲結束\n");
printf(" 請輸入你的選擇\n");
}
void choice()
{
char ch='0';
scanf(" %c",&ch);
switch(ch)
{
case 'a':
Mode1();
break;
case'b':
Mode2();
break;
case'c':
Help();
break;
case'd':
exit(0);
break;
default:
break;
}
}
int main(void)
{
while(1)
{
Menu();
choice();
}
return 0;
}