1. 程式人生 > >C++在控制檯上實現2048遊戲

C++在控制檯上實現2048遊戲

    剛學完C++基礎,想找一個專案練練手,萌發寫一個2048的遊戲的想法,既然有想法,就是幹!!自己第一次獨立完成一個專案(也不是全部是獨立的,開始之前參考過程式碼),雖然只有幾百行程式碼,但這是一個開始,朝著自己夢想一步一個腳印。fighting!!
    首先在網上找了一個2048的專案,http://www.jb51.net/article/51111.htm,用這個程式碼運行了一下,大概有了整體的認識,並且粗略的看了一下模組。在這個程式中,有一些bug:
    ①和我們平常玩的2048不同,這個遊戲生成的隨機數是2的次方,我們一般只會生成2和4;
    ②遊戲中每一次移動後生成新數的位置是第一個空格,降低遊戲的體驗;
    ③遊戲只有兩個相鄰的大小相同的數才會結合,中間存在0的話,不會結合;其實是由於每次移動只會移動一格導致的;
    ④遊戲中含有零,看起來不舒服;
    雖然有這些問題,但是這個程式給了我整體的思路,讓我能夠自己接下來走自己的路。

接下來是自己做專案遇到的一些問題和解決方法,最後附上自己的原始碼

一、控制檯如何從鍵盤上獲得方向鍵
    之前簡單的以為方向鍵就是簡單的ASCII碼,too young too simple。  http://blog.csdn.net/feilong911hao/article/details/42081967,看完這篇部落格之後弄明白。之前問過很多人,各種搜也沒找到,感謝博主和萬能的CSDN。  
    總結:①方向鍵有兩個位元組,第一個位元組不是ASCII碼,後面一個位元組才是
         ②使用getch()沒有回顯的從鍵盤輸入。

程式碼:

//返回值
//  1   上   72
// 2 下 80 // 3 左 75 // 4 右 77 int get_direction() { char c1,c2; int ret = 0; c1 = getch(); if (!isascii(c1)) { c2 = getch(); switch(c2) { case 72: ret = 1;break; case 80: ret = 2;break; case 75: ret = 3;break; case 77
: ret = 4;break; default: break; } } return ret; }
二、隨機數的生成
    使用srand()和rand(),srand()使用time(0)當前的時間當做隨機數種子,避免偽隨機數;
    http://wenku.baidu.com/link?url=XkB5uCfIkKL_LyBqEoM5ueoxl29mwXtEyfAzGSwfHsgGRB3-N9eR0O0EFoElSa1-YISWXb1mevClbOLytYDhFMoJrnrkhnlxK-brQsslt4O 

程式碼:

//隨機產生一個0-n-1的數字
int rand_pro_s(int n)
{
    srand(time(0));
    int k = rand()%n;
    return k;
}
三、移動(難點)
    將移動分為兩步,第一步是合併相鄰兩個相同的數字(中間可以含有0);第二步,方格里面的數字全部向移動的方向移動,去除中間的零。
    第一步:之前沒有理清思想,只合並了相鄰的兩個數字,沒有考慮含有0的情況。思路:遍歷每一行或者列,k來存放每一個非零的數,遇見一個非零,如果和k相等,那麼就將這個數變為2k,另外的數變為0.
    第二步:使用一個k來作為記錄非零的個數,然後遍歷。

程式碼

void up_dir()
{
    //完成第一步
    int i,j;
    for (i=0; i<4; i++)
    {
        /*for (j=0; j<3;)
        {
            if (array[j][i] == array[j+1][i])
            {
                array[j][i] = array[j][i] + array[j+1][i];
                array[j+1][i] = 0;
                j += 2;
                continue;
            }
            j++;
        }*/
        int k = 0;
        int x = 0; 
        int y = 0;
        for (j=0; j<4; j++)
        {
            if (k==array[j][i] && k!=0)
            {
                //array[x][y] = 2*array[x][y];
                //array[x][y] = 2*k;
                array[x][y] = 2*k;
                array[j][i] = 0;
                k = 0;
                continue;
            }
            if (array[j][i]!=0)
            {
                k = array[j][i];
                //此處的bug是x和y分別應該儲存j和i
                x = j;
                y = i;
            }
        }

    }

    for (i=0; i<4; i++)
    {
        int k = 0;
        for (j=0; j<4; j++)
        {
            //if (array[j][i])//此處有bug,假如k和j相等
            if (array[j][i])
            {
                if (k != j)
                {
                    array[k][i] = array[j][i];
                    array[j][i] = 0;
                }
                k++;
            }
        }
    }
    insert_num();
    system("cls");//清屏
    display();
}
四、如何隨機插入一個數(難點)
    使用剩餘空格數N,並且將空格的座標記錄下來,生成1-N的隨機數n,並且在第n個空格插入2或者4.
    tips:①vector<vector<int>> v(16 ,vector<int>());vector中含有vector不能定義為空
          ②插入數字的時候需要判斷空格數

