俄羅斯方塊,機器人設計

前不久收拾臺式機,
發現些東東,
以前寫的小程序:俄羅斯方塊,
於是打開玩了會,
看到界面相當醜,
於是想再改一下,
打開源代碼,驚奇的發現,
代碼中定義了一個機器人的抽象類,
但真正處理玩遊戲的方法並沒有實現,
於是我就想實現這個方法,
做一個機器人,
在做這個機器人時,想了很多辦法,
但最後只實現了一個很簡單的算法,
這個機器人還不怎麼智能.
先把代碼發在這,以後有時間再改進改進!
沒地方發代碼,需要的向vipexxe at 126 dot com 發郵件
我的機器人:

package com.bokee.nicend.boxgame.main;

import com.bokee.nicend.boxgame.game.Box;
import com.bokee.nicend.boxgame.gui.GamePanel;
import com.bokee.nicend.boxgame.robot.AbstractGamePanel;
import com.bokee.nicend.boxgame.robot.Step;

public class MyRobot extends Robot {
    public MyRobot(GamePanel panel) {
        super(panel);
    }

    @Override
    public void doBox(Box box) {
        方案1(getData(), box, true);
    }

    /**
     * @param data
     *            環境數據
     * @param box
     *            當前要處理的方塊
     * @param canDepth 是否允許遞歸判斷下一個方塊信息
     */
    private Step 方案1(boolean[][] data, Box box, boolean canDepth) {
        Box boxBack = box.copy();// 備份原方塊信息
        Box minBox = box.copy();// 最少空格時的方塊信息
        /**
         * 最優化方法
         */
        Step bestStep = new Step();
        /**
         * 綜合兩次的最優方法
         */
        Step bestTwoStep = new Step();

        boolean[][] dataBack = copyData(data);// 備份環境數據

        // 虛擬遊戲
        AbstractGamePanel abstractGamePanel = new AbstractGamePanel();

        // 此方塊的 每種變形 遍歷
        for (int j = 0; j < 4; j++) {
            // 按每個X座標 遍歷
            for (int i = 0; i <= getGamePanelWidth() - box.getBoxWidth(); i++) {
                // 設置方塊位置
                box.setPoint(i, /* 0-box.getBoxHeight() */0);
                // 設置虛擬遊戲環境
                abstractGamePanel.setData(data);
                abstractGamePanel.setBox(box);

                while (abstractGamePanel.moveDown())
                    ;

                Step currentStep = new Step();
                currentStep.setChage(j);
                currentStep.setX(box.getX());

                currentStep.setLine(abstractGamePanel.getDisponseLineNumber());
                currentStep.setRectCount(abstractGamePanel.getSpaceRectInBoxsHeight());
                currentStep.setHeight(data.length - abstractGamePanel.getRectHeight() - currentStep.getLine());
                currentStep.setSpaceCount(abstractGamePanel.getSpaceCountInBoxsHeight());
                currentStep.setSpaceNumber(abstractGamePanel.getLineSpaceNumber());

                if (canDepth) {
                    Box nextBox = box.willNext();
                    Step currnetNextBestStep = 方案1(copyData(data), nextBox, false);
                    // 兩步總共消去的行數
                    currnetNextBestStep.setLine(currnetNextBestStep.getLine() + currentStep.getLine());
                    if (currnetNextBestStep.compareTo(bestTwoStep) > 0) {
                        bestTwoStep = currnetNextBestStep;
                        bestStep = currentStep;
                        minBox = box.copy();
                    }
                } else {
                    if (currentStep.compareTo(bestStep) > 0) {
                        bestStep = currentStep;
                        bestTwoStep = currentStep;
                        minBox = box.copy();
                    }
                }
                data = copyData(dataBack);
            }
            // 方塊變形 進入下一個循環
            box.chang();
        }

        if (canDepth) {
            int x = minBox.getX();
            for (int i = 0; i < bestStep.getChage(); i++)
                moveUp();
            for (int i = 0; x < boxBack.getX() - i; i++)
                moveLeft();
            for (int i = 0; boxBack.getX() + i < x; i++)
                moveRight();
        }
        return bestStep;
    }

    private boolean[][] copyData(boolean[][] data) {
        return GamePanel.copyData(data);
    }
}

如果你覺得有趣,也可以自己繼承Roboot類,實現一個自己的機器人,
看看我們的機器人,哪個的更優化.
機器人用於計算的虛擬遊戲環境

package com.bokee.nicend.boxgame.robot;

import java.awt.Point;
import java.util.LinkedList;
import java.util.List;

import com.bokee.nicend.boxgame.game.Box;

/**
* 虛擬遊戲
* @author Butnet
*/
public class AbstractGamePanel {
    /**
     * 遊戲環境數據
     */
    private boolean[][] space = null;
    /**
     * 當前的方塊
     */
    private Box box = null;

    public Box getBox() {
        return box;
    }

    public void setBox(Box box) {
        this.box = box;
    }

    public void setData(boolean[][] data) {
        this.space = data;
    }

    public boolean[][] getData() {
        return space;
    }

    /**
     * 將方塊b設置爲不能移動
     * @param b
     */
    public void setNoMove(Box b) {
        if (b.getY() + b.getBoxHeight() > space.length)
            return;
        int[][] d = b.getPoints();
        for (int i = 0; i < d.length; i++) {
            if (b.getY() + d[i][1] < 0 || b.getX() + d[i][0] < 0)
                continue;
            space[b.getY() + d[i][1]][b.getX() + d[i][0]] = false;
        }
    }

    /**
     * 在虛擬遊戲中把當前方塊向下移動
     * @return 返回移動成功返回true,不能移動返回false
     */
    public boolean moveDown() {
        if (!canDown()) {
            setNoMove(box);
            return false;
        }
        if (box.getY() + box.getBoxHeight() == space.length) {
            setNoMove(box);
            return false;
        }
        box.setY(box.getY() + 1);
        return true;
    }

    /**
     * 判斷當前方塊是否能下移
     * @return
     */
    private boolean canDown() {
        int[][] ps = box.getPoints();
        for (int i = 0; i < ps.length; i++) {
            if (box.getY() + 1 + ps[i][1] >= space.length)
                return false;
            if (!space[box.getY() + 1 + ps[i][1]][box.getX() + ps[i][0]])
                return false;
        }
        return true;
    }

    /**
     * 用每行的空格生成一個數值,用於優化判斷
     * @return
     */
    public int getLineSpaceNumber() {
        int index = getRectHeight() - 1;
        if (index == -1)
            return 0;
        int re = 0;
        for (int i = index; i < space.length; i++) {
            int line = 0;
            for (int j = 0; j < space[i].length; j++)
                if (space[i][j])
                    line++;
            re = re * 10 + line;
        }
        return re;
    }

    /**
     * 取得消取的行數
     *
     * @return
     */
    public int getDisponseLineNumber() {
        int index = getRectHeight() - 1;
        if (index == -1)
            return 0;
        int line = 0;
        for (int i = index; i < space.length; i++) {
            boolean is = true;
            for (int j = 0; j < space[i].length; j++) {
                if (space[i][j]) {
                    is = false;
                    break;
                }
            }
            if (is)
                line++;
        }
        return line;
    }

    /**
     * 點數 下邊的方塊矩形中爲空的空格個數
     *
     * @return
     */
    public int getSpaceCountInBoxsHeight() {
        // TEST CASE 2
        int allSpaceCount = 0;
        for (int col = 0; col < space[0].length; col++) {
            boolean start = false;
            for (int row = 0; row < space.length; row++) {
                if (!start) {
                    if (!space[row][col])
                        start = true;
                    continue;
                }
                if (space[row][col])
                    allSpaceCount++;
            }
        }
        if (1 == 1)
            return allSpaceCount;

        // TEST CASE 1
        int topIndex = -1;
        for (int i = 0; i < space.length; i++) {
            for (int j = 0; j < space[i].length; j++) {
                if (!space[i][j]) {
                    topIndex = i;
                    break;
                }
            }
            if (topIndex != -1)
                break;
        }
        if (topIndex == -1)
            return 0;
        int count = 0;
        for (int i = topIndex; i < space.length; i++) {
            for (int j = 0; j < space[i].length; j++) {
                if (space[i][j])
                    count++;
            }
        }
        return count;
    }

