adding puyopuyo code.
Dev

Dev commited on 2018-07-21 10:16:11
Showing 12 changed files, with 1414 additions and 0 deletions.

... ...
@@ -0,0 +1,170 @@
1
+/*
2
+ * ScreenManager.java
3
+ *
4
+ * Created on 30 March, 2007, 12:35 AM
5
+ *
6
+ * To change this template, choose Tools | Template Manager
7
+ * and open the template in the editor.
8
+ */
9
+
10
+/**
11
+ *
12
+ * @author 
13
+ */
14
+import java.awt.*;
15
+import java.awt.image.BufferStrategy;
16
+import java.awt.image.BufferedImage;
17
+import javax.swing.JFrame;
18
+
19
+/**
20
+    The ScreenManager class manages initializing and displaying
21
+    full screen graphics modes.
22
+*/
23
+public class ScreenManager {
24
+
25
+    private GraphicsDevice device;
26
+
27
+    /**
28
+        Creates a new ScreenManager object.
29
+    */
30
+    public ScreenManager() {
31
+        GraphicsEnvironment environment =
32
+            GraphicsEnvironment.getLocalGraphicsEnvironment();
33
+        device = environment.getDefaultScreenDevice();
34
+    }
35
+
36
+
37
+    /**
38
+        Returns a list of compatible display modes for the
39
+        default device on the system.
40
+    */
41
+    public DisplayMode[] getCompatibleDisplayModes() {
42
+        return device.getDisplayModes();
43
+    }
44
+
45
+
46
+    /**
47
+        Returns the current display mode.
48
+    */
49
+    public DisplayMode getCurrentDisplayMode() {
50
+        return device.getDisplayMode();
51
+    }
52
+
53
+    /**
54
+        Enters full screen mode and changes the display mode.
55
+        If the specified display mode is null or not compatible
56
+        with this device, or if the display mode cannot be
57
+        changed on this system, the current display mode is used.
58
+        <p>
59
+        The display uses a BufferStrategy with 2 buffers.
60
+    */
61
+    public void setFullScreen(DisplayMode displayMode) {
62
+        JFrame frame = new JFrame("PuyoPuyo");
63
+        frame.setUndecorated(true);
64
+        frame.setIgnoreRepaint(true);
65
+        frame.setResizable(false);
66
+
67
+        device.setFullScreenWindow(frame);
68
+        if (displayMode != null && device.isDisplayChangeSupported())
69
+        {
70
+            try {
71
+                device.setDisplayMode(displayMode);
72
+            }
73
+            catch (IllegalArgumentException ex) { }
74
+        }
75
+        else{
76
+            System.out.println("Unable to switch to fullscreen... Exiting.");
77
+            System.exit(1);
78
+        }
79
+        frame.createBufferStrategy(2);
80
+    }
81
+
82
+
83
+    /**
84
+        Gets the graphics context for the display. The
85
+        ScreenManager uses double buffering, so applications must
86
+        call update() to show any graphics drawn.
87
+        <p>
88
+        The application must dispose of the graphics object.
89
+    */
90
+    public Graphics2D getGraphics() {
91
+        Window window = device.getFullScreenWindow();
92
+        if (window != null) {
93
+            BufferStrategy strategy = window.getBufferStrategy();
94
+            return (Graphics2D)strategy.getDrawGraphics();
95
+        }
96
+        else {
97
+            return null;
98
+        }
99
+    }
100
+
101
+
102
+    /**
103
+        Updates the display.
104
+    */
105
+    public void update() {
106
+        Window window = device.getFullScreenWindow();
107
+        if (window != null) {
108
+            BufferStrategy strategy = window.getBufferStrategy();
109
+            if (!strategy.contentsLost()) {
110
+                strategy.show();
111
+            }
112
+        }
113
+        // Sync the display on some systems.
114
+        // (on Linux, this fixes event queue problems)
115
+        Toolkit.getDefaultToolkit().sync();
116
+    }
117
+
118
+
119
+    /**
120
+        Returns the window currently used in full screen mode.
121
+        Returns null if the device is not in full screen mode.
122
+    */
123
+    public Window getFullScreenWindow() {
124
+        return device.getFullScreenWindow();
125
+    }
126
+
127
+
128
+    /**
129
+        Returns the width of the window currently used in full
130
+        screen mode. Returns 0 if the device is not in full
131
+        screen mode.
132
+    */
133
+    public int getWidth() {
134
+        Window window = device.getFullScreenWindow();
135
+        if (window != null) {
136
+            return window.getWidth();
137
+        }
138
+        else {
139
+            return 0;
140
+        }
141
+    }
142
+
143
+
144
+    /**
145
+        Returns the height of the window currently used in full
146
+        screen mode. Returns 0 if the device is not in full
147
+        screen mode.
148
+    */
149
+    public int getHeight() {
150
+        Window window = device.getFullScreenWindow();
151
+        if (window != null) {
152
+            return window.getHeight();
153
+        }
154
+        else {
155
+            return 0;
156
+        }
157
+    }
158
+
159
+
160
+    /**
161
+        Restores the screen's display mode.
162
+    */
163
+    public void restoreScreen() {
164
+        Window window = device.getFullScreenWindow();
165
+        if (window != null) {
166
+            window.dispose();
167
+        }
168
+        device.setFullScreenWindow(null);
169
+    }
170
+}
0 171
\ No newline at end of file
... ...
@@ -0,0 +1,516 @@
1
+/*
2
+ * backEnd.java
3
+ *
4
+ * Created on 31 March, 2007, 11:42 PM
5
+ *
6
+ * To change this template, choose Tools | Template Manager
7
+ * and open the template in the editor.
8
+ */
9
+
10
+import java.util.Arrays;
11
+import java.util.Comparator;
12
+import java.util.HashSet;
13
+import java.util.Iterator;
14
+import java.util.Stack;
15
+import java.util.Vector;
16
+
17
+/**
18
+ * Holds all the logic that drives the game.
19
+ * <p>The main engine of the game is comprised of the following
20
+ * four methods:
21
+ * <ul>
22
+ *    <li>{@link puyopuyo.backEnd#popPuyos(puyo[]) popPuyos} - This acts as an entry point to {@link puyopuyo.frontEnd# frontEnd} to the logic of the game.</li>
23
+ *    <li>{@link puyopuyo.backEnd#probe(puyo) probe(puyo)} - It identifies the chain due to puyo passed to it as a parameter.</li>
24
+ *    <li>{@link puyopuyo.backEnd#popAndMarkDroppings(HashSet) popAndMarkDroppings} - It removes the puyo from {@link puyopuyo.backEnd#boardMap boardMap}</li>
25
+ *    and also marks the puyo which is to move down because of popping.</li>
26
+ *    <li>{@link puyopuyo.backEnd#settleDown(puyo) settleDown} - Moves down the puyo (and all those above it) to fill</li>
27
+ *    in the void created due to popping of puyo.</li>
28
+ * </ul>
29
+ * </p>
30
+ * @author Dev Ghai
31
+ */
32
+public class backEnd extends puyo{
33
+    
34
+    /**
35
+     * Creates a new instance of backEnd, initialises the board
36
+     * and pushes a pair of puyos in {@link puyopuyo.backEnd#boardMap boardMap} using {@link puyopuyo.backEnd#pushPuyos() pushPuyos}.
37
+     * {@link puyopuyo.backEnd#boardMap boardMap} is a two dimensional array that the heart of the game. It logically
38
+     * represents the game's board in memory in form of an array whose width
39
+     * is equal to {@link puyopuyo.backEnd#puyosOnXAxis puyosOnXAxis} and height is equal to {@link puyopuyo.backEnd#puyosOnYAxis puyosOnYAxis}.
40
+     */
41
+    public backEnd() {
42
+        for (int i = 0; i<puyosOnXAxis; i++)
43
+            for(int j = 0; j<puyosOnYAxis; j++)
44
+                boardMap[i][j] = null;      //=> board is initially empty
45
+        pushPuyos();                        //and let the game begin!
46
+    }
47
+    //Clean and Build the Project to see the following 2 values take effect.
48
+    /**
49
+     * Holds the number of puyos on X Axis. Modify this value to effectively
50
+     * change the size of the board. Logic has been made to depend on it.
51
+     */
52
+    int puyosOnXAxis = 6;
53
+    /**
54
+     * Holds the number of puyos on Y Axis. Modify this value to effectively
55
+     * change the size of the board. Logic has been made to depend on it.
56
+     */
57
+    int puyosOnYAxis = 12;
58
+    /**
59
+     * Holds the minimum length of the chain in terms of puyos that will cause puyos
60
+     * to be popped from the board.
61
+     */
62
+    int popmin = 4;
63
+    /**
64
+     * Stores the pair of puyos pushed onto the board.
65
+     */
66
+    private puyo puyoPair [] = new puyo[2];
67
+    /**
68
+     * Returns a pair of puyos in form of an one dimensional array.
69
+     */
70
+    public puyo[] getPuyoPair(){
71
+        return puyoPair;
72
+    }
73
+    /**
74
+     * Integer value that holds the score of the game. Popping of one puyo
75
+     * adds 10 to the current score.
76
+     */
77
+    private int score = 0;
78
+    /**
79
+     * Returns the current score. {@link puyopuyo.backEnd#score score} is incremented by 10 points when
80
+     * one puyo is popped.
81
+     */
82
+    public int getScore(){
83
+        return score;
84
+    }
85
+    /**
86
+     * A boolean value that tells whether the game is over or not.
87
+     * 
88
+     * <p>This value is set in two cases -
89
+     * <li>
90
+     *        <ol>When {@link puyopuyo.backEnd#pushPuyos() pushPuyos} is unable to push a pair on the board.</ol>
91
+     *        <ol>When the user hits the Esc key, i.e. s/he wants to exit from the game.</ol>
92
+     * </li></p>
93
+     */
94
+    private boolean gameOver = false;
95
+    /**
96
+     * Logically tells if the game is over or not by returning the (boolean) value
97
+     * of {@link puyopuyo.backEnd#gameOver gameOver}.
98
+     */
99
+    public boolean isGameOver(){
100
+        return gameOver;
101
+    }
102
+    
103
+    /**
104
+     * This method allows {@link puyopuyo.frontEnd# frontEnd} to set the gameOver to true.
105
+     * <p>Game ends in two cases -
106
+     * <ol><li>When {@link puyopuyo.backEnd#pushPuyos() pushPuyos} is unable to push a pair on the board.</li>
107
+     *     <li>When the user hits the Esc key, i.e. s/he wants to exit from the game.</li>
108
+     * </ol></p>
109
+     * @param status 'status' of the game to be copied to {@link gameOver}.
110
+     */
111
+    public void setGameOver(boolean status){
112
+        gameOver = status;
113
+    }
114
+    /**
115
+     * This two dimensional array is the heart of the game. It logically
116
+     * represents the game's board in memory in form of an array whose width
117
+     * is equal to {@link puyopuyo.backEnd#puyosOnXAxis puyosOnXAxis} and height is equal to {@link puyopuyo.backEnd#puyosOnYAxis puyosOnYAxis}.
118
+     */
119
+    private puyo boardMap[][] = new puyo[puyosOnXAxis][puyosOnYAxis];
120
+    
121
+    /**
122
+     * Returns true if insertion successfully takes place in {@link puyopuyo.backEnd#boardMap boardMap}.
123
+     * @param p Puyo to insert in boardMap
124
+     * @param X X Co-ordinate of the insertion point.
125
+     * @param Y Y co-ordinate of the insertion point.
126
+     * @return Returns if the insertion was successful or not.
127
+     */
128
+    private synchronized boolean insertInBoardMap(puyo p, int X, int Y){
129
+        /*If boardMap[X,Y] holds null => it is empty & the new point obeys
130
+         * boundary conditions. Set the same and return true,
131
+         * else that cell is filled or lies outside board, return false.*/
132
+        
133
+        boolean newPointLiesOnBoard = (X>=0 & X<puyosOnXAxis) & (Y>=0 & Y<puyosOnYAxis);
134
+        if(newPointLiesOnBoard && boardMap[X][Y]==null){
135
+            boardMap[X][Y] = p;
136
+            return true;
137
+        }
138
+        //control will reach here only when the cell is previously filled or the point lies outside the board
139
+        return false;
140
+    }
141
+    
142
+    /**
143
+     * Removes puyo from the {@link puyopuyo.backEnd#boardMap boardMap}.
144
+     * @param X X co-ordinate in boardMap from which to remove puyo.
145
+     * @param Y Y co-ordinate of boardMap from which to remove the puyo.
146
+     */
147
+    private synchronized void removeFromBoardMap(int X, int Y){
148
+        boolean pointLiesOnBoard = (X>=0 & X<puyosOnXAxis) & (Y>=0 & Y<puyosOnYAxis);
149
+        if (pointLiesOnBoard && boardMap[X][Y]!=null)
150
+            boardMap[X][Y] = null;
151
+    }
152
+    
153
+    /**
154
+     * Returns {@link puyopuyo.backEnd#boardMap boardMap}. One of the main purposes of
155
+     * this method is to provide a two dimensional array to {@link puyopuyo.frontEnd# frontEnd}
156
+     * for printing the board onto screen. {@link puyopuyo.frontEnd#drawBoardMap() drawBoardMap}
157
+     * uses this method to extract the logical {@link puyopuyo.backEnd#boardMap boardMap} and print
158
+     * it onto the screen.
159
+     * @return boardMap
160
+     */
161
+    public puyo[][] getBoardMap(){
162
+        return boardMap;
163
+    }
164
+    /**
165
+     * Generates a new {@link puyo# puyo} and randomly assigns color to the generated {@link puyo# puyo}.
166
+     * @return A puyo with randomly generated colors.
167
+     */
168
+    private puyo getNewPuyo(){
169
+        Math.random();          //initiate the random number generator by first call
170
+        puyo p = new puyo();    //initialize p
171
+        switch((int)(Math.random()*10)%4) {
172
+            
173
+            case 0: p = new puyo("./images/redPuyo.png", 'r');  //red puyo
174
+            break;
175
+            case 1: p = new puyo("./images/greenPuyo.png", 'g');  //green puyo
176
+            break;
177
+            case 2: p = new puyo("./images/bluePuyo.png", 'b');  //blue puyo
178
+            break;
179
+            case 3: p = new puyo("./images/yellowPuyo.png", 'y');  //yellow puyo
180
+        }
181
+        return p;
182
+    }
183
+
184
+    /**
185
+     * Pushes a new pair of puyos in {@link puyopuyo.backEnd#boardMap boardMap} at the top of
186
+     * the board. If no new pair can be pushed, {@link puyopuyo.backEnd#gameOver gameOver} is set true via {@link puyopuyo.backEnd#setGameOver(boolean) setGameOver}.
187
+     */
188
+    
189
+    
190
+    
191
+    public void pushPuyos(){
192
+        int centerX = (puyosOnXAxis-1)/2;
193
+        if(boardMap[centerX][0]==null & boardMap[centerX+1][0]==null) {
194
+            puyo p1 = getNewPuyo();
195
+            puyo p2 = getNewPuyo();
196
+            p1.setX(centerX);   p1.setY(0);
197
+            boardMap[centerX][0] = p1;
198
+            p2.setX(++centerX); p2.setY(0); //centerX+1 causes second puyo to be printed over first puyo
199
+                                            //Hence v c only 1 puyo when a pair is pushed on board.
200
+            boardMap[centerX][0] = p2;
201
+            puyoPair[0] = p1;
202
+            puyoPair[1] = p2;
203
+        } else
204
+            setGameOver(true); //!!
205
+    }
206
+    /**
207
+     * Moves the puyo passed as parameter one positon to left in {@link puyopuyo.backEnd#boardMap boardMap}.
208
+     * It also updates the property of the puyo after successfully moving it.
209
+     * @param p puyo to be moved left.
210
+     * @return True if puyo was successfully moved and its property updated, else false
211
+     */
212
+    public boolean moveLeft(puyo p){
213
+        boolean retVal;
214
+        if( retVal = insertInBoardMap(p, p.getX() - 1, p.getY()) ){
215
+            removeFromBoardMap(p.getX(), p.getY());
216
+            p.setX(p.getX()-1); //update the puyo's property
217
+        }
218
+        return retVal;
219
+    }
220
+    
221
+    /**
222
+     * Moves the puyo passed as parameter one positon to right in {@link puyopuyo.backEnd#boardMap boardMap}.
223
+     * It also updates the property of the puyo after successfully moving it.
224
+     * @return True if puyo was successfully moved and its property updated, else false
225
+     * @param p Puyo to be moved right.
226
+     */
227
+    public boolean moveRight(puyo p){
228
+        boolean retVal;
229
+        if( retVal = insertInBoardMap(p, p.getX() + 1, p.getY())){
230
+            removeFromBoardMap(p.getX(), p.getY());
231
+            p.setX(p.getX()+1); //update puyo's property
232
+        }
233
+        return retVal;
234
+    }
235
+    
236
+    /**
237
+     * Moves the puyo passed as parameter one positon down in {@link puyopuyo.backEnd#boardMap boardMap}.
238
+     * It also updates the property of the puyo after successfully moving it.
239
+     * @return True if puyo was successfully moved and its property updated, else false
240
+     * @param p Puyo to be moved down.
241
+     */
242
+    public boolean moveDown(puyo p){
243
+        /* while(boundary conditions are ok & next cell is empty)
244
+         * The loop will exit when an attempt will be made to insert an imaginary
245
+         * puyo above the topmost puyo.
246
+         */
247
+        if( insertInBoardMap(p, p.getX(), p.getY()+1) ){
248
+            removeFromBoardMap(p.getX(), p.getY());
249
+            p.setY(p.getY()+1);
250
+            return true;
251
+        }
252
+        return false;
253
+    }
254
+    
255
+    /**
256
+     * Rotates clockwise the puyo p[1] around p[0].
257
+     * <p><b>DETAILED DESCRIPTION:</b><br>
258
+     *     p[0] will always be the pivot around which p[1] will rotate<br>
259
+     *     Determine the orientation of the pair:   HORIZONTAL or VERTICAL<br>
260
+     *     Determine position of p[1]           :   NORTH EAST SOUTH or WEST<br>
261
+     *     Move according to the determined position.<br>
262
+     *     Simple??
263
+     * </p>
264
+     * @param p Pair of puyos to rotate.
265
+     */
266
+    public void rotate(puyo[] p){
267
+        //only a pair can be rotated
268
+        if (p[0].getY()==p[1].getY()){
269
+            //=>lie in same row
270
+            if(p[1].getX() == p[0].getX() + 1){
271
+                //p[1] is on right => move p[1] SOUTH
272
+                if(insertInBoardMap(p[1], p[0].getX(), p[0].getY()+1)){
273
+                    //the cell below p[0] is empty & successful move has taken place
274
+                    //nullify previous position and update the status of puyo p[1]
275
+                    boardMap[p[1].getX()][p[1].getY()] = null;
276
+                    p[1].setX(p[0].getX());     p[1].setY(p[0].getY()+1);
277
+                }
278
+            } else if(p[0].getX() == p[1].getX() + 1) {
279
+                //p[1] is on the left => move p[1] NORTH
280
+                if(insertInBoardMap(p[1], p[0].getX(), p[0].getY()-1)){
281
+                    boardMap[p[1].getX()][p[1].getY()] = null;
282
+                    p[1].setX(p[0].getX());     p[1].setY(p[0].getY()-1);
283
+                }
284
+            }
285
+        }// horizontal case ends here
286
+        else if(p[0].getX() == p[1].getX()){
287
+            //=> lie in the same column
288
+            if(p[0].getY() == p[1].getY() + 1){
289
+                //p[1] is above p[0] => move p[1] EAST
290
+                if(insertInBoardMap(p[1], p[0].getX()+1, p[0].getY())){
291
+                    boardMap[p[1].getX()][p[1].getY()] = null;
292
+                    p[1].setX(p[0].getX() + 1);     p[1].setY(p[0].getY());
293
+                }
294
+            } else if(p[1].getY() == p[0].getY()+1){
295
+                //p[1] is below p[0] => move p[1] WEST
296
+                if(insertInBoardMap(p[1], p[0].getX()-1, p[0].getY())){
297
+                    boardMap[p[1].getX()][p[1].getY()] = null;
298
+                    p[1].setX(p[0].getX() - 1);     p[1].setY(p[0].getY());
299
+                }
300
+            }
301
+        }
302
+    }// end of the function
303
+    
304
+    /**
305
+     * Holds all the puyos to be removed from the {@link puyopuyo.backEnd#boardMap boardMap} due to them forming a chain
306
+     * of {@link puyopuyo.backEnd#popmin popmin} length.
307
+     */
308
+    private Stack puyosToBePopped = new Stack();
309
+    /**
310
+     * Holds the next set of puyos which have to be settled down and then checks
311
+     * have to be made once they cannot move downwards anymore.
312
+     */
313
+    private Stack nextSetOfPuyos = new Stack();
314
+    /**
315
+     * It is the entry point for {@link puyopuyo.frontEnd# frontEnd}.
316
+     * 
317
+     * <p>It also acts as 'manager', controlling the three methods that comprise the core logic:
318
+     * <ul>
319
+     *        <li>{@link puyopuyo.backEnd#probe(puyo) probe(puyo)}</li>
320
+     *        <li>{@link puyopuyo.backEnd#popAndMarkDroppings(HashSet) popAndMarkDroppings(HashSet)}</li>
321
+     *        <li>{@link puyopuyo.backEnd#settleDown(puyo) settleDown(puyo)}</li>
322
+     * </ul></p>
323
+     * @param p Puyo for which chain has to be identified and popped from the board.
324
+     */
325
+    public synchronized void popPuyos(puyo p[]){
326
+        //both of the puyos in the pair have settled down, check can begin with any puyo
327
+        
328
+        if(p.length == 0)    return; //termination condition for recursion. no more puyos available to work on
329
+        HashSet marked = new HashSet();
330
+        puyo[] temp;
331
+        for(int i = 0; i<p.length; i++){
332
+            marked = probe(p[i]);
333
+            if(marked.size()>=popmin)
334
+                puyosToBePopped.push(new HashSet(marked));
335
+            marked.clear();
336
+        }
337
+        
338
+        while(!puyosToBePopped.isEmpty()){
339
+            temp = popAndMarkDroppings((HashSet)puyosToBePopped.pop());
340
+            if(temp.length > 0)
341
+                nextSetOfPuyos.push(temp);
342
+        }
343
+        
344
+        Iterator scan = nextSetOfPuyos.iterator();//iterator doesn't remove from stack. Popping is done in next loop
345
+        while(scan.hasNext()){
346
+            temp = (puyo[])scan.next();
347
+            /*puyos are sorted in ascending order of getY() [popAndMarkDroppings returns a sorted array].
348
+             * The ones with greater value of Y need to be moved down before others otherwise they'll
349
+             * block the path of puyos above them... eventually leaving some puyos hanging in mid air.
350
+             */
351
+            for(int i=temp.length -1; i>=0; i--)
352
+                settleDown(temp[i]);
353
+        }
354
+        while(!nextSetOfPuyos.isEmpty())
355
+            popPuyos((puyo[])nextSetOfPuyos.pop());
356
+    }
357
+    
358
+    /**
359
+     * Settles the puyo passed as parameter down to the floor and also all the puyos above it.
360
+     * @param p Puyo to be moved down.
361
+     */
362
+    private synchronized void settleDown(puyo p){
363
+        int xPos = p.getX();
364
+        int yPos = p.getY();
365
+        //xPos and yPos are modified, xCopy and yCopy are used to check termination condition for recursion.
366
+        while(p!=null && insertInBoardMap(p, xPos, yPos+1)){
367
+            p.setY(yPos+1);
368
+            removeFromBoardMap(xPos, yPos);
369
+            yPos++;
370
+        }
371
+    }
372
+    
373
+    
374
+    /**
375
+     * Holds the puyos to be popped from {@link puyopuyo.backEnd#boardMap boardMap} as they form chains of length >= {@link puyopuyo.backEnd#popmin popmin}.
376
+     */
377
+    private HashSet removePuyos = new HashSet();
378
+    
379
+    /**
380
+     * Returns the set of puyos to be moved down because of chains formed by
381
+     * puyo, being passed as the argument.
382
+     * @param p Puyo for which chains on the board have to be identified.
383
+     * @return Set of puyos to be removed from the boardMap.
384
+     */
385
+    private synchronized HashSet probe(puyo p){
386
+        
387
+        removePuyos.add(p);    //****mark the puyo for which checks have to be done
388
+        
389
+        
390
+        int nextX = p.getX(), nextY = p.getY();
391
+        int directions[]={-1, +1};
392
+        
393
+        /* Description of the following loop:
394
+         * This method is called recursively and proceeds forward in the correct
395
+         * direction. Correct direction here is defined as that direction where
396
+         * a puyo with same color exists. procession is done by calling the same
397
+         * function with the new puyo (stored in temp).
398
+         * First it probes the one to left and proceeds in that direction, if
399
+         * there's a proper match. Then the one to right is checked. The above
400
+         * 2 activities are done in the first for loop.
401
+         * Likewise, the second for loop checks first below current puyo and
402
+         * then the puyo above it.
403
+         * In both the loops, if a matching puyo exists above, below or to left
404
+         * or right, the MATCHED puyo is added to the Set which holds the *unique*
405
+         * puyos to be removed. Then the control passes onto MATCHED puyo.
406
+         * Because the set holds unique values only, the control doesnot allow
407
+         * probing to proceed in direction of puyo already matched. Hence the
408
+         * control finally goes towards any uncharted direction.
409
+         * MATCHED puyo is added because when we reach end of a chain, the last
410
+         * puyo in a chain will not be added because the puyo from which the
411
+         * control came will already be in the set, hence not allowing the last
412
+         * matched puyo to be added to the set.
413
+         */
414
+        for (int i = 0 ; i < directions.length; i++){
415
+            nextX = p.getX()+directions[i];
416
+            if( (nextX >= 0 & nextX < puyosOnXAxis) && boardMap[nextX][nextY]!=null){ //boundary conditions
417
+                if(p.getColor()==boardMap[nextX][nextY].getColor()){
418
+                    if(removePuyos.add(boardMap[nextX][nextY]))
419
+                        //successful addition => temp has not been parsed previously, add it to set
420
+                        probe(boardMap[nextX][nextY]);   //proceed forward with the check in its direction
421
+                }
422
+            }
423
+        }
424
+        nextX = p.getX();   //nextX was changed by above loop
425
+        for (int i = 0 ; i < directions.length; i++){
426
+            nextY = p.getY()+directions[i];
427
+            if( (nextY >= 0 & nextY < puyosOnYAxis) && boardMap[nextX][nextY]!=null){  //boundary conditions
428
+                if(p.getColor()==boardMap[nextX][nextY].getColor()){
429
+                    if(removePuyos.add(boardMap[nextX][nextY]))
430
+                        //successful addition => temp has not been parsed previously, add it to set
431
+                        probe(boardMap[nextX][nextY]);   //proceed forward with the check in temp puyo's direction
432
+                }
433
+            }//end of if checking boundary condition
434
+        }
435
+        
436
+        return removePuyos;
437
+        
438
+    }//end of probe()
439
+    /**
440
+     * Pop the puyos marked by {@link puyopuyo.backEnd#probe(puyo) probe(puyo)} and also identifies all the puyos which have
441
+     * to be moved down because of popping.
442
+     * @param deletePuyos Puyos which have to be deleted from the boardMap.
443
+     * @return Puyos which have to be moved down.
444
+     */
445
+    private synchronized puyo[] popAndMarkDroppings(HashSet deletePuyos){    //:) pun intended
446
+        
447
+        /* it works on vectors and returns an array of puyos.
448
+         *Vectors are being used because they are already synchronized, can be
449
+         *converted to arrays after everything is done and can be resized dynamically
450
+         */
451
+        Vector v = new Vector();
452
+        puyo temp;
453
+        puyo puyoAboveTemp;
454
+        Iterator i = deletePuyos.iterator();
455
+        while(i.hasNext()){//goin thru each element exactly once
456
+            temp = (puyo)i.next();  //get an element from the set
457
+            //popping routine//
458
+            boardMap[temp.getX()][temp.getY()] = null; //remove temp from boardMap if not already removed
459
+            score+=10; //increment score by 10
460
+            //---------------//
461
+            //Marking routine//
462
+            try{
463
+                do{
464
+                    puyoAboveTemp = boardMap[temp.getX()][temp.getY()-1];
465
+                    if( (puyoAboveTemp!=null && !v.contains(puyoAboveTemp)) & !deletePuyos.contains(puyoAboveTemp) )  //puyoAboveTemp has not been already marked
466
+                        v.add(puyoAboveTemp);//add it to set of puyos to be moved down
467
+                    temp = puyoAboveTemp;
468
+                }while( temp!=null ); //puyo above the one being removed exists and is not the one to be popped
469
+            } catch (ArrayIndexOutOfBoundsException e){
470
+                /* This happens in a very special case in which a pair falls down
471
+                 *and one among then is blocked at y=0 and the other falls down
472
+                 *making a chain in the coloumn which is filled till y=0. When
473
+                 *the chain pops, the above loop moves upward and on finding 'puyoAboveTemp'
474
+                 *above puyo at y=0, it reports this exception. because it is a 
475
+                 *very special case, it need not be checked in the normal flow.
476
+                 *
477
+                 *When the exception occurs, the method should just continue with
478
+                 *popping the chain as all the puyos making up the column have been marked.
479
+                 *When exception has occured, control is already outside the loop and 
480
+                 *should proceed normally with the outer while loop...
481
+                 */
482
+                puyoAboveTemp = null;
483
+            }
484
+            //---------------//
485
+           temp = null; //puyoAboveTemp is null when control reaches here.
486
+        }//end of while
487
+        
488
+        puyo[] movePuyosDown = new puyo[v.size()];
489
+        movePuyosDown  = (puyo[])v.toArray(movePuyosDown);
490
+        v.clear();
491
+        if(movePuyosDown.length > 1)
492
+            Arrays.sort(movePuyosDown, new Comparator(){
493
+                public int compare(Object p1, Object p2){
494
+                    if ( (p1!=null && !(p1 instanceof puyo)) & (p2!=null && !(p2 instanceof puyo)) )
495
+                        throw new ClassCastException();
496
+                    /*In case of one puyo being null, the one's that aint null is returned
497
+                     to be greater. If both are null, value corresponding to equality is returned*/
498
+                    if( (p1 == null) & (p2 instanceof puyo) )
499
+                        return -1;   //once this evaluates to true, the control should not go further, thats y return statement is used here.
500
+                    else if ( (p1 instanceof puyo) & (p2 == null))
501
+                        return 1;
502
+                    else if ( (p1 == null) & (p2 == null))
503
+                        return 0;
504
+                    int retVal = 0;
505
+                    if ( ((puyo)p1).getY() < ((puyo)p2).getY() )
506
+                        retVal = -1;
507
+                    else if ( ((puyo)p1).getY() > ((puyo)p2).getY())
508
+                        retVal = 1;
509
+                    //if the two are equal, retVal = 0, which is the default value.
510
+                    return retVal;
511
+                }
512
+            } /* end of anonymous inner class*/
513
+            );
514
+            return movePuyosDown;
515
+    }
516
+}
... ...
@@ -0,0 +1,611 @@
1
+/*
2
+ * frontEnd.java
3
+ *
4
+ * Created on 30 March, 2007, 12:04 AM
5
+ *
6
+ * To change this template, choose Tools | Template Manager
7
+ * and open the template in the editor.
8
+ */
9
+
10
+import java.awt.AWTException;
11
+import java.awt.Color;
12
+import java.awt.Cursor;
13
+import java.awt.DisplayMode;
14
+import java.awt.Font;
15
+import java.awt.Graphics2D;
16
+import java.awt.Point;
17
+import java.awt.RenderingHints;
18
+import java.awt.Robot;
19
+import java.awt.Toolkit;
20
+import java.awt.Window;
21
+import java.awt.event.KeyEvent;
22
+import java.awt.event.KeyListener;
23
+import java.awt.event.MouseEvent;
24
+import java.awt.event.MouseListener;
25
+import java.awt.event.MouseMotionListener;
26
+import java.awt.image.ImageObserver;
27
+import java.io.File;
28
+import javax.swing.SwingUtilities;
29
+
30
+/**
31
+ * frontEnd manages the screen using {@link puyopuyo.ScreenManager# ScreenManager} and calls on {@link puyopuyo.backEnd# backEnd}
32
+ * to execute the logic.
33
+ * @author Dev Ghai
34
+ */
35
+public class frontEnd extends backEnd implements KeyListener, MouseMotionListener, MouseListener {
36
+    
37
+    /**
38
+     * <CODE>ImageObserver</CODE> object used to wait on puyo's image to
39
+     * load so that its heigth and width can be determined.
40
+     */
41
+    private ImageObserver observer;
42
+    /**
43
+     * Holds the width of the image representing the {@link puyopuyo.puyo# puyo}. It is assumed that all
44
+     * the images representing puyos have same height and width.
45
+     */
46
+    private final int puyoWidth = getPuyoPair()[0].getImage().getWidth(observer);
47
+   
48
+    /**
49
+     * Holds the height of the image representing the {@link puyopuyo.puyo# puyo}. It is assumed that all
50
+     * the images representing puyos have same height and width.
51
+     */
52
+    private final int puyoHeight = getPuyoPair()[1].getImage().getHeight(observer);
53
+
54
+    /**
55
+     * Used for printing on screen.
56
+     */
57
+    private Graphics2D g;
58
+    /**
59
+     * Returns the current graphics context.
60
+     */
61
+    private Graphics2D getG(){
62
+        return g;
63
+    }
64
+    
65
+    /**
66
+     * Sets the current graphics context.
67
+     */
68
+    private void setG(Graphics2D gr){  //used for initializing g
69
+        g = gr;
70
+    }
71
+    /**
72
+     * Creates a new instance of <CODE>frontEnd</CODE>
73
+     */
74
+    public frontEnd(){
75
+    }
76
+    
77
+    /**
78
+     * <ul><li>Creates an instance of the class.</li>
79
+     * <li>Initialises {@link puyopuyo.backEnd#backEnd() backEnd} by calling on its constructor.</li>
80
+     * <li>Adds the mouse and keyboard listeners.</li>
81
+     * <li>Draws the complete screen for the first time.</li></ul>
82
+     * @param autodetect Whether to autodetect the resolution at which to run the game.
83
+     */
84
+    public frontEnd(boolean autodetect) {
85
+        super();
86
+        initializeGraphics(autodetect);
87
+                
88
+        //add the listeners
89
+        Window window = screen.getFullScreenWindow();
90
+        window.addMouseListener(this);
91
+        window.addMouseMotionListener(this);
92
+        window.addKeyListener(this);
93
+        
94
+        drawBoardMap();
95
+    }
96
+    
97
+    /**
98
+     * Object of {@link puyopuyo.ScreenManager# ScreenManager}.
99
+     */
100
+    private ScreenManager screen;
101
+    /**
102
+     * Array of supported display modes.
103
+     */
104
+    private DisplayMode dm[];
105
+    /**
106
+     * Font used for printing text on the screen.
107
+     */
108
+    private Font f = new Font("Dialog", Font.PLAIN, 10);    //initializing with a dummy value.
109
+    /**
110
+     * Color of the border surrounding the playing area.
111
+     */
112
+    private Color borderColor = Color.ORANGE;
113
+    /**
114
+     * Color of the board. This color is also used as a background color to fill the screen.
115
+     */
116
+    private Color boardColor = Color.WHITE;
117
+    /**
118
+     * Width of the border surrounding the playing area, in pixels.
119
+     */
120
+    private int borderWidth = 8;
121
+    
122
+    /**
123
+     * <ul>
124
+     *    <li>Switch to most appropriate display resolution.</li>
125
+     *    <li>Switch to full screen if system allows to, else exit.</li>
126
+     *    <li>Determine the co-ordinates at which to print the score.</li>
127
+     *    <li>Initialize mouse.</li>
128
+     *    <li>Set the current Graphics context.</li>
129
+     *    <li>Initialize the font.</li>
130
+     * </ul>
131
+     * @param autodetect Enable autodetection of graphics mode or not.
132
+     */
133
+    private void initializeGraphics(boolean autodetect){
134
+        boolean switchedToFullscreen = false;
135
+        System.out.println("Initializing Graphics...");
136
+        screen = new ScreenManager();
137
+        if(autodetect){
138
+            dm = screen.getCompatibleDisplayModes();
139
+            System.out.println("Available Display Modes: ");
140
+            for(int i=dm.length-1 ; i>=0; i--){
141
+                System.out.println(dm[i].getWidth() + "x" + dm[i].getHeight() + " @ " + dm[i].getBitDepth() + " bits");
142
+                //Loop's runing in reverse dir coz in Windows systems, the modes are sorted
143
+                //in asc order, and 1024x768 is given preference.
144
+                    if( (dm[i].getWidth() == 1024 && dm[i].getHeight() == 768)
145
+                         || (dm[i].getWidth() == 800 && dm[i].getHeight() == 600) ){
146
+                    screen.setFullScreen(dm[i]);   //switch to fullscreen only if its supported
147
+                    switchedToFullscreen = true;
148
+                    break;
149
+                }
150
+            }
151
+            if(!switchedToFullscreen){
152
+                System.out.println("Your system doesn't support 1024x768 or 800x600 resolutions... \nAutoDetect failed!\nUsing the current DisplayMode");
153
+                screen.setFullScreen(screen.getCurrentDisplayMode());
154
+            }
155
+        }
156
+        else
157
+            screen.setFullScreen(screen.getCurrentDisplayMode());
158
+        System.out.println("PuyosOnXAxis: " + puyosOnXAxis + ", puyosOnYxis: " + puyosOnYAxis);
159
+        System.out.println("Dimensions of puyo's image = " + puyoHeight + "x" + puyoHeight);
160
+        System.out.println("Playing area dimensions: " + playingAreaWidth + "x" + playingAreaHeight);
161
+        System.out.println("Full screened at configuration: " + screen.getWidth() + "x" + screen.getHeight() + " @ " + screen.getCurrentDisplayMode().getBitDepth() + " bits");
162
+        scoreX = (screen.getWidth()/2)-(fontsize*2);
163
+        scoreY = screen.getHeight()-fontsize;
164
+        initializeMouse(screen.getFullScreenWindow());
165
+        Graphics2D g = screen.getGraphics();
166
+        setG(g);
167
+        getG().setRenderingHint(
168
+            RenderingHints.KEY_TEXT_ANTIALIASING,
169
+            RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
170
+        initializeFont();
171
+    }
172
+    /**
173
+     * Set the font file to use, over-riding the default font created during initialization.
174
+     */
175
+    private void initializeFont(){
176
+        File fontfile = new File("Pokemon.ttf");
177
+        try{
178
+            f = Font.createFont(Font.TRUETYPE_FONT, fontfile);
179
+        } catch(Exception ffe){
180
+            System.out.println("Font format Exception: " + ffe.toString());
181
+        }
182
+        getG().setFont(f.deriveFont((float)fontsize));
183
+        System.out.println("Using font: " + fontfile.toString());
184
+        getG().setColor(Color.RED);
185
+    }
186
+    
187
+    /**
188
+     * Stores X co-ordinate of the board (board contains playing area)
189
+     */
190
+    private int boardX;
191
+    /**
192
+     * Stores Y Co-ordinate of the board (board contains playing area)
193
+     */
194
+    private int boardY = 10;
195
+    /**
196
+     * playingAreaWidth = {@link puyopuyo.frontEnd#puyoWidth puyoWidth} * {@link puyopuyo.backEnd#puyosOnXAxis puyosOnXAxis}.
197
+     */
198
+    private final int playingAreaWidth = puyoWidth * puyosOnXAxis;
199
+    /**
200
+     * playingAreaHeight = {@link puyopuyo.frontEnd#puyoHeight puyoHeight} * {@link puyopuyo.backEnd#puyosOnYAxis puyosOnYAxis}.
201
+     */
202
+    private final int playingAreaHeight = puyoHeight * puyosOnYAxis;
203
+    /**
204
+     * Size of the font used for printing text on the screen.
205
+     */
206
+    private int fontsize = 50;
207
+    /**
208
+     * X co-ordinate of the point where score has to be printed.
209
+     */
210
+    private int scoreX;
211
+    /**
212
+     * Y co-ordinate of the point where score has to be printed.
213
+     */
214
+    private int scoreY;
215
+
216
+    /**
217
+     * Fills the screen with background color and draws the outline of the playing area.
218
+     */
219
+    public void drawScreen(){
220
+        //fill the screen with background color
221
+        getG().setColor(boardColor);
222
+        getG().fillRect(0, 0, screen.getWidth(), screen.getHeight());
223
+        //Board has to be center aligned horizontally
224
+        boardX = (screen.getWidth()/2) - ((playingAreaWidth+(2*borderWidth))/2);
225
+        //Draw the board
226
+        getG().setColor(borderColor);
227
+        getG().fillRoundRect(boardX,
228
+                boardY,
229
+                playingAreaWidth+(borderWidth*2),
230
+                playingAreaHeight+(borderWidth*2),
231
+                borderWidth,
232
+                borderWidth);
233
+        getG().setColor(boardColor);
234
+        getG().fillRoundRect(boardX + borderWidth,
235
+                boardY + borderWidth,
236
+                playingAreaWidth,
237
+                playingAreaHeight,
238
+                borderWidth,
239
+                borderWidth);
240
+        //Score Area
241
+        getG().fillRect(boardX, screen.getHeight()-(fontsize*2), screen.getWidth()/2, fontsize*2);  
242
+    }
243
+    
244
+    /**
245
+     * Draws puyos according to the {@link puyopuyo.backEnd#boardMap boardMap} within the playing
246
+     * area drawn by {@link puyopuyo.frontEnd#drawScreen() drawScreen}.
247
+     */
248
+    public synchronized void drawBoardMap(){
249
+        drawScreen();        //MS Windows specific.
250
+        getG().setColor(boardColor);
251
+        getG().fillRoundRect(boardX + borderWidth,
252
+                boardY + borderWidth,
253
+                playingAreaWidth,
254
+                playingAreaHeight,
255
+                borderWidth,
256
+                borderWidth);
257
+        //Score Area
258
+        getG().fillRect(boardX, screen.getHeight()-(fontsize*2), screen.getWidth()/2, fontsize*2);
259
+        puyo board[][] = super.getBoardMap();
260
+        for (int j=0; j<puyosOnYAxis; j++)
261
+            for(int i=0; i<puyosOnXAxis; i++){
262
+            if(board[i][j]!=null)
263
+                getG().drawImage(board[i][j].getImage(),
264
+                        boardX + borderWidth + (puyoWidth*i),
265
+                        boardY + borderWidth + (puyoHeight*j),
266
+                        null);
267
+            }
268
+        //Print the score
269
+        getG().setColor(Color.RED);
270
+        getG().drawString("Score: "+getScore(), scoreX, scoreY);
271
+        screen.update();
272
+    }
273
+    
274
+    /**
275
+     * Direction in which to rotate the puyo. This value tells {@link puyopuyo.frontEnd#movementWrapper(int) movementWrapper}
276
+     * to move the pair one step left.
277
+     */
278
+    private final int LEFT = 1;
279
+    /**
280
+     * Direction in which to rotate the puyo. This value tells {@link puyopuyo.frontEnd#movementWrapper(int) movementWrapper}
281
+     * to move the pair one step right.
282
+     */
283
+    private final int RIGHT = 2;
284
+    /**
285
+     * Direction in which to rotate the puyo. This value tells {@link puyopuyo.frontEnd#movementWrapper(int) movementWrapper}
286
+     * to move the pair one step down, or in other words, accelerate their fall.
287
+     */
288
+    private final int DOWN = 3;
289
+    /**
290
+     * It directs {@link puyopuyo.frontEnd#movementWrapper(int) movementWrapper} to rotate the pair.
291
+     */
292
+    private final int ROTATE = 4;
293
+    
294
+    /**
295
+     * Tells whether the game is paused or not. If it is, all the Mouse and
296
+     * Keyboard events are ignored. However, user is allowed to exit from the
297
+     * game.
298
+     */
299
+    private boolean paused = false;
300
+
301
+    /**
302
+     * Takes care of the movements on screen.
303
+     * <p>Converts the pair of puyos on screen to single puyos and operates on them.<br>
304
+     *     Note that all calls to {@link puyopuyo.backEnd# backEnd }have been synchronized. This also ensures
305
+     *     that though operations are performed on a pair, logically operations are
306
+     *     performed individually on each {@link puyopuyo.puyo# puyo}.
307
+     * </p>
308
+     * @param direction Direction in which to move the pair, or rotate it clockwise.
309
+     */
310
+    public synchronized void movementWrapper(int direction)    {
311
+        if(paused == true || isGameOver())  return;
312
+        boolean lowerCouldMove = false;
313
+        boolean upperCouldMove = false; //used to detect 'collisions'
314
+        int lower = -1; //index of the puyo which is lower when the 2 r vertically arranged
315
+        int upper = -1; //if any of the values is modified, this implies the puyos are arranged vertically
316
+        //Check the one which is below
317
+        if( (getPuyoPair()[0].getY()-1) == getPuyoPair()[1].getY() ){
318
+            //puyo at [0] is below
319
+            lower = 0;
320
+            upper = 1;
321
+        } else if ( (getPuyoPair()[1].getY()-1) == getPuyoPair()[0].getY() ){
322
+            //[1]'s below
323
+            lower = 1;
324
+            upper = 0;
325
+        }
326
+        switch(direction){
327
+            case LEFT:
328
+                if( (getPuyoPair()[0].getY() != getPuyoPair()[1].getY()) &
329
+                        (getPuyoPair()[0].getX() != getPuyoPair()[1].getX()))
330
+                    return; //return back without doing anything if the puyos dont lie in single row or single column
331
+                if (lower != -1){  //VERTICAL ORIENTATION [PATCH]
332
+                    if(moveLeft(getPuyoPair()[lower]))
333
+                        moveLeft(getPuyoPair()[upper]);  //move upper to left only if lower could move left first
334
+                }
335
+                //HORIZONTAL ORIENTATION: Check the one which is to left
336
+                else if(getPuyoPair()[0].getX() == (getPuyoPair()[1].getX()-1) ){
337
+                    //puyo at [0] is to left and both the puyos are joined
338
+                    moveLeft(getPuyoPair()[0]);
339
+                    moveLeft(getPuyoPair()[1]);
340
+                } else{
341
+                    //either the Xpositions are equal or [1]'s on left
342
+                    moveLeft(getPuyoPair()[1]);
343
+                    moveLeft(getPuyoPair()[0]);
344
+                }
345
+                break;
346
+            case RIGHT:
347
+                if( (getPuyoPair()[0].getY() != getPuyoPair()[1].getY()) &
348
+                        (getPuyoPair()[0].getX() != getPuyoPair()[1].getX()))
349
+                    return; //return back without doing anything if the puyos dont lie in single row or single column
350
+                if (lower != -1){  //VERTICAL ORIENTATION [PATCH]
351
+                    if(moveRight(getPuyoPair()[lower]))
352
+                        moveRight(getPuyoPair()[upper]);  //move upper to left only if lower could move left first
353
+                }
354
+                //HORIZONTAL ORIENTATION: Check the one which is to right
355
+                else if(getPuyoPair()[0].getX() == (getPuyoPair()[1].getX()-1) ){
356
+                    //puyo at [1] is to right
357
+                    moveRight(getPuyoPair()[1]);
358
+                    moveRight(getPuyoPair()[0]);
359
+                } else{
360
+                    //either the X positions are equal or [0]'s on right
361
+                    moveRight(getPuyoPair()[0]);
362
+                    moveRight(getPuyoPair()[1]);
363
+                }
364
+                break;
365
+            case DOWN: 
366
+                if(lower == -1){ //HORIZONTAL ORIENTATION => move any of the puyos first.
367
+                    lower = 1;
368
+                    upper = 0;
369
+                }
370
+                lowerCouldMove = moveDown(getPuyoPair()[lower]);
371
+                upperCouldMove = moveDown(getPuyoPair()[upper]);
372
+                //launch chain rxn of popping if both couldn't move
373
+                if( !lowerCouldMove & !upperCouldMove ){
374
+                    popPuyos(getPuyoPair());
375
+                    drawBoardMap();
376
+                    //now that the 2 have settled, push a new pair on board
377
+                    pushPuyos();
378
+                }
379
+                break;
380
+            case ROTATE: rotate(getPuyoPair());
381
+            break;
382
+        }
383
+        drawBoardMap();
384
+    }
385
+
386
+    /**
387
+     * <CODE>KeyEvent</CODE> listener that is responsible for firing appropriate actions corresponding
388
+     * to the key pressed.
389
+     * <p><ul><b>UP ARROW KEY</b> - Rotate the pair.</ul>
390
+     * <ul><b>LEFT ARROW KEY</b> - Move the pair to left.</ul>
391
+     * <ul><b>RIGHT ARROW KEY</b> - Move the pair to right.
392
+     * <ul><b>DOWN ARROW KEY</b> - Move the pair downwards/accelerate the fall.</ul>
393
+     * <ul><b>SPACEBAR</b> - Pause the game.</ul>
394
+     * <ul><b>ESC</b> - Quit from the game.</ul></p>
395
+     * @param e Virtual code of the key pressed.
396
+     */
397
+    public void keyPressed(KeyEvent e){
398
+        switch(e.getKeyCode()){
399
+            case KeyEvent.VK_ESCAPE:    setGameOver(true);          break;
400
+            case KeyEvent.VK_LEFT:      movementWrapper(LEFT);      break;
401
+            case KeyEvent.VK_RIGHT:     movementWrapper(RIGHT);     break;
402
+            case KeyEvent.VK_DOWN:      movementWrapper(DOWN);      break;
403
+            case KeyEvent.VK_UP:        movementWrapper(ROTATE);    break;
404
+            case KeyEvent.VK_SPACE:     paused = !paused;           break;
405
+        }
406
+    }
407
+    
408
+    /**
409
+     * <CODE>KeyListener</CODE> Interface: keyReleased. Ignored.
410
+     */
411
+    public void keyReleased(KeyEvent e){
412
+        //do nothing!
413
+    }
414
+    
415
+    /**
416
+     * <CODE>KeyListener</CODE> Interface: keyTyped. Ignored.
417
+     */
418
+    public void keyTyped(KeyEvent e){
419
+        //do nothing!
420
+    }
421
+    
422
+    
423
+    
424
+    /**
425
+     * From the <CODE>MouseListener</CODE> interface. <CODE>MouseListener</CODE> responsible for firing 
426
+     * appropriate events corresponding to the key pressed.
427
+     */
428
+    public void mousePressed(MouseEvent e) {
429
+        movementWrapper(ROTATE) ;
430
+    }
431
+    
432
+    /**
433
+     * From the <CODE>MouseListener</CODE> interface. Ignored.
434
+     */
435
+    public void mouseReleased(MouseEvent e) {
436
+        // do nothing
437
+    }
438
+    
439
+    /**
440
+     * From the <CODE>MouseListener</CODE> interface. Ignored.
441
+     */
442
+    public void mouseClicked(MouseEvent e) {
443
+        // called after mouse is released - ignored
444
+    }
445
+    
446
+    /**
447
+     * From the <CODE>MouseListener</CODE> interface. Ignored.
448
+     */
449
+    public void mouseEntered(MouseEvent e) {
450
+        //do nothing
451
+    }
452
+    
453
+    /**
454
+     * From the <CODE>MouseListener</CODE> interface. Ignored.
455
+     */
456
+    public void mouseExited(MouseEvent e) {
457
+        //do nothing
458
+    }
459
+    
460
+    /**
461
+     * From the <CODE>MouseMotionListener</CODE> interface. Ignored.
462
+     */
463
+    public void mouseDragged(MouseEvent e) {
464
+        //do nothing
465
+    }
466
+    
467
+    /**
468
+     * From the <CODE>MouseMotionListener</CODE> interface. Determines in which direction has
469
+     * the mouse moved and then recenters it.
470
+     */
471
+    public synchronized void mouseMoved(MouseEvent e) {
472
+        if(paused == true) return;
473
+        // this event is from re-centering the mouse - ignore it
474
+        if (isRecentering &&
475
+                centerLocation.x == e.getX() &&
476
+                centerLocation.y == e.getY()) {
477
+            isRecentering = false;
478
+        }
479
+        
480
+        else {
481
+            int dx = e.getX() - mouseLocation.x;
482
+            int dy = e.getY() - mouseLocation.y;
483
+            if(dx<0)        //Mouse moved left
484
+                movementWrapper(LEFT);
485
+            else if(dx>0)   //Mouse moved right
486
+                movementWrapper(RIGHT);
487
+            else if(dy>0)   //Mouse moved down
488
+                movementWrapper(DOWN);
489
+            //Movements towards north are to be ignored
490
+            recenterMouse();
491
+            
492
+            
493
+        }
494
+        mouseLocation.x = e.getX();
495
+        mouseLocation.y = e.getY();
496
+    }
497
+    
498
+    /**
499
+     * Object of <CODE>Robot</CODE> class used for recentering the mouse.
500
+     */
501
+    private Robot robot;
502
+    /**
503
+     * <CODE>Point</CODE> object storing the mouse's location.
504
+     */
505
+    private Point mouseLocation;
506
+    /**
507
+     * Holds the center point of the screen.
508
+     */
509
+    private Point centerLocation;
510
+    /**
511
+     * <CODE>Boolean</CODE> telling if the mouse is re-centering or not.
512
+     */
513
+    private boolean isRecentering;
514
+    
515
+    /**
516
+     * Initializes the mouse, recenters it and hides the mouse pointer.
517
+     * @param window Window for which to initialize the mouse.
518
+     */
519
+    private void initializeMouse(Window window){
520
+        //hide the mouse pointer
521
+        Cursor invisibleCursor =
522
+                Toolkit.getDefaultToolkit().createCustomCursor(
523
+                Toolkit.getDefaultToolkit().getImage(""),
524
+                new Point(0,0),"invisible");
525
+        window.setCursor(invisibleCursor);
526
+        System.out.println("Mouse Pointer is now hidden!");
527
+        
528
+        mouseLocation = new Point();
529
+        centerLocation = new Point();
530
+        isRecentering = false;
531
+        
532
+        try {
533
+            robot = new Robot();
534
+            recenterMouse();
535
+            mouseLocation.x = centerLocation.x;
536
+            mouseLocation.y = centerLocation.y;
537
+        } catch (AWTException ex) {
538
+            System.out.println("Couldn't create Robot! Mouse initialization failed!!");
539
+        }
540
+    }
541
+    
542
+    /**
543
+     * Uses the <CODE>Robot</CODE> class to try to position the mouse in the
544
+     * center of the screen.
545
+     * <p>Note that use of the <CODE>Robot</CODE> class may not be available
546
+     * on all platforms.</p>
547
+     */
548
+    private synchronized void recenterMouse() {
549
+        Window window = screen.getFullScreenWindow();
550
+        if (robot != null && window.isShowing()) {
551
+            centerLocation.x = window.getWidth() / 2;
552
+            centerLocation.y = window.getHeight() / 2;
553
+            SwingUtilities.convertPointToScreen(centerLocation,
554
+                    window);
555
+            isRecentering = true;
556
+            robot.mouseMove(centerLocation.x, centerLocation.y);
557
+        }
558
+    }
559
+    /**
560
+     * Kills the thread and exits from the game while restoring the screen
561
+     * and unhiding the mouse pointer.
562
+     */
563
+    public void goodbye(){  //do cleanup ops before exiting
564
+       /* Restore Cursor
565
+        * Restore Screen
566
+        * Kill the thread
567
+        */
568
+	System.out.println("GoodBye!!");
569
+        getG().setColor(Color.MAGENTA);
570
+        getG().drawString("GoodBye!", 10, screen.getHeight()-50);
571
+        getG().drawString(":(", screen.getWidth()-100, screen.getHeight()-50);
572
+        screen.update();
573
+        try {
574
+            Thread.sleep(1000);
575
+        } catch (InterruptedException ex) { }
576
+        Cursor normalCursor =
577
+                Cursor.getDefaultCursor();
578
+        Window window = screen.getFullScreenWindow();
579
+        window.setCursor(normalCursor);
580
+        screen.restoreScreen();
581
+        System.exit(0);
582
+    }
583
+	/**
584
+     * 'Mainest' Method Of ALL :D
585
+     * @param args the command line arguments
586
+     */
587
+    public static void main(String[] args) {
588
+        frontEnd w;
589
+        if(args.length>0 && args[0].equalsIgnoreCase(new String("autodetect")))
590
+             w = new frontEnd(true);
591
+        else w = new frontEnd(false);
592
+        
593
+        while(!w.isGameOver()){
594
+            w.movementWrapper(3);   //3 implies down
595
+            try{
596
+                Thread.sleep(500);
597
+            } catch (InterruptedException ex) {
598
+                System.out.println("Main Thread Interrupted! Reason: " + ex.toString());
599
+            }
600
+        }
601
+		try
602
+		{
603
+			 w.goodbye();
604
+		}
605
+		catch (Exception e)
606
+		{
607
+			System.out.println(e.toString());
608
+		}
609
+       
610
+    }
611
+}
... ...
@@ -0,0 +1,114 @@
1
+/*
2
+ * puyo.java
3
+ *
4
+ * Created on 16 April, 2007, 3:00 AM
5
+ *
6
+ * To change this template, choose Tools | Template Manager
7
+ * and open the template in the editor.
8
+ */
9
+
10
+import java.awt.Image;
11
+import javax.swing.ImageIcon;
12
+
13
+/**
14
+ * Creates a puyo object that holds all the its properties- 
15
+ * the image representing the puyo, logical x and y positions (in array {@link puyopuyo.backEnd#boardMap boardMap})
16
+ * and a character representing the color of the puyo.
17
+ * @author Dev Ghai
18
+ */
19
+public class puyo{
20
+    
21
+     /**
22
+     * Creates a new puyo and associates image file <b>filename</b> to the puyo
23
+     * and sets its color to <b>c</b>.
24
+     * @param filename File name of the image that has to be associated with the puyo.
25
+     * @param c Color of the puyo
26
+     * <p>Following are its possible values:
27
+     * <ul>
28
+     *    <li>'r' - Red</li>
29
+     *    <li>'g' - Green</li>
30
+     *    <li>'b' - Blue</li>
31
+     *    <li>'y' - Yellow</li>
32
+     * </ul>
33
+     */
34
+    public puyo(String filename, char c){
35
+        image = new ImageIcon(filename).getImage();
36
+        x=0;
37
+        y=0;
38
+        color = c;
39
+    }
40
+    /**
41
+     * Creates a default puyo without assigning any image or color to it.
42
+     */
43
+    public puyo(){}
44
+    /**
45
+     * Holds the image that represents the puyo.
46
+     */
47
+    private Image image;
48
+    
49
+    /**
50
+     * Returns the image associated with the puyo.
51
+     */
52
+    public Image getImage(){
53
+        return image;
54
+    }
55
+    
56
+    /**
57
+     * Holds the X-Co-ordinate of the puyo in {@link puyopuyo.backEnd#boardMap}
58
+     */
59
+    private int x;
60
+    
61
+    /**
62
+     * Returns the X-Co-ordinate of the puyo in {@link puyopuyo.backEnd#boardMap boardMap}.
63
+     */
64
+    public int getX(){
65
+        return x;
66
+    }
67
+    
68
+    /**
69
+     * Sets the X-Co-ordinate of the puyo in {@link puyopuyo.backEnd#boardMap boardMap} to xPos.
70
+     * @param xPos New x position of puyo in {@link puyopuyo.backEnd#boardMap boardMap}.
71
+     */
72
+    public void setX(int xPos){
73
+        x = xPos;
74
+    }
75
+    
76
+    /**
77
+     * Holds the Y-Co-ordinate of the puyo
78
+     */
79
+    private int y;
80
+    
81
+    /**
82
+     * Returns the Y-Co-ordinate of the puyo in the {@link puyopuyo.backEnd#boardMap boardMap}
83
+     */
84
+    public int getY(){
85
+        return y;
86
+    }
87
+    
88
+    /**
89
+     * Sets the Y-Co-ordinate of the puyo in {@link puyopuyo.backEnd#boardMap boardMap} to yPos.
90
+     * @param yPos New y position of puyo in {@link puyopuyo.backEnd#boardMap boardMap}.
91
+     */
92
+    public void setY(int yPos){
93
+        y = yPos;
94
+    }
95
+    
96
+    /**
97
+     * Holds the color of the puyo. The color is stored first letter of the color string.
98
+     * For example 'r' is stored for red.
99
+     */
100
+    private char color;
101
+    
102
+    /**
103
+     * Returns the color of the puyo -
104
+     * <ul>
105
+     *    <li>'r' - Red</li>
106
+     *    <li>'g' - Green</li>
107
+     *    <li>'b' - Blue</li>
108
+     *    <li>'y' - Yellow</li>
109
+     * </ul>
110
+     */
111
+    public char getColor(){
112
+        return color;
113
+    }
114
+}
... ...
@@ -0,0 +1 @@
1
+..\..\..\Java\bin\java.exe frontEnd
0 2
\ No newline at end of file
... ...
@@ -0,0 +1 @@
1
+java frontEnd
... ...
@@ -0,0 +1 @@
1
+java frontEnd
0 2
\ No newline at end of file
1 3