Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Помогите пожалуйста с оптимизацией тетриса (https://javascript.ru/forum/misc/16904-pomogite-pozhalujjsta-s-optimizaciejj-tetrisa.html)

klerik113 27.04.2011 20:20

Помогите пожалуйста с оптимизацией тетриса
 
Помогите пожалуйста оптимизировать тетрис. Исходник написан каряво и на двухядерном проце 1.8 одно ядро забито полностью.
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Tetris</title>
<link media="all" rel="stylesheet" type="text/css" href="css/all.css" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/tetris.js"></script>
</head>
<body>

</body>
</html>

tetris.js
Array.prototype.null = function()
{
	for (indexMass = 0; indexMass < this.length; indexMass++)
	{
		this[indexMass] = 0;
	}
};

var container = new Array();
containerHeight = 23;
containerWidth = 16;
for (i = 0; i < containerHeight; i++)
{
	container[i] = new Array(containerWidth);
	container[i].null();
}

for (i = 0; i<containerHeight; i++)
{
	container[i][0] = 1;
	container[i][1] = 1;
	if (i == containerHeight-1 || i == containerHeight-2)
	{
		for (j = 0; j<containerWidth; j++)
		{
			container[i][j] = 1;
		}
	}
	container[i][containerWidth-1] = 1;
	container[i][containerWidth-2] = 1;
}

typeFigure=[
			[ [0, 0, 1, 0], [0, 0, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0] ], //J+
			[ [0, 0, 0, 0], [1, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0] ],
			[ [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 0, 0] ],
			[ [0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 1], [0, 0, 0, 0] ],
			[ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0] ], //L+
			[ [0, 0, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0] ],
			[ [0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0] ],
			[ [0, 0, 0, 0], [0, 1, 1, 1], [0, 1, 0, 0], [0, 0, 0, 0] ],
			[ [0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0] ], //S
			[ [0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0] ],
			[ [0, 0, 0, 0], [0, 0, 1, 1], [0, 1, 1, 0], [0, 0, 0, 0] ],
			[ [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0] ],
			[ [0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0] ], //Z
			[ [0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 0] ],
			[ [0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0] ],
			[ [0, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0] ],
			[ [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0] ], //O+
			[ [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0] ],
			[ [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0] ],
			[ [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0] ],
			[ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1] ], //I+
			[ [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0] ],
			[ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1] ],
			[ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0] ],
			[ [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0] ], //T+
			[ [0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0] ],
			[ [0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0] ],
			[ [0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0] ],
			];

function Figure (index)
{
	this.x = null;
	this.y = null;
	this.index = index || (Math.floor(Math.random() * 7) * 4);
	this.type = typeFigure[this.index];
	if (this.type == null || undefined)
		alert("type of figure is not defined");
}

Figure.prototype.validityAppend = function(x, y)
{
	result = new Array(4);	
	for (k = 0; k < 4; k++)
	{
		result[k] = new Array(4);
		figureSlice = this.type[k];
		containerSlice = container [y + k] .slice (x, x + 4);
		for (j = 0; j < 4; j++)
		{
			result[k][j] = figureSlice [j] + containerSlice [j];
			if (result[k][j] == 2)
				return false;
		}
	}
return true;	
};

Figure.prototype.figureAppend = function(x, y)
{
	if(!x && !y)
		return false;
	this.x = x;
	this.y = y;
	result = this.validityAppend(x, y);
	if (result!=false)
	{
		for(i = 0; i < 4; i++)
		{
			container[y + i].splice(x, 4, 
			this.type[i][0] + container[y + i][x], 
			this.type[i][1] + container[y + i][x + 1],
			this.type[i][2] + container[y + i][x + 2], 
			this.type[i][3] + container[y + i][x + 3]);
		}
		return true;
	}
	return false;
}
Figure.prototype.searchFigure = function()
{
	for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 4; j++)
		{
			if (this.type[i][j] == 1)
			{
				if (container[this.y + i][this.x + j] != 1)
					return false;
			}
		}
	}
	return true;
}
Figure.prototype.deleteFigure = function()
{
if (this.searchFigure() == true)
	{
		for (i = 0; i < 4; i++)
		{
			for (j = 0; j < 4; j++)
			{
				if (this.type[i][j] == 1)
				{
					container[this.y + i][this.x + j] = 0;
				}
			}
		}
	}
}

Figure.prototype.overturnFigure = function()
{
	this.deleteFigure();
	reserv = this.index;
	indexx = this.index;
	if (this.index >= 3)
		indexx = this.index % 4;
	if (indexx == 3)
		this.index = this.index - 3;
	else
		this.index++;
	this.type = typeFigure[this.index];
	if(this.figureAppend(this.x, this.y))
		return true;
	else
	{
		this.index = reserv;
		this.type = typeFigure[this.index];
		this.figureAppend(this.x, this.y);
		return false;
	}
}

Figure.prototype.left = function()
{
	if(this.x > 0)
	{
	this.deleteFigure();
	if(this.figureAppend(this.x - 1, this.y))
		{
			this.xl = this.x;
			this.yl = this.y;
			return true;
		}
	else
		{
			this.figureAppend(this.x + 1, this.y);
			return false;
		}
	}
}

Figure.prototype.right = function()
{
	if(this.x < containerWidth)
	{
		this.deleteFigure();
		if(this.figureAppend(this.x + 1, this.y))
		{
			this.xr = this.x;
			this.yr = this.y;
			return true;
		}
		else
		{
			this.figureAppend(this.x - 1, this.y);
			return false;
		}
	}
}

Figure.prototype.down = function()
{
	if(this.y <= containerHeight)
	{
		this.deleteFigure();
		if (this.figureAppend(this.x, this.y + 1))
		{
			this.xd = this.x;
			this.yd = this.y;
			return true;
		}
		else
		{
			this.figureAppend(this.x, this.y - 1);
			return false;
		}
	}
}

Figure.prototype.completeSeries = function (mas)
{
	for (i = 0; i < containerWidth; i++)
	{
		if (mas[i] == 0)
			return false;
	}
	return true;
}

Figure.prototype.completeSeriesDelete = function ()
{
	for (k = 2; k < containerHeight - 2; k++)
	{
		if (figure1.completeSeries(container[k]))
		{
			container.splice(k, 1);
			container.unshift([1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]);
		}
	}
}

$(document).ready(function()
{
	time = new Date();
	time = time.getTime();
	$(document).keypress(function(e)
	{
		keypressTime = new Date();
		if ( !(time + 50 > keypressTime.getTime()) )
		{
			switch(e.keyCode)
			{
				case 37:
					figure1.left(); 
					time = keypressTime.getTime();
					break;
				case 39:
					figure1.right();
					time = keypressTime.getTime();
					break;
				case 38:
					figure1.overturnFigure(); 
					time = keypressTime.getTime();
					break;
				case 40:
					if(!figure1.down())
					{
						figure1 = new Figure();
						figure1.completeSeriesDelete();
						if (!figure1.figureAppend(6, 0))
							exit();
					}
					time = keypressTime.getTime();
					break;
			}
		}
	});
});	
	
function exit()
{
	alert('exit');
}

$(document).ready(function(){
var count = 0;
figure1= new Figure();
figure1.figureAppend(6, 0);

setInterval(function(){

	$("body").html(function(){
		res="<table>";
		for(i=0; i<containerHeight; i++)
		{
			res+="<tr>";
			for(j=0; j<containerWidth; j++)
			{
				res+="<td";
				if(container[i][j]==1)
					res+=" class='videmii'";
				res+=">&nbsp;</td>";
			}
			res+="</tr>";
		}
		res+="</table>";
		return res;
	});
	

}, 50);

setInterval(function(){
	if(!figure1.down())
	{
		figure1= new Figure();
		figure1.completeSeriesDelete();
		if (!figure1.figureAppend(6, 0))
			exit();
	}
	
	
}, 1000);

});

all.css
body{margin: 0; padding: 0;}
table{font-size: 5px;}
td{width: 15px; height: 15px; border: 1px solid;}
.videmii{background: black;}

B@rmaley.e><e 27.04.2011 20:57

Цитата:

Сообщение от klerik113
setInterval(function(){
	 
	    $("body").html(function(){
	        res="<table>";
	        for(i=0; i<containerHeight; i++)
	        {
	            res+="<tr>";
	            for(j=0; j<containerWidth; j++)
	            {
	                res+="<td";
	                if(container[i][j]==1)
	                    res+=" class='videmii'";
	                res+=">&nbsp;</td>";
	            }
	            res+="</tr>";
	        }
	        res+="</table>";
	        return res;
	    });
	      
	}, 50);

Зачем Вы каждые 50 миллисекунд создаете таблицу заново? Не проще работать с существующей таблицей, изменяя только изменившиеся ячейки?

klerik113 27.04.2011 23:49

Над этим я уже думал но не знаю как сделать. У меня функция вставки и все остальное изменяет большой массив container и потом я его вывожу переписывая полностью таблицу. Как сделать иначе подскажите плз.

B@rmaley.e><e 28.04.2011 00:25

Менять существующую таблицу.
Почитайте о работе с DOM'ом.

klerik113 28.04.2011 00:46

Тоесть перебрать массив и если какой-то элемент изменился то заменить ячейку таблици?

B@rmaley.e><e 28.04.2011 01:04

Можно просто пройтись по всем ячейкам таблицы, поставив или убрав для них класс videmii (пользоваться транслитом нехорошо - используйте английский язык). Повторное задание того же класса не скажется на производительности, но сделает обновление таблицы удобнее.

klerik113 28.04.2011 01:39

Спасибо вроде понял. Пробовал убрать вывод таблици $(body).append, без него задействуется 5 - 10% проца. А с выводом 40 -50%

klerik113 28.04.2011 02:39

заменил
$("body").html(function(){
		res="<table>";
		for(i=0; i<containerHeight; i++)
		{
			res+="<tr>";
			for(j=0; j<containerWidth; j++)
			{
				res+="<td";
				if(container[i][j]==1)
					res+=" class='videmii'";
				res+=">&nbsp;</td>";
			}
			res+="</tr>";
		}
		res+="</table>";
		return res;
	});

setInterval(function(){
	for(m=0; m<containerHeight - 2; m++)
		{
			tr = $("table tr")[m];
			for(n=2; n<containerWidth - 2; n++)
			{
				td = $(tr).children("td")[n];
				if (container[m][n]==1)
					$(td).addClass("videmii");
				else
					$(td).removeClass("videmii");
			}
		}
	
}, 50);

Загрузка проца пошла на 60%. Что-то у меня руки карявые

poorking 28.04.2011 03:19

Вы в setInterval делаете выборки, получите ссылку на таблицу заранее, а не выбирайте ее каждые 50миллисекунд, далее вы как то странно выбираете ячейки, сначала делаете выборку tr = $("table tr")[m];
, то есть получаете одного дитя выборки, а потом снова при выборе td заворачиваете td = $(tr).children("td")[n] и тут же берете снова одного дитя, потом $(td).addClass("videmii");
снова заворачиваете... Я jquery не знаю, но по-моему так там и работает и чтобы взять из выборки объект jquery к нему надо обращаться не selection[i] а selection.eq(i) кажется. (или наоборот :D :D)
Выберите таблицу ДО setInterval, а потом перемещайтесь по ней методами jquery, а не делайте выборки каждый раз
UPD
И кстати к ячейкам таблицы удобно обращаться table.rows[r].cells[c].className = "videmii"
table.rows[r].cells[c].className = ""
Это если обращаться не к библиотечным объектам а к голым узлам, ну там то уж точно что нибудь для этого есть

klerik113 28.04.2011 14:37

poorking,
Спасибо. Написал без jQuery. Работает отлично)). Правда при нажатии клавиши вниз всеравно чуть подвисает((. Теперь понял что в таких случаях надо оптимизировать и переходить аж на Ассемблер))
table = $("table")[0];
setInterval(function(){
	for(m=0; m<23; m++)
		{
			
			//tr = $("table tr")[m];
			for(n=0; n<16; n++)
			{
				td = table.rows[m].cells[n];//$(tr).children("td")[n];
				if (container[m][n]==1)
					td.className = "videmii";
				else
					td.className = "";
			}
		}
	
}, 50);


Часовой пояс GMT +3, время: 16:34.