程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 編程之美1.17——俄羅斯方塊游戲

編程之美1.17——俄羅斯方塊游戲

編輯:C++入門知識

問題:
讓電腦自動下俄羅斯方塊游戲。

解法:
對當前的積木塊,枚舉它旋轉後的每一個形狀從每一列落下的棋盤,將該棋盤和前一個棋盤進行對比,並打分,最後取得分最高的那個形狀和那一列作為電腦的當前操作。(鑒於有讀者不會用這個程序,在此說明下,運行這個程序需要加上文件重定向<1_17.txt,或者把程序中的控制台輸入scanf改成文件輸入FILE* fin=fopen("1_17.txt"); fscanf(fin,"%d",...);)

[cpp] 
#include <iostream> 
#include <algorithm> 
#include <cstdlib> 
#include <ctime> 
using namespace std; 
 
// 積木塊的信息 
#define BLOCK_SIZE  7 
#define ROTATE_SIZE 4 
#define SIDE_LEN    4 
const int BLOCK_AREA = SIDE_LEN*SIDE_LEN; 
// 棋盤的信息 
#define HORIZ_LEN   12 
#define VERT_LEN    15 
const int CHESS_AREA = HORIZ_LEN*VERT_LEN; 
// 其它信息 
#define TOP_STEP    25 
#define inf         10000 
// 計分信息 
const int clearLineScore[] = {0, 1, 3, 7, 13}; 
 
struct Block    // 積木塊 

    void init(unsigned char *l)  
    { 
        memcpy(layout, l, BLOCK_AREA); 
        int i, j; 
        for (i=0; i<SIDE_LEN; i++) 
        { 
            for (j=SIDE_LEN-1; j>=0 && layout[j*SIDE_LEN+i]==0; j--); 
            maxRow[i] = j+1; 
        } 
        for(i=0; i<SIDE_LEN && maxRow[i]==0; i++); 
        minCol = i; 
        for (i=SIDE_LEN-1; i>=0 && maxRow[i]==0; i--); 
        maxCol = i; 
    } 
    unsigned char layout[BLOCK_AREA];   // 積木塊的布局 
    unsigned char maxRow[SIDE_LEN];     // 積木塊每一列所占區域的最大行,取值從1開始 
    unsigned char minCol;               // 積木塊所占區域的最小值列和最大列,取值從0開始 
    unsigned char maxCol; 
}; 
 
Block blockSet[BLOCK_SIZE][ROTATE_SIZE];    // 7種積木塊,每種積木塊有4種旋轉方向 
unsigned char chess[CHESS_AREA];        // 棋盤的布局 
unsigned char nextChess[CHESS_AREA];    // 下一步棋盤的布局 
int height[HORIZ_LEN];                  // 棋盤每一列所占區域的最小行,即高度 
 
void calcHeight(unsigned char *curchess)    // 計算當前棋盤的高度信息 

    int i, j; 
    for (i=0; i<HORIZ_LEN; i++) 
    { 
        for (j=0; j<VERT_LEN && curchess[j*HORIZ_LEN+i]==0; j++); 
        height[i] = j; 
    } 

 
// 計算若積木塊從offsetX列落下,會落在第幾行,即offsetY 
int calcBottomOffsetY(const Block& b, int offsetX)   

    int offsetY = VERT_LEN; 
    for (int i=0; i<SIDE_LEN; i++) 
    { 
        if (b.maxRow[i]==0) continue; 
        offsetY = min(offsetY, height[offsetX+i]-b.maxRow[i]); 
    } 
    return offsetY; 

 
// 將積木塊貼到棋盤上 
void pasteTo(unsigned char *curchess, const Block& b, 
    int offsetX, int offsetY) 

    for (int i=b.minCol; i<=b.maxCol; i++) 
        for (int j=0; j<SIDE_LEN; j++) 
        { 
            unsigned char bij = b.layout[j*SIDE_LEN + i]; 
            unsigned char& cij = curchess[(j+offsetY)*HORIZ_LEN + i+offsetX]; 
            if (bij && cij==0) 
                cij = bij; 
            else if (bij && cij) 
                cout << "ERROR" << endl; 
        } 

 
// 消去[offsetY,offsetY+SIDE_LEN)中remline為1的行 
void clearLines(unsigned char *curchess, int offsetY, unsigned char *remline) 

    int i, j, gap=0; 
    for (j=offsetY+SIDE_LEN-1; j>=0; j--) 
    { 
        if (j-offsetY>=0 && remline[j-offsetY]) 
            gap++; 
        else if (gap) 
        { 
            memcpy(curchess+(j+gap)*HORIZ_LEN, curchess+j*HORIZ_LEN, HORIZ_LEN); 
        } 
    } 

 
