問題概述
這是一個使用java swing實現的小遊戲,和之前的貪吃蛇以及五子棋類似,閒來無聊的作品,不過,這次的作品相較於前兩個遊戲在代碼水平有很大的提高,結論是,編程能力的提高是寫更多的代碼寫出來的,不是看一系列的書籍看出來的。
代碼部分經過一天的清明節假期,只是雛形漸漸出現,還有很多的細節需要推敲。比如,消行的這個問題,遍歷數據,原則上從下邊一行開始消除,也就是逆向,然後將上邊的內容依次下移。
如果使用二維數組的遍歷,需要每次都要訪問全局數據,鄙人採用了傳入局部數據方法。
使用了工廠設計模式,對多種形狀做繼承處理。
提取一些簡易的數據結構,作爲輔助類(工具類使用)。
代碼完成及問題的結局
實際的開發工作所用時間從週末到週三的晚上,大約四天的功夫,當然不是說完整的四天都在編寫代碼。畢竟還要上班,只是閒暇的時間來做這部分工作。
關於上邊提到的問題的解決,採用的方式是循環掃描,這種最簡單的方案,如果有一行掃描需要消行,在消行之後需要重新進行掃描,這是最關鍵的一點。
代碼部分少不了對諸多方塊圖形的描述,也就是需要很多枚舉類型的參與,並且需要對某一類圖形的子狀態作進一步的描述,也就是需要一種“繼承”的枚舉類型,參照了《Java編程思想》關於枚舉這一部分的講述。
關於圖形的移動,需要判定是否可以作相應的移動,包括向左,向右,以及向下,判斷需要考慮俄羅斯方塊最外邊的框,以及現有的圖形是否對能移動的圖形有遮擋。
圖形的類使用了繼承的方法,也就是使用工廠的模式。
關於圖形子狀態的相互轉換,使用了策略模式,也就對不同的圖形採用差異化的變形方法。
圖形子狀態的改變可以考慮設計模式的職責鏈,或者狀態模式,本代碼沒有采用相應的實現。
完整的代碼可以看文章最後的博客地址。
程序最終效果圖
代碼部分
代碼還不完整,只能實現一些基本的功能,並且沒有經過完整,全面的測試,另外俄羅斯方塊的所有形狀還沒有添加完全。希望讀者斧正。感謝有你。
代碼已經完整了。剩下的就是重構代碼。加入一些新的圖形極其子狀態。
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());
}
}