-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGridPanel.java~
More file actions
362 lines (324 loc) · 11.1 KB
/
GridPanel.java~
File metadata and controls
362 lines (324 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/**
* This class displays the grid of one level. It uses a 2d-array
* of JButtons (which are colored/bordered to indicate their "type").
* The JButtons allow the use of a KeyListener which allows the user
* to move his/her piece with the keyboard arrow keys. A GridPanel
* also contains an undoStack which allows the user to undo his/her
* previous moves. Each GridPanel should represent a different level.
* <p>
* Priscilla was primarily responsible for the implementation of this class
*
* @author Priscilla Lee
* @version December 2 2014
*/
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import javafoundations.*;
import java.util.*;
import javax.swing.border.*;
public class GridPanel extends JPanel{
//public final static constant vars (directions)
public final static int LEFT = 0, RIGHT = 1, UP = 2, DOWN = 3;
//private instance vars
private JButton[][] buttonGrid;
private GridGraph gridGraph;
private ArrayStack<UserMove> undoStack; //to store moves for our undo button
private int x, y; //keeps track of player’s current position
private int width, height;
private int counter, limit; //keeps track of # of steps moved vs limited steps
private LevelPanel lPanel;
private ArrayList<GridCoordinate> hints;
private int hintCounter;
/**
* Constructor that constructs a 2d array of JButtons and an undoStack.
*
* @param lp the LevelPanel that will contain this GridPanel
* @param gg the GridGraph that corresponds to this GridPanel
*/
public GridPanel(LevelPanel lp, GridGraph gg) {
lPanel = lp;
gridGraph = gg;
width = gridGraph.getWidth();
height = gridGraph.getHeight();
//setting layout & background & size
setLayout(new GridLayout(height, width));
setBackground(ColorScheme.background());
setPreferredSize(new Dimension(500,500));
setMinimumSize(new Dimension(500,500));
setMaximumSize(new Dimension(500,500));
//create button grid of all WHITE JButtons
buttonGrid = new JButton[height][width];
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) {
JButton tile = new JButton();
tile.addKeyListener(new ArrowListener());
tile.setOpaque(true);
tile.setBackground(Color.WHITE);
tile.setBorder(BorderScheme.standard());
//set font & font size
int n = 0;
if (height < 5 && width < 5) n = 30;
else if (height < 10 && width < 10) n = 25;
else if (height < 15 && width < 15) n = 20;
else if (height < 20 && width < 20) n = 15;
else n = 10;
tile.setFont(new Font("Calibri", Font.BOLD, n));
buttonGrid[r][c] = tile;
add(tile);
}
}
//set current position, counter, and limit
GridCoordinate start = gridGraph.getBegin();
x = start.getX();
y = start.getY();
buttonGrid[x][y].setBackground(ColorScheme.character());
counter = 0;
limit = gridGraph.getShortestPath();
//set ("color in") blocks
for (GridCoordinate block: gridGraph.getBlocks()) {
int x = block.getX();
int y = block.getY();
buttonGrid[x][y].setBackground(ColorScheme.block());
}
//set ("add border to") targets
ArrayList<GridCoordinate> targets = gridGraph.getTargets();
for (GridCoordinate target: targets) {
int x = target.getX();
int y = target.getY();
buttonGrid[x][y].setBorder(BorderScheme.target(width, height));
}
//create undoStack
undoStack = new ArrayStack<UserMove>();
//store list of hints
hints = gridGraph.getPathAnswer();
hintCounter = 0;
}
/**
* Returns the current number of steps the user has moved.
*
* @return the current step count
*/
public int getStepCount(){
return counter;
}
/**
* Displays a hint from the computer to help the user find the shortest path.
*/
public void hint() {
if (hints.size() <= 1)
return;
GridCoordinate gc = hints.remove(hints.size()-2);
int x = gc.getX();
int y = gc.getY();
buttonGrid[x][y].setBackground(ColorScheme.hintPath());
buttonGrid[x][y].setText("<html><font color='white'>" +
(++hintCounter) + "</font></html>");
}
/**
* Resets the grid completely by undoing all moves that have been made. This
* method is meant to be called by LevelPanel when its reset button is pressed.
*/
public void reset() {
while (!undoStack.isEmpty())
undo(); //keep undo-ing until no more left
}
/**
* Undoes the most recent move made by the user. This method is meant to be
* called by LevelPanel when its undo button is pressed.
*/
public void undo() {
if (undoStack.size()>0) {
UserMove lastMove = undoStack.pop();
lastMove.undo();
}
}
/**
* Moves the player's piece on the screen according to the direction given.
*
* @param direction the direction in which the player intends to move
*/
public void move(int direction) {
UserMove move = new UserMove(direction);
move.move();
}
/**
* Returns true if player has successfully completed the level. This method
* loops through all the targets and checks to make sure they have all
* been visited by the player's piece.
*
* @return a boolean indicating whether the level has been completed
*/
public boolean levelComplete() {
ArrayList<GridCoordinate> targets = gridGraph.getTargets();
for (GridCoordinate target: targets)
{ //has each target been reached (not white?)
int tx = target.getX();
int ty = target.getY();
JButton t = buttonGrid[tx][ty];
if (t.getBackground().equals(Color.WHITE))
return false; //return false if a target hasn't been reached
}
return true;
}
/**
* Private inner class that implements KeyListener and allows user to use arrow
* arrow keys to move his/her piece in the grid.
*/
private class ArrowListener implements KeyListener {
//keyPressed method required for KeyListener interface
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
move(LEFT);
else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
move(RIGHT);
else if (e.getKeyCode() == KeyEvent.VK_UP)
move(UP);
else if (e.getKeyCode() == KeyEvent.VK_DOWN)
move(DOWN);
else if (e.getKeyCode() == KeyEvent.VK_U)
undo();
else if (e.getKeyCode() == KeyEvent.VK_R)
reset();
else if (e.getKeyCode() == KeyEvent.VK_H)
hint();
else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (gridGraph.getLevel() == 0)
lPanel.loadRandomLevel(gridGraph.getWidth(), gridGraph.getHeight());
else
lPanel.loadNextLevel();
}
}
//keyReleased method required for interface
public void keyReleased(KeyEvent e){}
//keyTyped method required for interface
public void keyTyped(KeyEvent e){}
}
/**
* Private inner class that represents a move made by the user. This class
* will be used to check if a move is valid, to move the piece on the
* GUI grid, and also to store information to be used by the undo function.
*/
private class UserMove {
//private instance vars
private int direction;
private Color repColor;
private String repText;
private JButton oldButton, newButton;
private int oldX, oldY, newX, newY;
/**
* Constructor that creates a UserMove by storing the direction given.
*
* @param d the direction of the user's mvoe
*/
public UserMove(int d) {
direction = d;
//save old position
oldX = x; oldY = y;
oldButton = buttonGrid[oldX][oldY];
//determine and save new position
if (direction == LEFT) y--;
else if (direction == RIGHT) y++;
else if (direction == UP) x--;
else if (direction == DOWN) x++;
newX = x; newY = y;
if (newX >= 0 && newX < height && newY >= 0 && newY < width)
newButton = buttonGrid[newX][newY];
else
newButton = buttonGrid[0][0]; //use a "dummy" button
//save anything that was replaced by moving this piece
repColor = newButton.getBackground();
repText = newButton.getText();
}
/**
* Actually moves the player's piece on the screen.
*/
public void move() {
if (!isValidMove()) {//BAD MOVE!!
x = oldX; y = oldY; //reset x and y position
return; //don't do anything if the move is invalid
}
//leave path (color + number)
if (oldIsTarget())
oldButton.setBackground(ColorScheme.target());
else
oldButton.setBackground(ColorScheme.path());
oldButton.setText("<html><font color='white'>" +
(counter++) + "</font></html>");
//move piece (color, push onto undo, update labels)
newButton.setBackground(ColorScheme.character());
newButton.setText("");
undoStack.push(this);
lPanel.updateStepsLabel();
lPanel.updateNextLabel();
}
/**
* Returns the color that was replaced by this move.
*
* @return the color that was replaced by this move.
*/
public Color getReplacedColor() {
return repColor;
}
/**
* Returns the text that was replaced by this move.
*
* @return the text that was replaced by this move.
*/
public String getReplacedText() {
return repText;
}
/**
* Private helper method that returns true if the position of this move
* contains a target.
*
* @return a boolean indicating whether the position contains a target
*/
private boolean oldIsTarget() {
ArrayList<GridCoordinate> targets = gridGraph.getTargets();
for (GridCoordinate target: targets) {
if (target.getX()==oldX && target.getY()==oldY)
return true;
}
return false;
}
/**
* Private helper method that returns true if the move attempted is valid.
*
* @return a boolean that indicates whether this move is allowed
*/
private boolean isValidMove() {
if (counter >= limit)
return false;
return isValidPosition();
}
/**
* Private helper method that returns true if the position of this move
* is valid on grid.
*
* @return a boolean indicating whether the given position exists in the grid
*/
private boolean isValidPosition() {
boolean validX = newX>=0 && newX<height;
boolean validY = newY>=0 && newY<width;
if (validX && validY)
return !(newButton.getBackground().equals(ColorScheme.block()));
return false;
}
/**
* Undoes this move.
*/
public void undo() {
//move character back to "old" button (color, lower counter, update labels)
x = oldX; y = oldY;//update current position
oldButton.setBackground(ColorScheme.character());
oldButton.setText("");
counter--;
lPanel.updateStepsLabel();
lPanel.updateNextLabel();
//"uncover" what this move replaced (restore replaced color + text)
newButton.setBackground(repColor);
newButton.setText(repText);
}
}
}