// 計算[offsetX,offsetX+SIDE_LEN)列的洞的個數 
int calcHoles(unsigned char *curchess, int offsetX, int offsetY) 

    int i, j; 
    int holeCount = 0; 
    for (i=offsetX; i<offsetX+SIDE_LEN; i++) 
    { 
        if (i<0 || i>=HORIZ_LEN) continue; 
        for (j=offsetY; j<VERT_LEN && curchess[j*HORIZ_LEN+i]==0; j++); 
        for (; j<VERT_LEN; j++) 
            if (curchess[j*HORIZ_LEN+i]==0) 
                holeCount++; 
    } 
    return holeCount; 

 
// 計算當前棋盤的得分 
int calcScore(unsigned char *curchess, int offsetX, int offsetY) 

    int i, j, score = 0; 
    int remlineCount = 0; 
    unsigned char remline[SIDE_LEN] = {0}; 
    // 統計消行數 
    for (j=offsetY; j<offsetY+SIDE_LEN; j++) 
    { 
        for (i=0; i<HORIZ_LEN && curchess[j*HORIZ_LEN+i]; i++); 
        if (i==HORIZ_LEN)  
        { 
            remlineCount++; 
            remline[j-offsetY] = 1; 
        } 
    } 
    score += clearLineScore[remlineCount]; 
    // 統計洞的個數 
    if (remlineCount) 
        clearLines(curchess, offsetY, remline); 
    int holeCount = calcHoles(curchess, offsetX, offsetY) -  
                    calcHoles(chess, offsetX, offsetY); 
    score -= holeCount*4; 
    // 位置過高則扣分 
    if (holeCount > 5) score -= 15; 
    if (offsetY-remlineCount < VERT_LEN*3/5) 
        score -= VERT_LEN*3/5-(offsetY-remlineCount); 
    return score; 

 
void output(unsigned char *curchess) 

    for (int j=0; j<VERT_LEN; j++) 
    { 
        for (int i=0; i<HORIZ_LEN; i++) 
            cout << curchess[j*HORIZ_LEN+i] << " "; 
        cout << endl; 
    } 

 
int main() 

    srand(time(0)); 
    int i, j, k, n, m; 
    // 初始化積木塊 
    for (i=0; i<BLOCK_SIZE; i++) 
        for (j=0; j<ROTATE_SIZE; j++) 
        { 
            unsigned char l[BLOCK_AREA]; 
            for (k=0; k<BLOCK_AREA; k++) 
                scanf("%d",&l[k]); 
            blockSet[i][j].init(l); 
        } 
    // 初始化棋盤 
    for (i=0; i<CHESS_AREA; i++) 
        scanf("%d",&chess[i]); 
    // 顯示前TOP_STEP步 
    int offsetX, offsetY; 
    unsigned char tmpchess[CHESS_AREA]; 
    for (n=TOP_STEP; n>=0; n--) 
    { 
        output(chess); 
        calcHeight(chess);  // 為每一步計算一次height數組,避免計算offsetY時過多的重復計算 
        int bind = rand()%BLOCK_SIZE;   // 積木塊的序號 
        int maxScore = -inf; 
        for (j=0; j<ROTATE_SIZE; j++)    // 要考慮積木塊的各種旋轉情況 
        { 
            const Block& b = blockSet[bind][j];     // 得到當前的積木塊 
            for (offsetX=-b.minCol; offsetX<HORIZ_LEN-b.maxCol; offsetX++) 
            { 
                // 計算從offsetX列落下,所落在棋盤的位置offsetY 
                offsetY = calcBottomOffsetY(b, offsetX); 
                if (offsetY<0) continue; 
                memcpy(tmpchess, chess, CHESS_AREA); 
                pasteTo(tmpchess, b, offsetX, offsetY); // 在棋盤中添加積木塊 
                int curScore = calcScore(tmpchess, offsetX, offsetY);   // 計算當前情況下的得分 
                if (curScore > maxScore) 
                { 
                    maxScore = curScore;  www.2cto.com
                    memcpy(nextChess, tmpchess, CHESS_AREA); 
                } 
            } 
        } 
        memcpy(chess, nextChess, CHESS_AREA); 
    } 


 

作者:linyunzju

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved