1 package erland.game.tetris;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import erland.network.NetworkConnectionInterface;
22 import erland.game.GameServerEnvironmentInterface;
23 import erland.game.GamePlayerInterface;
24
25 import java.awt.*;
26
27 public class TetrisPlayer implements GamePlayerInterface {
28 private NetworkConnectionInterface connection;
29 /*** Current active block in the main game area */
30 protected Block block;
31 /*** Current active block in the preview block area */
32 protected Block blockNext;
33 /*** Counter that is increased every update, when it reaches the current game
34 speed the active block will be moved down one step */
35 protected int updateCounter;
36 /*** Number of levels */
37 protected final int MAX_LEVEL=9;
38 /*** Maximum block speed */
39 protected final int MAX_SPEED=20;
40 /*** Current score */
41 protected long score;
42 /*** Current level */
43 protected int level;
44 /*** Number of rows that has been removed in this level */
45 protected int rowsThisLevel;
46 /*** Container representing the main game area */
47 protected BlockContainerData mainContainer;
48 /*** Number of rows that has to be removed before level is increased */
49 protected final int ROWS_PER_LEVEL=10;
50 /*** true if game is completed or game over has occurred */
51 protected boolean bEnd=false;
52 /*** Indicates if the player has updated data */
53 private boolean bUpdated;
54 /*** Game environment */
55 protected GameServerEnvironmentInterface environment;
56
57 public TetrisPlayer(GameServerEnvironmentInterface environment) {
58 this.environment = environment;
59 mainContainer = new BlockContainerData(10,30);
60 init();
61 }
62
63 public void setConnection(NetworkConnectionInterface connection) {
64 this.connection = connection;
65 }
66
67 public NetworkConnectionInterface getConnection() {
68 return connection;
69 }
70
71 public void doCommand(String command) {
72 if(command.equals("RIGHT")) {
73 moveRight();
74 }else if(command.equals("LEFT")) {
75 moveLeft();
76 }else if(command.equals("ROTATE")) {
77 rotateRight();
78 }else if(command.equals("DOWN")) {
79 moveDownBottom();
80 }
81 bUpdated = true;
82 }
83
84 public void init() {
85 mainContainer.clear();
86 }
87
88 public void startNewGame() {
89 bEnd = false;
90 level = 1;
91 score = 0;
92 rowsThisLevel=0;
93 updateCounter=0;
94 mainContainer.clear();
95 block=null;
96 blockNext=null;
97 }
98 public boolean isGameOver() {
99 return bEnd;
100 }
101 public boolean isCompleted() {
102 return (bEnd && level>MAX_LEVEL);
103 }
104 public boolean update() {
105 updateCounter++;
106 if(updateCounter>(MAX_SPEED-level*2)) {
107 updateCounter=0;
108 if(!bEnd) {
109 if(this.block==null) {
110 if(this.blockNext==null) {
111 blockNext = BlockFactory.getInstance().nextBlock(this);
112 }
113 block = blockNext;
114 blockNext = BlockFactory.getInstance().nextBlock(this);
115 blockNext.init(1,0,0);
116 block.init(mainContainer.getWidth()/2,-1,0);
117 if(!block.moveDown(mainContainer)) {
118 removeCompletedRows();
119 environment.getHighScore().save();
120 bEnd = true;
121 }
122 }else {
123 if(!block.moveDown(mainContainer)) {
124 removeCompletedRows();
125 block = null;
126 }
127 }
128 if(rowsThisLevel>=ROWS_PER_LEVEL) {
129 rowsThisLevel-=ROWS_PER_LEVEL;
130 score+=200*level;
131 environment.getHighScore().update(score);
132 level++;
133 }
134 if(level>MAX_LEVEL) {
135 bEnd=true;
136 environment.getHighScore().save();
137 }
138 }
139 return true;
140 }
141 return false;
142 }
143
144 /***
145 * Removes all completed rows in the main game area and increases score
146 */
147 protected void removeCompletedRows()
148 {
149 for(int y=mainContainer.getHeight()-1;y>=0;y--) {
150 boolean bCompleted = true;
151 boolean bCompletedWithSameColor=true;
152 Color c=mainContainer.getColor(0,y);
153 for(int x=0;x<mainContainer.getWidth();x++) {
154 if(!mainContainer.isUsed(x,y)) {
155 bCompleted = false;
156 }else {
157 if(c==null || !c.equals(mainContainer.getColor(x,y))) {
158 bCompletedWithSameColor=false;
159 }
160 }
161 }
162 if(bCompleted) {
163 for(int i=y;i>0;i--) {
164 for(int j=0;j<mainContainer.getWidth();j++) {
165 if(mainContainer.isUsed(j,i-1)) {
166 mainContainer.setUsed(j,i,mainContainer.getColor(j,i-1));
167 }else {
168 mainContainer.setUnused(j,i);
169 }
170 }
171 }
172 mainContainer.clearRow(0);
173 y++;
174 if(!bCompletedWithSameColor) {
175 score+=(10*level);
176 }else {
177 score+=(100*level);
178 }
179 environment.getHighScore().update(score);
180 rowsThisLevel++;
181 }
182 }
183 }
184
185
186 public String getBlockString(Block b) {
187 StringBuffer sb = new StringBuffer(2);
188 Color c = null;
189 if(b!=null) {
190 c = b.getColor();
191 if(c==Color.red) {
192 sb.append('1');
193 }else if(c==Color.green) {
194 sb.append('2');
195 }else if(c==Color.yellow) {
196 sb.append('3');
197 }else if(c==Color.cyan) {
198 sb.append('4');
199 }else if(c==Color.blue) {
200 sb.append('5');
201 }else if(c==Color.pink) {
202 sb.append('6');
203 }else if(c==Color.magenta) {
204 sb.append('7');
205 }else {
206 sb.append('7');
207 }
208
209 int r = b.getRotation();
210 r=r/90;
211 sb.append(r);
212
213 if(b.getX()<10) {
214 sb.append(('0'));
215 }
216 if(b.getX()<0) {
217 sb.append('0');
218 }else {
219 sb.append(b.getX());
220 }
221 if(b.getY()<10) {
222 sb.append(('0'));
223 }
224 if(b.getY()<0) {
225 sb.append(('0'));
226 }else {
227 sb.append(b.getY());
228 }
229 }else {
230 sb.append("000000");
231 }
232 return sb.toString();
233 }
234 public String getNumberString(int length, long number) {
235 StringBuffer sb = new StringBuffer(length);
236 int maxNumber=1;
237 for(int i=1;i<length;i++) {
238 maxNumber*=10;
239 if(number<maxNumber) {
240 sb.append('0');
241 }
242 }
243 sb.append(number);
244 return sb.toString();
245 }
246 public String toString() {
247 bUpdated = false;
248 return getBlockString(block)+getBlockString(blockNext)+mainContainer.toString()+getNumberString(6,score)+getNumberString(6,environment.getHighScore().get())+getNumberString(2,level);
249
250
251 }
252 /***
253 * Move the active block in the main game area one step left
254 * @return true/false (Success/Failure)
255 */
256 public boolean moveLeft()
257 {
258 if(block != null) {
259 return block.moveLeft(mainContainer);
260 }
261 return false;
262 }
263
264 /***
265 * Move the active block in the main game area one step right
266 * @return true/false (Success/Failure)
267 */
268 public boolean moveRight()
269 {
270 if(block != null) {
271 return block.moveRight(mainContainer);
272 }
273 return false;
274 }
275
276 /***
277 * Rotate the active block in the main game area 90 degrees clockwize
278 * @return true/false (Success/Failure)
279 */
280 public boolean rotateRight()
281 {
282 if(block != null) {
283 return block.rotateRight(mainContainer);
284 }
285 return false;
286 }
287
288 /***
289 * Move the active block in the main game area one step down
290 * @return true/false (Success/Failure)
291 */
292 public boolean moveDown()
293 {
294 if(block != null) {
295 return block.moveDown(mainContainer);
296 }
297 return false;
298 }
299
300 public boolean moveDownBottom()
301 {
302 while(moveDown()) {
303 ;
304 }
305 return false;
306 }
307
308 public boolean needUpdate() {
309 return bUpdated;
310 }
311
312 public BlockContainerData getMainContainer() {
313 return mainContainer;
314 }
315
316 public Block getNextBlock() {
317 return blockNext;
318 }
319
320 public long getScore() {
321 return score;
322 }
323
324 public int getLevel() {
325 return level;
326 }
327 }