Skip to content

Commit 91c663c

Browse files
authored
Add files via upload
1 parent b6e91b0 commit 91c663c

File tree

3 files changed

+540
-0
lines changed

3 files changed

+540
-0
lines changed

src/com/zetcode/Board.java

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
package com.zetcode;
2+
3+
import java.awt.Color;
4+
import java.awt.Dimension;
5+
import java.awt.Graphics;
6+
import java.awt.event.KeyAdapter;
7+
import java.awt.event.KeyEvent;
8+
import javax.swing.JLabel;
9+
import javax.swing.JPanel;
10+
import java.util.Timer;
11+
12+
import java.util.TimerTask;
13+
import com.zetcode.Shape.Tetrominoe;
14+
15+
public class Board extends JPanel {
16+
17+
private static final long serialVersionUID = 1L;
18+
private final int BOARD_WIDTH = 10;
19+
private final int BOARD_HEIGHT = 22;
20+
private final int INITIAL_DELAY = 100;
21+
private final int PERIOD_INTERVAL = 300;
22+
23+
private Timer timer;
24+
private boolean isFallingFinished = false;
25+
private boolean isStarted = false;
26+
private boolean isPaused = false;
27+
private int numLinesRemoved = 0;
28+
private int curX = 0;
29+
private int curY = 0;
30+
private JLabel statusbar;
31+
private Shape curPiece;
32+
private Tetrominoe[] board;
33+
34+
public Board(Tetris parent) {
35+
36+
initBoard(parent);
37+
}
38+
39+
private void initBoard(Tetris parent) {
40+
41+
setFocusable(true);
42+
timer = new Timer();
43+
timer.scheduleAtFixedRate(new ScheduleTask(),
44+
INITIAL_DELAY, PERIOD_INTERVAL);
45+
46+
curPiece = new Shape();
47+
48+
statusbar = parent.getStatusBar();
49+
board = new Tetrominoe[BOARD_WIDTH * BOARD_HEIGHT];
50+
addKeyListener(new TAdapter());
51+
clearBoard();
52+
}
53+
54+
private int squareWidth() {
55+
return (int) getSize().getWidth() / BOARD_WIDTH;
56+
}
57+
58+
private int squareHeight() {
59+
return (int) getSize().getHeight() / BOARD_HEIGHT;
60+
}
61+
62+
private Tetrominoe shapeAt(int x, int y) {
63+
return board[(y * BOARD_WIDTH) + x];
64+
}
65+
66+
public void start() {
67+
68+
isStarted = true;
69+
clearBoard();
70+
newPiece();
71+
}
72+
73+
private void pause() {
74+
75+
if (!isStarted) {
76+
return;
77+
}
78+
79+
isPaused = !isPaused;
80+
81+
if (isPaused) {
82+
83+
statusbar.setText("Paused");
84+
} else {
85+
86+
statusbar.setText(String.valueOf(numLinesRemoved));
87+
}
88+
}
89+
90+
private void doDrawing(Graphics g) {
91+
92+
Dimension size = getSize();
93+
int boardTop = (int) size.getHeight() - BOARD_HEIGHT * squareHeight();
94+
95+
for (int i = 0; i < BOARD_HEIGHT; ++i) {
96+
97+
for (int j = 0; j < BOARD_WIDTH; ++j) {
98+
99+
Tetrominoe shape = shapeAt(j, BOARD_HEIGHT - i - 1);
100+
101+
if (shape != Tetrominoe.NoShape) {
102+
103+
drawSquare(g, 0 + j * squareWidth(),
104+
boardTop + i * squareHeight(), shape);
105+
}
106+
}
107+
}
108+
109+
if (curPiece.getShape() != Tetrominoe.NoShape) {
110+
111+
for (int i = 0; i < 4; ++i) {
112+
113+
int x = curX + curPiece.x(i);
114+
int y = curY - curPiece.y(i);
115+
drawSquare(g, 0 + x * squareWidth(),
116+
boardTop + (BOARD_HEIGHT - y - 1) * squareHeight(),
117+
curPiece.getShape());
118+
}
119+
}
120+
}
121+
122+
@Override
123+
public void paintComponent(Graphics g) {
124+
125+
super.paintComponent(g);
126+
doDrawing(g);
127+
}
128+
129+
private void dropDown() {
130+
131+
int newY = curY;
132+
133+
while (newY > 0) {
134+
135+
if (!tryMove(curPiece, curX, newY - 1)) {
136+
137+
break;
138+
}
139+
140+
--newY;
141+
}
142+
143+
pieceDropped();
144+
}
145+
146+
private void oneLineDown() {
147+
148+
if (!tryMove(curPiece, curX, curY - 1)) {
149+
150+
pieceDropped();
151+
}
152+
}
153+
154+
private void clearBoard() {
155+
156+
for (int i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i) {
157+
board[i] = Tetrominoe.NoShape;
158+
}
159+
}
160+
161+
private void pieceDropped() {
162+
163+
for (int i = 0; i < 4; ++i) {
164+
165+
int x = curX + curPiece.x(i);
166+
int y = curY - curPiece.y(i);
167+
board[(y * BOARD_WIDTH) + x] = curPiece.getShape();
168+
}
169+
170+
removeFullLines();
171+
172+
if (!isFallingFinished) {
173+
newPiece();
174+
}
175+
}
176+
177+
private void newPiece() {
178+
179+
curPiece.setRandomShape();
180+
curX = BOARD_WIDTH / 2 + 1;
181+
curY = BOARD_HEIGHT - 1 + curPiece.minY();
182+
183+
if (!tryMove(curPiece, curX, curY)) {
184+
185+
curPiece.setShape(Tetrominoe.NoShape);
186+
timer.cancel();
187+
isStarted = false;
188+
statusbar.setText("GAME OVER!");
189+
}
190+
}
191+
192+
private boolean tryMove(Shape newPiece, int newX, int newY) {
193+
194+
for (int i = 0; i < 4; ++i) {
195+
196+
int x = newX + newPiece.x(i);
197+
int y = newY - newPiece.y(i);
198+
199+
if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) {
200+
return false;
201+
}
202+
203+
if (shapeAt(x, y) != Tetrominoe.NoShape) {
204+
return false;
205+
}
206+
}
207+
208+
curPiece = newPiece;
209+
curX = newX;
210+
curY = newY;
211+
212+
repaint();
213+
214+
return true;
215+
}
216+
217+
private void removeFullLines() {
218+
219+
int numFullLines = 0;
220+
221+
for (int i = BOARD_HEIGHT - 1; i >= 0; --i) {
222+
boolean lineIsFull = true;
223+
224+
for (int j = 0; j < BOARD_WIDTH; ++j) {
225+
226+
if (shapeAt(j, i) == Tetrominoe.NoShape) {
227+
228+
lineIsFull = false;
229+
break;
230+
}
231+
}
232+
233+
if (lineIsFull) {
234+
235+
++numFullLines;
236+
237+
for (int k = i; k < BOARD_HEIGHT - 1; ++k) {
238+
for (int j = 0; j < BOARD_WIDTH; ++j) {
239+
240+
board[(k * BOARD_WIDTH) + j] = shapeAt(j, k + 1);
241+
}
242+
}
243+
}
244+
}
245+
246+
if (numFullLines > 0) {
247+
248+
numLinesRemoved += numFullLines;
249+
statusbar.setText(String.valueOf(numLinesRemoved));
250+
isFallingFinished = true;
251+
curPiece.setShape(Tetrominoe.NoShape);
252+
repaint();
253+
}
254+
}
255+
256+
private void drawSquare(Graphics g, int x, int y,
257+
Tetrominoe shape) {
258+
259+
Color colors[] = {
260+
new Color(0, 0, 0), new Color(204, 102, 102),
261+
new Color(102, 204, 102), new Color(102, 102, 204),
262+
new Color(204, 204, 102), new Color(204, 102, 204),
263+
new Color(102, 204, 204), new Color(218, 170, 0)
264+
};
265+
266+
Color color = colors[shape.ordinal()];
267+
268+
g.setColor(color);
269+
g.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2);
270+
271+
g.setColor(color.brighter());
272+
g.drawLine(x, y + squareHeight() - 1, x, y);
273+
g.drawLine(x, y, x + squareWidth() - 1, y);
274+
275+
g.setColor(color.darker());
276+
g.drawLine(x + 1, y + squareHeight() - 1,
277+
x + squareWidth() - 1, y + squareHeight() - 1);
278+
g.drawLine(x + squareWidth() - 1, y + squareHeight() - 1,
279+
x + squareWidth() - 1, y + 1);
280+
281+
}
282+
283+
private void doGameCycle() {
284+
285+
update();
286+
repaint();
287+
}
288+
289+
private void update() {
290+
291+
if (isPaused) {
292+
return;
293+
}
294+
295+
if (isFallingFinished) {
296+
297+
isFallingFinished = false;
298+
newPiece();
299+
} else {
300+
301+
oneLineDown();
302+
}
303+
}
304+
305+
private class TAdapter extends KeyAdapter {
306+
307+
@Override
308+
public void keyPressed(KeyEvent e) {
309+
310+
System.out.println("key pressed");
311+
312+
if (!isStarted || curPiece.getShape() == Tetrominoe.NoShape) {
313+
return;
314+
}
315+
316+
int keycode = e.getKeyCode();
317+
318+
if (keycode == KeyEvent.VK_P) {
319+
pause();
320+
return;
321+
}
322+
323+
if (isPaused) {
324+
return;
325+
}
326+
327+
switch (keycode) {
328+
329+
case KeyEvent.VK_LEFT:
330+
tryMove(curPiece, curX - 1, curY);
331+
break;
332+
333+
case KeyEvent.VK_RIGHT:
334+
tryMove(curPiece, curX + 1, curY);
335+
break;
336+
337+
case KeyEvent.VK_DOWN:
338+
tryMove(curPiece.rotateRight(), curX, curY);
339+
break;
340+
341+
case KeyEvent.VK_UP:
342+
tryMove(curPiece.rotateLeft(), curX, curY);
343+
break;
344+
345+
case KeyEvent.VK_SPACE:
346+
dropDown();
347+
break;
348+
349+
case KeyEvent.VK_D:
350+
oneLineDown();
351+
break;
352+
}
353+
}
354+
}
355+
356+
private class ScheduleTask extends TimerTask {
357+
358+
@Override
359+
public void run() {
360+
361+
doGameCycle();
362+
}
363+
}
364+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy