俄羅斯方塊的源碼實現

問題概述

  1. 這是一個使用java swing實現的小遊戲,和之前的貪吃蛇以及五子棋類似,閒來無聊的作品,不過,這次的作品相較於前兩個遊戲在代碼水平有很大的提高,結論是,編程能力的提高是寫更多的代碼寫出來的,不是看一系列的書籍看出來的

  2. 代碼部分經過一天的清明節假期,只是雛形漸漸出現,還有很多的細節需要推敲。比如,消行的這個問題,遍歷數據,原則上從下邊一行開始消除,也就是逆向,然後將上邊的內容依次下移。

  3. 如果使用二維數組的遍歷,需要每次都要訪問全局數據,鄙人採用了傳入局部數據方法。

  4. 使用了工廠設計模式,對多種形狀做繼承處理。

  5. 提取一些簡易的數據結構,作爲輔助類(工具類使用)。

代碼完成及問題的結局

  1. 實際的開發工作所用時間從週末到週三的晚上,大約四天的功夫,當然不是說完整的四天都在編寫代碼。畢竟還要上班,只是閒暇的時間來做這部分工作。

  2. 關於上邊提到的問題的解決,採用的方式是循環掃描,這種最簡單的方案,如果有一行掃描需要消行,在消行之後需要重新進行掃描,這是最關鍵的一點。

  3. 代碼部分少不了對諸多方塊圖形的描述,也就是需要很多枚舉類型的參與,並且需要對某一類圖形的子狀態作進一步的描述,也就是需要一種“繼承”的枚舉類型,參照了《Java編程思想》關於枚舉這一部分的講述。

  4. 關於圖形的移動,需要判定是否可以作相應的移動,包括向左,向右,以及向下,判斷需要考慮俄羅斯方塊最外邊的框,以及現有的圖形是否對能移動的圖形有遮擋。

  5. 圖形的類使用了繼承的方法,也就是使用工廠的模式。

  6. 關於圖形子狀態的相互轉換,使用了策略模式,也就對不同的圖形採用差異化的變形方法。

  7. 圖形子狀態的改變可以考慮設計模式的職責鏈,或者狀態模式,本代碼沒有采用相應的實現。

  8. 完整的代碼可以看文章最後的博客地址。

程序最終效果圖

俄羅斯方塊


代碼部分

代碼還不完整,只能實現一些基本的功能,並且沒有經過完整,全面的測試,另外俄羅斯方塊的所有形狀還沒有添加完全。希望讀者斧正。感謝有你。

代碼已經完整了。剩下的就是重構代碼。加入一些新的圖形極其子狀態。


com.game

Teris.java

package com.game;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

import com.game.shape.Shape;
import com.game.state.ShapeEnum;
import com.game.util.Enums;
import com.game.util.SameRow;
import com.game.util.Utils;

public class Teris extends JFrame {

    /**
     * This is the main GUI of Teris, which the code executed.
     */
    private static final long serialVersionUID = 1L;
    private int row;
    private int column;
    private JPanel mainframe;
    private JPanel control;
    private BorderLayout border;
    private FlowLayout flow;
    private JButton start;
    private JButton exit;
    private TerisPanel board;
    private List<Point> data;
    private ActionListener actionlistener;
    private KeyAdapter keylistener;
    private ActionListener timelistener;
    private Timer time;
    private int speed;
    private JTextField score;
    private Shape shape;
    private int limitTop;
    private SameRow sameRow;

    public Teris(String title, int row, int column) {
        super(title);
        this.row = row;
        this.column = column;
        initial();
        setSize(300, (int) (300 * this.row * 1.0 / this.column));
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationByPlatform(true);
        this.setVisible(true);
        this.requestFocus();
    }

    private void initial() {
        data = new ArrayList<Point>();
        speed = 1000;
        limitTop = row;
        sameRow = new SameRow();
        loadShape();
        createComponent();
        layOut();
        listeners();
    }

    private void createComponent() {
        start = new JButton("Start");
        exit = new JButton("Exit");
        mainframe = new JPanel();
        control = new JPanel();
        border = new BorderLayout();
        board = new TerisPanel(data, row, column);
        flow = new FlowLayout();
        score = new JTextField();
        score.setEditable(false);
    }

