用C挑戰無準備寫2048

来源:https://www.cnblogs.com/YaLi/archive/2019/03/16/10544882.html
-Advertisement-
Play Games

下午在刷題過程中,忽然想寫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/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、基本的@property使用,可以把函數當做屬性用 2、@property的set,deleter,get 3、@property demo 4、property函數使用 5、property函數操作私有屬性的get和set方法 ...
  • 學Python這麼久了,一直想做個界面出來,最近發現Python有個內置庫tkinter,利用它可以很輕鬆做出一些簡易的UI界面 關註公眾號「**Python專欄**」,後臺回覆關鍵字:**zsxq03**,獲取本文全部代碼 ...
  • 在《Java編程思想》中關於泛型的講解中,提到了自限定類型: 作者說道: 這就像兩面鏡子彼此照向對方所引起的目眩效果一樣,是一種無限反射。 類接受泛型參數 ,而 由一個邊界限定,這個邊界就是擁有T作為其參數的 接下來,作者用了近3頁的紙來進行解釋這個問題,且語言極其晦澀難懂(可能是翻譯的問題),但是 ...
  • 第一問:TCP與UDP的區別 參考答案: 1.基於連接與無連接 2.TCP要求系統資源較多,UDP較少; 3.UDP程式結構較簡單 4.流模式(TCP)與數據報模式(UDP); 5.TCP保證數據正確性,UDP可能丟包 6.TCP保證數據順序,UDP不保證 考點:聽說騰訊必考TCP,反正TCP的三次 ...
  • 1. 模板字元串簡介: 顧名思義,模板字元串是用來定義一個模板是使用的,就像Vue,React中的template語法。 首先,先來瞭解一下template string的基本用法: 在ES5中,我們大多都有過拼串的經歷吧。 模板字元串的語法是反引號(`` --> 鍵盤左上角),利用反引號將字元串封 ...
  • 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6467 看到這題,簡單數學???對不起我給數學老師丟臉了! 這裡解釋一下第二步到第三步:假設n=3,第二步{1*C(1,1)+1*C(1,2)+1*C(1,3)+2*C(2,2)+2*C(2,3)+3*C ...
  • java基礎--提示對話框的使用 2019-03-17-00:35:50 雲林原創 一、顯示信息對話框:使用“JOptionPane.showMessageDialog”顯示: 使用實例: 1、顯示錯誤類型對話框: 視圖: 2、傳達信息類型對話框: 視圖: 3、警告對話框: 視圖: 4、提問對話框: ...
  • java基礎--常用函數總結 2019-3-16-23:28:01 雲林原創 1、split()字元串分割函數 將一個字元串分割為子字元串,然後將結果作為字元串數組返回。 2、Math.floor( )舍掉小數取整數 3、Math.rint( )四捨五入取整數 4、Math.ceil( )進位取整數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...