五、如何判定遊戲結束
    看是否能夠水平移動或者豎直移動,在移動操作的函式中修改,不改變二維陣列的值即可

程式所有的程式碼

#include <iostream>
#include <cstdlib>  //rand(),time()
#include <ctime>    
#include <conio.h>  //getch()
#include <ctype.h>  //
#include <vector>
#include <math.h>   //pow
#include <iomanip>  //setw

using namespace std;

int array[4][4] = {0};//申請全域性陣列作為方格里面的數


//0—3的隨機數產生
int rand_pro()
{
    srand(time(0));
    int k = rand()%4;
    return k;
}

////////////////////////////////////介面函式////////////////////////////////////////////////////////////
//之前的介面
void display1()
{
    int i,j;
    for (i=0; i<4; i++)
    {
        for(j=0; j<4; j++)
        {
            cout<<array[i][j]<<"    ";
        }
        cout<<endl;
    }
    cout<<"----------------------------------"<<endl;
}

//介面美化,不顯示0,顯示外框
void display2()
{
    int i,j;
    for (i=0; i<4; i++)
    {
        for(j=0; j<4; j++)
        {
            if (array[i][j] == 0)
            {
                cout<<" "<<"    ";
            }
            else
                cout<<array[i][j]<<"    ";
        }
        cout<<endl;
    }
    cout<<"----------------------------------"<<endl;
}