    private void layOut() {
        getContentPane().add(mainframe);
        mainframe.setLayout(border);
        mainframe.add(control, BorderLayout.NORTH);
        control.setLayout(flow);
        control.add(start);
        control.add(score);
        control.add(exit);
        score.setPreferredSize(new Dimension(70, 30));
        score.setText("0");
        mainframe.add(board, BorderLayout.CENTER);
    }

    private void listeners() {
        /*
         * action listener for the button of start)(for start) and end(for exit)
         */
        actionlistener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String command = e.getActionCommand();
                if (command.equals("Exit")) {
                    System.exit(0);
                } else if (command.equals("Start")) {
                    time.start();
                    requestFocus();
                }
            }
        };
        /*
         * The keyboard listener to direction key(the key in here is you can not
         * get the reverse direction) and speed key(w for high speed, s for low
         * speed).
         */
        keylistener = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int code = e.getKeyCode();
                if (code == KeyEvent.VK_LEFT) {
                    shiftLeft();
                } else if (code == KeyEvent.VK_RIGHT) {
                    shiftRight();
                } else if (code == KeyEvent.VK_UP) {
                    speed += 100;
                    time.setDelay(speed);
                    System.out.println(speed);
                } else if (code == KeyEvent.VK_DOWN) {
                    speed -= 100;
                    speed = 0 == speed ? 100 : speed;
                    time.setDelay(speed);
                    System.out.println(speed);
                } else if (code == KeyEvent.VK_SPACE) {
                    changeShape();
                } else {
                }
            }
        };
        timelistener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move();
                repaint();
            }
        };
        /**
         * here set the timer to the speed of 1 grid/sec
         */
        time = new Timer(speed, timelistener);
        this.addKeyListener(keylistener);
        start.addActionListener(actionlistener);
        exit.addActionListener(actionlistener);
    }

    protected boolean shiftLeft() {
        shape.ShiftLeft();
        boolean canShiftLeft = !Utils.hasSamePoint(data);
        if (!canShiftLeft) {
            shape.ShiftRight();
        }
        return canShiftLeft;
    }

    protected boolean shiftRight() {
        shape.ShiftRight();
        boolean canShiftRight = !Utils.hasSamePoint(data);
        if (!canShiftRight) {
            shape.ShiftLeft();
        }
        return canShiftRight;
    }

    protected boolean changeShape() {
        try {
            shape.changeShape();
        } catch (Exception e) {
            e.printStackTrace();
        }
        boolean canChangeShape = !Utils.hasSamePoint(data);
        for (Point item : shape.getData()) {
            if (item.x >= row || item.y >= column || item.x < 0 || item.y < 0) {
                canChangeShape = false;
                System.out.println("Care");
                break;
            }
        }
        if (!canChangeShape) {
            try {
                shape.unChangeShape();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return canChangeShape;
    }

    private void move() {
        if (isAlive()) {
            if (isMoveFinished()) {
                updateLimitTop();
                updateScore(); // 消方塊
                loadShape();
                speed = 1000;
                time.setDelay(speed);
            } else {
                shape.ShiftDown();
            }
        } else {
            time.stop();
            // JOptionPane.showMessageDialog(this, "You Lose! Come on!");
            int choice = JOptionPane.showConfirmDialog(this, "try again!", "Message", JOptionPane.YES_NO_OPTION);
            if (JOptionPane.YES_OPTION == choice) {
                /**
                 * ready for the restart the game.
                 */
                score.setText("0");
            }
        }
    }

    private void updateScore() {
        int counter = 0;
        for (int i = row - 1; i >= 0; i--) {
            for (Point item : data) {
                if (i == item.x) {
                    counter++;
                }
            }
            if (column == counter) {
                sameRow.setRow(i);
                data.removeIf(sameRow);
                score.setText(String.valueOf(Integer.valueOf(score.getText()) + 1));
                moveTopToBelow(i);
                /*
                 * here need to Re-scanning the row of i to be sure whether
                 * there is exist another row can collapsed.
                 */
                i++;
            }
            counter = 0;
        }
    }

    private void updateLimitTop() {
        for (Point item : data) {
            limitTop = Math.min(limitTop, item.x);
        }
    }

    private void moveTopToBelow(int i) {
        for (Point item : data) {
            if (item.x < i) {
                item.x++;
            }
        }
    }

    /*
     * This method should check whether the game can go on. same with
     * canShiftDown function.
     */
    private boolean isAlive() {
        return limitTop > 0;
    }

    /*
     * This method will check whether single move is overd. no data overlapped.
     */
    private boolean isMoveFinished() {
        boolean flag = false;
        if (shape.ShiftDown()) {
            flag = Utils.hasSamePoint(data);
            shape.ShiftUp();
        } else {
            flag = true;
        }
        return flag;
    }

    private void loadShape() {
        shape = Utils.makeShape(Enums.random(ShapeEnum.class), row, column);
        int shiftToCenter = column / 2 - shape.getCenterOfShape();
        for (int i = 0; i < shiftToCenter; i++) {
            shape.ShiftRight();
        }
        data.addAll(shape.getData());
    }

    public static void main(String[] args) {
        new Teris("test", 50, 25);
    }

}

TerisPanel.java

package com.game;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.List;

import javax.swing.JPanel;

/**
 * in this file draw the background and the moving snake.
 */
public class TerisPanel extends JPanel {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private int row;
    private int column;
    private List<Point> data;

    public TerisPanel() {
        this(null, 20, 10);
    }

    public TerisPanel(List<Point> data, int row, int column) {
        if (data == null) {
            try {
                throw new Exception("The List<Point> should not be null, which can be empty.");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        this.data = data;
        this.row = row;
        this.column = column;
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D gg = (Graphics2D) g;
        int squre = (this.getWidth() - 50) / column;
        /**
         * from the point (25, 10) draw the game's background.
         */
        /*
         * below draw the background gird.
         */
        int x = 25;
        int y = 10;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                gg.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f,
                        new float[] { 5f, 5f }, 0f));
                gg.setColor(Color.yellow);
                gg.drawRect(x + j * squre, y + i * squre, squre, squre);
            }
        }

        /*
         * draw the russia squre which meaningful to game.
         */
        for (Point item : data) {
            gg.setColor(Color.GREEN);
            gg.fillRect(x + item.y * squre, y + item.x * squre, squre, squre);
        }

        gg.setStroke(new BasicStroke(5f));
        gg.setColor(Color.blue);
        gg.drawRect(24, 9, squre * column + 2, squre * row + 2);
        gg.dispose();
    }
}

