Тетрис — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Totamonik (обсуждение | вклад) |
(Добавлена ссылка на файл) |
||
(не показана 1 промежуточная версия 1 участника) | |||
Строка 1: | Строка 1: | ||
+ | ==Описание== | ||
+ | |||
+ | Реализация копьютерной игры тетрис на языке программирования JavaScript | ||
+ | |||
+ | Исполнитель: [[Бакута Артём|Бакута Артём]] | ||
+ | |||
+ | Группа 13632/1 Кафедра Теоретической механики | ||
+ | |||
+ | Файл:[[https://csspbstu-my.sharepoint.com/:w:/g/personal/bakuta_ad_edu_spbstu_ru/EUhgTweJoiRGkRsNAJYFuPEB3PDm0ceEIPsR2nG1jQYF-g?e=lI4tSY]] | ||
+ | |||
+ | ==Визуализация== | ||
{{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Bakuta_AD/tetris.html |width=800 |height=650 |border=0 }} | {{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Bakuta_AD/tetris.html |width=800 |height=650 |border=0 }} | ||
+ | |||
+ | ==Код программы== | ||
+ | <div class="mw-collapsible mw-collapsed"> | ||
+ | '''Код программы на языке JavaScript:''' <div class="mw-collapsible-content"> | ||
+ | <syntaxhighlight lang="javascript" line start="1" enclose="div"> | ||
+ | // indicates the table in the page, this table is the main panel that will display the game | ||
+ | var tbl; | ||
+ | // Game state 0: not started; 1 run; 2 abort; | ||
+ | var status = 0; | ||
+ | // timer, the timer will do moveDown operation | ||
+ | var timer; | ||
+ | //fraction | ||
+ | var score = 0; | ||
+ | //True if this is the first piece | ||
+ | // Needed to generate the next piece | ||
+ | var ff; | ||
+ | //area is an 18*10 array that also corresponds to the table's table. Initially 0, if occupied, 1 | ||
+ | // Counter for droped lines | ||
+ | var DropedLines = 0; | ||
+ | //Speed of the game from 1 to 0.3 | ||
+ | var speed = 1; | ||
+ | //Level of current game | ||
+ | var level = 1; | ||
+ | // Incresing the score if lines are dropping in a raw | ||
+ | var factor = 0; | ||
+ | |||
+ | var isDown = true; | ||
+ | var area = new Array(18); | ||
+ | for(var i=0;i<18;i++) | ||
+ | { | ||
+ | area[i] = new Array(10); | ||
+ | } | ||
+ | for(var i=0;i<18;i++) | ||
+ | { | ||
+ | for(var j=0; j<10; j++) | ||
+ | { | ||
+ | area[i][j] = 0; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // The currently active square, which can be moved left and right, variant. When it bottoms out, the area will be updated; | ||
+ | var activeBlock; | ||
+ | var nextBlock; | ||
+ | // Produce a square shape with 7 basic shapes. | ||
+ | function generateBlock() | ||
+ | { | ||
+ | activeBlock = null; | ||
+ | document.getElementById("speed").innerText = " " + speed; | ||
+ | if (ff == false) | ||
+ | { | ||
+ | activeBlock = nextBlock; | ||
+ | eraseNext(); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | activeBlock = gen(); | ||
+ | } | ||
+ | nextBlock = gen(); | ||
+ | |||
+ | //Check if the four small squares just produced can be placed in the initialized position. | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | if(!isCellValid(activeBlock[i].x, activeBlock[i].y)) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | ff = false; | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | // Randomly generate 0-6 array, representing 7 forms. | ||
+ | function gen() | ||
+ | { | ||
+ | var block = new Array(4); | ||
+ | var t = (Math.floor(Math.random()*20)+1)%19; | ||
+ | // The repetition prevents an appearance the same blocks many times in a raw | ||
+ | switch(t) | ||
+ | { | ||
+ | case 0: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:0, y:5}; | ||
+ | block[3] = {x:1, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 1: | ||
+ | { | ||
+ | block[0] = {x:0, y:3}; | ||
+ | block[1] = {x:0, y:4}; | ||
+ | block[2] = {x:0, y:5}; | ||
+ | block[3] = {x:0, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 2: | ||
+ | { | ||
+ | block[0] = {x:0, y:5}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:2, y:4}; | ||
+ | break; | ||
+ | } | ||
+ | case 3: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:2, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 4: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:1, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 5: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:2, y:4}; | ||
+ | block[3] = {x:2, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 6: | ||
+ | { | ||
+ | block[0] = {x:0, y:5}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:1, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 7: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:0, y:5}; | ||
+ | block[3] = {x:1, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 8: | ||
+ | { | ||
+ | block[0] = {x:0, y:3}; | ||
+ | block[1] = {x:0, y:4}; | ||
+ | block[2] = {x:0, y:5}; | ||
+ | block[3] = {x:0, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 9: | ||
+ | { | ||
+ | block[0] = {x:0, y:5}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:2, y:4}; | ||
+ | break; | ||
+ | } | ||
+ | case 10: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:2, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 11: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:1, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 12: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:2, y:4}; | ||
+ | block[3] = {x:2, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 13: | ||
+ | { | ||
+ | block[0] = {x:0, y:5}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:1, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 14: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:0, y:5}; | ||
+ | block[3] = {x:1, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 15: | ||
+ | { | ||
+ | block[0] = {x:0, y:3}; | ||
+ | block[1] = {x:0, y:4}; | ||
+ | block[2] = {x:0, y:5}; | ||
+ | block[3] = {x:0, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 16: | ||
+ | { | ||
+ | block[0] = {x:0, y:5}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:2, y:4}; | ||
+ | break; | ||
+ | } | ||
+ | case 17: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:2, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | case 18: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:1, y:5}; | ||
+ | block[3] = {x:1, y:6}; | ||
+ | break; | ||
+ | } | ||
+ | case 19: | ||
+ | { | ||
+ | block[0] = {x:0, y:4}; | ||
+ | block[1] = {x:1, y:4}; | ||
+ | block[2] = {x:2, y:4}; | ||
+ | block[3] = {x:2, y:5}; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | return block; | ||
+ | } | ||
+ | //Move Downward | ||
+ | function moveDown() | ||
+ | { | ||
+ | // Check the bottom boundary. | ||
+ | if(checkBottomBorder()) | ||
+ | { | ||
+ | //No bottoming, erase the current graphic, | ||
+ | erase(); | ||
+ | // Update the current drawing coordinates | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | activeBlock[i].x = activeBlock[i].x + 1; | ||
+ | } | ||
+ | // Repaint the current graphics | ||
+ | paint(); | ||
+ | } | ||
+ | // bottoming out, | ||
+ | else | ||
+ | { | ||
+ | // Stop the current timer, that is, stop automatically moving down. | ||
+ | clearInterval(timer); | ||
+ | // Update the area array. | ||
+ | updatearea(); | ||
+ | // Consumer | ||
+ | var lines = deleteLine(); | ||
+ | //if there is a break, then | ||
+ | if(lines!=0){ | ||
+ | DropedLines++; | ||
+ | factor++; | ||
+ | // Update the score | ||
+ | score = score + lines*10*factor; | ||
+ | for (var i = 1; i < 10; i++) | ||
+ | { | ||
+ | if (score - i*50 >= 0) { level = i+1; } | ||
+ | } | ||
+ | updatescore(); | ||
+ | // Wipe the entire panel | ||
+ | erasearea(); | ||
+ | //Redraw panel | ||
+ | paintarea(); | ||
+ | } | ||
+ | else { factor = 0 } | ||
+ | |||
+ | if (level > 1) | ||
+ | { | ||
+ | speed = 1-0.1*level; | ||
+ | } | ||
+ | |||
+ | //Generate a new graphic and determine if it can be placed in the original position. | ||
+ | if(!generateBlock()) | ||
+ | { | ||
+ | alert("Game over!"); | ||
+ | status = 2; | ||
+ | return; | ||
+ | } | ||
+ | paint(); | ||
+ | //timer, execute moveDown every second | ||
+ | timer = setInterval(moveDown, 1000*speed) | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function straightDown() | ||
+ | { | ||
+ | var currentBlock = activeBlock; | ||
+ | for(var i = 0; i < 18; i++) | ||
+ | { | ||
+ | if (currentBlock == activeBlock) | ||
+ | { | ||
+ | moveDown(); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | } | ||
+ | |||
+ | //Left move | ||
+ | function moveLeft() | ||
+ | { | ||
+ | if(checkLeftBorder()) | ||
+ | { | ||
+ | erase(); | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | activeBlock[i].y = activeBlock[i].y - 1; | ||
+ | } | ||
+ | paint(); | ||
+ | } | ||
+ | } | ||
+ | //Right move | ||
+ | function moveRight() | ||
+ | { | ||
+ | if(checkRightBorder()) | ||
+ | { | ||
+ | erase(); | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | activeBlock[i].y = activeBlock[i].y + 1; | ||
+ | } | ||
+ | paint(); | ||
+ | } | ||
+ | } | ||
+ | //rotate, because there may be squares over the existing squares after the rotation. | ||
+ | // First use a tmpBlock, copy the contents of activeBlock to tmpBlock, | ||
+ | // Try to rotate tmpBlock, if the detection after rotation found no squares conflict, then | ||
+ | // Give the value of the rotated tmpBlock to activeBlock. | ||
+ | function rotate() | ||
+ | { | ||
+ | var tmpBlock = new Array(4); | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | tmpBlock[i] = {x:0, y:0}; | ||
+ | } | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | tmpBlock[i].x = activeBlock[i].x; | ||
+ | tmpBlock[i].y = activeBlock[i].y; | ||
+ | } | ||
+ | // Calculate the center point of the four points first, then the four points are rotated 90 degrees around the center. | ||
+ | var cx = Math.round((tmpBlock[0].x + tmpBlock[1].x + tmpBlock[2].x + tmpBlock[3].x)/4); | ||
+ | var cy = Math.round((tmpBlock[0].y + tmpBlock[1].y + tmpBlock[2].y + tmpBlock[3].y)/4); | ||
+ | // The main algorithm of rotation. Can be broken down to understand. | ||
+ | // First assume that the rotation around the source point. Then add the coordinates of the center point. | ||
+ | |||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | tmpBlock[i].x = cx+cy-activeBlock[i].y; | ||
+ | tmpBlock[i].y = cy-cx+activeBlock[i].x; | ||
+ | } | ||
+ | // Check whether the rotation of the rear grid is legal. | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | if(!isCellValid(tmpBlock[i].x,tmpBlock[i].y)) | ||
+ | { | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | //if it is legal, erase | ||
+ | erase(); | ||
+ | // Reassign the activeBlock. | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | activeBlock[i].x = tmpBlock[i].x; | ||
+ | activeBlock[i].y = tmpBlock[i].y; | ||
+ | } | ||
+ | //Redraw. | ||
+ | paint(); | ||
+ | } | ||
+ | //Check the left border and try to move one to the left to see if it is legal. | ||
+ | function checkLeftBorder() | ||
+ | { | ||
+ | for(var i=0; i<activeBlock.length; i++) | ||
+ | { | ||
+ | if(activeBlock[i].y==0) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | if(!isCellValid(activeBlock[i].x, activeBlock[i].y-1)) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | //Check the right border and try to move one to the right to see if it is legal. | ||
+ | function checkRightBorder() | ||
+ | { | ||
+ | for(var i=0; i<activeBlock.length; i++) | ||
+ | { | ||
+ | if(activeBlock[i].y==9) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | if(!isCellValid(activeBlock[i].x, activeBlock[i].y+1)) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | //Check the bottom boundary and try to move one down to see if it is legal. | ||
+ | function checkBottomBorder() | ||
+ | { | ||
+ | for(var i=0; i<activeBlock.length; i++) | ||
+ | { | ||
+ | if(activeBlock[i].x==17) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | if(!isCellValid(activeBlock[i].x+1, activeBlock[i].y)){ | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | //Check if the coordinates of (x,y) already exist in the area, and the existence indicates that the square is illegal. | ||
+ | function isCellValid(x, y) | ||
+ | { | ||
+ | if(x>17||x<0||y>9||y<0) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | if(area[x][y]==1) | ||
+ | { | ||
+ | return false; | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | //erase | ||
+ | function erase() | ||
+ | { | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="white"; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function eraseNext() | ||
+ | { | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | tbl2.rows[nextBlock[i].x].cells[nextBlock[i].y-3].style.backgroundColor="#EBEBEB"; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // paint activity graphics | ||
+ | function paint() | ||
+ | { | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="#CC3333"; | ||
+ | } | ||
+ | for(var i = 0; i < 4; i++) | ||
+ | { | ||
+ | tbl2.rows[nextBlock[i].x].cells[nextBlock[i].y-3].style.backgroundColor="#CC3333"; | ||
+ | } | ||
+ | } | ||
+ | // Update the area array | ||
+ | function updatearea() | ||
+ | { | ||
+ | for(var i=0; i<4; i++) | ||
+ | { | ||
+ | area[activeBlock[i].x][activeBlock[i].y]=1; | ||
+ | } | ||
+ | } | ||
+ | // Consumer | ||
+ | function deleteLine() | ||
+ | { | ||
+ | var lines = 0; | ||
+ | for(var i=0; i<18; i++) | ||
+ | { | ||
+ | var j=0; | ||
+ | for(; j<10; j++) | ||
+ | { | ||
+ | if(area[i][j]==0) | ||
+ | { | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | if(j==10) | ||
+ | { | ||
+ | lines++; | ||
+ | if(i!=0) | ||
+ | { | ||
+ | for(var k=i-1; k>=0; k--) | ||
+ | { | ||
+ | area[k+1] = area[k]; | ||
+ | } | ||
+ | } | ||
+ | area[0] = generateBlankLine(); | ||
+ | } | ||
+ | } | ||
+ | return lines; | ||
+ | } | ||
+ | // Wipe the entire panel | ||
+ | function erasearea() | ||
+ | { | ||
+ | for(var i=0; i<18; i++) | ||
+ | { | ||
+ | for(var j=0; j<10; j++) | ||
+ | { | ||
+ | tbl.rows[i].cells[j].style.backgroundColor = "white"; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | // Redraw the entire panel | ||
+ | function paintarea() | ||
+ | { | ||
+ | for(var i=0;i<18;i++) | ||
+ | { | ||
+ | for(var j=0; j<10; j++) | ||
+ | { | ||
+ | if(area[i][j]==1) | ||
+ | { | ||
+ | tbl.rows[i].cells[j].style.backgroundColor = "#CC3333"; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | //Generate a blank line. | ||
+ | function generateBlankLine() | ||
+ | { | ||
+ | var line = new Array(10); | ||
+ | for(var i=0; i<10; i++) | ||
+ | { | ||
+ | line[i] = 0; | ||
+ | } | ||
+ | return line; | ||
+ | } | ||
+ | // Update the score | ||
+ | function updatescore() | ||
+ | { | ||
+ | document.getElementById("score").innerText = " " + score; | ||
+ | document.getElementById("lines").innerText = " " + DropedLines; | ||
+ | document.getElementById("level").innerText = " " + level; | ||
+ | } | ||
+ | // keyboard control | ||
+ | function keyControl() | ||
+ | { | ||
+ | if(status !=1 ) | ||
+ | { | ||
+ | return; | ||
+ | } | ||
+ | var code = event.keyCode; | ||
+ | switch(code) | ||
+ | { | ||
+ | case 32: | ||
+ | { | ||
+ | straightDown(); | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | case 37: | ||
+ | { | ||
+ | moveLeft(); | ||
+ | break; | ||
+ | } | ||
+ | case 38: | ||
+ | { | ||
+ | rotate(); | ||
+ | break; | ||
+ | } | ||
+ | case 39: | ||
+ | { | ||
+ | moveRight(); | ||
+ | break; | ||
+ | } | ||
+ | case 40: | ||
+ | { | ||
+ | moveDown(); | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | //Start | ||
+ | function begin(e) | ||
+ | { | ||
+ | e.disabled = true; | ||
+ | ff = true; | ||
+ | status = 1; | ||
+ | tbl = document.getElementById("area"); | ||
+ | tbl2 = document.getElementById("NextPiece"); | ||
+ | if(!generateBlock()) | ||
+ | { | ||
+ | alert("Game over!"); | ||
+ | status = 2; | ||
+ | return; | ||
+ | } | ||
+ | paint(); | ||
+ | timer = setInterval(moveDown,1000*speed); | ||
+ | } | ||
+ | document.onkeydown=keyControl; | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | </div> |
Текущая версия на 10:27, 14 июня 2019
Описание[править]
Реализация копьютерной игры тетрис на языке программирования 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;