應用C說話完成2048小游戲的辦法。本站提示廣大學習愛好者:(應用C說話完成2048小游戲的辦法)文章只能為提供參考,不一定能成為您想要的結果。以下是應用C說話完成2048小游戲的辦法正文
預備任務
起首上一張圖,由於這裡只是在用C說話驗證算法,所以沒有對界面做很好的優化,丑是理所應該的。
懂得了游戲的任務道理,現實上可以將游戲描寫為四個帶無方向的統一操作:
1、將一切數字向一個偏向挪動至中央沒有空位
2、將相鄰的兩個雷同的數字加和然後放在更接近挪動偏向前部的一個地位上
別的須要斷定一下玩家以後輸出的內容能否可以履行,假如弗成以履行期待用戶下一筆記錄。
同時須要對游戲的過程停止掌握,假如可以持續游戲,那末運轉玩家持續輸出下一條指令,而假如弗成以停止,那末提醒沒法持續游戲的提醒。
起首的成績就是光標鍵的輸出。光標鍵屬於功效鍵,應用慣例的scanf固然是沒法停止讀取的,而應用加倍接近硬件的getch()停止以字節為單元的尺度輸出。當應用getch()函數停止尺度輸出時,假如用戶輸出了一個功效鍵,例如光標鍵、Home、PgUp、PgDn、End之類的鍵,getch()將可以或許讀獲得到兩個字符。當碰到功效鍵輸出的時刻,可以編寫一個檢測法式以獲得對應按鍵的數據:
#include<stdio.h>
int main(){
while(1){
printf("%d\n",getch());
}
}
隨後運轉這個數據提取法式,法式將依照一個字節一行,以整型的格局輸入getch獲得的數據。這裡我查詢到2048須要用到的四個按鍵↑↓←→對應的兩個字節為:
按鍵 第一字節 第二字節 ↑ 224 72 ↓ 224 80 ← 224 75 → 224 77然後就是游戲的重要的代碼
#include<stdio.h> //尺度輸出輸入
#include<stdlib.h> //根本對象函數
#define bool int //C裡邊沒有布爾類型,就本身造
#define true 1 //bool的兩種值
#define false 0
int MAP[4][4]= {0}; //地圖,默許0以為是空位
typedef enum { //界說一個偏向類型的列舉變量
UNKNOW,
UP,
DOWN,
LEFT,
RIGHT
} Direction;
void printMap(); //繪制圖形
Direction getNextDirection(); //從鍵盤讀入下一個用戶操作
bool canMove(Direction direction); //斷定能否可以停止指定偏向的操作
void doAction(); //游戲事宜
void move(Direction direction); //挪動數字
void putNew(); //放入一個新的數字
int main() { //主函數
Direction nextStep; //下一步
int i,j;
srand(time(0));
putNew(); //游戲開端默許放兩個數字
putNew();
printMap(); //打印格子
while(1) {
if(!canMove(UP)&&!canMove(LEFT)&&!canMove(DOWN)&&!canMove(RIGHT)) break; //隨意率性偏向都不克不及挪動,那末終止游戲
nextStep=getNextDirection(); //獲得下一個用戶操作
if(nextStep==UNKNOW) continue; //假如不曉得用戶按了個甚麼鍵或許用戶胡亂按的,那末進入新的輪回
if(!canMove(nextStep)) continue; //假如下一步弗成持續操作,進入新的輪回
system("cls"); //關於Windows來講,履行敕令行敕令cls清屏
doAction(nextStep); //履行操作
putNew(); //放新的數字
printMap(); //打印格子
}
printf("You Died!"); //提醒游戲停止
while(1); //期待游戲停止
}
void printMap() {
int i,j;
printf("*-------*-------*-------*-------*\n");
for(i=0; i<4; i++) {
printf("|");
for(j=0; j<4; j++) {
MAP[i][j]?printf("%d",MAP[i][j]):printf(" ");
printf("\t|");
if(j>2)
printf("\n");
}
printf("*-------*-------*-------*-------*\n");
}
}
void doAction(Direction direction){
int i,j,k;
/**
* 為了便利處置成績,將每一個偏向的活動操作簡化為三步
* 1.將數字合並到一個偏向
* 2.處置雷同數字可消,並將消失落的數據定為0
* 3.再次將數字合並到一個偏向
*/
//1.挪動數字,撤消數字之間的空位
move(direction);
//2.依照偏向處置雷同數字
switch(direction){
case UP:
//按列列舉
for(i=0;i<4;i++){
//關於每行的每個元素
for(j=0;j<3;j++){
//假如元素非零,而且以後和下一個雷同,以後的翻倍,下一個置零
if(MAP[j][i]&&MAP[j][i]==MAP[j+1][i]){
MAP[j][i]+=MAP[j+1][i];
MAP[j+1][i]=0;
}
}
}
break;
case LEFT://同上
for(i=0;i<4;i++)
for(j=0;j<3;j++)
if(MAP[i][j]&&MAP[i][j]==MAP[i][j+1]){
MAP[i][j]+=MAP[i][j+1];
MAP[i][j+1]=0;
}
break;
case DOWN://同上
for(i=0;i<4;i++)
for(j=3;j>0;j--)
if(MAP[j][i]&&MAP[j][i]==MAP[j-1][i]){
MAP[j][i]+=MAP[j-1][i];
MAP[j-1][i]=0;
}
break;
case RIGHT://同上
for(i=0;i<4;i++)
for(j=3;j>0;j--)
if(MAP[i][j]&&MAP[i][j]==MAP[i][j-1]){
MAP[i][j]+=MAP[i][j-1];
MAP[i][j-1]=0;
}
break;
}
//3.挪動數字,撤消由於上一步置零進程中新發生的空位
move(direction);
}
void move(Direction direction) { //挪動數字
int i,j,k;
switch(direction) {
case UP:
//按列列舉
for(i=0;i<4;i++)
//關於每行的每個元素
for(j=0;j<4;j++)
//假如非零,那末應該撤消以後地位,後邊元素向前挪動
if(!MAP[j][i]){
for(k=j;k<3;k++){
MAP[k][i]=MAP[k+1][i];
}
//新發生的空地位零
MAP[k][i]=0;
}
break;
case LEFT://同上
for(i=0;i<4;i++)
for(j=0;j<4;j++)
if(!MAP[i][j]){
for(k=j;k<3;k++){
MAP[i][k]=MAP[i][k+1];
}
MAP[i][k]=0;
}
break;
case DOWN://同上
for(i=0;i<4;i++)
for(j=3;j>=0;j--)
if(!MAP[j][i]){
for(k=j;k>0;k--){
MAP[k][i]=MAP[k-1][i];
}
MAP[k][i]=0;
}
break;
case RIGHT://同上
for(i=0;i<4;i++)
for(j=3;j>=0;j--)
if(!MAP[i][j]){
for(k=j;k>0;k--){
MAP[i][k]=MAP[i][k-1];
}
MAP[i][k]=0;
}
break;
}
}
bool canMove(Direction direction) { //斷定能否可以停止指定偏向的操作
int i,j;
switch(direction) {
case UP:
//順次檢討每列
for(i=0;i<4;i++){
//起首消除在遠真個一串空位,直接將j指向第一個非零元素
for(j=3;j>=0;j--)
if(MAP[j][i])
break;
//j>0代表這一列並不是全體為0
if(j>0)
//順次檢討每個殘剩元素,碰見空位直接前往true
for(;j>=0;j--)
if(!MAP[j][i])
return true;
//順次檢討相鄰的元素能否存在雷同的非零數字
for(j=3;j>0;j--)
if(MAP[j][i]&&MAP[j][i]==MAP[j-1][i])
return true;
}
break;
case DOWN://同上
for(i=0;i<4;i++){
for(j=0;j<4;j++)
if(MAP[j][i]) break;
if(j<4)
for(;j<4;j++)
if(!MAP[j][i]) return true;
for(j=0;j<3;j++)
if(MAP[j][i]&&MAP[j][i]==MAP[j+1][i])
return true;
}
break;
case LEFT://同上
for(i=0; i<4; i++){
for(j=3;j>=0;j--)
if(MAP[i][j])
break;
if(j>=0)
for(;j>=0;j--)
if(!MAP[i][j])
return true;
for(j=0;j<3;j++)
if(MAP[i][j]&&MAP[i][j]==MAP[i][j+1])
return true;
}
break;
case RIGHT://同上
for(i=0; i<4; i++){
for(j=0;j<4;j++)
if(MAP[i][j])
break;
if(j<4)
for(;j<4;j++)
if(!MAP[i][j])
return true;
for(j=0;j<3;j++){
if(MAP[i][j]&&MAP[i][j]==MAP[i][j+1])
return true;
}
}
break;
}
//當許可前提都被檢討事後,前往弗成履行的成果
return false;
}
Direction getNextDirection() {
//第一個字節必需是224,不然剖斷輸出的不是功效鍵
if(getch()!=224) return UNKNOW;
//依據第二字節對應出來用戶的操作
switch(getch()) {
case 72:
return UP;
case 80:
return DOWN;
case 75:
return LEFT;
case 77:
return RIGHT;
default:
return UNKNOW;
}
}
void putNew(){
//為了便利操作,暫時存儲一下一切余暇格子的指針,如許可以用一個線性的內存隨機拜訪完成對一切空位中任一空位的隨機拜訪.
int* boxes[16]={NULL};
//用光降時保留目的格子的地址
int* target;
//統計一共有若干個有用空格
int count=0;
int i,j;
//統計空位,發明空位即保留地址並累加計數器
for(i=0;i<4;i++)
for(j=0;j<4;j++)
if(!MAP[i][j]){
boxes[count]=&MAP[i][j];
count++;
}
if(count){
//假如有空位,那末對這一名停止隨機賦值操作,關於每位能夠性是雷同的
target=boxes[rand()%count];
//50%能夠湧現2 50% 能夠湧現4
*target=rand()%2?2:4;
}
}
總結
以上就是這篇文章的全體內容了,小編以為像俄羅斯方塊、2048這些略微偏算法的小游戲是法式員必寫的幾個小法式。願望這篇文章對年夜家的進修或許任務能有所贊助,假如有疑問年夜家可以留言交換。