com.game.shape

Shape.java

package com.game.shape;

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

public abstract class Shape {
    protected List<Point> data;
    private int limitLeft;
    private int limitRight;
    private int limitBelow;
    private int limitTop;
    private int row;
    private int column;
    private int centerOfShape;

    public Shape(List<Point> data, int row, int column) {
        this.data = data;
        this.row = row;
        this.column = column;
        initialLimits();
        getLimits();
    }

    public void initialLimits() {
        limitLeft = column;
        limitRight = -1;
        limitBelow = -1;
        limitTop = row;
    }

    public void getLimits() {
        int sum = 0;
        for (Point item : data) {
            limitLeft = Math.min(limitLeft, item.y);
            limitRight = Math.max(limitRight, item.y);
            limitTop = Math.min(limitTop, item.x);
            limitBelow = Math.max(limitBelow, item.x);
            sum += item.y;
        }
        centerOfShape = sum / data.size();
    }

    public boolean ShiftLeft() {
        if (0 == limitLeft) {
            return false;
        }
        limitLeft--;
        limitRight--;
        for (Point item : data) {
            item.y = item.y - 1;
        }
        return true;
    }

    public boolean ShiftRight() {
        if (column - 1 == limitRight) {
            return false;
        }
        limitLeft++;
        limitRight++;
        for (Point item : data) {
            item.y = item.y + 1;
        }
        return true;
    }

    public boolean ShiftDown() {
        if (row - 1 == limitBelow) {
            return false;
        }
        limitTop++;
        limitBelow++;
        for (Point item : data) {
            item.x = item.x + 1;
        }
        return true;
    }

    public boolean ShiftUp() {
        limitTop--;
        limitBelow--;
        for (Point item : data) {
            item.x = item.x - 1;
        }
        return true;
    }

    public List<Point> getData() {
        return data;
    }

    public void setData(List<Point> data) {
        this.data = data;
    }

    public int getCenterOfShape() {
        return centerOfShape;
    }

    abstract public boolean changeShape() throws Exception;

    abstract public boolean unChangeShape() throws Exception;
}

SqureShape.java

package com.game.shape;

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

public class SqureShape extends Shape {

    /*
     * The shape is below: ** **
     */
    public SqureShape(List<Point> data, int row, int column) {
        super(data, row, column);
    }

    @Override
    public boolean changeShape() {
        return true;
    }

