Тетрис

Материал из 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;