Тетрис
Материал из Department of Theoretical and Applied Mechanics
Описание[править]
Реализация копьютерной игры тетрис на языке программирования JavaScript
Исполнитель: Бакута Артём
Группа 13632/1 Кафедра Теоретической механики
Файл:[[1]]
Визуализация[править]
Код программы[править]
Код программы на языке JavaScript:
1 // indicates the table in the page, this table is the main panel that will display the game
2 var tbl;
3 // Game state 0: not started; 1 run; 2 abort;
4 var status = 0;
5 // timer, the timer will do moveDown operation
6 var timer;
7 //fraction
8 var score = 0;
9 //True if this is the first piece
10 // Needed to generate the next piece
11 var ff;
12 //area is an 18*10 array that also corresponds to the table's table. Initially 0, if occupied, 1
13 // Counter for droped lines
14 var DropedLines = 0;
15 //Speed of the game from 1 to 0.3
16 var speed = 1;
17 //Level of current game
18 var level = 1;
19 // Incresing the score if lines are dropping in a raw
20 var factor = 0;
21
22 var isDown = true;
23 var area = new Array(18);
24 for(var i=0;i<18;i++)
25 {
26 area[i] = new Array(10);
27 }
28 for(var i=0;i<18;i++)
29 {
30 for(var j=0; j<10; j++)
31 {
32 area[i][j] = 0;
33 }
34 }
35
36 // The currently active square, which can be moved left and right, variant. When it bottoms out, the area will be updated;
37 var activeBlock;
38 var nextBlock;
39 // Produce a square shape with 7 basic shapes.
40 function generateBlock()
41 {
42 activeBlock = null;
43 document.getElementById("speed").innerText = " " + speed;
44 if (ff == false)
45 {
46 activeBlock = nextBlock;
47 eraseNext();
48 }
49 else
50 {
51 activeBlock = gen();
52 }
53 nextBlock = gen();
54
55 //Check if the four small squares just produced can be placed in the initialized position.
56 for(var i=0; i<4; i++)
57 {
58 if(!isCellValid(activeBlock[i].x, activeBlock[i].y))
59 {
60 return false;
61 }
62 }
63 ff = false;
64 return true;
65 }
66
67 // Randomly generate 0-6 array, representing 7 forms.
68 function gen()
69 {
70 var block = new Array(4);
71 var t = (Math.floor(Math.random()*20)+1)%19;
72 // The repetition prevents an appearance the same blocks many times in a raw
73 switch(t)
74 {
75 case 0:
76 {
77 block[0] = {x:0, y:4};
78 block[1] = {x:1, y:4};
79 block[2] = {x:0, y:5};
80 block[3] = {x:1, y:5};
81 break;
82 }
83 case 1:
84 {
85 block[0] = {x:0, y:3};
86 block[1] = {x:0, y:4};
87 block[2] = {x:0, y:5};
88 block[3] = {x:0, y:6};
89 break;
90 }
91 case 2:
92 {
93 block[0] = {x:0, y:5};
94 block[1] = {x:1, y:4};
95 block[2] = {x:1, y:5};
96 block[3] = {x:2, y:4};
97 break;
98 }
99 case 3:
100 {
101 block[0] = {x:0, y:4};
102 block[1] = {x:1, y:4};
103 block[2] = {x:1, y:5};
104 block[3] = {x:2, y:5};
105 break;
106 }
107 case 4:
108 {
109 block[0] = {x:0, y:4};
110 block[1] = {x:1, y:4};
111 block[2] = {x:1, y:5};
112 block[3] = {x:1, y:6};
113 break;
114 }
115 case 5:
116 {
117 block[0] = {x:0, y:4};
118 block[1] = {x:1, y:4};
119 block[2] = {x:2, y:4};
120 block[3] = {x:2, y:5};
121 break;
122 }
123 case 6:
124 {
125 block[0] = {x:0, y:5};
126 block[1] = {x:1, y:4};
127 block[2] = {x:1, y:5};
128 block[3] = {x:1, y:6};
129 break;
130 }
131 case 7:
132 {
133 block[0] = {x:0, y:4};
134 block[1] = {x:1, y:4};
135 block[2] = {x:0, y:5};
136 block[3] = {x:1, y:5};
137 break;
138 }
139 case 8:
140 {
141 block[0] = {x:0, y:3};
142 block[1] = {x:0, y:4};
143 block[2] = {x:0, y:5};
144 block[3] = {x:0, y:6};
145 break;
146 }
147 case 9:
148 {
149 block[0] = {x:0, y:5};
150 block[1] = {x:1, y:4};
151 block[2] = {x:1, y:5};
152 block[3] = {x:2, y:4};
153 break;
154 }
155 case 10:
156 {
157 block[0] = {x:0, y:4};
158 block[1] = {x:1, y:4};
159 block[2] = {x:1, y:5};
160 block[3] = {x:2, y:5};
161 break;
162 }
163 case 11:
164 {
165 block[0] = {x:0, y:4};
166 block[1] = {x:1, y:4};
167 block[2] = {x:1, y:5};
168 block[3] = {x:1, y:6};
169 break;
170 }
171 case 12:
172 {
173 block[0] = {x:0, y:4};
174 block[1] = {x:1, y:4};
175 block[2] = {x:2, y:4};
176 block[3] = {x:2, y:5};
177 break;
178 }
179 case 13:
180 {
181 block[0] = {x:0, y:5};
182 block[1] = {x:1, y:4};
183 block[2] = {x:1, y:5};
184 block[3] = {x:1, y:6};
185 break;
186 }
187 case 14:
188 {
189 block[0] = {x:0, y:4};
190 block[1] = {x:1, y:4};
191 block[2] = {x:0, y:5};
192 block[3] = {x:1, y:5};
193 break;
194 }
195 case 15:
196 {
197 block[0] = {x:0, y:3};
198 block[1] = {x:0, y:4};
199 block[2] = {x:0, y:5};
200 block[3] = {x:0, y:6};
201 break;
202 }
203 case 16:
204 {
205 block[0] = {x:0, y:5};
206 block[1] = {x:1, y:4};
207 block[2] = {x:1, y:5};
208 block[3] = {x:2, y:4};
209 break;
210 }
211 case 17:
212 {
213 block[0] = {x:0, y:4};
214 block[1] = {x:1, y:4};
215 block[2] = {x:1, y:5};
216 block[3] = {x:2, y:5};
217 break;
218 }
219 case 18:
220 {
221 block[0] = {x:0, y:4};
222 block[1] = {x:1, y:4};
223 block[2] = {x:1, y:5};
224 block[3] = {x:1, y:6};
225 break;
226 }
227 case 19:
228 {
229 block[0] = {x:0, y:4};
230 block[1] = {x:1, y:4};
231 block[2] = {x:2, y:4};
232 block[3] = {x:2, y:5};
233 break;
234 }
235 }
236 return block;
237 }
238 //Move Downward
239 function moveDown()
240 {
241 // Check the bottom boundary.
242 if(checkBottomBorder())
243 {
244 //No bottoming, erase the current graphic,
245 erase();
246 // Update the current drawing coordinates
247 for(var i=0; i<4; i++)
248 {
249 activeBlock[i].x = activeBlock[i].x + 1;
250 }
251 // Repaint the current graphics
252 paint();
253 }
254 // bottoming out,
255 else
256 {
257 // Stop the current timer, that is, stop automatically moving down.
258 clearInterval(timer);
259 // Update the area array.
260 updatearea();
261 // Consumer
262 var lines = deleteLine();
263 //if there is a break, then
264 if(lines!=0){
265 DropedLines++;
266 factor++;
267 // Update the score
268 score = score + lines*10*factor;
269 for (var i = 1; i < 10; i++)
270 {
271 if (score - i*50 >= 0) { level = i+1; }
272 }
273 updatescore();
274 // Wipe the entire panel
275 erasearea();
276 //Redraw panel
277 paintarea();
278 }
279 else { factor = 0 }
280
281 if (level > 1)
282 {
283 speed = 1-0.1*level;
284 }
285
286 //Generate a new graphic and determine if it can be placed in the original position.
287 if(!generateBlock())
288 {
289 alert("Game over!");
290 status = 2;
291 return;
292 }
293 paint();
294 //timer, execute moveDown every second
295 timer = setInterval(moveDown, 1000*speed)
296 }
297 }
298
299 function straightDown()
300 {
301 var currentBlock = activeBlock;
302 for(var i = 0; i < 18; i++)
303 {
304 if (currentBlock == activeBlock)
305 {
306 moveDown();
307 }
308 else
309 {
310 break;
311 }
312 }
313
314
315 }
316
317 //Left move
318 function moveLeft()
319 {
320 if(checkLeftBorder())
321 {
322 erase();
323 for(var i=0; i<4; i++)
324 {
325 activeBlock[i].y = activeBlock[i].y - 1;
326 }
327 paint();
328 }
329 }
330 //Right move
331 function moveRight()
332 {
333 if(checkRightBorder())
334 {
335 erase();
336 for(var i=0; i<4; i++)
337 {
338 activeBlock[i].y = activeBlock[i].y + 1;
339 }
340 paint();
341 }
342 }
343 //rotate, because there may be squares over the existing squares after the rotation.
344 // First use a tmpBlock, copy the contents of activeBlock to tmpBlock,
345 // Try to rotate tmpBlock, if the detection after rotation found no squares conflict, then
346 // Give the value of the rotated tmpBlock to activeBlock.
347 function rotate()
348 {
349 var tmpBlock = new Array(4);
350 for(var i=0; i<4; i++)
351 {
352 tmpBlock[i] = {x:0, y:0};
353 }
354 for(var i=0; i<4; i++)
355 {
356 tmpBlock[i].x = activeBlock[i].x;
357 tmpBlock[i].y = activeBlock[i].y;
358 }
359 // Calculate the center point of the four points first, then the four points are rotated 90 degrees around the center.
360 var cx = Math.round((tmpBlock[0].x + tmpBlock[1].x + tmpBlock[2].x + tmpBlock[3].x)/4);
361 var cy = Math.round((tmpBlock[0].y + tmpBlock[1].y + tmpBlock[2].y + tmpBlock[3].y)/4);
362 // The main algorithm of rotation. Can be broken down to understand.
363 // First assume that the rotation around the source point. Then add the coordinates of the center point.
364
365 for(var i=0; i<4; i++)
366 {
367 tmpBlock[i].x = cx+cy-activeBlock[i].y;
368 tmpBlock[i].y = cy-cx+activeBlock[i].x;
369 }
370 // Check whether the rotation of the rear grid is legal.
371 for(var i=0; i<4; i++)
372 {
373 if(!isCellValid(tmpBlock[i].x,tmpBlock[i].y))
374 {
375 return;
376 }
377 }
378 //if it is legal, erase
379 erase();
380 // Reassign the activeBlock.
381 for(var i=0; i<4; i++)
382 {
383 activeBlock[i].x = tmpBlock[i].x;
384 activeBlock[i].y = tmpBlock[i].y;
385 }
386 //Redraw.
387 paint();
388 }
389 //Check the left border and try to move one to the left to see if it is legal.
390 function checkLeftBorder()
391 {
392 for(var i=0; i<activeBlock.length; i++)
393 {
394 if(activeBlock[i].y==0)
395 {
396 return false;
397 }
398 if(!isCellValid(activeBlock[i].x, activeBlock[i].y-1))
399 {
400 return false;
401 }
402 }
403 return true;
404 }
405 //Check the right border and try to move one to the right to see if it is legal.
406 function checkRightBorder()
407 {
408 for(var i=0; i<activeBlock.length; i++)
409 {
410 if(activeBlock[i].y==9)
411 {
412 return false;
413 }
414 if(!isCellValid(activeBlock[i].x, activeBlock[i].y+1))
415 {
416 return false;
417 }
418 }
419 return true;
420 }
421 //Check the bottom boundary and try to move one down to see if it is legal.
422 function checkBottomBorder()
423 {
424 for(var i=0; i<activeBlock.length; i++)
425 {
426 if(activeBlock[i].x==17)
427 {
428 return false;
429 }
430 if(!isCellValid(activeBlock[i].x+1, activeBlock[i].y)){
431 return false;
432 }
433 }
434 return true;
435 }
436 //Check if the coordinates of (x,y) already exist in the area, and the existence indicates that the square is illegal.
437 function isCellValid(x, y)
438 {
439 if(x>17||x<0||y>9||y<0)
440 {
441 return false;
442 }
443 if(area[x][y]==1)
444 {
445 return false;
446 }
447 return true;
448 }
449 //erase
450 function erase()
451 {
452 for(var i=0; i<4; i++)
453 {
454 tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="white";
455 }
456 }
457
458 function eraseNext()
459 {
460 for(var i=0; i<4; i++)
461 {
462 tbl2.rows[nextBlock[i].x].cells[nextBlock[i].y-3].style.backgroundColor="#EBEBEB";
463 }
464 }
465
466 // paint activity graphics
467 function paint()
468 {
469 for(var i=0; i<4; i++)
470 {
471 tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="#CC3333";
472 }
473 for(var i = 0; i < 4; i++)
474 {
475 tbl2.rows[nextBlock[i].x].cells[nextBlock[i].y-3].style.backgroundColor="#CC3333";
476 }
477 }
478 // Update the area array
479 function updatearea()
480 {
481 for(var i=0; i<4; i++)
482 {
483 area[activeBlock[i].x][activeBlock[i].y]=1;
484 }
485 }
486 // Consumer
487 function deleteLine()
488 {
489 var lines = 0;
490 for(var i=0; i<18; i++)
491 {
492 var j=0;
493 for(; j<10; j++)
494 {
495 if(area[i][j]==0)
496 {
497 break;
498 }
499 }
500 if(j==10)
501 {
502 lines++;
503 if(i!=0)
504 {
505 for(var k=i-1; k>=0; k--)
506 {
507 area[k+1] = area[k];
508 }
509 }
510 area[0] = generateBlankLine();
511 }
512 }
513 return lines;
514 }
515 // Wipe the entire panel
516 function erasearea()
517 {
518 for(var i=0; i<18; i++)
519 {
520 for(var j=0; j<10; j++)
521 {
522 tbl.rows[i].cells[j].style.backgroundColor = "white";
523 }
524 }
525 }
526 // Redraw the entire panel
527 function paintarea()
528 {
529 for(var i=0;i<18;i++)
530 {
531 for(var j=0; j<10; j++)
532 {
533 if(area[i][j]==1)
534 {
535 tbl.rows[i].cells[j].style.backgroundColor = "#CC3333";
536 }
537 }
538 }
539 }
540 //Generate a blank line.
541 function generateBlankLine()
542 {
543 var line = new Array(10);
544 for(var i=0; i<10; i++)
545 {
546 line[i] = 0;
547 }
548 return line;
549 }
550 // Update the score
551 function updatescore()
552 {
553 document.getElementById("score").innerText = " " + score;
554 document.getElementById("lines").innerText = " " + DropedLines;
555 document.getElementById("level").innerText = " " + level;
556 }
557 // keyboard control
558 function keyControl()
559 {
560 if(status !=1 )
561 {
562 return;
563 }
564 var code = event.keyCode;
565 switch(code)
566 {
567 case 32:
568 {
569 straightDown();
570 break;
571 }
572
573 case 37:
574 {
575 moveLeft();
576 break;
577 }
578 case 38:
579 {
580 rotate();
581 break;
582 }
583 case 39:
584 {
585 moveRight();
586 break;
587 }
588 case 40:
589 {
590 moveDown();
591 break;
592 }
593 }
594 }
595
596
597 //Start
598 function begin(e)
599 {
600 e.disabled = true;
601 ff = true;
602 status = 1;
603 tbl = document.getElementById("area");
604 tbl2 = document.getElementById("NextPiece");
605 if(!generateBlock())
606 {
607 alert("Game over!");
608 status = 2;
609 return;
610 }
611 paint();
612 timer = setInterval(moveDown,1000*speed);
613 }
614 document.onkeydown=keyControl;