yoon2566 commited on
Commit
17df001
ยท
verified ยท
1 Parent(s): 37d0e24

Create code.js

Browse files
Files changed (1) hide show
  1. code.js +258 -0
code.js ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // DOM ์š”์†Œ ๊ฐ€์ ธ์˜ค๊ธฐ
2
+ const canvas = document.getElementById('tetris-board');
3
+ const context = canvas.getContext('2d');
4
+ const scoreElement = document.getElementById('score');
5
+ const startButton = document.getElementById('start-button');
6
+
7
+ // ๊ฒŒ์ž„ ๋ณด๋“œ ์„ค์ •
8
+ const ROWS = 20;
9
+ const COLS = 10;
10
+ const BLOCK_SIZE = 30;
11
+
12
+ context.canvas.width = COLS * BLOCK_SIZE;
13
+ context.canvas.height = ROWS * BLOCK_SIZE;
14
+
15
+ // ๋ธ”๋ก ์ƒ‰์ƒ ๋ฐ ๋ชจ์–‘ ์ •์˜
16
+ const COLORS = [null, '#FF0D72', '#0DC2FF', '#0DFF72', '#F538FF', '#FF8E0D', '#FFE138', '#3877FF'];
17
+ const SHAPES = [
18
+ [], // 0๋ฒˆ ์ธ๋ฑ์Šค๋Š” ๋น„์›Œ๋‘ 
19
+ [[1, 1, 1, 1]], // I
20
+ [[1, 1, 1], [0, 1, 0]], // T
21
+ [[1, 1, 1], [1, 0, 0]], // L
22
+ [[1, 1, 1], [0, 0, 1]], // J
23
+ [[1, 1, 0], [0, 1, 1]], // S
24
+ [[0, 1, 1], [1, 1, 0]], // Z
25
+ [[1, 1], [1, 1]] // O
26
+ ];
27
+
28
+ let board = Array.from({ length: ROWS }, () => Array(COLS).fill(0));
29
+ let score = 0;
30
+ let gameOver = false;
31
+ let currentPiece;
32
+ let gameInterval;
33
+
34
+ // ํ”Œ๋ ˆ์ด์–ด(ํ˜„์žฌ ๋ธ”๋ก) ๊ฐ์ฒด
35
+ class Piece {
36
+ constructor(shape, color) {
37
+ this.shape = shape;
38
+ this.color = color;
39
+ this.x = Math.floor(COLS / 2) - Math.floor(shape[0].length / 2);
40
+ this.y = 0;
41
+ }
42
+
43
+ draw() {
44
+ context.fillStyle = this.color;
45
+ this.shape.forEach((row, y) => {
46
+ row.forEach((value, x) => {
47
+ if (value > 0) {
48
+ context.fillRect((this.x + x) * BLOCK_SIZE, (this.y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
49
+ }
50
+ });
51
+ });
52
+ }
53
+
54
+ move(dx, dy) {
55
+ this.x += dx;
56
+ this.y += dy;
57
+ }
58
+ }
59
+
60
+ // ์ƒˆ๋กœ์šด ๋ธ”๋ก ์ƒ์„ฑ
61
+ function generateNewPiece() {
62
+ const rand = Math.floor(Math.random() * (SHAPES.length - 1)) + 1;
63
+ const shape = SHAPES[rand];
64
+ const color = COLORS[rand];
65
+ return new Piece(shape, color);
66
+ }
67
+
68
+ // ๊ฒŒ์ž„ ๋ณด๋“œ ๊ทธ๋ฆฌ๊ธฐ
69
+ function drawBoard() {
70
+ board.forEach((row, y) => {
71
+ row.forEach((value, x) => {
72
+ if (value > 0) {
73
+ context.fillStyle = COLORS[value];
74
+ context.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
75
+ }
76
+ });
77
+ });
78
+ }
79
+
80
+ // ์ „์ฒด ํ™”๋ฉด ๋‹ค์‹œ ๊ทธ๋ฆฌ๊ธฐ
81
+ function draw() {
82
+ context.clearRect(0, 0, canvas.width, canvas.height);
83
+ drawBoard();
84
+ if (currentPiece) {
85
+ currentPiece.draw();
86
+ }
87
+ }
88
+
89
+ // ์ถฉ๋Œ ๊ฐ์ง€
90
+ function isValidMove(piece, dx = 0, dy = 0) {
91
+ return piece.shape.every((row, y) => {
92
+ return row.every((value, x) => {
93
+ if (value === 0) {
94
+ return true;
95
+ }
96
+ const newX = piece.x + x + dx;
97
+ const newY = piece.y + y + dy;
98
+ return newX >= 0 && newX < COLS && newY < ROWS && (board[newY] && board[newY][newX] === 0);
99
+ });
100
+ });
101
+ }
102
+
103
+ // ๋ธ”๋ก ํšŒ์ „
104
+ function rotatePiece() {
105
+ const shape = currentPiece.shape;
106
+ const newShape = shape[0].map((_, colIndex) => shape.map(row => row[colIndex]).reverse());
107
+
108
+ const originalX = currentPiece.x;
109
+ let offsetX = 1;
110
+
111
+ const tempPiece = { ...currentPiece, shape: newShape };
112
+
113
+ if (isValidMove(tempPiece)) {
114
+ currentPiece.shape = newShape;
115
+ return;
116
+ }
117
+
118
+ while (true) {
119
+ if (isValidMove(tempPiece, offsetX)) {
120
+ currentPiece.x += offsetX;
121
+ currentPiece.shape = newShape;
122
+ return;
123
+ }
124
+ if (offsetX > 0) {
125
+ if (offsetX > tempPiece.shape[0].length) break;
126
+ offsetX = -(offsetX + 1);
127
+ } else {
128
+ if (Math.abs(offsetX) > tempPiece.shape[0].length) break;
129
+ offsetX = -(offsetX - 1);
130
+ }
131
+ }
132
+ currentPiece.x = originalX;
133
+ }
134
+
135
+
136
+ // ๋ธ”๋ก์„ ๋ณด๋“œ์— ๊ณ ์ •
137
+ function lockPiece() {
138
+ currentPiece.shape.forEach((row, y) => {
139
+ row.forEach((value, x) => {
140
+ if (value > 0) {
141
+ const boardY = currentPiece.y + y;
142
+ const boardX = currentPiece.x + x;
143
+ if (boardY < ROWS) {
144
+ const colorIndex = COLORS.indexOf(currentPiece.color);
145
+ board[boardY][boardX] = colorIndex > 0 ? colorIndex : 1;
146
+ }
147
+ }
148
+ });
149
+ });
150
+ }
151
+
152
+ // ์ค„ ์ œ๊ฑฐ
153
+ function clearLines() {
154
+ let linesCleared = 0;
155
+ for (let y = ROWS - 1; y >= 0; y--) {
156
+ if (board[y].every(value => value > 0)) {
157
+ linesCleared++;
158
+ board.splice(y, 1);
159
+ board.unshift(Array(COLS).fill(0));
160
+ y++;
161
+ }
162
+ }
163
+ if (linesCleared > 0) {
164
+ score += linesCleared * 100;
165
+ scoreElement.textContent = score;
166
+ }
167
+ }
168
+
169
+ // ๊ฒŒ์ž„ ์˜ค๋ฒ„ ํ™•์ธ
170
+ function checkGameOver() {
171
+ if (!isValidMove(currentPiece)) {
172
+ gameOver = true;
173
+ clearInterval(gameInterval);
174
+ alert(`Game Over! Your score: ${score}`);
175
+ startButton.textContent = "Restart Game";
176
+ }
177
+ }
178
+
179
+ // --- ์ถ”๊ฐ€๋œ ๋ถ€๋ถ„: ํ•˜๋“œ ๋“œ๋กญ ํ•จ์ˆ˜ ---
180
+ function hardDrop() {
181
+ // ์ด๋™ ๊ฐ€๋Šฅํ•œ ๋™์•ˆ ๊ณ„์† ์•„๋ž˜๋กœ ์ด๋™์‹œํ‚ด
182
+ while (isValidMove(currentPiece, 0, 1)) {
183
+ currentPiece.move(0, 1);
184
+ score += 2; // ํ•˜๋“œ ๋“œ๋กญ ๋ณด๋„ˆ์Šค ์ ์ˆ˜
185
+ }
186
+ scoreElement.textContent = score;
187
+ // ๋ธ”๋ก์ด ๋ฉˆ์ถ˜ ํ›„ ๋ฐ”๋กœ ๋‹ค์Œ ๊ฒŒ์ž„ ๋ฃจํ”„ ์‹คํ–‰ (๊ณ ์ •, ์ค„ ์ œ๊ฑฐ, ์ƒˆ ๋ธ”๋ก ์ƒ์„ฑ)
188
+ gameLoop();
189
+ }
190
+
191
+ // ๊ฒŒ์ž„ ๋ฃจํ”„
192
+ function gameLoop() {
193
+ if (gameOver) return;
194
+
195
+ if (isValidMove(currentPiece, 0, 1)) {
196
+ currentPiece.move(0, 1);
197
+ } else {
198
+ lockPiece();
199
+ clearLines();
200
+ currentPiece = generateNewPiece();
201
+ checkGameOver();
202
+ }
203
+ draw();
204
+ }
205
+
206
+ // --- ์ˆ˜์ •๋œ ๋ถ€๋ถ„: ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ---
207
+ document.addEventListener('keydown', (event) => {
208
+ if (gameOver || !currentPiece) return;
209
+
210
+ switch (event.key) {
211
+ case 'ArrowLeft':
212
+ if (isValidMove(currentPiece, -1, 0)) currentPiece.move(-1, 0);
213
+ break;
214
+ case 'ArrowRight':
215
+ if (isValidMove(currentPiece, 1, 0)) currentPiece.move(1, 0);
216
+ break;
217
+ case 'ArrowDown':
218
+ if (isValidMove(currentPiece, 0, 1)) {
219
+ currentPiece.move(0, 1);
220
+ score += 1;
221
+ scoreElement.textContent = score;
222
+ } else {
223
+ gameLoop();
224
+ }
225
+ break;
226
+ case 'ArrowUp':
227
+ rotatePiece();
228
+ break;
229
+ case ' ': // ์ŠคํŽ˜์ด์Šค๋ฐ” ํ‚ค
230
+ event.preventDefault(); // ์ŠคํŽ˜์ด์Šค๋ฐ”์˜ ๊ธฐ๋ณธ ๋™์ž‘(ํŽ˜์ด์ง€ ์Šคํฌ๋กค) ๋ฐฉ์ง€
231
+ hardDrop();
232
+ break;
233
+ }
234
+ draw();
235
+ });
236
+
237
+ // ๊ฒŒ์ž„ ์‹œ์ž‘
238
+ function startGame() {
239
+ board = Array.from({ length: ROWS }, () => Array(COLS).fill(0));
240
+ score = 0;
241
+ scoreElement.textContent = score;
242
+ gameOver = false;
243
+ currentPiece = generateNewPiece();
244
+
245
+ if (gameInterval) clearInterval(gameInterval);
246
+ gameInterval = setInterval(gameLoop, 800);
247
+
248
+ draw();
249
+ startButton.textContent = "Start Game";
250
+ }
251
+
252
+ startButton.addEventListener('click', startGame);
253
+
254
+ // ์ดˆ๊ธฐ ์•ˆ๋‚ด
255
+ context.fillStyle = 'white';
256
+ context.font = '20px Arial';
257
+ context.textAlign = 'center';
258
+ context.fillText('Click "Start Game" to play!', canvas.width / 2, canvas.height / 2);