俄罗斯方块的源码实现

问题概述

  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地址

你可能感兴趣的:(java,游戏,源码,俄罗斯方块)