    @Override
    public boolean unChangeShape() {
        return true;
    }

}

LongShape.java

package com.game.shape;

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

import com.game.state.ShapeInterface.LONG;

public class LongShape extends Shape {
    private LONG state;

    public LongShape(List<Point> data, int row, int column) {
        super(data, row, column);
        state = LONG.HORIZONTAL;
    }

    @Override
    public boolean changeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case HORIZONTAL:
            data.get(0).setLocation(point.x - 2, point.y);
            data.get(1).setLocation(point.x - 1, point.y);
            data.get(3).setLocation(point.x + 1, point.y);
            state = LONG.VERTICAL;
            break;
        case VERTICAL:
            data.get(0).setLocation(point.x, point.y - 2);
            data.get(1).setLocation(point.x, point.y - 1);
            data.get(3).setLocation(point.x, point.y + 1);
            state = LONG.HORIZONTAL;
            break;
        default:
            throw new Exception("sth wrong here LongShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

    @Override
    public boolean unChangeShape() throws Exception {
        try {
            changeShape();
            return false;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

}

TriangleShape.java

package com.game.shape;

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

import com.game.state.ShapeInterface.TRIANGLE;

public class TriangleShape extends Shape {
    private TRIANGLE state;

    public TriangleShape(List<Point> data, int row, int column) {
        super(data, row, column);
        state = TRIANGLE.TOP;
    }

    @Override
    public boolean changeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case TOP:
            data.get(0).setLocation(point.x, point.y + 1);
            data.get(1).setLocation(point.x - 1, point.y);
            data.get(3).setLocation(point.x + 1, point.y);
            state = TRIANGLE.RIGHT;
            break;
        case RIGHT:
            data.get(0).setLocation(point.x + 1, point.y);
            data.get(1).setLocation(point.x, point.y + 1);
            data.get(3).setLocation(point.x, point.y - 1);
            state = TRIANGLE.DOWN;
            break;
        case DOWN:
            data.get(0).setLocation(point.x, point.y - 1);
            data.get(1).setLocation(point.x + 1, point.y);
            data.get(3).setLocation(point.x - 1, point.y);
            state = TRIANGLE.LEFT;
            break;
        case LEFT:
            data.get(0).setLocation(point.x - 1, point.y);
            data.get(1).setLocation(point.x, point.y - 1);
            data.get(3).setLocation(point.x, point.y + 1);
            state = TRIANGLE.TOP;
            break;
        default:
            throw new Exception("sth wrong here : TriangleShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

    @Override
    public boolean unChangeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case TOP:
            data.get(0).setLocation(point.x, point.y - 1);
            data.get(1).setLocation(point.x + 1, point.y);
            data.get(3).setLocation(point.x - 1, point.y);
            state = TRIANGLE.LEFT;
            break;
        case RIGHT:
            data.get(0).setLocation(point.x - 1, point.y);
            data.get(1).setLocation(point.x, point.y - 1);
            data.get(3).setLocation(point.x, point.y + 1);
            state = TRIANGLE.TOP;
            break;
        case DOWN:
            data.get(0).setLocation(point.x, point.y + 1);
            data.get(1).setLocation(point.x - 1, point.y + 1);
            data.get(3).setLocation(point.x + 1, point.y - 1);
            state = TRIANGLE.RIGHT;
            break;
        case LEFT:
            data.get(0).setLocation(point.x + 1, point.y);
            data.get(1).setLocation(point.x, point.y + 1);
            data.get(3).setLocation(point.x, point.y - 1);
            state = TRIANGLE.DOWN;
            break;
        default:
            throw new Exception("sth wrong here : TriangleShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

}

SevenShape.java

package com.game.shape;

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

import com.game.state.ShapeInterface.SEVEN;

public class SevenShape extends Shape {
    private SEVEN state;

    public SevenShape(List<Point> data, int row, int column) {
        super(data, row, column);
        state = SEVEN.LEFT;
    }

    @Override
    public boolean changeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case LEFT:
            data.get(0).setLocation(point.x - 1, point.y + 1);
            data.get(1).setLocation(point.x, point.y + 1);
            data.get(3).setLocation(point.x, point.y - 1);
            state = SEVEN.TOP;
            break;
        case TOP:
            data.get(0).setLocation(point.x + 1, point.y + 1);
            data.get(1).setLocation(point.x + 1, point.y);
            data.get(3).setLocation(point.x - 1, point.y);
            state = SEVEN.RIGHT;
            break;
        case RIGHT:
            data.get(0).setLocation(point.x + 1, point.y - 1);
            data.get(1).setLocation(point.x, point.y - 1);
            data.get(3).setLocation(point.x, point.y + 1);
            state = SEVEN.DOWN;
            break;
        case DOWN:
            data.get(0).setLocation(point.x - 1, point.y - 1);
            data.get(1).setLocation(point.x - 1, point.y);
            data.get(3).setLocation(point.x + 1, point.y);
            state = SEVEN.LEFT;
            break;
        default:
            throw new Exception("sth wrong here SevenShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

    @Override
    public boolean unChangeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case LEFT:
            data.get(0).setLocation(point.x + 1, point.y - 1);
            data.get(1).setLocation(point.x, point.y - 1);
            data.get(3).setLocation(point.x, point.y + 1);
            state = SEVEN.DOWN;
            break;
        case TOP:
            data.get(0).setLocation(point.x - 1, point.y - 1);
            data.get(1).setLocation(point.x - 1, point.y);
            data.get(3).setLocation(point.x + 1, point.y);
            state = SEVEN.LEFT;
            break;
        case RIGHT:
            data.get(0).setLocation(point.x - 1, point.y + 1);
            data.get(1).setLocation(point.x, point.y + 1);
            data.get(3).setLocation(point.x, point.y - 1);
            state = SEVEN.TOP;
            break;
        case DOWN:
            data.get(0).setLocation(point.x + 1, point.y + 1);
            data.get(1).setLocation(point.x + 1, point.y);
            data.get(3).setLocation(point.x - 1, point.y);
            state = SEVEN.RIGHT;
            break;
        default:
            throw new Exception("sth wrong here SevenShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

}

ReverseSevenShape.java

package com.game.shape;

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

import com.game.state.ShapeInterface.REVERSESEVEN;

public class ReverseSevenShape extends Shape {
    private REVERSESEVEN state;

    public ReverseSevenShape(List<Point> data, int row, int column) {
        super(data, row, column);
        state = REVERSESEVEN.LEFT;
    }

    @Override
    public boolean changeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case RIGHT:
            data.get(0).setLocation(point.x, point.y + 1);
            data.get(1).setLocation(point.x + 1, point.y + 1);
            data.get(3).setLocation(point.x, point.y - 1);
            state = REVERSESEVEN.DOWN;
            break;
        case DOWN:
            data.get(0).setLocation(point.x + 1, point.y);
            data.get(1).setLocation(point.x + 1, point.y - 1);
            data.get(3).setLocation(point.x - 1, point.y);
            state = REVERSESEVEN.LEFT;
            break;
        case LEFT:
            data.get(0).setLocation(point.x, point.y - 1);
            data.get(1).setLocation(point.x - 1, point.y - 1);
            data.get(3).setLocation(point.x, point.y + 1);
            state = REVERSESEVEN.TOP;
            break;
        case TOP:
            data.get(0).setLocation(point.x - 1, point.y);
            data.get(1).setLocation(point.x - 1, point.y + 1);
            data.get(3).setLocation(point.x + 1, point.y);
            state = REVERSESEVEN.RIGHT;
            break;
        default:
            throw new Exception("sth wrong here ReverseSevenShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

    @Override
    public boolean unChangeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case RIGHT:
            data.get(0).setLocation(point.x, point.y - 1);
            data.get(1).setLocation(point.x - 1, point.y - 1);
            data.get(3).setLocation(point.x, point.y + 1);
            state = REVERSESEVEN.TOP;
            break;
        case DOWN:
            data.get(0).setLocation(point.x - 1, point.y);
            data.get(1).setLocation(point.x - 1, point.y + 1);
            data.get(3).setLocation(point.x + 1, point.y);
            state = REVERSESEVEN.RIGHT;
            break;
        case LEFT:
            data.get(0).setLocation(point.x, point.y + 1);
            data.get(1).setLocation(point.x + 1, point.y + 1);
            data.get(3).setLocation(point.x, point.y - 1);
            state = REVERSESEVEN.DOWN;
            break;
        case TOP:
            data.get(0).setLocation(point.x + 1, point.y);
            data.get(1).setLocation(point.x + 1, point.y - 1);
            data.get(3).setLocation(point.x - 1, point.y);
            state = REVERSESEVEN.LEFT;
            break;
        default:
            throw new Exception("sth wrong here ReverseSevenShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

}

ChairShape.java

package com.game.shape;

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

import com.game.state.ShapeInterface.CHAIR;

public class ChairShape extends Shape {
    private CHAIR state;

    public ChairShape(List<Point> data, int row, int column) {
        super(data, row, column);
        state = CHAIR.HORIZONTAL;
    }

    @Override
    public boolean changeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case HORIZONTAL:
            data.get(0).setLocation(point.x - 1, point.y + 1);
            data.get(1).setLocation(point.x - 1, point.y);
            data.get(3).setLocation(point.x, point.y - 1);
            state = CHAIR.VERTICAL;
            break;
        case VERTICAL:
            data.get(0).setLocation(point.x - 1, point.y - 1);
            data.get(1).setLocation(point.x, point.y - 1);
            data.get(3).setLocation(point.x + 1, point.y);
            state = CHAIR.HORIZONTAL;
            break;
        default:
            throw new Exception("sth wrong here : TriangleShape");
        }
        initialLimits();
        getLimits();
        return true;
    }

    @Override
    public boolean unChangeShape() throws Exception {
        try {
            changeShape();
            return false;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

}

ReverseChairShpae.java

package com.game.shape;

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

import com.game.state.ShapeInterface.REVERSECHAIR;

public class ReverseChairShpae extends Shape {
    private REVERSECHAIR state;

    public ReverseChairShpae(List<Point> data, int row, int column) {
        super(data, row, column);
        state = REVERSECHAIR.HORIZONTAL;
    }

    @Override
    public boolean changeShape() throws Exception {
        Point point = data.get(2);
        switch (state) {
        case HORIZONTAL:
            data.get(0).setLocation(point.x, point.y + 1);
            data.get(1).setLocation(point.x - 1, point.y);
            data.get(3).setLocation(point.x - 1, point.y - 1);
            state = REVERSECHAIR.VERTICAL;
            break;
        case VERTICAL:
            data.get(0).setLocation(point.x - 1, point.y);
            data.get(1).setLocation(point.x, point.y - 1);
            data.get(3).setLocation(point.x + 1, point.y - 1);
            state = REVERSECHAIR.HORIZONTAL;
            break;
        default:
            throw new Exception("sth wrong here : ReverseChairShpae");
        }
        initialLimits();
        getLimits();
        return true;
    }

    @Override
    public boolean unChangeShape() throws Exception {
        try {
            changeShape();
            return false;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

}

com.game.state

ShapeEnum.java

package com.game.state;

public enum ShapeEnum {
    SQURE(ShapeInterface.SQURE.class), LONG(ShapeInterface.LONG.class), TRIANGLE(ShapeInterface.TRIANGLE.class), SEVEN(
            ShapeInterface.SEVEN.class), REVERSESEVEN(ShapeInterface.REVERSESEVEN.class), CHAIR(
                    ShapeInterface.CHAIR.class), REVERSECHAIR(ShapeInterface.REVERSECHAIR.class);
    ShapeInterface[] values;

    ShapeEnum(Class<? extends ShapeInterface> kind) {
        values = kind.getEnumConstants();
    }
}

ShapeInterface.java

package com.game.state;

public interface ShapeInterface {
    enum SQURE implements ShapeInterface {
        SQURE
    }

    enum LONG implements ShapeInterface {
        HORIZONTAL, VERTICAL
    }

    enum TRIANGLE implements ShapeInterface {
        TOP, RIGHT, DOWN, LEFT
    }

    enum SEVEN implements ShapeInterface {
        LEFT, TOP, RIGHT, DOWN
    }

    enum REVERSESEVEN implements ShapeInterface {
        RIGHT, DOWN, LEFT, TOP
    }

    enum CHAIR implements ShapeInterface {
        HORIZONTAL, VERTICAL
    }

    enum REVERSECHAIR implements ShapeInterface {
        HORIZONTAL, VERTICAL
    }
}

com.game.util

Enums.java

package com.game.util;

import java.util.Random;

public class Enums {
    private static Random rand = new Random();

    public static <T extends Enum<T>> T random(Class<T> ec) {
        return random(ec.getEnumConstants());
    }

    public static <T> T random(T[] values) {
        return values[rand.nextInt(values.length)];
    }
}

SameRow.java

package com.game.util;

import java.awt.Point;
import java.util.function.Predicate;

public class SameRow implements Predicate<Point> {
    /*
     * This class used for to check whether the Point in same row. predict
     * function.
     */
    private int row;

    public SameRow() {
        this(10);
    }

    public SameRow(int row) {
        this.row = row;
    }

    public void setRow(int row) {
        this.row = row;
    }

    @Override
    public boolean test(Point t) {
        return t.x == row;
    }
}

ShapeData.java

package com.game.util;

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

import com.game.state.ShapeEnum;

public class ShapesData {
    private static List<Point> data;

    public static List<Point> makeShapeData(ShapeEnum shape) {
        switch (shape) {
        case SQURE:
            data = new ArrayList<Point>();
            data.add(new Point(-2, 0));
            data.add(new Point(-2, 1));
            data.add(new Point(-1, 0));
            data.add(new Point(-1, 1));
            break;
        case LONG:
            data = new ArrayList<Point>();
            data.add(new Point(-1, 0));
            data.add(new Point(-1, 1));
            data.add(new Point(-1, 2));
            data.add(new Point(-1, 3));
            break;
        case TRIANGLE:
            data = new ArrayList<Point>();
            data.add(new Point(-2, 1));
            data.add(new Point(-1, 0));
            data.add(new Point(-1, 1));
            data.add(new Point(-1, 2));
            break;
        case SEVEN:
            data = new ArrayList<Point>();
            data.add(new Point(-3, 0));
            data.add(new Point(-3, 1));
            data.add(new Point(-2, 1));
            data.add(new Point(-1, 1));
            break;
        case REVERSESEVEN:
            data = new ArrayList<Point>();
            data.add(new Point(-3, 0));
            data.add(new Point(-3, 1));
            data.add(new Point(-2, 0));
            data.add(new Point(-1, 0));
            break;
        case CHAIR:
            data = new ArrayList<Point>();
            data.add(new Point(-3, 0));
            data.add(new Point(-2, 0));
            data.add(new Point(-2, 1));
            data.add(new Point(-1, 1));
            break;
        case REVERSECHAIR:
            data = new ArrayList<Point>();
            data.add(new Point(-3, 1));
            data.add(new Point(-2, 1));
            data.add(new Point(-2, 0));
            data.add(new Point(-1, 0));
            break;
        default:
            return null;
        }
        return data;
    }
}

Utils.java

package com.game.util;

import java.awt.Point;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.game.shape.ChairShape;
import com.game.shape.LongShape;
import com.game.shape.ReverseChairShpae;
import com.game.shape.ReverseSevenShape;
import com.game.shape.SevenShape;
import com.game.shape.Shape;
import com.game.shape.SqureShape;
import com.game.shape.TriangleShape;
import com.game.state.ShapeEnum;

public class Utils {

    public static Shape makeShape(ShapeEnum shape, int row, int column) {
        switch (shape) {
        case SQURE:
            return new SqureShape(ShapesData.makeShapeData(shape), row, column);
        case LONG:
            return new LongShape(ShapesData.makeShapeData(shape), row, column);
        case TRIANGLE:
            return new TriangleShape(ShapesData.makeShapeData(shape), row, column);
        case SEVEN:
            return new SevenShape(ShapesData.makeShapeData(shape), row, column);
        case REVERSESEVEN:
            return new ReverseSevenShape(ShapesData.makeShapeData(shape), row, column);
        case CHAIR:
            return new ChairShape(ShapesData.makeShapeData(shape), row, column);
        case REVERSECHAIR:
            return new ReverseChairShpae(ShapesData.makeShapeData(shape), row, column);
        default:
            return null;
        }
    }

    public static boolean hasSamePoint(List<Point> data) {
        Set<Point> set = new HashSet<Point>();
        set.addAll(data);
        return set.size() != data.size();
    }
}


com.game.test

TestSqure.java

package com.game.test;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.game.shape.SqureShape;
import com.game.state.ShapeEnum;
import com.game.util.ShapesData;

public class TestSqure {
    private SqureShape squre;

    @Before
    public void setUp() throws Exception {
        squre = new SqureShape(ShapesData.makeShapeData(ShapeEnum.SQURE), 20,
                10);
        Assert.assertNotNull(squre);
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testchangeShape() {
        Assert.assertTrue(squre.changeShape());
    }

    @Test
    public void testunChangeShape() {
        Assert.assertTrue(squre.unChangeShape());
    }

}

最新的源碼在GitHub地址

發佈了58 篇原創文章 · 獲贊 18 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章