void display() //顯示棋盤  
{  
    cout<<setw(46)<<"X2048 by ziyunmumu"<<endl;  
    cout<<setw(50)<<" |-----------------------|"<<endl;  
    for(int i=0;i<=3;i++)   
    {  
        cout<<setw(24)<<"";  
        for(int j=0;j<=3;j++)  
        {  
            //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED); 
            if (array[i][j] == 0)
            {
                cout<<setw(2)<<"|"<<setw(4)<<" ";  
            }
            else
                cout<<setw(2)<<"|"<<setw(4)<<array[i][j];  

            if(j==3)  
            {  
                cout<<setw(2)<<"|"<<endl;  
                cout<<setw(50)<<" |-----------------------|"<<endl;  
            }  
        }  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////新遊戲的開始////////////////////////////////////////////////////////////
void new_game()
{
    //初始化內容
    int i,j;
    for(i=0;i<4;i++)
    {
        for (j=0;j<4;j++)
        {
            array[i][j] = 0;
        }
    }

    int m = rand_pro();
    int n = rand_pro();
    array[m][n] = 2;
    display();
}
////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////
//隨機產生一個0-n-1的數字
int rand_pro_s(int n)
{
    srand(time(0));
    int k = rand()%n;
    return k;
}

//隨機產生一個1-n的數字
int rand_pro_ss(int n)
{
    srand(time(0));
    int k = rand()%n+1;
    return k;
}

//統計0的個數,並且通過一個vector來存放座標
//p需要判斷
vector<vector<int>> zero_num(int* p)
{
    int i,j;
    int k = 0;

    vector<vector<int>> v(16 ,vector<int>());

    for (i=0; i<4; i++)
    {
        for (j=0; j<4; j++)
        {
            if (array[i][j] == 0)
            {
                v[k].push_back(i);
                v[k].push_back(j);
                k++;
            }
        }
    }
    *p = k;
    return v;
}


//隨機插入一個數字,通空格的個數隨機插入
//返回值為true就說明成功插入,否則未能插入
bool insert_num()
{
    int k = 0;
    vector<vector<int>> v;
    v = zero_num(&k);

    if (k>0)
    {
        int m = rand_pro_s(k);
        int x = v[m][0];
        int y = v[m][1];
        array[x][y] = pow(2.0,rand_pro_ss(2));
        return true;
    }
    return false;
}



////////////////////////////////////獲得鍵盤方向////////////////////////////////////////////////////////////
//獲取方向
//返回值
//  1   上   72
//  2   下   80
//  3   左   75
//  4   右   77
int get_direction()
{
    char c1,c2;
    int ret = 0;
    c1 = getch();
    if (!isascii(c1))
    {
        c2 = getch();
        switch(c2)
        {
        case 72: ret = 1;break;
        case 80: ret = 2;break;
        case 75: ret = 3;break;
        case 77: ret = 4;break;
        default: break;
        }
    }
    return ret;
}
////////////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////移動操作////////////////////////////////////////////////////////////
//上下左右操作
//操作分為兩步,首先將相鄰的相同數字加起來,然後去除空格
//操作完之後需要插入數字

//之前分為兩步的想法有問題,假如是兩個相同數字之間有0的話,也是可以結合的

void up_dir()
{
    //完成第一步
    int i,j;
    for (i=0; i<4; i++)
    {
        /*for (j=0; j<3;)
        {
            if (array[j][i] == array[j+1][i])
            {
                array[j][i] = array[j][i] + array[j+1][i];
                array[j+1][i] = 0;
                j += 2;
                continue;
            }
            j++;
        }*/
        int k = 0;
        int x = 0; 
        int y = 0;
        for (j=0; j<4; j++)
        {
            if (k==array[j][i] && k!=0)
            {
                //array[x][y] = 2*array[x][y];
                //array[x][y] = 2*k;
                array[x][y] = 2*k;
                array[j][i] = 0;
                k = 0;
                continue;
            }
            if (array[j][i]!=0)
            {
                k = array[j][i];
                //此處的bug是x和y分別應該儲存j和i
                x = j;
                y = i;
            }
        }

    }

    for (i=0; i<4; i++)
    {
        int k = 0;
        for (j=0; j<4; j++)
        {
            //if (array[j][i])//此處有bug,假如k和j相等
            if (array[j][i])
            {
                if (k != j)
                {
                    array[k][i] = array[j][i];
                    array[j][i] = 0;
                }
                k++;
            }
        }
    }


    insert_num();
    system("cls");//清屏
    display();
}

void down_dir()
{
    //完成第一步
    int i,j;
    for (i=0; i<4; i++)
    {
        /*for (j=3; j>0;)
        {
            if (array[j][i] == array[j-1][i])
            {
                array[j][i] = array[j][i] + array[j-1][i];
                array[j-1][i] = 0;
                j -= 2;
                continue;
            }
            j--;
        }*/
        int k = 0;
        int x = 0; 
        int y = 0;
        for (j=3; j>=0; j--)
        {
            if (k==array[j][i] && k!=0)
            {
                array[x][y] = 2*k;
                array[j][i] = 0;
                k = 0;
                continue;
            }
            if (array[j][i]!=0)
            {
                k = array[j][i];
                x = j;
                y = i;
            }
        }
    }

    for (i=0; i<4; i++)
    {
        int k = 3;
        for (j=3; j>=0; j--)
        {
            if (array[j][i])
            {
                if (k != j)
                {
                    array[k][i] = array[j][i];
                    array[j][i] = 0;
                }
                k--;
            }
        }
    }

    insert_num();
    system("cls");//清屏
    display();
}


void left_dir()
{
    int i,j;
    for (i=0; i<4; i++)
    {
        int k = 0;
        int x = 0; 
        int y = 0;
        for (j=0; j<4; j++)
        {
            if (k==array[i][j] && k!=0)
            {
                array[x][y] = 2*k;
                array[i][j] = 0;
                k = 0;
                continue;
            }
            if (array[i][j]!=0)
            {
                k = array[i][j];
                x = i;
                y = j;
            }
        }

    }

    for (i=0; i<4; i++)
    {
        int k = 0;
        for (j=0; j<4; j++)
        {
            if (array[i][j])
            {
                if (k != j)
                {
                    array[i][k] = array[i][j];
                    array[i][j] = 0;
                }
                k++;
            }
        }
    }

    insert_num();
    system("cls");//清屏
    display();
}


void right_dir()
{
    //完成第一步
    int i,j;
    for (i=0; i<4; i++)
    {
        int k = 0;
        int x = 0; 
        int y = 0;
        for (j=3; j>=0; j--)
        {
            if (k==array[i][j] && k!=0)
            {
                array[x][y] = 2*k;
                array[i][j] = 0;
                k = 0;
                continue;
            }
            if (array[i][j]!=0)
            {
                k = array[i][j];
                x = i;
                y = j;
            }
        }
    }

    for (i=0; i<4; i++)
    {
        int k = 3;
        for (j=3; j>=0; j--)
        {
            if (array[i][j])
            {
                if (k != j)
                {
                    array[i][k] = array[i][j];
                    array[i][j] = 0;
                }
                k--;
            }
        }
    }

    insert_num();
    system("cls");//清屏
    display();
}
////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////遊戲結束////////////////////////////////////////////////////////////
//判斷遊戲結束
//將求解最大值和判斷2048糅合在一起
bool iswin()
{
    int i,j;
    for (i=0; i<4; i++)
    {
        for (j=0; j<4; j++)
        {
            if (array[i][j] == 2048)
            {
                return true;
            }
        }
    }
    return false;
}


//建構函式can_up...,不能改變全域性變數的值
//只需要兩個方向,水平或者垂直;
bool can_ver()
{
    int i,j;
    for (i=0; i<4; i++)
    {
        int k = 0;
        for (j=0; j<4; j++)
        {
            if (k==array[j][i] && k!=0)
            {
                return true;
            }
            if (array[j][i]!=0)
            {
                k = array[j][i];
            }
        }
    }
    return false;
}

bool can_hor()
{
    int i,j;
    for (i=0; i<4; i++)
    {
        int k = 0;
        for (j=3; j>=0; j--)
        {
            if (k==array[i][j] && k!=0)
            {
                return true;
            }
            if (array[i][j]!=0)
            {
                k = array[i][j];
            }
        }
    }
    return false;
}

//怎麼做到提前預判已經不能左右移動了
bool islose()
{
    int k = 0;
    zero_num(&k);
    if (k>0)
    {
        return false;
    }
    if (can_ver() || can_hor())
    {
        return false;
    }
    return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////



void main()
{
    new_game();
    int dir = 0;
    while(1)
    {
        if (iswin())
        {
            cout<<"you win"<<endl;
            break;
        }
        if (islose())
        {
            cout<<"you lose"<<endl;
            break;
        }
        dir = get_direction();
        switch(dir)
        {
        case 1: up_dir();break;
        case 2: down_dir();break;
        case 3: left_dir();break;
        case 4: right_dir();break;
        default:break;
        }
    }

    system("pause");
}

相關推薦

C++在控制檯實現2048遊戲

剛學完C++基礎,想找一個專案練練手,萌發寫一個2048的遊戲的想法,既然有想法,就是幹!!自己第一次獨立完成一個專案(也不是全部是獨立的,開始之前參考過程式碼),雖然只有幾百行程式碼,但這是一個開始,朝著自己夢想一步一個腳印。fighting!!

c++實現2048遊戲控制檯

#ifndef CGAME_H #define CGAME_H #include <windows.h> #include <String> #define ROW 4 //格子總行數 #define COLUMN 4 //格子總列數 class cGame { pub

C語言實現2048遊戲

文章目錄列印介面生成隨機數是否獲勝移動遊戲程式碼: 2048遊戲在很長一段時間內是一款很火的小遊戲。 遊戲要求: 最開始兩個隨機數 每次生成一個隨機數2或者4,生成4的概率是1/10 鍵盤上下左右鍵控制遊戲的走向 當出現2048數字時,玩家獲勝 列印介面

C語言介面實現2048遊戲

這是我在大一第二學期(兩年前)為了參加比賽,自學後寫的一個Dome,拿出來和大家分享一下,程式碼為兩年前的程式碼,未改動,優化以及各式可能很一般,請見諒。 #include "stdio.h" #include "stdlib.h" #include "time.h" #d

詳解!C語言程式設計實現遊戲“三子棋”

今天我們來程式設計實現一個充滿童趣的小遊戲“三子棋” 先來說一下三子棋的規則: 三子棋又叫九宮棋、圈圈叉叉、一條龍等。 將正方形對角線連起來,或相對兩邊依次擺上三個雙方棋子, 總之只要將自己的三個棋子走成一條線, 對方就算輸了。 不用再過多解釋了,相信大家一定都玩過! 那麼,該

C語言】實現遊戲掃雷

用C語言實現掃雷小遊戲,一共有三部分的程式碼 game.h #ifndef __GAME_H_ #define __GAME_H_ #include <stdio.h> #include <stdlib.h> #include <time.h> #def

C語言】實現遊戲三子棋

三子棋的規則:在九宮格棋盤中,只要橫、豎、對角線都能走成一條直線,就贏了。 我將實現三子棋遊戲的程式分為三個部分 第一部分:標頭檔案 game.h #ifndef _GAME_H_ #define _GAME_H_ #include <string.h> #include

C++控制檯貪吃蛇小遊戲詳細教程

遊戲截圖     開始動畫:    遊戲過程:  遊戲架構設計 該遊戲的玩法簡單,玩家通過鍵盤方向鍵控制蛇上下左右移動,吃到食物得分並增長,碰到牆或者自己的身體則死亡,遊戲結束。  整個遊戲其實就是一個無窮的迴圈,直到退出遊戲時退出迴圈

c語言簡單實現掃雷遊戲

對於掃雷遊戲,我相信每個人都玩過,大概瞭解它應有的操作和大概的原理。那我們應該怎樣著手去實現掃雷遊戲呢…… 首先對於雷陣這個介面,就想到可以定義的一個二維陣列,我們不可能把把雷的位置也顯示出來,所有需要定義2個二維陣列:mine用來佈雷,show用來顯示掃雷

c語言編寫的2048遊戲程式碼,大家可以參考一下這些

2048_launcher.c#include <stdio.h> #include <stdlib.h> #include <Windows.h> void main() { printf("正在啟動中,請稍後!\n"); Sleep(

C++實現2048遊戲控制檯版的)

無聊,在公司寫了個2048小遊戲的程式,聊以自娛。(事實是我手機壞了,沒得玩)。 很簡單,直接上程式碼了。 #include <iostream> #include <windows.h> #include <ctime> using

C++、Qt實現的小遊戲2048

圖片 explicit AC 向上 類的構造函數 += cli 而後 遊戲 窗口布局與遊戲截圖: 實現思路: 1.使用二維數組模擬整個遊戲網格,並將二維數組中每個數的大小用作遊戲中每個網格中的數據。 2.將對遊戲的數據及數據的操作(即玩家的操

c++實現2048[牛客網、控制檯]

1.前言 剛學完c++基礎,找個專案練練手,於是上牛客網找了個2048練練手,文章最後給出原始碼 2.簡介 一次只能合併相鄰的兩個數字,例如 [2 2 2 2] ,向右合併以後是 [空 空 4 4] ,不是 [空 空 空 8] 每次合併的時候,合併方向優先順序高,例如 [空

C# 控制檯實現的五子棋遊戲

今天用到陣列在控制檯做了一個五子棋遊戲,實現如下: static void Main(string[] args)        {            string[,] QP = new string[17, 17];                          

C++ 實現 2048控制檯版)

// 山寨黑框框 2048 #include #include #include using namespace std; #define rand(x) ( rand() % (x) ) #define UP 1 #define DOWN 2 #define LEFT 3 #define

2048遊戲(java控制檯-原生jdk實現)

import java.util.Random; import java.util.Scanner; public class game_2048 { public static int score = 0; public static Random random

C語言在linux終端下實現2048遊戲:第二版

原來我轉載過一個機遇ncurses的2048,今天無聊自己手寫了一個,看下我的目錄結構: $ tree ../2048/ ../2048/ ├── 2048.c ├── 2048.h └── main.c 0 directories, 3 files 2048.h

C++ 控制檯2048遊戲

先說說2048遊戲的規則: 開始的時候空格中會出現兩個數字(只能為2或者4),使用者可以選擇上下左右鍵進行移動,數字們整體沿著方向移動,中間不存在空格,如果相鄰的兩個數字相等,那麼合併至沿著方向的後一個,更新最大值,總分數加上新出現的數字。當出現2048,Win。或者沒有空

C#實現2048遊戲

要實現這個簡單的小遊戲主要在於實現一個方向移動 數字的移動及合併該如何處理 然後其它方向的邏輯是相同的 我做的這個基本功能實現了 主要分為三個類 Box.cs格子類(一些格子裡儲存的資料,行下標,列下標,是否合併過的開關。。) Grid.cs網格類(主要演算法在裡

C++練習例項———控制檯程式碼實現坦克大戰小遊戲

    坦克大戰是一款經典的遊戲,今天我來介紹一個在vs中僅用控制檯程式碼實現的坦克大戰小遊戲,在很多學校裡作為一個面對物件程式設計的大作業,對於學習C++的多型性很有幫助。程式的架構思路由老師提供,遊戲中用到了EasyX圖形庫,這個庫非常小巧輕便,下載地址:https://