1. 程式人生 > >C語言寫的2048小遊戲

C語言寫的2048小遊戲

基於"基於C_語言的2048演算法設計_顏冠鵬.pdf" 這一篇文獻提供的思路 在中國知網上能找到 就不貼具體內容了 [摘 要] 針對2048的遊戲規則,分析了該遊戲的演算法特點,對其相關的功能需求和演算法設計進行了簡單介紹,提出了一種 新的設計方案。解決了該設計在方陣資料結構、運動演算法和遊戲結束判斷方面的問題,並闡述了以佇列方式進行座標運算和操 作擴充套件的關鍵技術。軟體測試表明,該設計的方塊數值最大值受方陣階數和操作次數的限制,四階方陣的理論最大值為 65 536, 智力極高的人可達 16 384,而一般人僅能達到 2 048 左右。 [關鍵詞] 2048 演算法設計 資料結構 座標運算 佇列 中圖分類號:TP301.6 文獻標識碼:A 文章編號:1008- 1739(2014)24- 62- 5

主要是幾個小的函式 用兩個for迴圈列印地圖和遍歷地圖 把一個4*4的二維陣列改成一個一維陣列來簡化處理思路

學到的知識

switch函式每一個case都需要加break來結束判斷 for在c99標準下 初始化的迴圈變數和外界所有變數毫無關係 c99標準才有了布林型變數 儘量不要大迴圈套小迴圈 巢狀四層迴圈之後就暈了 下斷點都不好除錯 如果陣列越界訪問會返回0 隨機數函式必須撒種子 不然每次都是同一個值

//
//  main.c
//  2048
//  表示 為了練習C語言 在這先寫著一個小遊戲吧
//  “聽說以後上課要用?”
//  除錯程式碼已註釋 目前遊戲所有功能均實現
//  唯一不足的是在蘋果系統環境無getch函式
//  且不會自行實現 在其他系統直接include <conio.h>
//  把getchar改為getch即可暢玩2048
//  Created by licsber on 2018/10/11.
//  Copyright © 2018 licsber. All rights reserved.
//

#include <stdio.h>//emmmm
#include <stdbool.h> //c裡沒有布林型變數 c99標準才加的
#include <time.h>//用於產生隨機數
#include <stdlib.h>
//#include <ncurses.h>//圖形介面庫 等後來更新printMap函式再引用

void gameStart(void);//遊戲開始
void randomAdd(void);//在空格隨機加2和4 其中2為十分之九概率
void printMap(void);//用printf列印地圖
void getDirection(void);//讀取鍵盤輸入
void moveUp(void);//上
void moveDown(void);//下
void moveLeft(void);//左
void moveRight(void);//右
void moveForward(void);//推進
void moveMerge(void);//合併
bool checkIfGameOver(void);//檢測遊戲是否over 即無空位同時相鄰陣列元素各不相等
void restart(void);//重新開始
void loop(void);//循環遊戲
//int countZero(void);//還有幾個是0
//int returnZero(int line);

int score = 0;//當前得分
int map[4][4]={
    {0,0,0,0},
    {0,0,0,0},
    {0,0,0,0},
    {0,0,0,0}
};//這是地圖 用二維陣列實現
int tmp[4] = {0,0,0,0};

void gameStart(void){
    printf("Welcome to play 2048 game! by licsber\n");
    randomAdd();
    printMap();
    printf("[w][s][a][d]move [r]restart [q]quit\n");
}

void randomAdd(void){
    srand((unsigned int)time(NULL));//撒隨機數種子
    //printf("%d",rand());
    int i,j,time = 0;//行 列 迴圈次數(debug用)
    do{
        i = rand() % 4;
        j = rand() % 4;
        time++;
    }while (map[i][j] != 0);
    if (rand() % 10 == 0 ) {
        map[i][j]=4;
    }
    else{
        map[i][j]=2;
    }
    //printf("%d",time);
    //上面的程式碼在格子快滿之後也有機率迴圈N次都不停
    //todo改進方案:先找到所有空格子
    //下面的程式碼是有問題的 有機率無限迴圈
    /*
     bool finish = 0;//本輪是否已放置方塊
     for (int i = 0; i < 4; i++) {
     for (int j = 0; j < 4; j++) {
     if (!map[i][j]) {
     if (rand() % 16 == 0 && finish == 0) {
     // 十分之一的概率放4
     if (rand() % 10 == 0 ) {
     map[i][j]=4;
     }
     else{
     map[i][j]=2;
     }
     finish = 1;
     }
     }
     }
     }
     if (finish == 0) {
     randomAdd();
     }
     else{
     return;
     }
     */
}