    /**
     * 返回 下邊方塊形成的空格區域個數
     *
     * @return
     */
    public int getSpaceRectInBoxsHeight() {
        int topIndex = -1;
        for (int i = 0; i < space.length; i++) {
            for (int j = 0; j < space[i].length; j++) {
                if (!space[i][j]) {
                    // System.out.println("i="+i+", j="+j);
                    // System.out.println("Box.X="+box.getX()+"
                    // Box.Y="+box.getY());
                    topIndex = i;
                    break;
                }
            }
            if (topIndex != -1)
                break;
        }
        if (topIndex == -1)
            return 0;

        List<Point> ps = new LinkedList<Point>();
        for (int i = topIndex; i < space.length; i++) {
            for (int j = 0; j < space[i].length; j++) {
                if (space[i][j]) {
                    ps.add(new Point(i, j));
                }
            }
        }
        // TODO: 返回 下邊方塊形成的空格區域個數
        List<List<Point>> rects = new LinkedList<List<Point>>();
        for (int i = 0; i < ps.size(); i++) {
            Point p = ps.get(i);
            List<Point> rect = null;
            boolean add = false;
            for (List<Point> r : rects) {
                if (r.contains(new Point(p.x - 1, p.y)))
                    r.add(p);
                else if (r.contains(new Point(p.x + 1, p.y)))
                    r.add(p);
                else if (r.contains(new Point(p.x, p.y - 1)))
                    r.add(p);
                else if (r.contains(new Point(p.x, p.y + 1)))
                    r.add(p);
                else if (r.contains(p))
                    ;
                else
                    continue;
                add = true;
                break;
            }
            if (add)
                continue;
            rect = new LinkedList<Point>();
            rects.add(rect);
            rect.add(p);
        }
        // 返回區域個數
        return rects.size();
    }

    /**
     * 判斷不能移動的方塊組成的高度
     * @return
     */
    public int getRectHeight() {
        int topIndex = -1;
        for (int i = 0; i < space.length; i++) {
            for (int j = 0; j < space[i].length; j++) {
                if (!space[i][j]) {
                    topIndex = i;
                    break;
                }
            }
            if (topIndex != -1)
                break;
        }
        return topIndex + 1;
    }
}

用於機器人比較優劣的步驟類:

package com.bokee.nicend.boxgame.robot;

/**
* 保存機器人每步的結果
*
* @author Butnet
*/
public class Step {
    /**
     * 此時的方塊變形次數
     */
    int chage = 0;
    /**
     * 此時方塊的X座標
     */
    int x = 0 ;
    /**
     * 空格的個數
     */
    int spaceCount = 0;//1
    /**
     * 空格形成的連續區域個數
     */
    int rectCount = 0;//
    /**
     * 結果在區域中的高度
     */
    int height = 0;//2
    /**
     * 每行中空格形成的數值
     */
    int spaceNumber = 0;//
    /**
     * 這一步所得到的權值
     */
    int roleValue = 0;
    /**
     * 這一步消去的方塊行數
     */
    int line = 0;//0
    /**
     * 以最壞情況構造一個步驟
     */
    public Step() {
        chage = 0;
        x = 0;
        spaceCount = Integer.MAX_VALUE;
        rectCount = Integer.MAX_VALUE;
        height = Integer.MAX_VALUE;
        spaceNumber = Integer.MAX_VALUE;
        roleValue = Integer.MIN_VALUE;
    }

    public int getSpaceCount() {
        return spaceCount;
    }

    public int getSpaceNumber() {
        return spaceNumber;
    }
    public int getHeight() {
        return height;
    }
    public int getLine() {
        return line;
    }
    public int getRectCount() {
        return rectCount;
    }
    public int getRoleValue() {
        return roleValue;
    }

    public void setSpaceCount(int spaceCount) {
        this.spaceCount = spaceCount;
    }

    public void setRectCount(int rectCount) {
        this.rectCount = rectCount;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void setSpaceNumber(int spaceNumber) {
        this.spaceNumber = spaceNumber;
    }

    public void setRoleValue(int roleValue) {
        this.roleValue = roleValue;
    }

    public void setLine(int line) {
        this.line = line;
    }

    public int getChage() {
        return chage;
    }

    public void setChage(int chage) {
        this.chage = chage;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }
    /**
     * 比較兩個步驟的優劣
     * @return 如果更優化返回 1 相同返回 0 落後返回 -1
     * */
    public int compareTo(Step step){
        if(line>step.line)
            return 1;
        if(line==step.line){
            if(spaceCount<step.spaceCount)
                return 1;
            if(spaceCount==step.spaceCount){
                if(height<step.height)
                    return 1;
                if(height==step.height){
                    if(rectCount<step.rectCount)return 1;
                    if(rectCount==step.rectCount){
                        if(spaceNumber<step.spaceNumber)return 1;
                        if(spaceNumber==step.spaceNumber)return 0;
                        return -1;
                    }
                    return -1;
                }
                return -1;
            }
            return -1;
        }
        return -1;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章