-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLightGrid.java
291 lines (256 loc) · 8.91 KB
/
LightGrid.java
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
/**
* @(#)LightGrid.java
*
*
* @author
* @version 1.00 2017/2/19
*/
//Swing package GUI components
import javax.swing.JPanel;
//AWT package GUI details
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
//AWT Listener Events
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* Implements a new LightGrid object for the game. A LightGrid
* is a specialized 2D grid of Lights (JButtons). The LightGrid's
* responsibilities are to instantiate each Light with a starting
* state, organize them into a GridLayout, and once a Light has
* been clicked determine which of the Lights it was.
* <p>
* Once the Light that was clicked is found, the LightGrid should
* handle finding all adjacent Lights and toggling each of them
* on/off, and count the number of lights that are still on each
* turn.
* <p>
* LightGrid extends a JPanel in order to implement all of the
* properties of a simple container object including the Layout
* features so a GridLayout can be created to organize the Lights.
*
*/
public class LightGrid extends JPanel {
/** Size of square grid as percent of height of the GameWindow */
public static final int SIZE = (int)(GameWindow.HEIGHT * .8);
/** Number of cells in a row/column of the grid (Lights Out is a 5x5 grid) */
public static final int CELLS = 5;
/** Underlying 2D array for grid of lights */
private Light[][] grid;
/** Game Listener passed from the top level JFrame */
private MouseListener gameListener;
/**
* Counter for number of lights that are currently on. Player
* wins the game once all lights are off (i.e. counter == 0)
*/
private int lightCounter;
/**
* Creates a new LightGrid object and assigns the specified
* MouseListener passed from the top level JFrame to the
* gameListener field for use with the Lights in the game.
* <p>
* The default implementation should establish the listener
* field, set the size to that specified above, set the
* layout to a GridLayout with the correct number of cells,
* instantiate the underlying 2D array to hold the Lights,
* and finally invoke the process for initializing those
* Lights in the grid.
*
*/
public LightGrid(MouseListener listener)
{
/************************************************
* Correctly assign the listener, set the size *
* of the LightGrid, assign a GridLayout with *
* the correct number of rows/columns, create *
* the underlying 2D array, and correctly *
* invoke the initialization of the individual *
* lights. *
************************************************/
gameListener = listener;
this.setSize(SIZE, SIZE);
this.setLayout(new GridLayout(CELLS,CELLS));
grid = new Light[CELLS][CELLS];
this.initializeLights();
}
/**
* Correctly instantiates a Light object for each spot
* in the grid with a 50% chance for that light to start
* in the ON state. If a Light gets switched to ON, be
* sure to correctly incriment the light counter. Each
* light needs to be instantiated, on/off state determined,
* added to the grid in the proper location, assigned the
* mouse listener passed from the top level JFrame, and
* finally (which is the easiest to forget) it must be added
* to 'this' LightGrid (JPanel) itself.
* <p>
* Very common to confuse that adding of the Light to the
* 2D array and adding it to the JPanel as the same thing.
* IT IS NOT! If you want something to show up inside of
* a container, you must add it straight to the container
* itself. Once added, the layout specifications determine
* where exactly the component will be placed or if no layout
* exists (switched to null) then the set bounds method must
* be invoked to determine where exactly the component should
* go (we did this at the top level JFrame).
*
*
*/
private void initializeLights()
{
/****************************************************
* Correctly create a Light for each spot in the *
* grid, toggle the light on with a 50% chance, *
* assign the listener from the top level JFrame to *
* each Light, and count the total number of Lights *
* that are switched on *
****************************************************/
for (int i = 0; i< grid.length; i++) {
for ( int j = 0; j < grid[i].length; j++) {
int chance = (int) ((Math.random() * 2) + 1);
grid[i][j] = new Light();
grid[i][j].addMouseListener(gameListener);
if (chance == 1) {
grid[i][j].toggle();
lightCounter += 1;
}
this.add(grid[i][j]);
}
}
}
/**
* Invoked by top level JFrame class when it is determined
* a left mouse click has occurred on one of the Lights in
* the grid. This method must correctly find the source of
* the mouse click (which Light was clicked) by invoking
* the correct information from the passed MouseEvent.
* <p>
* Once the Light source is found, this method should pass
* the required information for which Light was clicked to
* the method that handles toggling the Light and all of
* the adjacent lights.
* <p>
* Once this process is complete, it is here we will invoke
* the repaint method for the JPanel in order for the
* screen to update the changes, then for efficiency exit
* the method before the loop finishes.
*
* @param e MouseEvent that occurred in the game passed
* from the top level JFrame class when it is
* determined the event was triggered by a left
* mouse click on one of the lights in the grid.
*
*
*/
public void onLeftClick(MouseEvent e)
{
/********************************************
* Correctly determine which Light was the *
* source of the click, then correctly use *
* that information to toggle the Light and *
* all adjacent lights. Then, invoke the *
* repaint and exit the method early. *
********************************************/
for (int i = 0; i < CELLS; i++) {
for (int j = 0; j< CELLS; j++) {
if (e.getSource() == grid[i][j]) {
this.toggleAdjacentLights(i,j);
this.repaint();
return;
}
}
}
}
/**
* Uses the specified coordinates to correctly toggle
* the given light and each adjacent light. A Light is
* adjacent to another if it is directly above/below
* or to the side of the first Light. Diagonals are
* NOT adjacent.
*
* @param r Row number of the Light that was
* determined to be clicked
*
* @param c Column number of the Light that was
* determined to be clicked
*
*
*/
public void toggleAdjacentLights(int r, int c)
{
/********************************************
* Correctly toggle the Light at the given *
* location and all adjacent lights while *
* also tracking the total number of lights *
* that are on with the counter. *
********************************************/
grid[r][c].toggle();
if (inBounds((r+1),c) ) {
grid[r + 1][c].toggle();
}
if ( inBounds((r-1), c)) {
grid[r - 1][c].toggle();
}
if (inBounds(r,(c+1))) {
grid[r][c +1].toggle();
}
if (inBounds(r,(c-1))) {
grid[r][c -1].toggle();
}
lightCounter = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j].isOn()) {
lightCounter += 1;
}
}
}
}
public boolean inBounds(int r, int c) {
if ((c >= CELLS) || (r >= CELLS) || (c < 0) || (r < 0) ) {
return false;
}
else{
return true;
}
}
/**
* Resets the light grid by switching each light off
* and correctly randomizing which lights are on with
* a 50% chance and correctly updates the light counter.
*
*/
public void reset()
{
/********************************************************
* Reset the counter and each Light in the grid with *
* a 50% chance of being switched on, and keep track of *
* total number switched on. *
********************************************************/
lightCounter = 0;
for (int i = 0; i <grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
int chance = (int) ((Math.random() * 2) + 1);
grid[i][j].turnOff();
if (chance == 1) {
grid[i][j].toggle();
lightCounter += 1;
}
}
}
}
/**
* Return current number of lights that are on
*
* @return Total number of lights that remain
* on inside the grid.
*
*/
public int getNumberOfLightsOn()
{
return this.lightCounter;
}
}