下午在刷題過程中,忽然想寫2048了,以彌補以前寫的那個千多行的,所以簡單思考了一下準備採取的數據結構就開始了,本以為一個小時能搞定,結果後面改bug還是多花了些時間。因為在醫院,所以聲音不敢太大,如果看,建議耳機+聲音最大,可以考慮倍速。個人感覺用C寫這些東西的意義在於,你去掉了一些花里胡哨的東西 ...
下午在刷題過程中,忽然想寫2048了,以彌補以前寫的那個千多行的,所以簡單思考了一下準備採取的數據結構就開始了,本以為一個小時能搞定,結果後面改bug還是多花了些時間。因為在醫院,所以聲音不敢太大,如果看,建議耳機+聲音最大,可以考慮倍速。個人感覺用C寫這些東西的意義在於,你去掉了一些花里胡哨的東西,而真的用你的邏輯思考出了這個東西怎麼寫,並寫出來了。亂花漸欲迷人眼,難的是堅守本心!明白學一個東西的意義,有時候比學習它更重要!嗯就這樣。下麵貼上代碼和錄製的視頻鏈接。
//2019年3月16日 17:29:07 //2048 //1、地圖數據結構 2、合併和移動? 3、判斷勝負 #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<conio.h> #include<time.h> #include<string.h> #define N 5//地圖大小 #define M 13//table表的長度 #define WINFLAG 11 char map[N][N];//地圖 int table[M];//查表使用 void Init(); void Run(); void Print(); int Win(); void Lose(); int IsLose(); int Up(int *isChange); int Down(int *isChange); int Left(int *isChange); int Right(int *isChange); void Generator(int dir); void gotoxy(int x, int y); //將游標調整到(x,y)的位置 //游標隱藏 void HideCursor() ; //隱藏游標顯示 int main(void) { srand((unsigned)time(NULL)); HideCursor(); Init(); Run(); return 0; } void Generator(int dir) { //按下右,就按列掃,從左往右隨機選一個數生成 //按下上,就按行掃,從下網上隨機選一個數生成 // int begin; // int end; // int mul;//增量 // for(int i = begin;i != end;i += mul) // for(int i = 0;i < N;++i) // for(j = N-1;j >= 0;--j) int flag = 0; int i1 = -1,i2 = -1; if(dir == 1 || dir == 2) { int begin,end,mul; dir == 1?begin = 0,end = N,mul = 1:begin = N-1,end = -1,mul = -1; for(int i = 0;i < N;++i) for(int j = begin;j != end;j += mul) { //保證選一個數,然後其他的隨機 if(map[i][j] == 0)//選到了一個數 { if(flag == 0)//之前沒選到過 { i1 = i; i2 = j; flag = 1; } else { if(rand()%3 < 2) { i1 = i; i2 = j; } } } } } else if(dir == 3 || dir == 4) { int begin,end,mul; dir == 3?begin = 0,end = N,mul = 1:begin = N-1,end = -1,mul = -1; for(int j = begin;j != end;j += mul) for(int i = 0;i < N;++i) { //保證選一個數,然後其他的隨機 if(map[i][j] == 0)//選到了一個數 { if(flag == 0)//之前沒選到過 { i1 = i; i2 = j; flag = 1; } else { if(rand()%3 < 2) { i1 = i; i2 = j; } } } } } if(i1 == i2 && i2 == -1) return; map[i1][i2] = 1; } int Up(int *isChange) { //往上,所以是從上往下掃描 //一列一列的算 for(int j = 0;j < N;++j) { int k = 0; for(int i = 1;i < N;++i) { if(map[i][j] != 0)//當前處理的這一位是有數字的 { //只要是非0,且沒有合併,則相加 //這裡保證map[i][j]是有數字的 if(map[i][j] == map[k][j]) { //與那個數字進行交互。合併操作 map[k][j] += 1; map[i][j] = 0; if(map[k][j] == 12) return 5; *isChange = 1; } else if(map[k][j] == 0)//我們是說k是第一個非零的,但初始的時候我們為了好運算,是沒做判斷的 { //把當前位置上的數移過去 特判的移動操作 map[k][j] = map[i][j]; map[i][j] = 0; *isChange = 1; } else if(k+1 != i)//移動操作 { map[k+1][j] = map[i][j];//2 0 0 4 2 4 0 0 map[i][j] = 0;//4 2 0 0 ++k; *isChange = 1; } else//沒有合併,且不是特判的 ++k; } } } return 1; } int Down(int *isChange) { for(int j = 0;j < N;++j) { int k = N-1; for(int i = N-2;i >= 0;--i) { if(map[i][j] != 0)//當前處理的這一位是有數字的 { //只要是非0,且沒有合併,則相加 //這裡保證map[i][j]是有數字的 if(map[i][j] == map[k][j]) { //與那個數字進行交互。合併操作 map[k][j] += 1; map[i][j] = 0; if(map[k][j] == 12) return 5; *isChange = 1; } else if(map[k][j] == 0)//我們是說k是第一個非零的,但初始的時候我們為了好運算,是沒做判斷的 { //把當前位置上的數移過去 特判的移動操作 map[k][j] = map[i][j]; map[i][j] = 0; *isChange = 1; } else if(k-1 != i)//移動操作 { map[k-1][j] = map[i][j];//2 0 0 4 2 4 0 0 map[i][j] = 0;//4 2 0 0 --k; *isChange = 1; } else//沒有合併,且不是特判的 --k; } } } return 2; } int Left(int *isChange) { //合併?什麼情況下合併?什麼情況下移動? //一行一行處理 //從左往右處理 //這個有數字,我們才需要處理,沒數字不用管 2 0 4 8 2 4 0 8 2 4 8 0 for(int i = 0;i < N;++i) { int k = 0; for(int j = 1;j < N;++j) { if(map[i][j] != 0)//當前處理的這一位是有數字的 { //這裡保證map[i][j]是有數字的 if(map[i][j] == map[i][k]) { //與那個數字進行交互。合併操作 map[i][k] += 1; map[i][j] = 0; if(map[i][k] == 12) return 5; *isChange = 1; } else if(map[i][k] == 0)//我們是說k是第一個非零的,但初始的時候我們為了好運算,是沒做判斷的 { //把當前位置上的數移過去 特判的移動操作 map[i][k] = map[i][j]; map[i][j] = 0; *isChange = 1; } else if(k+1 != j)//移動操作 { map[i][k+1] = map[i][j];//2 0 0 4 2 4 0 0 map[i][j] = 0;//4 2 0 0 ++k; *isChange = 1; } else ++k; } } } return 3; } int Right(int *isChange) { //從右至左 for(int i = 0;i < N;++i) { int k = N-1; for(int j = N-2;j >= 0;--j) { if(map[i][j] != 0)//當前處理的這一位是有數字的 { //這裡保證map[i][j]是有數字的 if(map[i][j] == map[i][k]) { //與那個數字進行交互。合併操作 map[i][k] += 1; map[i][j] = 0; if(map[i][k] == 12) return 5; *isChange = 1; } else if(map[i][k] == 0)//我們是說k是第一個非零的,但初始的時候我們為了好運算,是沒做判斷的 { map[i][k] = map[i][j]; map[i][j] = 0; *isChange = 1; } else if(k-1 != j)//移動操作 { map[i][k-1] = map[i][j]; map[i][j] = 0; --k; *isChange = 1; } else --k; } } } return 4; } void Init() { int n = 16;//隨機地圖的數目 //先求table table[0] = 1; for(int i = 1;i < M;++i) table[i] = table[i-1]<<1;//等同於*2 // for(int i = 0;i < M;++i) // printf("%5d",table[i]); //及時測試,驗證正確性,免得日後找bug麻煩 //隨機地圖 隨機生成3個2? memset(map,0,sizeof(map)); for(int i = 0;i < n;++i) { int i1 = rand()%N; int i2 = rand()%N; //隨機一組下標,讓地圖那個位置變成1 map[i1][i2] = 1; //這個1代表2的一次,最終展現的是2 } } void Run() { int isChange = 0;//檢測是否發生了變化 int flag = 0; while(1) { Print(); isChange = 0; switch(getch()) { case 'w':flag = Up(&isChange);break; case 's':flag = Down(&isChange);break; case 'a':flag = Left(&isChange);break; case 'd':flag = Right(&isChange);break; } if(flag != 5 && isChange) Generator(flag); if(flag == 5) { Win(); break; } else if(IsLose()) { Print(); Lose(); break; } } } void Print() { gotoxy(0,0); for(int i = 0;i < N;++i) { for(int j = 0;j < N;++j) if(map[i][j] != 0) printf("%3d ",table[map[i][j]]); else printf(" "); putchar('\n'); } } int Win() { printf("You are winner!\n"); } void Lose() { printf("You are loser!\n"); } int IsLose() { //判斷是否還具備可操作空間 for(int i = 0;i < N;++i) for(int j = 0;j < N-1;++j) { if(map[i][j] == map[i][j+1]) return 0; else if(map[i][j]*map[i][j+1] == 0) return 0; } for(int j = 0;j < N;++j) for(int i = 0;i < N-1;++i) { if(map[i][j] == map[i+1][j]) return 0; else if(map[i][j]*map[i+1][j] == 0) return 0; } Print(); return 1; } //游標跳轉 void gotoxy(int x, int y) //將游標調整到(x,y)的位置 { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); COORD pos; pos.X = x; pos.Y = y; SetConsoleCursorPosition(handle, pos); } //游標隱藏 void HideCursor() //隱藏游標顯示 { CONSOLE_CURSOR_INFO cursor_info = { 1, 0 }; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); }View Code
嗶哩嗶哩配套視頻鏈接:https://www.bilibili.com/video/av46465862/