void printMap(void){
    for (int i = 0; i < 4; i++) {
        printf("          ");
        for (int j = 0; j < 4; j++) {
            printf("%4d ",map[i][j]);
        }
        printf("\n");
    }
    return;
}

void getDirection(void){
    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
    char in = getchar();
    switch (in) {
        case 'w':
            moveUp();
            break;
        case 's':
            moveDown();
            break;
        case 'a':
            moveLeft();
            break;
        case 'd':
            moveRight();
            break;
        case 'r':
            restart();
            break;
        case 'q':
            exit(0);
            break;
        default:
            getDirection();
            break;
    }
}

void moveUp(void){
    for (int line = 0; line < 4; line++) {
        for (int i = 0; i < 4; i++) {
            tmp[i] = map[i][line];
        }
        moveMerge();
        for (int i = 0; i < 4; i++) {
            map[i][line] = tmp[i];
        }
    }
}

void moveDown(void){
    for (int line = 0; line < 4; line++) {
        for (int i = 0; i < 4; i++) {
            tmp[3 - i] = map[i][line];
        }
        moveMerge();
        for (int i = 0; i < 4; i++) {
            map[i][line] = tmp[3 - i];
        }
    }
}

void moveLeft(void){
    for (int line = 0; line < 4; line++) {
        for (int i = 0; i < 4; i++) {
            tmp[i] = map[line][i];
        }
        moveMerge();
        for (int i = 0; i < 4; i++) {
            map[line][i] = tmp[i];
        }
    }
}

void moveRight(void){
    for (int line = 0; line < 4; line++) {
        for (int i = 3; i >= 0; i--) {
            tmp[3 - i] = map[line][i];
        }
        moveMerge();
        for (int i = 3; i >= 0; i--) {
            map[line][i] = tmp[3 - i];
        }
    }
}

bool checkIfGameOver(void){
    //先檢查格子是不是都滿了
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (!map[i][j]) {
                //只要有空的格子 遊戲就沒結束
                return false;
            }
        }
    }
    //格子滿了之後
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 3; j++) {
            if (map[i][j] == map[i+1][j] || map[i][j] == map[i][j+1]) {
                //如果一個格子和它右邊或下邊相等 遊戲也沒結束
                //這裡陣列如果越界訪問會返回0 所以不影響結果
                return false;
            }
        }
    }
    return true;
}

void moveForward(void){
    //i為0的話就把最先一個非零的j挪到i的位置
    int j = 0;
    for (int i = 0; i < 4; i++) {
        j++;
        if (tmp[i] == 0) {
            for (; j < 4; j++) {
                if (tmp[j] != 0) {
                    tmp[i] = tmp[j];
                    tmp[j] = 0;
                    break;
                }
            }
        }
    }
}

void moveMerge(void){
    //處理合並 每合併一次就推進一次
    moveForward();
    for (int i = 0; i < 3; i++) {
        if (tmp[i] == tmp[i + 1]) {
            tmp[i] *=2;
            tmp[i + 1] = 0;
            moveForward();
        }
    }
}


/*
int countZero(void){
    int zero = 0;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (!map[i][j]) {
                zero++;
            }
        }
    }
    return zero;
}
*/

void restart(void){
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            map[i][j] = 0;
        }
    }
    gameStart();
    loop();
}



void loop(void){
    for(;;) {
        getDirection();
        printMap();
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (!map[i][j]) {
                    //只要有空的格子 就加
                    randomAdd();
                    goto go;
                }
            }
        }
    go:
        if (checkIfGameOver() ==  true){
            printf("You are lose!");
            exit(0);
        }
    }
}

int main() {
    gameStart();
    loop();
    return 0;
}