我正在使用Model-view-controller方法开发floodFill游戏。现在我被困在构建一个堆栈,可以存储我的gameModel对象的克隆。
public class GameModel implements Cloneable {
/**
* predefined values to capture the color of a DotInfo
*/
public static final int COLOR_0 = 0;
public static final int COLOR_1 = 1;
public static final int COLOR_2 = 2;
public static final int COLOR_3 = 3;
public static final int COLOR_4 = 4;
public static final int COLOR_5 = 5;
public static final int NUMBER_OF_COLORS = 6;
/**
* The current selection color
*/
private int currentSelectedColor;
/**
* The size of the game.
*/
private int sizeOfGame;
/**
* A 2 dimentionnal array of sizeOfGame*sizeOfGame recording the state of each dot
*/
private DotInfo[][] model;
/**
* The number of steps played since the last reset
*/
private int numberOfSteps;
/**
* The number of captered dots
*/
private int numberCaptured;
/**
* Random generator
*/
private Random generator;
/**
* Constructor to initialize the model to a given size of board.
*
* @param size
* the size of the board
*/
public GameModel(int size) {
generator = new Random();
sizeOfGame = size;
reset();
}
/**
* Resets the model to (re)start a game. The previous game (if there is one)
* is cleared up .
*/
public void reset(){
model = new DotInfo[sizeOfGame][sizeOfGame];
for(int i = 0; i < sizeOfGame; i++){
for(int j = 0; j < sizeOfGame; j++){
model[i][j] = new DotInfo(i,j,generator.nextInt(NUMBER_OF_COLORS));
}
}
numberOfSteps =0;
}
/**
* Getter method for the size of the game
*
* @return the value of the attribute sizeOfGame
*/
public int getSize(){
return sizeOfGame;
}
/**
* returns the color of a given dot in the game
*
* @param i
* the x coordinate of the dot
* @param j
* the y coordinate of the dot
* @return the status of the dot at location (i,j)
*/
public int getColor(int i, int j){
return isCaptured(i, j) ? currentSelectedColor : model[i][j].getColor();
}
/**
* returns true is the dot is captured, false otherwise
*
* @param i
* the x coordinate of the dot
* @param j
* the y coordinate of the dot
* @return the status of the dot at location (i,j)
*/
public boolean isCaptured(int i, int j){
return model[i][j].isCaptured();
}
/**
* Sets the status of the dot at coordinate (i,j) to captured
*
* @param i
* the x coordinate of the dot
* @param j
* the y coordinate of the dot
*/
public void capture(int i, int j){
model[i][j].setCaptured(true);
numberCaptured++;
}
/**
* Getter method for the current number of steps
*
* @return the current number of steps
*/
public int getNumberOfSteps(){
return numberOfSteps;
}
/**
* Setter method for currentSelectedColor
*
* @param val
* the new value for currentSelectedColor
*/
public void setCurrentSelectedColor(int val) {
currentSelectedColor = val;
}
/**
* Getter method for currentSelectedColor
*
* @return currentSelectedColor
*/
public int getCurrentSelectedColor() {
return currentSelectedColor ;
}
/**
* Getter method for the model's dotInfo reference
* at location (i,j)
*
* @param i
* the x coordinate of the dot
* @param j
* the y coordinate of the dot
*
* @return model[i][j]
*/
public DotInfo get(int i, int j) {
return model[i][j];
}
/**
* The metod <b>step</b> updates the number of steps. It must be called
* once the model has been updated after the payer selected a new color.
*/
public void step(){
numberOfSteps++;
}
/**
* The metod <b>isFinished</b> returns true iff the game is finished, that
* is, all the dats are captured.
*
* @return true if the game is finished, false otherwise
*/
public boolean isFinished(){
return numberCaptured == sizeOfGame*sizeOfGame;
}
public GameModel clone(){
try {
return (GameModel)super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
/**
* Builds a String representation of the model
*
* @return String representation of the model
*/
public String toString(){
StringBuffer b = new StringBuffer();
for(int i = 0; i < sizeOfGame; i++){
for(int j = 0; j < sizeOfGame; j++){
b.append(getColor(i, j) + " ");
}
b.append("\n");
}
return b.toString();
}
}
正如您所看到的,我已经实现了cloneable并且已经定义了将clone方法覆盖为抽象类。
我正在尝试克隆模型,以便控制器可以在其actionPerformed undo方法中使用该函数。
public class GameController implements ActionListener{
/**
* Reference to the view of the board
*/
private GameView gameView;
/**
* Reference to the model of the game
*/
private GameModel gameModel;
private GameModel oldMove;
private int size;
private int i;
private int j;
private Stack<DotInfo> stack;
private boolean setting1;
private boolean setting2;
Stack<GameModel> steps;
/**
* Constructor used for initializing the controller. It creates the game's view
* and the game's model instances
*
* @param size
* the size of the board on which the game will be played
*/
public GameController(int size) {
gameModel = new GameModel(size);
gameView = new GameView(gameModel, this);
reset();
}
/**
* resets the game
*/
public void reset(){
steps= new GenericLinkedStack<GameModel>();
gameModel.reset();
flood();
gameView.update();
setting1 = false;
setting2 = false;
}
/**
* Callback used when the user clicks a button (reset or quit)
*
* @param e
* the ActionEvent
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof DotButton) {
if(gameModel.getNumberOfSteps()==0){
int row = ((DotButton)(e.getSource())).getRow();
int column = ((DotButton)(e.getSource())).getColumn();
gameModel.capture(row,column);
}
selectColor(((DotButton)(e.getSource())).getColor());
} else if (e.getSource() instanceof JButton) {
JButton clicked = (JButton)(e.getSource());
if (clicked.getText().equals("Quit")) {
System.exit(0);
} else if (clicked.getText().equals("Reset")){
reset();
} else if (clicked.getText().equals("Redo")) {
} else if (clicked.getText().equals("Undo")) {
steps.pop();
gameView.update();
} else if (clicked.getText().equals("Settings")) {
gameView.settingsMenu();
}
} else if (e.getSource() instanceof JRadioButton) {
JRadioButton clickedR = (JRadioButton)(e.getSource());
if (clickedR.getText().equals("Torus")) {
setting1 = true;
}
if (clickedR.getText().equals("Diagonal")) {
setting2 = true;
}
}
}
/**
* <b>selectColor</b> is the method called when the user selects a new color.
* If that color is not the currently selected one, then it applies the logic
* of the game to capture possible locations. It then checks if the game
* is finished, and if so, congratulates the player, showing the number of
* moves, and gives to options: start a new game, or exit
* @param color
* the newly selected color
*/
public void selectColor(int color){
steps.push(gameModel.clone());
if(color != gameModel.getCurrentSelectedColor()) {
gameModel.setCurrentSelectedColor(color);
flood();
gameModel.step();
gameView.update();
finished();
}
}
/**
* <b>flood</b> is the method that computes which new dots should be ``captured''
* when a new color has been selected. The Model is updated accordingly
*/
private void flood() {
size = gameModel.getSize()-1;
stack = new GenericLinkedStack<DotInfo>();
for(int i =0; i < gameModel.getSize(); i++) {
for(int j =0; j < gameModel.getSize(); j++) {
if(gameModel.isCaptured(i,j)) {
stack.push(gameModel.get(i,j));
}
}
}
DotInfo dotInfo;
while(!stack.isEmpty()){
dotInfo = stack.pop();
i = dotInfo.getX();
j = dotInfo.getY();
orthogonal();
if (setting1 == true) {
torus();
}
if (setting2 == true) {
diagonal();
}
}
}
/**
* <b>shouldBeCaptured</b> is a helper method that decides if the dot
* located at position (i,j), which is next to a captured dot, should
* itself be captured
* @param i
* row of the dot
* @param j
* column of the dot
*/
private boolean shouldBeCaptured(int x, int y) {
return (!gameModel.isCaptured(x, y) && (gameModel.getColor(x,y) == gameModel.getCurrentSelectedColor())) ? true : false;
}
private void captureAndStack(int x, int y) {
gameModel.capture(x, y);
stack.push(gameModel.get(x,y));
}
private void finished() {
if(gameModel.isFinished()) {
if (gameView.finishedMenu() == 0) {
reset();
} else {
System.exit(0);
}
}
}
我正在使用堆栈来保存游戏的状态,但我不确定如何使用过去的状态更新视图。我不认为你需要看我游戏的视图类。
有人可以引导我走正确的路径,我应该实施哪些方法以及在哪里。