<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x41F;&#x43E;&#x441;&#x43B;&#x435;&#x434;&#x43D;&#x438;&#x435; &#x442;&#x435;&#x43C;&#x44B;: &#x423;&#x440;&#x43E;&#x43A;&#x438;</title><link>https://computercraft.ru/forum/85-uroki/</link><description>&#x41F;&#x43E;&#x441;&#x43B;&#x435;&#x434;&#x43D;&#x438;&#x435; &#x442;&#x435;&#x43C;&#x44B;: &#x423;&#x440;&#x43E;&#x43A;&#x438;</description><language>ru</language><item><title>&#x41E;&#x43A;&#x43A;&#x443;&#x43B;&#x44C;&#x442;&#x43D;&#x44B;&#x435; &#x43F;&#x440;&#x430;&#x43A;&#x442;&#x438;&#x43A;&#x438; &#x43F;&#x440;&#x438; &#x43F;&#x43E;&#x438;&#x441;&#x43A;&#x435; &#x440;&#x443;&#x434;&#x44B;</title><link>https://computercraft.ru/topic/3950-okkultnye-praktiki-pri-poiske-rudy/</link><description><![CDATA[
<p>
	В моде OpenComputers есть интересное устройство, которое позволяет определить плотность блока на расстоянии.
</p>

<p>
	Но вот беда, данные он выдает довольно шумные и чем больше расстояние, тем больше шума.
</p>

<p>
	 
</p>

<p>
	Чтобы определить подлинную плотность блока, можно просканировать его несколько раз, а результат усреднить. Шум, мешающий сканированию, имеет вероятностную природу. И после нескольких сканирований можно статистически найти, какая вероятней всего плотность у блока.
</p>

<p>
	За один тик мы можем просканировать 64 блока. Чтобы проанализировать всю доступную область (65 x 65 x 64) сотней итераций, нам понадобится 422500 тиков, что равно 21125 секунд или 352 минуты, то есть без малого 6 часов.
</p>

<p>
	Но сколько раз надо сканировать? Сто? Тысячу?
</p>

<p>
	 
</p>

<p>
	Нам открыто тайное знание и есть точный ответ.<br>
	Один. Всего за одно сканирование мы можем найти руду среди любых других блоков. Если хочется абсолютной уверенности, придется сделать пару магических пассов и просканировать повторно.
</p>

<p>
	 
</p>

<p>
	<span style="font-size:18px;">Начнем с теории.</span>
</p>

<p>
	 
</p>

<p>
	Для начала откроем код мода и найдем функцию <strong>geolyzer.scan</strong>, она располагается <a href="https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala#L17" rel="external nofollow">[здесь]</a> <em>src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala</em> и называется <span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">onGeolyzerScan()</span><br>
	Просмотрев код, мы можем понять, что функция принимает параметры, по этим параметрам сканирует блоки в мире. Делает разные проверки вроде <span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">world.blockExists(x, y, z) &amp;&amp; !world.isAirBlock(x, y, z)</span>, чтобы убедится, что блок есть. Потом получает информацию о блоке по координатам, делает еще несколько проверок (опять проверить, что блок все-таки есть <span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">block != null</span>, проверяет дополнительные параметры: <span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">includeReplaceable</span>, <span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">isFluid(block)</span>, <span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">block.isReplaceable(world, blockPos.x, blockPos.y, blockPos.z)</span>)<br>
	Потом происходит измерение расстояния до блока. И в конце берется плотность, смешивается с шумом и расстоянием. Результат добавляется к таблице блоков и отправляется игроку.
</p>

<p>
	 
</p>

<p>
	Вроде-бы ничего необычного. Шум, расстояние, плотность. Нам и так известна зависимость силы шума от расстояния.
</p>

<p>
	 
</p>

<p>
	И вот тут начинается волшебство.<br>
	Рассмотрим поподробнее <a href="https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala#L44" rel="external nofollow">код вычисления</a> итоговой плотности блока.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">e.data(index) = e.data(index) * distance * Settings.get.geolyzerNoise + block.getBlockHardness(world, x, y, z)</span></pre>

<p>
	Коротко можно это записать в виде формулы: <strong>R = G * D * N + H</strong><br>
	G - это сгенерированный шум.<br>
	D - расстояние до блока.<br>
	N - множитель шума из конфига (стандартно - 2).<br>
	H - настоящая плотность.<br>
	R - результат работы геосканера.
</p>

<p>
	 
</p>

<p>
	Если мы попробуем в качестве эксперимента отнять от результата предполагаемую плотность, то ничего нового не узнаем. Если обратим все операции с известными значениями, то получим только шум.
</p>

<p>
	 
</p>

<p>
	А можем ли мы так же разобрать формулу шума? Давайте попробуем.
</p>

<p>
	 
</p>

<p>
	Несколькими строками выше <a href="https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala#L25" rel="external nofollow">[ссылка]</a>. Можно наблюдать получение массива случайных байт.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">val noise = new Array[Byte](e.data.length)
world.rand.nextBytes(noise)</span></pre>

<p>
	Далее следует нормализация значений.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted">
<span class="pln">noise.map(_ / 128f / 33f).copyToArray(e.data)</span></pre>

<p>
	Хм. Так-так-так. Если мы это все обьеденим с предыдущей формулой, то получится что-то вроде такого:<br>
	<strong>R = G(RANDOM_BYTE / 128 / 33) * D * N + H</strong>
</p>

<p>
	 
</p>

<p>
	И что это нам дает?<br>
	А то, что исходное псевдослучайное число имеет жесткую дискретность. ГПСЧ дает случайные числа типа <em>byte</em>, а это только 256 значений (-128, +127).<br>
	Нам известны все значения, кроме <strong>H</strong> и <strong>RANDOM_BYTE</strong>, что нам это дает?<br>
	Мы можем предположить значение <strong>H</strong> и обратить всю формулу.<br>
	<strong>(R - H) / D / N * 128 * 33</strong><br>
	Для стандартного конфига можно сократить до:<br>
	<strong>2112 * (R - H) / D</strong>
</p>

<p>
	 
</p>

<p>
	А теперь тайное знание для тех, кто не понял самостоятельно.
</p>

<p>
	<br>
	Мы взяли желаемую плотность блока (например 3 для руды).<br>
	Подставили вместо H.<br>
	Получили случайное значение.<br>
	Можем легко определить, угадали ли плотность или нет.
</p>

<p>
	 
</p>

<p>
	Из-за дискретности случайных значений генератора, распределение вероятностей для блоков с разной плотностью не одинаковое.
</p>

<p>
	<img alt="cbdzk30.png" class="ipsImage" data-ratio="74.59" height="364" width="488" src="https://i.imgur.com/cbdzk30.png">
</p>

<p>
	 
</p>

<p>
	 
</p>

<p>
	<span style="font-size:18px;">Перейдем к практике.</span>
</p>

<p>
	 
</p>

<p>
	Вот код простого скрипта, который в заданном радиусе ищет блоки с нужной плотностью. Результат выводится на голопроектор.
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> sqrt </span><span class="pun">=</span><span class="pln"> math</span><span class="pun">.</span><span class="pln">sqrt
</span><span class="kwd">local</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'component'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> geolyzer </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">geolyzer
</span><span class="kwd">local</span><span class="pln"> hologram </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">hologram

</span><span class="kwd">local</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> distance</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> z</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> sqrt</span><span class="pun">(</span><span class="pln">x</span><span class="pun">^</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">^</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z</span><span class="pun">^</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> magic</span><span class="pun">(</span><span class="pln">R</span><span class="pun">,</span><span class="pln"> H</span><span class="pun">,</span><span class="pln"> D</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">2112</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">R </span><span class="pun">-</span><span class="pln"> H</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> D </span><span class="pun">%</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> visualize</span><span class="pun">(</span><span class="pln">hardness</span><span class="pun">,</span><span class="pln"> elevation</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">)</span><span class="pln">
  hologram</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">()</span><span class="pln">
  hologram</span><span class="pun">.</span><span class="pln">setScale</span><span class="pun">(</span><span class="lit">9</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">local</span><span class="pln"> blocks</span><span class="pun">,</span><span class="pln"> result
  </span><span class="kwd">for</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="pln">size</span><span class="pun">,</span><span class="pln"> size </span><span class="kwd">do</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> z </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="pln">size</span><span class="pun">,</span><span class="pln"> size </span><span class="kwd">do</span><span class="pln">
      blocks </span><span class="pun">=</span><span class="pln"> geolyzer</span><span class="pun">.</span><span class="pln">scan</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> z</span><span class="pun">,</span><span class="pln"> elevation</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">for</span><span class="pln"> i_y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
        result </span><span class="pun">=</span><span class="pln"> magic</span><span class="pun">(</span><span class="pln">blocks</span><span class="pun">[</span><span class="pln">i_y</span><span class="pun">],</span><span class="pln"> hardness</span><span class="pun">,</span><span class="pln"> distance</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> i_y</span><span class="pun">+</span><span class="pln">elevation</span><span class="lit">-1</span><span class="pun">,</span><span class="pln"> z</span><span class="pun">))</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> blocks</span><span class="pun">[</span><span class="pln">i_y</span><span class="pun">]</span><span class="pln"> </span><span class="pun">~=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">result </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.9998</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> result </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0.00005</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
          hologram</span><span class="pun">.</span><span class="pln">set</span><span class="pun">(</span><span class="pln">x</span><span class="lit">+24</span><span class="pun">,</span><span class="pln"> i_y</span><span class="pun">,</span><span class="pln"> z</span><span class="lit">+24</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">end</span><span class="pln">
      </span><span class="kwd">end</span><span class="pln">
    </span><span class="kwd">end</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> hrd</span><span class="pun">,</span><span class="pln"> ele</span><span class="pun">,</span><span class="pln"> siz </span><span class="pun">=</span><span class="pln"> table</span><span class="pun">.</span><span class="pln">unpack</span><span class="pun">({...})</span><span class="pln">
hrd </span><span class="pun">=</span><span class="pln"> hrd </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
ele </span><span class="pun">=</span><span class="pln"> ele </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">-32</span><span class="pln">
siz </span><span class="pun">=</span><span class="pln"> siz </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">16</span><span class="pln">
visualize</span><span class="pun">(</span><span class="pln">hrd</span><span class="pun">,</span><span class="pln"> ele</span><span class="pun">,</span><span class="pln"> siz</span><span class="pun">)</span></pre>

<p>
	А вот результат:
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		 
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img alt="grNrLdJ.png" class="ipsImage" data-ratio="64.60" height="480" width="743" src="https://i.imgur.com/grNrLdJ.png"><br>
			<br>
			<img alt="fZVZjrO.png" class="ipsImage" data-ratio="64.60" height="480" width="743" src="https://i.imgur.com/fZVZjrO.png"><br>
			 
		</p>
	</div>
</div>

<p>
	 
</p>

<p>
	При сканировании заметны артефакты. Когда разные плотности близки на целочисленных расстояниях, позникают коллизии. <br>
	Это можно частично компенсировать, если есть блок кандидат на ошибку.
</p>

<p>
	<br>
	На любом расстоянии можно рассчитать абсолютный минимальный и максимальный уровень шума. С расстоянием, у близких плотностей пересечение значений увеличивается, но если плотность блока не в области пересечений, то можно точно определить к какой области он относится.
</p>

<p>
	 
</p>

<p>
	<img alt="P4v8cL8.png" class="ipsImage" data-ratio="73.29" height="406" width="554" src="https://i.imgur.com/P4v8cL8.png"><br>
	Пересечение плотностей руды (3) и камня (1.5), точками обозначены три сканирования блока руды.
</p>

<p>
	 
</p>

<p>
	Результаты обратного вычисления для разных плотностей хорошо это демонстрируют.
</p>

<p>
	<img alt="onqp1Vm.png" class="ipsImage" data-ratio="75.00" height="480" width="640" src="https://i.imgur.com/onqp1Vm.png">
</p>

<p>
	 
</p>

<p>
	Для компенсации артефактов надо ввести дополнительное условие: полученный <strong>RANDOM_BYTE</strong> должен быть в диапазоне -128:127.<br>
	Вот финальный скрипт и результат.
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> sqrt </span><span class="pun">=</span><span class="pln"> math</span><span class="pun">.</span><span class="pln">sqrt
</span><span class="kwd">local</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'component'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> geolyzer </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">geolyzer
</span><span class="kwd">local</span><span class="pln"> hologram </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">hologram

</span><span class="kwd">local</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> distance</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> z</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> sqrt</span><span class="pun">(</span><span class="pln">x</span><span class="pun">^</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">^</span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> z</span><span class="pun">^</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> magic</span><span class="pun">(</span><span class="pln">R</span><span class="pun">,</span><span class="pln"> H</span><span class="pun">,</span><span class="pln"> D</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">2112</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">R </span><span class="pun">-</span><span class="pln"> H</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> D
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> visualize</span><span class="pun">(</span><span class="pln">hardness</span><span class="pun">,</span><span class="pln"> elevation</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">)</span><span class="pln">
  hologram</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">()</span><span class="pln">
  hologram</span><span class="pun">.</span><span class="pln">setScale</span><span class="pun">(</span><span class="lit">9</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">local</span><span class="pln"> blocks</span><span class="pun">,</span><span class="pln"> result
  </span><span class="kwd">for</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="pln">size</span><span class="pun">,</span><span class="pln"> size </span><span class="kwd">do</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> z </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="pln">size</span><span class="pun">,</span><span class="pln"> size </span><span class="kwd">do</span><span class="pln">
      blocks </span><span class="pun">=</span><span class="pln"> geolyzer</span><span class="pun">.</span><span class="pln">scan</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> z</span><span class="pun">,</span><span class="pln"> elevation</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">for</span><span class="pln"> i_y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
        result </span><span class="pun">=</span><span class="pln"> magic</span><span class="pun">(</span><span class="pln">blocks</span><span class="pun">[</span><span class="pln">i_y</span><span class="pun">],</span><span class="pln"> hardness</span><span class="pun">,</span><span class="pln"> distance</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> i_y</span><span class="pun">+</span><span class="pln">elevation</span><span class="lit">-1</span><span class="pun">,</span><span class="pln"> z</span><span class="pun">))</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> blocks</span><span class="pun">[</span><span class="pln">i_y</span><span class="pun">]</span><span class="pln"> </span><span class="pun">~=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> result </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">-128</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> result </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">127</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">result</span><span class="pun">%</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.9998</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> result</span><span class="pun">%</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0.0002</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
          hologram</span><span class="pun">.</span><span class="pln">set</span><span class="pun">(</span><span class="pln">x</span><span class="lit">+24</span><span class="pun">,</span><span class="pln"> i_y</span><span class="pun">,</span><span class="pln"> z</span><span class="lit">+24</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">end</span><span class="pln">
      </span><span class="kwd">end</span><span class="pln">
    </span><span class="kwd">end</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> hrd</span><span class="pun">,</span><span class="pln"> ele</span><span class="pun">,</span><span class="pln"> siz </span><span class="pun">=</span><span class="pln"> table</span><span class="pun">.</span><span class="pln">unpack</span><span class="pun">({...})</span><span class="pln">
hrd </span><span class="pun">=</span><span class="pln"> hrd </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
ele </span><span class="pun">=</span><span class="pln"> ele </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">-32</span><span class="pln">
siz </span><span class="pun">=</span><span class="pln"> siz </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">16</span><span class="pln">
visualize</span><span class="pun">(</span><span class="pln">hrd</span><span class="pun">,</span><span class="pln"> ele</span><span class="pun">,</span><span class="pln"> siz</span><span class="pun">)</span></pre>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		 
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			<img alt="l3rb7E1.png" class="ipsImage" data-ratio="75.65" height="525" width="694" src="https://i.imgur.com/l3rb7E1.png">
		</p>
	</div>
</div>

<p>
	 
</p>

<p>
	Для более точного определения плотности можно сделать два сканирования. Одно сместить относительно другого так, чтобы расстояния с артефактами не совпадали.
</p>

<p>
	 
</p>

<p>
	Чтобы не выполнять тяжелую операцию sqrt, можно создать словарь, где [x^2 + y^2 + z^2] = sqrt(x^2 + y^2 + z^2), всего понадобится 1742 уникальных значений.
</p>

<p>
	 
</p>

<p>
	P.S. Пост является компиляцией знаний из <a href="https://computercraft.ru/topic/3346-vychislenie-pogreshnosti-geoskanera/" rel="">[этой]</a> темы. Собрал, чтобы перевести и опубликовать на официальном форуме.
</p>

<p>
	Автор идеи хакнуть геосканер - <a contenteditable="false" data-ipshover="" data-ipshover-target="https://computercraft.ru/profile/13296-eu_tomat/?do=hovercard" data-mentionid="13296" href="https://computercraft.ru/profile/13296-eu_tomat/" rel="">@eu_tomat</a>
</p>

]]></description><guid isPermaLink="false">3950</guid><pubDate>Wed, 06 Jan 2021 11:58:57 +0000</pubDate></item><item><title>Open Peripheral Addons: Terminal Glasses &#x432; OpenComputers</title><link>https://computercraft.ru/topic/2592-open-peripheral-addons-terminal-glasses-v-opencomputers/</link><description><![CDATA[
<p>
	OpenPeripheral предоставляет мощный функционал по созданию собственных интерфейсов в виде очков дополненной реальности "Terminal Glasses". К сожалению, полного списка функционала и всех нюансов по работе с этими очками не найти. Присутствуют некоторые отрывки, небольшие видео с результатами работы и прочие поделки. Но! Спустя пару бессонных ночей, декомпилированного кода и трёх литров чая, удалось описать полный функционал этих очков.
</p>

<p>
	 
</p>

<p>
	Основные возможности очков и периферии:
</p>

<ul>
	<li>
		Отображение геометрических объектов различной сложности и цветовой гаммы.
	</li>
	<li>
		Отображение текста.
	</li>
	<li>
		Отображение жидкостей и предметов.
	</li>
	<li>
		Взаимодействие с мышью/клавиатурой.
	</li>
	<li>
		Чтение сообщений чата.
	</li>
	<li>
		Специальные команды чата, не отображающиеся в нем.
	</li>
	<li>
		Возможность индивидуальной работы с каждым пользователем терминала.
	</li>
	<li>
		Установка очков в любой шлем.
	</li>
</ul>

<p>
	 
</p>

<p>
	Возможности данных очков я опишу по разделам, в лучших традициях вики <img alt=":)" data-emoticon="" src="https://computercraft.ru/uploads/emoticons/default_smile.png" title=":)">
</p>

<p>
	Для начала, определю некоторые понятия.
</p>

<p>
	Система терминальных очков состоит из трёх предметов: терминала, очков, беспроводной клавиатуры.
</p>

<p>
	Терминал является центром всей системы, через него происходит общение между компьютером и очками. Также он хранит все данные интерфейса и пользователей.
</p>

<p>
	На очки выводится вся графическая информация, а сами очки передают сообщения или команды чата на терминал.
</p>

<p>
	Беспроводная клавиатура позволяет дополнить всю систему, своей возможностью контроля элементов при помощи клавиатуры и мыши.
</p>

<p>
	 
</p>

<p>
	Как выводить информацию на очки:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> com </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">"component"</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> opb </span><span class="pun">=</span><span class="pln"> com</span><span class="pun">.</span><span class="pln">openperipheral_bridge

</span><span class="com">-- Построение интерфейса происходит во внутреннем буффере терминала (он же мост).</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> text </span><span class="pun">=</span><span class="pln"> opb</span><span class="pun">.</span><span class="pln">addText</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0xffef7f</span><span class="pun">)</span><span class="pln"> </span><span class="com">-- Создаем компонент "Текст".</span><span class="pln">
</span><span class="com">-- Его нужно создать только один раз, в остальное время можно обращаться по ссылке и изменять любой параметр.</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="kwd">do</span><span class="pln"> </span><span class="com">-- В качестве примера будет выводится счетчик секунд.</span><span class="pln">
  text</span><span class="pun">.</span><span class="pln">setText</span><span class="pun">(</span><span class="pln">tostring</span><span class="pun">(</span><span class="pln">counter</span><span class="pun">))</span><span class="pln"> </span><span class="com">-- Обновляем текста компонента.</span><span class="pln">
  
  opb</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">()</span><span class="pln"> </span><span class="com">-- Для отображения графики на экране, необходимо отправить буффер на очки.</span><span class="pln">
  
  os</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="com">-- Ждем секунду и прибавляем счетчик.</span><span class="pln">
  counter </span><span class="pun">=</span><span class="pln"> counter</span><span class="lit">+1</span><span class="pln">
</span><span class="kwd">end</span></pre>

<p>
	 
</p>

<p>
	<span style="font-size:18px;"><strong>API</strong></span>
</p>

<p>
	Перед тем как перейти к API, нужно знать:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="pln">Color</span><span class="pun">:</span><span class="pln">number </span><span class="com">-- Число в формате TrueColor RGB (по умолчанию 0xffffff).</span><span class="pln">
Opacity</span><span class="pun">:</span><span class="pln">number </span><span class="com">-- Прозрачность, число от 0.0 до 1.0 (по умолчанию 1).</span><span class="pln">
</span><span class="pun">Знак</span><span class="pln"> </span><span class="str">'?'</span><span class="pln"> </span><span class="com">-- Опциональный параметр/функция.</span></pre>

<p>
	 
</p>

<p>
	<strong>События</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			Все события имеют несколько одинаковых параметров, остальные описываются индивидуально:
		</p>

		<div>
			<pre class="ipsCode prettyprint lang-lua prettyprinted">

<span class="pln">componentAddress</span><span class="pun">:</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> userName</span><span class="pun">:</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> userUUID</span><span class="pun">:</span><span class="pln">string</span></pre>

			<p>
				 
			</p>
		</div>

		<p>
			Сами события:
		</p>

		<div>
			<pre class="ipsCode prettyprint lang-lua prettyprinted">

<span class="pln">glasses_key_down</span><span class="pun">(</span><span class="pln">keyCode</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> char</span><span class="pun">:</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> isRepeat</span><span class="pun">:</span><span class="pln">boolean</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие нажатия или удержания(isRepeat = true) кнопки клавиатуры.</span><span class="pln">

glasses_key_up</span><span class="pun">(</span><span class="pln">keyCode</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие отпускания кнопки клавиатуры.</span><span class="pln">

glasses_mouse_scroll</span><span class="pun">(</span><span class="pln">value</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие поворота колесика мыши.</span><span class="pln">

glasses_mouse_down</span><span class="pun">(</span><span class="pln">button</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие нажатия кнопки мыши.</span><span class="pln">

glasses_mouse_up</span><span class="pun">(</span><span class="pln">button</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие отпускания кнопки мыши.</span><span class="pln">

glasses_component_mouse_wheel</span><span class="pun">(</span><span class="pln">id</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> private</span><span class="pun">:</span><span class="pln">boolean</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln"> 
</span><span class="com">-- Событие поворота колесика мыши над интерактивным элементом.</span><span class="pln">
</span><span class="com">-- Параметр id является идентификатором объекта, над которым сработало событие.</span><span class="pln">
</span><span class="com">-- Позиции x,y относительно позиции объекта.</span><span class="pln">
</span><span class="com">-- Поле private устанавливается если элемент находится в интерфейсе отдельного пользователя.</span><span class="pln">

glasses_component_mouse_down</span><span class="pun">(</span><span class="pln">id</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> private</span><span class="pun">:</span><span class="pln">boolean</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> button</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие нажатия кнопки мыши над интерактивным элементом.</span><span class="pln">
</span><span class="com">-- Параметр id является идентификатором объекта, над которым сработало событие.</span><span class="pln">
</span><span class="com">-- Позиции x,y относительно позиции объекта.</span><span class="pln">

glasses_component_mouse_up</span><span class="pun">(</span><span class="pln">id</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> private</span><span class="pun">:</span><span class="pln">boolean</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> button</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие отпускания кнопки мыши над интерактивным элементом.</span><span class="pln">
</span><span class="com">-- Параметр id является идентификатором объекта, над которым сработало событие.</span><span class="pln">
</span><span class="com">-- Позиции x,y относительно позиции объекта.</span><span class="pln">

glasses_mouse_drag</span><span class="pun">(</span><span class="pln">deltaX</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> deltaY</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Событие перетаскивания мышью (движение с зажатой клавишей мыши).</span><span class="pln">

glasses_attach
</span><span class="com">-- Событие экипировки очков.</span><span class="pln">

glasses_detach
</span><span class="com">-- Событие снятия очков.</span><span class="pln">

glasses_capture
</span><span class="com">-- Событие входа в режим захвата.</span><span class="pln">

glasses_release
</span><span class="com">-- Событие выхода из режима захвата.</span><span class="pln">

glasses_chat_message</span><span class="pun">(</span><span class="pln">msg</span><span class="pun">:</span><span class="pln">string</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Пользователь отправил сообщение в чат.</span><span class="pln">

glasses_chat_command</span><span class="pun">(</span><span class="pln">command</span><span class="pun">:</span><span class="pln">string</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- Пользователь отправил команду.</span><span class="pln">
</span><span class="com">-- Командой является сообщение в чат, начинающееся с символов '$$'</span></pre>
		</div>
	</div>
</div>

<p>
	 
</p>

<p>
	<strong>Строковые константы</strong>
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="pln">VerticalAlignment</span><span class="pun">:[</span><span class="pln">TOP</span><span class="pun">,</span><span class="pln"> MIDDLE</span><span class="pun">,</span><span class="pln"> BOTTOM</span><span class="pun">]</span><span class="pln">
HorizontalAlignment</span><span class="pun">:[</span><span class="pln">LEFT</span><span class="pun">,</span><span class="pln"> MIDDLE</span><span class="pun">,</span><span class="pln"> RIGHT</span><span class="pun">]</span><span class="pln">
GuiElement</span><span class="pun">:[</span><span class="pln">OVERLAY</span><span class="pun">,</span><span class="pln"> PORTAL</span><span class="pun">,</span><span class="pln"> HOTBAR</span><span class="pun">,</span><span class="pln"> CROSSHAIRS</span><span class="pun">,</span><span class="pln"> BOSS_HEALTH</span><span class="pun">,</span><span class="pln"> HEALTH</span><span class="pun">,</span><span class="pln"> ARMOR</span><span class="pun">,</span><span class="pln"> FOOD</span><span class="pun">,</span><span class="pln"> MOUNT_HEALTH</span><span class="pun">,</span><span class="pln"> AIR</span><span class="pun">,</span><span class="pln"> EXPERIENCE</span><span class="pun">,</span><span class="pln"> JUMP_BAR</span><span class="pun">,</span><span class="pln"> OBJECTIVES</span><span class="pun">]</span></pre>

<p>
	 
</p>

<p>
	<strong>Структуры данных</strong>
</p>

<p>
	SimpleBox, ColoredPoint, Coord, User
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			Структура таблиц, возвращаемых или задаваемых функциям.
		</p>

		<div>
			<pre class="ipsCode prettyprint lang-lua prettyprinted">

<span class="pln">SimpleBox </span><span class="com">-- Содержит информацию о положении и размере области.</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln">number
  left</span><span class="pun">:</span><span class="pln">number
  width</span><span class="pun">:</span><span class="pln">number
  height</span><span class="pun">:</span><span class="pln">number

ColoredPoint </span><span class="com">-- Содержит информацию о вершине: её положение и цвет.</span><span class="pln">
  x</span><span class="pun">:</span><span class="pln">number
  y</span><span class="pun">:</span><span class="pln">number
  rgb</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?</span><span class="pln">

Coord </span><span class="com">-- Содержит информацию о координатах объекта.</span><span class="pln">
  x</span><span class="pun">:</span><span class="pln">number
  y</span><span class="pun">:</span><span class="pln">number

User</span><span class="pun">:</span><span class="pln"> </span><span class="com">-- Содержит информацию о пользователе терминала.</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln">string </span><span class="com">-- Имя игрока.</span><span class="pln">
  uuid</span><span class="pun">:</span><span class="pln">string </span><span class="com">-- Уникальный идентификатор игрока в терминале.</span></pre>

			<p>
				 
			</p>
		</div>
	</div>
</div>

<p>
	 
</p>

<p>
	<strong>Абстрактные объекты</strong>
</p>

<p>
	Drawable, BoundedShape, Box
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			Здесь я описал базовый функционал некоторых типов объектов, наследники которых реализуют этот функционал.
		</p>

		<div>
			<pre class="ipsCode prettyprint lang-lua prettyprinted">

<span class="pln">Drawable </span><span class="com">-- Базовый интерфейс всех отображаемых объектов</span><span class="pln">
  getId</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Получить идентификатор объекта в терминале.</span><span class="pln">
  delete</span><span class="pun">()</span><span class="pln">
    </span><span class="com">-- Удалить объект из терминала.</span><span class="pln">
  getType</span><span class="pun">():</span><span class="pln">string
    </span><span class="com">-- Получить тип объекта.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setVisible</span><span class="pun">():</span><span class="pln">boolean
    </span><span class="com">-- Получить или установить видимость объекта.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setClickable</span><span class="pun">():</span><span class="pln">boolean
    </span><span class="com">-- Получить или установить интерактивность объекта.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setRotation</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Получить или установить текущий поворот объекта (в градусах).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setUserdata</span><span class="pun">():</span><span class="pln">object
    </span><span class="com">-- Получить или установить кастомные данные. Могут быть любого типа,</span><span class="pln">
    </span><span class="com">-- используются для хранения данных/ссылок и т.п. (при необходимости).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setZ</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Получить или установить положение объекта по оси 'Z'.</span><span class="pln">
    </span><span class="com">-- Принимаются значения от -32768 до 32767 (short), но отображаться будут только в пределах [-999, 1000].</span><span class="pln">
    </span><span class="com">-- Чем больше значение - тем "ближе" объект.</span><span class="pln">
  setScreenAnchor</span><span class="pun">(</span><span class="pln">horizontal</span><span class="pun">:</span><span class="pln">HorizontalAlignment</span><span class="pun">,</span><span class="pln"> vertical</span><span class="pun">:</span><span class="pln">VerticalAlignment</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Установить начальную точку отсчета.</span><span class="pln">
    </span><span class="com">-- Т.е. позицию {x:0,y:0} относительно экрана.</span><span class="pln">
  setObjectAnchor</span><span class="pun">(</span><span class="pln">horizontal</span><span class="pun">:</span><span class="pln">HorizontalAlignment</span><span class="pun">,</span><span class="pln"> vertical</span><span class="pun">:</span><span class="pln">VerticalAlignment</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Установить конечную точку отсчета.</span><span class="pln">
    </span><span class="com">-- Т.е. сдвигает координаты {x:0,y:0} объекта на ширину и/или высоту объекта.</span><span class="pln">
    </span><span class="com">-- Также является осью поворота объекта.</span><span class="pln">
  setAlignment</span><span class="pun">(</span><span class="pln">horizontal</span><span class="pun">:</span><span class="pln">HorizontalAlignment</span><span class="pun">,</span><span class="pln"> vertical</span><span class="pun">:</span><span class="pln">VerticalAlignment</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Устанавливает начальную и конечную точку отсчета одновременно.</span><span class="pln">

BoundedShape</span><span class="pun">:</span><span class="pln">Drawable </span><span class="com">-- Базовый объект для объектов с произвольным набором вершин(точек).</span><span class="pln">
  getBoundingBox</span><span class="pun">():</span><span class="pln">SimpleBox
    </span><span class="com">-- Возвращает экранную позицию и размер объекта.</span><span class="pln">

Box</span><span class="pun">:</span><span class="pln">Drawable </span><span class="com">-- Базовый объект для прямоугольников.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setX</span><span class="pun">():</span><span class="pln">number
  get</span><span class="pun">/</span><span class="pln">setY</span><span class="pun">():</span><span class="pln">number
  get</span><span class="pun">/</span><span class="pln">setWidth</span><span class="pun">():</span><span class="pln">number
  get</span><span class="pun">/</span><span class="pln">setHeight</span><span class="pun">():</span><span class="pln">number</span></pre>

			<p>
				 
			</p>
		</div>
	</div>
</div>

<p>
	 
</p>

<p>
	<strong>Графические объекты</strong>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			Имеют расширенные возможности по представлению изображения на экране.
		</p>

		<div>
			<pre class="ipsCode prettyprint lang-lua prettyprinted">

<span class="pln">Point</span><span class="pun">:</span><span class="pln">Drawable </span><span class="com">-- Точка на экране.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setCoord</span><span class="pun">():</span><span class="pln">Coord
    </span><span class="com">-- Экранные координаты точки.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setSize</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Размер точки (по умолчанию 1).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity</span><span class="pun">():</span><span class="pln">Opacity

SolidLine</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Закрашенная линия.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setWidth</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Ширина линии (по умолчанию 1).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP1</span><span class="pun">():</span><span class="pln">Coord
    </span><span class="com">-- Первая точка линии.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP2</span><span class="pun">():</span><span class="pln">Coord
    </span><span class="com">-- Вторая точка линии.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity</span><span class="pun">():</span><span class="pln">Opacity

GradientLine</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Линия с градиентным переходом.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setWidth</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Ширина линии (по умолчанию 1).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP1</span><span class="pun">():</span><span class="pln">ColoredPoint
    </span><span class="com">-- Первая точка линии.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP2</span><span class="pun">():</span><span class="pln">ColoredPoint
    </span><span class="com">-- Вторая точка линии.</span><span class="pln">

SolidLineStrip</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Закрашенная произвольная линия.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setWidth</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Ширина линии (по умолчанию 1).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setPoints</span><span class="pun">():</span><span class="pln">Coord</span><span class="pun">[]</span><span class="pln">
    </span><span class="com">-- Получить или установить вершины линии.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">getPoints</span><span class="pun">(</span><span class="pln">index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">):</span><span class="pln">Coord
    </span><span class="com">-- Получить вершину по индексу.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">setPoints</span><span class="pun">(</span><span class="pln">point</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Установить вершину по индексу.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity</span><span class="pun">():</span><span class="pln">Opacity

GradientLineStrip</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Произвольная линия с градиентным переходом.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setWidth</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Ширина линии (по умолчанию 1).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setPoints</span><span class="pun">():</span><span class="pln">ColoredPoint</span><span class="pun">[]</span><span class="pln">
    </span><span class="com">-- Получить или установить вершины линии.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">getPoints</span><span class="pun">(</span><span class="pln">index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">):</span><span class="pln">ColoredPoint
    </span><span class="com">-- Получить вершину по индексу.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">setPoints</span><span class="pun">(</span><span class="pln">point</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Установить вершину по индексу.</span><span class="pln">

SolidBox</span><span class="pun">:</span><span class="pln">Box </span><span class="com">-- Закрашенный прямоугольник.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity</span><span class="pun">():</span><span class="pln">Opacity

GradientBox</span><span class="pun">:</span><span class="pln">Box </span><span class="com">-- Прямоугольник с градиентным переходом.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setColor1</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity1</span><span class="pun">():</span><span class="pln">Opacity
  get</span><span class="pun">/</span><span class="pln">setColor2</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity2</span><span class="pun">():</span><span class="pln">Opacity
  get</span><span class="pun">/</span><span class="pln">setGradient</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Направление градиента, 1 - снизу/вверх, остальные значения - справа/налево.</span><span class="pln">

SolidTriangle</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Закрашенный треугольник.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP1</span><span class="pun">():</span><span class="pln">Coord
  get</span><span class="pun">/</span><span class="pln">setP2</span><span class="pun">():</span><span class="pln">Coord
  get</span><span class="pun">/</span><span class="pln">setP3</span><span class="pun">():</span><span class="pln">Coord
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity</span><span class="pun">():</span><span class="pln">Opacity

GradientTriangle</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Треугольник с градиентным переходом.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP1</span><span class="pun">():</span><span class="pln">ColoredPoint
  get</span><span class="pun">/</span><span class="pln">setP2</span><span class="pun">():</span><span class="pln">ColoredPoint
  get</span><span class="pun">/</span><span class="pln">setP3</span><span class="pun">():</span><span class="pln">ColoredPoint

SolidQuad</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Закрашенный четырёхугольник.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP1</span><span class="pun">():</span><span class="pln">Coord
  get</span><span class="pun">/</span><span class="pln">setP2</span><span class="pun">():</span><span class="pln">Coord
  get</span><span class="pun">/</span><span class="pln">setP3</span><span class="pun">():</span><span class="pln">Coord
  get</span><span class="pun">/</span><span class="pln">setP4</span><span class="pun">():</span><span class="pln">Coord
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity</span><span class="pun">():</span><span class="pln">Opacity

GradientQuad</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Четырёхугольник с градиентным переходом.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setP1</span><span class="pun">():</span><span class="pln">ColoredPoint
  get</span><span class="pun">/</span><span class="pln">setP2</span><span class="pun">():</span><span class="pln">ColoredPoint
  get</span><span class="pun">/</span><span class="pln">setP3</span><span class="pun">():</span><span class="pln">ColoredPoint
  get</span><span class="pun">/</span><span class="pln">setP4</span><span class="pun">():</span><span class="pln">ColoredPoint

SolidPolygon</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Закрашенная произвольная фигура.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setPoints</span><span class="pun">():</span><span class="pln">Coord</span><span class="pun">[]</span><span class="pln">
    </span><span class="com">-- Получить или установить вершины фигуры.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">getPoints</span><span class="pun">(</span><span class="pln">index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">):</span><span class="pln">Coord
    </span><span class="com">-- Получить вершину по индексу.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">setPoints</span><span class="pun">(</span><span class="pln">point</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Установить вершину по индексу.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setOpacity</span><span class="pun">():</span><span class="pln">Opacity

GradientPolygon</span><span class="pun">:</span><span class="pln">BoundedShape </span><span class="com">-- Произвольная фигура с градиентным переходом.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setPoints</span><span class="pun">():</span><span class="pln">ColoredPoint</span><span class="pun">[]</span><span class="pln">
    </span><span class="com">-- Получить или установить вершины фигуры.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">getPoints</span><span class="pun">(</span><span class="pln">index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">):</span><span class="pln">ColoredPoint
    </span><span class="com">-- Получить вершину по индексу.</span><span class="pln">
  </span><span class="pun">?</span><span class="pln">setPoints</span><span class="pun">(</span><span class="pln">point</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Установить вершину по индексу.</span><span class="pln">

ItemIcon</span><span class="pun">:</span><span class="pln">Drawable </span><span class="com">-- Иконка предмета с размерами 16х16</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setX</span><span class="pun">():</span><span class="pln">number
  get</span><span class="pun">/</span><span class="pln">setY</span><span class="pun">():</span><span class="pln">number
  get</span><span class="pun">/</span><span class="pln">setScale</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Размер иконки (по умолчанию 1).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setItemId</span><span class="pun">():</span><span class="pln">string
    </span><span class="com">-- Полный id предмета.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setMeta</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Метаданные объекта (поворот и т.п.).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setDamageBar</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Полоска прочности объекта.</span><span class="pln">
    </span><span class="com">-- 0.0 - полоса отсутствует, 1.0 - полоса пустая (закончилась прочность).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setLabel</span><span class="pun">():</span><span class="pln">string
    </span><span class="com">-- Текст с информацией о количестве.</span><span class="pln">
    </span><span class="com">-- Тем не менее, может принимать и отображать любой текст.</span><span class="pln">

LiquidIcon</span><span class="pun">:</span><span class="pln">Box </span><span class="com">-- Прямоугольник с текустурой жидкости.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setFluid</span><span class="pun">():</span><span class="pln">string
    </span><span class="com">-- Имя жидкости (не id блока).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setAlpha</span><span class="pun">():</span><span class="pln">Opacity

Text</span><span class="pun">:</span><span class="pln">Drawable </span><span class="com">-- Текстовое поле.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setX</span><span class="pun">():</span><span class="pln">number
  get</span><span class="pun">/</span><span class="pln">setY</span><span class="pun">():</span><span class="pln">number
  get</span><span class="pun">/</span><span class="pln">setText</span><span class="pun">():</span><span class="pln">string
    </span><span class="com">-- Отображаемый текст.</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setScale</span><span class="pun">():</span><span class="pln">number
    </span><span class="com">-- Размер текста (по умолчанию 1).</span><span class="pln">
  get</span><span class="pun">/</span><span class="pln">setColor</span><span class="pun">():</span><span class="pln">Color
  get</span><span class="pun">/</span><span class="pln">setAlpha</span><span class="pun">():</span><span class="pln">Opacity</span></pre>
		</div>
	</div>
</div>

<p>
	 
</p>

<p>
	<strong>Управление графическими объектами</strong><br>
	DrawableFactory, DrawableContainer
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<pre class="ipsCode prettyprint lang-lua prettyprinted">

<span class="pln">DrawableFactory </span><span class="com">-- Фабрика отображаемых объектов. Созданный объект автоматически добавляется в контейнер.</span><span class="pln">
  addPoint</span><span class="pun">(</span><span class="pln">coord</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?):</span><span class="pln">Point
    </span><span class="com">-- Создать объект Point - точку.</span><span class="pln">
  addLine</span><span class="pun">(</span><span class="pln">p1</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> p2</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?):</span><span class="pln">SolidLine
    </span><span class="com">-- Создать объект SolidLine - цветную линию.</span><span class="pln">
  addGradientLine</span><span class="pun">(</span><span class="pln">p1</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> p2</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">):</span><span class="pln">GradientLine
    </span><span class="com">-- Создать объект GradientLine - линию с градиентным переходом.</span><span class="pln">
  addLineList</span><span class="pun">(</span><span class="pln">color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?,</span><span class="pln"> point1</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> point2</span><span class="pun">...):</span><span class="pln">SolidLineStrip
    </span><span class="com">-- Создать объект SolidLineStrip - произвольную цветную линию.</span><span class="pln">
  addGradientLineList</span><span class="pun">(</span><span class="pln">point1</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> point2</span><span class="pun">...):</span><span class="pln">GradientLineStrip
    </span><span class="com">-- Создать объект GradientLineStrip - произвольную линию с градиентным переходом.</span><span class="pln">
  addBox</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?):</span><span class="pln">SolidBox
    </span><span class="com">-- Создать объект SolidBox - цветной прямоугольник.</span><span class="pln">
  addGradientBox</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?,</span><span class="pln">
        color2</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity2</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?,</span><span class="pln"> gradient</span><span class="pun">:</span><span class="pln">number</span><span class="pun">):</span><span class="pln">GradientBox
    </span><span class="com">-- Создать объект GradientBox - прямоугольник с градиентным переходом.</span><span class="pln">
    </span><span class="com">-- Параметр gradient определяет направление градиента, 1 - вертикальный, 2 - горизонтальный.</span><span class="pln">
    </span><span class="com">-- Если gradient установлен в 0, color2 и opacity2 игнорируются - получается цветной прямоугольник.</span><span class="pln">
  addTriangle</span><span class="pun">(</span><span class="pln">p1</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> p2</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> p3</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?):</span><span class="pln">SolidTriangle
    </span><span class="com">-- Создать объект SolidTriangle - цветной треугольник.</span><span class="pln">
  addGradientTriangle</span><span class="pun">(</span><span class="pln">p1</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> p2</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> p3</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">):</span><span class="pln">GradientTriangle
    </span><span class="com">-- Создать объект GradientTriangle - треугольник с градиентным переходом.</span><span class="pln">
  addQuad</span><span class="pun">(</span><span class="pln">p1</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> p2</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> p3</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> p4</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?):</span><span class="pln">SolidQuad
    </span><span class="com">-- Создать объект SolidQuad - цветной четырёхугольник.</span><span class="pln">
  addGradientQuad</span><span class="pun">(</span><span class="pln">p1</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> p2</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> p3</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> p4</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">):</span><span class="pln">GradientQuad
    </span><span class="com">-- Создать объект GradientQuad - четырёхугольник с градиентным переходом.</span><span class="pln">
  addPolygon</span><span class="pun">(</span><span class="pln">color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?,</span><span class="pln"> opacity</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?,</span><span class="pln"> point1</span><span class="pun">:</span><span class="pln">Coord</span><span class="pun">,</span><span class="pln"> point2</span><span class="pun">...):</span><span class="pln">SolidPolygon
    </span><span class="com">-- Создать объект SolidPolygon - произвольную цветную фигуру.</span><span class="pln">
  addGradientPolygon</span><span class="pun">(</span><span class="pln">point1</span><span class="pun">:</span><span class="pln">ColoredPoint</span><span class="pun">,</span><span class="pln"> point2</span><span class="pun">...):</span><span class="pln">GradientPolygon
    </span><span class="com">-- Создать объект GradientPolygon - произвольную фигуру с градиентным переходом.</span><span class="pln">
  addIcon</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> id</span><span class="pun">:</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> meta</span><span class="pun">:</span><span class="pln">number</span><span class="pun">?):</span><span class="pln">ItemIcon
    </span><span class="com">-- Создать объект ItemIcon - иконку предмета с размерами 16*16.</span><span class="pln">
  addFluid</span><span class="pun">/</span><span class="pln">addLiquid</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> liquid</span><span class="pun">:</span><span class="pln">string</span><span class="pun">):</span><span class="pln">LiquidIcon
    </span><span class="com">-- Создать объект LiquidIcon - прямоугольник с текстурой жидкости.</span><span class="pln">
  addText</span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">:</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">?):</span><span class="pln">Text
    </span><span class="com">-- Создать объект Text - цветной текст.</span><span class="pln">

DrawableContainer </span><span class="com">-- Хранит отображаемые объекты.</span><span class="pln">
  getById</span><span class="pun">/</span><span class="pln">getObjectById</span><span class="pun">(</span><span class="pln">id</span><span class="pun">:</span><span class="pln">number</span><span class="pun">):</span><span class="pln">Drawable
    </span><span class="com">-- Получить объект по идентификатору.</span><span class="pln">
  getAllIds</span><span class="pun">():</span><span class="pln">number</span><span class="pun">[]</span><span class="pln">
    </span><span class="com">-- Получить идентификаторы хранящихся объектов.</span><span class="pln">
  getAllObjects</span><span class="pun">():{</span><span class="pln">id</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> obj</span><span class="pun">:</span><span class="pln">Drawable</span><span class="pun">}</span><span class="pln">
    </span><span class="com">-- Получить таблицу хранящихся объектов.</span><span class="pln">
  clear</span><span class="pun">()</span><span class="pln">
    </span><span class="com">-- Удалить все объекты.</span></pre>

		<p>
			 
		</p>
	</div>
</div>

<p>
	 
</p>

<p>
	<b>Управление терминалом</b>
</p>

<div class="ipsSpoiler" data-ipsspoiler="">
	<div class="ipsSpoiler_header">
		<span>Скрытый текст</span>
	</div>

	<div class="ipsSpoiler_contents">
		<p>
			Объекты обеспечивающие взаимодействие с терминалом и пользователями.
		</p>

		<pre class="ipsCode prettyprint lang-lua prettyprinted">

<span class="pln">UserSurface</span><span class="pun">:</span><span class="pln">DrawableContainer</span><span class="pun">,</span><span class="pln"> DrawableFactory </span><span class="com">-- Контролирует интерфейс отдельно взятого пользователя.</span><span class="pln">

CaptureControl </span><span class="com">-- Предоставляет управление "режимом захвата" во время использования "Беспроводной клавиатуры".</span><span class="pln">
  stopCapturing</span><span class="pun">()</span><span class="pln">
  </span><span class="com">-- Остановить захват.</span><span class="pln">
  setBackground</span><span class="pun">(</span><span class="pln">color</span><span class="pun">:</span><span class="pln">Color</span><span class="pun">,</span><span class="pln"> alpha</span><span class="pun">:</span><span class="pln">Opacity</span><span class="pun">?)</span><span class="pln">
  </span><span class="com">-- Установить цвет и прозрачность фона.</span><span class="pln">
  setKeyRepeat</span><span class="pun">(</span><span class="kwd">repeat</span><span class="pun">:</span><span class="pln">boolean</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Включить/отключить периодический повтор события "glasses_key_down" (по умолчанию false).</span><span class="pln">
  setDragParameters</span><span class="pun">(</span><span class="pln">distance</span><span class="pun">:</span><span class="pln">number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln">number</span><span class="pun">)</span><span class="pln">
    </span><span class="com">-- Установить минимальную дистанцию для возникновения события "glasses_mouse_drag"</span><span class="pln">
    </span><span class="com">-- и минимальное время между срабатываниями (в тиках).</span><span class="pln">
    </span><span class="com">-- По умолчанию distance=5, delay=10, эти значения также являются минимальными.</span><span class="pln">
  toggleGuiElements</span><span class="pun">({</span><span class="pln">element</span><span class="pun">:</span><span class="pln">GuiElement</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">:</span><span class="pln">boolean</span><span class="pun">})</span><span class="pln">
    </span><span class="com">-- Установить видмость стандартных графических элементов.</span><span class="pln">

TerminalGlassesBridge</span><span class="pun">:</span><span class="pln">DrawableContainer</span><span class="pun">,</span><span class="pln"> DrawableFactory </span><span class="com">-- Управляет интерфейсами и хранит данные пользователей.</span><span class="pln">
  getGuid</span><span class="pun">():</span><span class="pln">string
    </span><span class="com">-- Получить уникальный идентификатор терминала.</span><span class="pln">
  sync</span><span class="pun">()</span><span class="pln">
    </span><span class="com">-- Отправить графические данные на очки всех пользователей.</span><span class="pln">
  getUsers</span><span class="pun">():</span><span class="pln">User</span><span class="pun">[]</span><span class="pln">
    </span><span class="com">-- Получить всех пользователей терминала.</span><span class="pln">
  getSurfaceByName</span><span class="pun">(</span><span class="pln">username</span><span class="pun">:</span><span class="pln">string</span><span class="pun">):</span><span class="pln">UserSurface
    </span><span class="com">-- Получить холст по имени игрока.</span><span class="pln">
  getSurfaceByUUID</span><span class="pun">(</span><span class="pln">uuid</span><span class="pun">:</span><span class="pln">string</span><span class="pun">):</span><span class="pln">UserSurface
    </span><span class="com">-- Получить холст по уникальному идентификатору игрока.</span><span class="pln">
  getCaptureControl</span><span class="pun">(</span><span class="pln">uuid</span><span class="pun">:</span><span class="pln">string</span><span class="pun">):</span><span class="pln">CaptureControl
    </span><span class="com">-- Получить контроллер режима захвата.</span></pre>
	</div>
</div>

<p>
	 
</p>

<p>
	Вот такая шпаргалка по очкам, надеюсь пригодится <img alt=":)" data-emoticon="" src="https://computercraft.ru/uploads/emoticons/default_smile.png" title=":)">
</p>

]]></description><guid isPermaLink="false">2592</guid><pubDate>Wed, 24 Apr 2019 20:51:14 +0000</pubDate></item><item><title>&#x41E;&#x431;&#x44A;&#x435;&#x43A;&#x442;&#x43D;&#x43E;-&#x43E;&#x440;&#x438;&#x435;&#x43D;&#x442;&#x438;&#x440;&#x43E;&#x432;&#x430;&#x43D;&#x43D;&#x43E;&#x435; &#x43F;&#x440;&#x43E;&#x433;&#x440;&#x430;&#x43C;&#x43C;&#x438;&#x440;&#x43E;&#x432;&#x430;&#x43D;&#x438;&#x435; &#x438; Lua</title><link>https://computercraft.ru/topic/56-obektno-orientirovannoe-programmirovanie-i-lua/</link><description><![CDATA[
<p>В данной статье я хотел бы показать, как можно применять объектно-ориентированный подход при программировании на lua. Если Вы ранее не сталкивались с ООП в других языках, статья вряд ли станет Вам полезной ибо не предназначена для обучения объектно-ориентированному мышлению, а лишь приводит пример реализации объектов.</p>
<p>Lua не относится к объектно-ориентированным языкам, поскольку не содержит стандартных механизмов создания и использования объектов. Но lua-таблица является настолько гибким инструментом, что позволяет реализовать практически любую структуру, присущую другим языкам. В том числе и объекты.</p>
<p> </p>
<p>Прежде чем создавать экземпляры объекта, необходимо описать соответствующий ему класс.</p>
<p></p>
<pre class="ipsCode prettyprint lang-auto">ClassA={}
ClassA.__index=ClassA</pre>По большому счету, называть это классом нельзя, поскольку класс — это абстракция, служащая шаблоном для создания объекта. Сдесь же мы имеем дело с вполне реальной таблицей. Поэтому ClassA будем называть объектом-прототипом.<p>Как видите, я не описал никаких полей объекта-прототипа т. к. в отличии от таких языков как Delphi и C++, поля таблицы в lua можно описывать когда угодно, а не только при создании таблицы. Поля будем прописывать в конструкторе класса при создании экземпляра объекта. Единственное поле <strong>__index</strong> содержит указатель на сам класс. Это нужно будет для правильной работы оператора self.</p>
<p> </p>
<p>Создадим конструктор:</p>
<p></p>
<pre class="ipsCode prettyprint lang-auto">function ClassA:new(_Name)
  local obj={Name = _Name}
  setmetatable(obj,self)
  print('Constructor ClassA for '..obj.Name)
  return obj
end</pre>Что делает конструктор?<p>Строка 1. Создает экземпляр теперь уже объекта, описывает поля объекта и присваивает полям начальные значения.</p>
<p>Строка 2. Переопределяет метатаблицу вновь созданного объекта, в результате чего объект получает доступ к методам класса. Методов пока нет, но они будут описаны позже.</p>
<p>Строка 3. Это необязательная строка. Я ее сюда вставил для демонстрации работы конструктора.</p>
<p>Строка 4. Возвращает созданный объект.</p>
<p> </p>
<p>Теперь создадим парочку методов:</p>
<p></p>
<pre class="ipsCode prettyprint lang-auto">function ClassA:Metod1()
    print('Metod1 of ClassA for '..self.Name)
end

function ClassA:Metod2()
    print('Metod2 of ClassA for '..self.Name)
end</pre>Зачем два? В дальнейшем один из них будет наследован, а другой перекрыт методом наследника.<p> </p>
<p>И так, мы создали объект-прототип. Пора создавать экземпляры объекта. Экземпляры будем хранить в таблице objects. Для создания экземпляра вызываем конструктор</p>
<p></p>
<pre class="ipsCode prettyprint lang-auto">objects={}

for i = 1,2 do
    objects[i] = ClassA:new('Object#'..i)
end</pre>
<p>Смотрим что получилось</p>
<p></p>
<pre class="ipsCode prettyprint lang-auto">for i=1,2 do

    objects[i]:Metod1()
    objects[i]:Metod2()
end</pre>
<p>Вот программа в полном сборе.</p>
<p></p>
<pre class="ipsCode prettyprint lang-auto">ClassA={}
ClassA.__index=ClassA

function ClassA:new(_Name)
    local obj={Name = _Name}
    setmetatable(obj,self)
    print('Constructor ClassA for '..obj.Name)
    return obj
end

function ClassA:Metod1()
    print('Metod1 of ClassA for '..self.Name)
end

function ClassA:Metod2()
    print('Metod2 of ClassA for '..self.Name)
end

objects={}
for i = 1,2 do
    objects[i] = ClassA:new('Object#'..i)
end

for i=1,2 do
    objects[i]:Metod1()
    objects[i]:Metod2()
end
</pre>
<p>Если все сделано правильно, после запуска программы Вы должны наблюдать вот такие сообщения:</p>
<p>[ATTACH]115[/ATTACH]</p>
<p>В следующий раз я расскажу о наследовании методов объекта и их полиморфизме.</p>
<p><a class="ipsAttachLink ipsAttachLink_image" href="https://computercraft.ru/uploads/monthly_06_2014/post-6-14160784008126.jpg" data-fileid="88" rel=""><img src="https://computercraft.ru/uploads/monthly_06_2014/post-6-14160784008126_thumb.jpg" data-fileid="88" class="ipsImage ipsImage_thumbnailed" alt="post-6-14160784008126_thumb.jpg"></a></p>


]]></description><guid isPermaLink="false">56</guid><pubDate>Wed, 11 Jun 2014 10:05:18 +0000</pubDate></item><item><title>&#x41E;&#x43F;&#x442;&#x438;&#x43C;&#x438;&#x437;&#x430;&#x446;&#x438;&#x44F; &#x43A;&#x43E;&#x434;&#x430;</title><link>https://computercraft.ru/topic/4153-optimizatsiya-koda/</link><description><![CDATA[
<p>
	Решил я как-то поискать методы оптимизации кода для ОпенКомпов, и Луа в целом. Но на форуме, вроде, я не нашел тему, где в одном месте сконцентрированы вещи, помогающие в оптимизации. Разве что нашел одну <a href="https://oc.cil.li/topic/243-memory-management/" rel="external nofollow">ветку</a>, на заморском форуме, вот ее компиляция/перевод/адаптация/дополнение:<br>
	(за помощь в переводе, спасибо <a href="https://computercraft.ru/profile/26254-koshaklol/" rel="">KoshakLol</a> и <a href="https://translate.google.com" rel="external nofollow">Google Translate</a>)<br>
	 
</p>

<p>
	<strong><span style="font-size:22px;"># Место в памяти</span></strong><br>
	<br>
	Вот таблица, где есть, сколько что занимает в памяти:<br>
	boolean, number и string занимают 9 байт.<br>
	Указатель на функцию, или на таблицу, тоже 9 байт.<br>
	Пустая функция (<span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">function() end</span>) занимает 93 байт, пустая функция с return (<span style="color:#111;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#f1f1f1;padding:0 4px;border:1px solid #d6d6d6;margin:2px 2px 2px 0;">function() return true end</span>) занимает 102 байт.<br>
	Пустая таблица занимает 36 байт, плюс за каждую степень двойки (2^n) еще дополнительно:
</p>

<ul>
	<li>
		9 байт для 0-1 элементов в таблице
	</li>
	<li>
		18 байт для 2 элементов в таблице
	</li>
	<li>
		36 байт для 3-4 элементов в таблице
	</li>
	<li>
		71 байт для 5-8 элементов в таблице
	</li>
	<li>
		142 байт для 9-16 элементов в таблице
	</li>
	<li>
		284 байт для 17-32 элементов в таблице
	</li>
	<li>
		569 байт для 33-64 элементов в таблице
	</li>
</ul>

<p>
	и т.д.<br>
	И, кстати, таблицы не сжимаются, то есть если туда запихать 1000 элементов, а потом удалить их, то весить она будет, как будто в ней все еще 1000 элементов<br>
	 
</p>

<p>
	<span style="font-size:22px;"><strong># Сборка мусора</strong></span>
</p>

<p>
	<br>
	Автоматический сборщик мусора в опенкомпах вроде бы отключен, и вызывается только через os.sleep(0), и то не гарантированно, так что разработчик мода советует его вызывать 10 раз подряд, чтоб уж точно<br>
	И еще, автоматический сборщик чистит ТОЛЬКО локальные переменные
</p>

<p>
	<br>
	<strong><span style="font-size:22px;"># Советы сомнительной эффективности </span></strong><span style="font-size:22px;">(от них я не засек прироста)</span>
</p>

<p>
	<br>
	Убрать из кода деление, потому что оно, якобы, медленнее, чем умножение (условно:)
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> n </span><span class="pun">/</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="com">--&gt;</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> n </span><span class="pun">*</span><span class="pln"> </span><span class="lit">0.25</span></pre>

<p>
	Заменить все условные операторы, на логические тернарные операторы, где это возможно (условно:)
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">&gt;</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
    c </span><span class="pun">=</span><span class="pln"> a
</span><span class="kwd">else</span><span class="pln">
    c </span><span class="pun">=</span><span class="pln"> b
</span><span class="kwd">end</span><span class="pln">
</span><span class="com">--&gt;</span><span class="pln">
c </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">&gt;</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> a </span><span class="kwd">or</span><span class="pln"> b</span></pre>

<p>
	(Если вы не поняли, что сейчас вообще было, то в <a href="https://computercraft.ru/topic/1058-logicheskie-vyrazheniya-v-lua-ili-izbavlyaemsya-ot-logicheskih-blokov/" rel="">этой</a> теме все расписано)
</p>

<p>
	Менять переменные местами, без буфера (Lua 5.3+)
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">174</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> b </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
a </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">~</span><span class="pln"> b
b </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">~</span><span class="pln"> b
a </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">~</span><span class="pln"> b
print</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">
</span><span class="com">--&gt; 3</span><span class="pln">
print</span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln">
</span><span class="com">--&gt; 174</span></pre>

<p>
	(Если вы не поняли, что сейчас вообще было, то ищите битовую операцию XOR)<br>
	Этот совет дает хотя бы небольшой прирост, из-за того, что нет лишний переменной, но этот плюс нивелируется, если ее удалить
</p>

<p>
	<br>
	<strong><span style="font-size:22px;"># В итоге</span></strong>
</p>

<p>
	<br>
	Не используйте рекурсию функций, а если совсем приспичило, то почаще вставляйте сбор мусора<br>
	Не используйте замыкания (это когда функция возвращает другую функцию)<br>
	Старайтесь не использовать таблицы, вместо них лучше делать так:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> coords </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">370</span><span class="pun">}</span><span class="pln"> </span><span class="com">-- (72 байта)</span><span class="pln">
</span><span class="com">--&gt;</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">370</span><span class="pln"> </span><span class="com">-- (27 байт)</span><span class="pln">
</span><span class="com">-- или вообще</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> xyz </span><span class="pun">=</span><span class="pln"> </span><span class="lit">010020370</span><span class="pln"> </span><span class="com">-- (9 байт)</span><span class="pln">
print</span><span class="pun">(</span><span class="str">"z = "</span><span class="pun">,</span><span class="pln"> xyz </span><span class="pun">//</span><span class="pln"> </span><span class="lit">1000000</span><span class="pun">,</span><span class="pln"> </span><span class="str">"\ny = "</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> xyz </span><span class="pun">//</span><span class="pln"> </span><span class="lit">1000</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> </span><span class="str">"\nz = "</span><span class="pun">,</span><span class="pln"> xyz </span><span class="pun">%</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">)</span><span class="pln">
</span><span class="com">-- (Если вы не поняли, что сейчас вообще было, то ищите деление с остатком)</span></pre>

<p>
	Старайтесь не использовать не-локальные переменные, так как они бьют по архитектуре программы, и их не собирает гарбадж коллектор<br>
	<br>
	<span style="font-size:22px;"><strong># P.S</strong></span><br>
	<br>
	В данной заметке рассматривалась только сторона оптимизации кода, определенный код может отвратительно выглядеть, но работать быстро, и наоборот, в реальных программах лучше соблюдать баланс, между красотой, и быстродействием, в какой-нибудь программе для EEPROM'a, допустим, вообще о красоте кода не идет и речи<br>
	Ну это в целом все, что я хотел рассказать, если есть исправления/уточнения/дополнения/свои_идеи, то милости прошу в комментарии
</p>

]]></description><guid isPermaLink="false">4153</guid><pubDate>Thu, 01 Apr 2021 03:24:16 +0000</pubDate></item><item><title>&#x428;&#x430;&#x431;&#x43B;&#x43E;&#x43D;&#x44B;</title><link>https://computercraft.ru/topic/70-shablony/</link><description><![CDATA[
<p style="margin-left:600px;"><span style="font-size:12px;"><em>- Я умею читать чужие мысли!</em></span></p>
<p style="margin-left:600px;"><span style="font-size:12px;"><em>- А я умею читать чужие регулярные выражения!</em></span></p>
<p style="margin-left:600px;"><span style="font-size:12px;"><em>- Ты победил</em></span></p>
<p> </p>
<p>Люди, которые программируют приложения, связанные с обменом по сети rednet или сохранением на диск, часто сталкиваются с необходимостью преобразования массива данных различных типов в строку и последующим его восстановлением. Под массивом я подразумеваю не отдельно взятую таблицу, а несколько переменных, которые нужно упаковать в одну строку. Самый простой но не самый лучший способ решить эту задачу - поместить все необходимые данные в таблицу и воспользоваться функциями serialize, unserialize из библиотеки textutilse. О недостатках такого способа я уже когда-то говорил и сегодня повторяться не буду. А расскажу о том, как эту проблему решаю я. Предположим нам необходимо упаковать в одну строку значения нескольких переменных (x, y, z). Причем строка должна содержать не только значения переменных, но и информацию о том, что это за переменные. Думаю с упаковкой ни у кого больших проблем не возникнет. Сделать это можно, к примеру, так: s='x='..x..' y='..y..' z='..z В результате мы получим строку, которая содержит имена наших переменных и их значения, отделенные от имен знаками равенства. 'x=10 y=11 z=12' Вроде просто. Но как из этой строки извлечь заложенную в нее информацию, а именно имена и значения? Конечно, можно написать большой и сложный алгоритм посимвольного разбора строки. К счастью, вся скучная работа уже сделана за нас и поставленную задачу мы можем выполнить буквально в одно действие. Я говорю о функциях match и gmatch из библиотеки string. Назначение этих функций - поиск шаблона в строке. К примеру, в строке s, которую я привел выше, я хочу найти подстроку 'y=11'. Для этого я вызываю функцию s:match('y=11') которая и вернет мне искомую подстроку, если она там есть. Параметр 'y=11' будем называть шаблоном. Если шаблон в строке не найден, функция вернет nil. Правда здорово?</p>

]]></description><guid isPermaLink="false">70</guid><pubDate>Fri, 27 Jun 2014 13:16:31 +0000</pubDate></item><item><title>&#x41C;&#x435;&#x442;&#x43E;&#x434;&#x438;&#x43A;&#x430; &#x443;&#x441;&#x43A;&#x43E;&#x440;&#x435;&#x43D;&#x43D;&#x43E;&#x433;&#x43E; &#x432;&#x44B;&#x447;&#x438;&#x441;&#x43B;&#x435;&#x43D;&#x438;&#x44F; &#x43A;&#x43E;&#x43D;&#x441;&#x442;&#x430;&#x43D;&#x442;&#x44B; &#x448;&#x443;&#x43C;&#x430; &#x433;&#x435;&#x43E;&#x441;&#x43A;&#x430;&#x43D;&#x435;&#x440;&#x430;</title><link>https://computercraft.ru/topic/3352-metodika-uskorennogo-vychisleniya-konstanty-shuma-geoskanera/</link><description><![CDATA[
<div>
	<div>
		<h3>
			Методика ускоренного вычисления константы шума геосканера
		</h3>

		<div>
			<table>
				<tbody>
					<tr>
						<td>
							 
						</td>
						<td>
							 
						</td>
					</tr>
				</tbody>
			</table>
		</div>

		<div>
			<p>
				Предлагаю ознакомиться с методикой, позволяющий максимально быстро и абсолютно точно вычислить константу шума геосканера (geolyzerNoise в config/OpenComputers.cfg).
			</p>
		</div>

		<div>
			<p>
				 
			</p>

			<p>
				Методика и скрипты тестировались в среде OpenComputers-MC1.7.10-1.7.5.1290-universal.jar. Сохранит ли эта методика свою актуальность в будущем, вселцело зависит от авторов мода.
			</p>
		</div>

		<div>
			<h4>
				Зачем знать константу шума геосканера?
			</h4>

			<div>
				<p>
					Не на всех серверах параметр geolyzerNoise сохраняет значение по умолчанию. Алгоритмы же поиска руд, использующие для своей работы геосканер, в большинстве своём эффективны лишь при определённых параметрах шума. При увеличении или уменьшении зашумлённости будут эффективны другие алгоритмы. Поэтому знание точных параметров шума геосканера поможет использовать наиболее эффективные алгоритмы поиска руд на конкретном сервере в конкретных условиях шума.
				</p>
			</div>
		</div>

		<div>
			<h4>
				Традиционный алгоритм
			</h4>

			<div>
				<p>
					Традиционный алгоритм использует выполнение многократного сканирования плотности блока, поиск минимального и максимального значений и вычисление разницы между ними. Плюсом алгоритма является его простота. Минусом является низкая точность. Для повышения точности используется увеличение кратности сканирования, но даже очень большая кратность не даёт гарантии абсолютной точности. Всегда есть небольшой шанс, что шум окажется немного больше найденного алгоритмом.
				</p>
			</div>
		</div>

		<div>
			<h4>
				Дискретная структура шума
			</h4>

			<div>
				<p>
					Как было обнаружено в недавнем обсуждении про <a href="https://computercraft.ru/topic/3346-vychislenie-pogreshnosti-geoskanera/?do=findComment&amp;comment=42492" rel=""> вычисление погрешности геосканера</a>, шум имеет дискретную природу. Согласно <a href="https://github.com/MightyPirates/OpenComputers/blob/cca7f202d5040156bf93a0ef687fd6447fbfd07d/src/main/scala/li/cil/oc/integration/vanilla/EventHandlerVanilla.scala#L25_L44" rel="external nofollow"> коду OpenComputers</a> для каждого из сканируемых расстояний существует 256 возможных значений шума. Знание этого факта позволяет нам считать результат достигнутым, как только сканер выдаст 256 уникальных значений плотности одного и того же блока. Плюсом такого подхода будет абсолютная точность. Главный же минус заключается в том, что получение всех 256 значений может занять даже больше времени, чем получение реальных минимума и максимума плотности. В моих экспериментах на получение всех 256 значений уходит примерно 10-20k попыток сканирования.
				</p>

				<p>
					 
				</p>
			</div>

			<div>
				<p>
					Вот скрипт для наглядности:
				</p>
			</div>

			<div>
				<div>
					<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="com">-- демонстрация: шум геосканера имеет 256 фиксированных значений</span><span class="pln">
</span><span class="com">-- установка: любой блок, сверху блок геосканера, на него спавним комп /oc_sc</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> scan </span><span class="pun">=</span><span class="pln"> require</span><span class="str">'component'</span><span class="pun">.</span><span class="pln">geolyzer</span><span class="pun">.</span><span class="pln">scan

</span><span class="kwd">local</span><span class="pln"> uniqTbl </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> uniqCnt </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> v

</span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="lit">1e4</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
  v </span><span class="pun">=</span><span class="pln"> scan</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">-1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">1</span><span class="pun">)[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> uniqTbl</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
    uniqTbl</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    uniqCnt </span><span class="pun">=</span><span class="pln"> uniqCnt </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    print</span><span class="pun">((</span><span class="str">"try: %d, uniqCnt: %d"</span><span class="pun">):</span><span class="pln">format</span><span class="pun">(</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> uniqCnt </span><span class="pun">))</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
  os</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">   </span><span class="com">-- ^C для останова</span><span class="pln">
</span><span class="kwd">end</span></pre>

					<p>
						Наблюдая за скриптом, легко заметить, как медленно добираются последние из оставшихся уникальных значений. Алгоритм абсолютно точен, но неоптимален.
					</p>
				</div>
			</div>
		</div>

		<div>
			<h4>
				Оптимизация поиска
			</h4>

			<div>
				<p>
					Оптимизировать вычисления нам поможет знание о том, что все 256 значений шума расположены равномерно, расстояния между смежными значениями одинаковы, и они ровно в 256 раз меньше расстояния между максимальным и минимальным из значений. В пределах погрешности вычислений, разумеется.
				</p>
			</div>

			<div>
				<p>
					 
				</p>

				<p>
					Это значит, что для вычисления константы шума достаточно найти любые два смежных значения и вычислить разницу между ними. Но смежными эти значения должны быть в своей полной таблице из 256 значений, в то время как в целях оптимизации рабочая таблица должна быть заполнена как можно меньшим количеством данных, и поэтому соседство значений в рабочей таблице не означает обязательности их соседства в полной.
				</p>
			</div>

			<div>
				<p>
					 
				</p>

				<p>
					Уменьшать количество значений в рабочей таблице следует ровно до того момента, пока это не мешает обнаружению двух смежных значений. Можно сказать и наоборот: пополнять таблицу новыми значениями следует ровно до тех пор, пока смежные значения не удаётся обнаружить с абсолютной точностью.
				</p>
			</div>

			<div>
				<p>
					 
				</p>

				<p>
					Самое очевидное, что приходит в голову, это набрать ровно 129 уникальных значений, и найти среди них ближайших соседей. Почему 129, а не 128? Потому что при 128 уникальных значениях возможна редкая ситуация, когда эти найденные значения находятся в полной таблице ровно через одно. Это маловероятно, но возможно. Зачем рисковать? Тем более, 129 элементов почти всегда находятся примерно за 200 попыток сканирований, что можно увидеть, наблюдая за работой демонстрационного скрипта.
				</p>
			</div>

			<div>
				<p>
					 
				</p>

				<p>
					Но внимательный читатель наверняка заметит, что может быть достаточно использовать и 128 значений при условии, что они размещены неравномерно относительно друг друга. Почти всегда 129-ое значение оказывается необязательным. И если развить эту мысль, то выяснится, что и 127 значений почти всегда будет достаточно при введении дополнительных условий. Тем же путём можно перейти к 126 значениям и т.д. В итоге окажется, что роль играет не равномерность расположения значений относительно друг друга, а расстояние между крайними элементами и между двумя ближайшими. А для этой цели может быть достаточно даже трёх найденных значений. В лучшем случае. Но в худшем могут потребоваться и все 129 значений.
				</p>
			</div>
		</div>

		<div>
			<h4>
				Оптимальный алгоритм
			</h4>

			<div>
				<p>
					В общем виде алгоритм сводится к циклическому получению очередного значения от геосканера и поиску разницы между всеми найденными значениями. И если соотношение максимальной разницы к минимальной превысит 128, то результат достигнут: минимальная разница между найденными значениями обязана быть равной разнице между смежными значениями в полной таблице. Результатом умножения минимальной разницы на 128*33 будет искомая нами константа geolyzerNoise из файла конфигурации.
				</p>
			</div>

			<div>
				<p>
					 
				</p>

				<p>
					Результирующий код может выглядеть, например, так:
				</p>
			</div>

			<div>
				<div>
					<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="com">-- измеритель шума геосканера (константы geolyzerNoise в config/OpenComputers.cfg)</span><span class="pln">
</span><span class="com">-- установка: любой блок, сверху блок геосканера, на него спавним комп /oc_sc</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> abs </span><span class="pun">=</span><span class="pln"> require</span><span class="str">'math'</span><span class="pun">.</span><span class="pln">abs
</span><span class="kwd">local</span><span class="pln"> scan </span><span class="pun">=</span><span class="pln"> require</span><span class="str">'component'</span><span class="pun">.</span><span class="pln">geolyzer</span><span class="pun">.</span><span class="pln">scan

</span><span class="com">-- округление до сотых долей для сокрытия погрешностей</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> round</span><span class="pun">(</span><span class="pln"> v </span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">v</span><span class="pun">*</span><span class="lit">1e2+0.5</span><span class="pun">)//</span><span class="lit">1</span><span class="pun">/</span><span class="lit">1e2</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">
</span><span class="com">-- множитель для восстановления значения шума до справочного</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> mul </span><span class="pun">=</span><span class="pln"> </span><span class="lit">128</span><span class="pun">*</span><span class="lit">33</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> uniqTbl </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> uniqCnt </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">

</span><span class="com">-- текущее значение, разница с другим значением, минимальная и максимальная разница</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> val</span><span class="pun">,</span><span class="pln"> dif</span><span class="pun">,</span><span class="pln"> min</span><span class="pun">,</span><span class="pln"> max
</span><span class="com">-- флаг обновления экстремумов</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> fUpd

</span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="lit">99</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
  os</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  val </span><span class="pun">=</span><span class="pln"> scan</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">-1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">1</span><span class="pun">)[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">

  fUpd </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="com">-- обрабатывать только новые уникальные значения</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> uniqTbl</span><span class="pun">[</span><span class="pln">val</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
    </span><span class="com">-- обновить информацию о минимальной и максимальной разнице</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> v</span><span class="pun">,</span><span class="pln">_ </span><span class="kwd">in</span><span class="pln"> pairs</span><span class="pun">(</span><span class="pln">uniqTbl</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
      dif </span><span class="pun">=</span><span class="pln"> abs</span><span class="pun">(</span><span class="pln"> val</span><span class="pun">-</span><span class="pln">v </span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> min </span><span class="kwd">or</span><span class="pln"> min</span><span class="pun">&gt;</span><span class="pln">dif </span><span class="kwd">then</span><span class="pln"> min</span><span class="pun">=</span><span class="pln">dif fUpd</span><span class="pun">=</span><span class="kwd">true</span><span class="pln"> </span><span class="kwd">end</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> max </span><span class="kwd">or</span><span class="pln"> max</span><span class="pun">&lt;</span><span class="pln">dif </span><span class="kwd">then</span><span class="pln"> max</span><span class="pun">=</span><span class="pln">dif fUpd</span><span class="pun">=</span><span class="kwd">true</span><span class="pln"> </span><span class="kwd">end</span><span class="pln">
    </span><span class="kwd">end</span><span class="pln">
    </span><span class="com">-- пополнить таблицу уникальных значений</span><span class="pln">
    uniqTbl</span><span class="pun">[</span><span class="pln">val</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    uniqCnt </span><span class="pun">=</span><span class="pln"> uniqCnt </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">

  </span><span class="com">-- при обновлении вывести информацию на экран</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> fUpd </span><span class="kwd">then</span><span class="pln">
    print</span><span class="pun">((</span><span class="str">"uniq:%2d/%2d |  min:%7.3f | max:%7.3f | max/min:%7.3f"</span><span class="pun">):</span><span class="pln">format</span><span class="pun">(</span><span class="pln"> uniqCnt</span><span class="pun">,</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> round</span><span class="pun">(</span><span class="pln">min</span><span class="pun">*</span><span class="pln">mul</span><span class="pun">),</span><span class="pln"> round</span><span class="pun">(</span><span class="pln">max</span><span class="pun">*</span><span class="pln">mul</span><span class="pun">),</span><span class="pln"> round</span><span class="pun">(</span><span class="pln">max</span><span class="pun">/</span><span class="pln">min</span><span class="pun">)</span><span class="pln"> </span><span class="pun">))</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
  </span><span class="com">-- закончить по достижении результата</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> fUpd </span><span class="kwd">and</span><span class="pln"> max</span><span class="pun">/</span><span class="pln">min </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">128</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
    </span><span class="kwd">break</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="com">-- сообщить результат</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> fUpd </span><span class="kwd">and</span><span class="pln"> max</span><span class="pun">/</span><span class="pln">min </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">128</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
  print</span><span class="pun">((</span><span class="str">"Congratulations! geolyzerNoise = %f"</span><span class="pun">):</span><span class="pln">format</span><span class="pun">(</span><span class="pln"> round</span><span class="pun">(</span><span class="pln">min</span><span class="pun">*</span><span class="pln">mul</span><span class="pun">)</span><span class="pln"> </span><span class="pun">))</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
  print</span><span class="pun">(</span><span class="str">"Failure! Tray again please!"</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">end</span></pre>

					<p>
						 
					</p>
				</div>
			</div>
		</div>

		<div>
			<h4>
				Результат
			</h4>

			<div>
				<p>
					Знание об особенностях генерации шума геосканера, позволило достичь абсолютно точных результатов при очень малом времени сканирования при вычислении константы шума геосканера. В лучшем случае результат можно получить за три сканирования. В типичном случае требуется около 20 сканирований, что требует около одной секунды времени. Самый худший случай не ограничен ничем, но использованное в моём скрипте ограничение в 99 сканирвоаний ни разу не было достигнуто за несколько сотен попыток.
				</p>
			</div>

			<div>
				<p>
					 
				</p>

				<p>
					И это ещё не всё, что может дать знание о шуме геосканера. <strong>Пошумим, брат!</strong>
				</p>
			</div>
		</div>
	</div>
</div>

]]></description><guid isPermaLink="false">3352</guid><pubDate>Sat, 25 Apr 2020 16:27:13 +0000</pubDate></item><item><title>&#x41A;&#x430;&#x43A; &#x443;&#x431;&#x440;&#x430;&#x442;&#x44C; &#x447;&#x451;&#x440;&#x43D;&#x44B;&#x435; &#x43F;&#x43E;&#x43B;&#x43E;&#x441;&#x44B; &#x43F;&#x43E; &#x43A;&#x440;&#x430;&#x44F;&#x43C; &#x44D;&#x43A;&#x440;&#x430;&#x43D;&#x430; OpenComputers</title><link>https://computercraft.ru/topic/2413-kak-ubrat-chyornye-polosy-po-krayam-ekrana-opencomputers/</link><description><![CDATA[
<p>
	На днях в чате прозвучал вопрос, как убрать чёрные полосы по краям экрана. На форуме есть замечательная библиотека от <a contenteditable="false" data-ipshover="" data-ipshover-target="https://computercraft.ru/profile/14123-ecs/?do=hovercard" data-mentionid="14123" href="https://computercraft.ru/profile/14123-ecs/" rel="">@ECS</a>, которая хорошо решает поставленную задачу: <a href="https://computercraft.ru/topic/1130-avtomaticheskii-mssahtab-monitora-izbavliaemsia/" rel="">http://computercraft.ru/topic/1130-avtomaticheskii-mssahtab-monitora-izbavliaemsia/</a>
</p>

<p>
	Но есть два нюанса:
</p>

<p>
	1) Код библиотеки явно избыточен.
</p>

<p>
	2) При чтении кода библиотеки создаётся впечатление, что она работает на неведомой магии тёмных сил, что демотивирует новичков, изучающих OpenComputers.
</p>

<p>
	Я намерен восполнить данный недостаток.
</p>

<p>
	 
</p>

<p>
	<strong>Прочтение этого гайда поможет любому желающему написать кусочек кода под нужды конкретной программы, не подтягивая библиотечный код.</strong>
</p>

<p>
	 
</p>

<p>
	Благодарю <a contenteditable="false" data-ipshover="" data-ipshover-target="https://computercraft.ru/profile/69-totoro/?do=hovercard" data-mentionid="69" href="https://computercraft.ru/profile/69-totoro/" rel="">@Totoro</a> за предоставленную информацию:
</p>

<p>
	1) Текстура блока имеет размер 16 px, а ширина рамки монитора – 2 px;
</p>

<p>
	2) Высота символа на экране в два раза больше его ширины.
</p>

<p>
	Данной информации достаточно для получения всех необходимых формул. Приступим:
</p>

<p>
	 
</p>

<p>
	<strong>Первый шаг: получить соотношение сторон экрана, выраженное в символах</strong>
</p>

<p>
	 
</p>

<p>
	В мире Майнкрафта текстура блока имеет размер в 16 пикселей. На рамку с каждой стороны тратится по 2 пикселя независимо от размера монитора.
</p>

<p>
	<img alt="Pdqexqc.png" src="https://i.imgur.com/Pdqexqc.png">
</p>

<p>
	 
</p>

<p>
	Очевидно, что размер монитора в пикселях кратен 16 и пропорционален количеству использованных блоков, а размер полезной части экрана всегда меньше размера монитора на 4 пикселя как по вертикали, так и по горизонтали. Поэтому разрешение нескольких мониторов, выставленных в ряд, всегда составит <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">16*n-4</span> пикселей по соответствующей координатной оси.
</p>

<p>
	 
</p>

<p>
	Это подтверждает и формула от <a contenteditable="false" data-ipshover="" data-ipshover-target="https://computercraft.ru/profile/14123-ecs/?do=hovercard" data-mentionid="14123" href="https://computercraft.ru/profile/14123-ecs/" rel="">@ECS</a>, реализованная в функции calculateAspect(screens), но имеющая более сложный вид. Я предлагаю и вовсе отказаться от отдельной функции, т. к. в текущих условиях это будет напрасной тратой ресурсов.
</p>

<p>
	 
</p>

<p>
	Немного поясняющего кода:
</p>

<pre class="ipsCode prettyprint lang-auto">
-- размер монитора в блоках
sw,sh = component.screen.getAspectRatio()
-- размер экрана монитора с учётом затрат на рамку:
sw_ = sw*16-4
sh_ = sh*16-4
-- соотношение сторон экрана, выраженное в пикселях текстуры блока
sa = sw_/sh_
-- соотношение сторон экрана, выраженное в символах
sa = 2*sw_/sh_
-- оно же без промежуточных присваиваний:
sa = 2*(sw*16-4)/(sh*16-4)
-- оно же после упрощения формулы и сокращения количества операций
sa = (sw*2-0.5)/(sh-0.25)</pre>

<p>
	<strong>Второй шаг: скорректировать разрешение графической карты под соотношение сторон экрана</strong>
</p>

<p>
	 
</p>

<p>
	Теперь требуется получить максимально доступное разрешение GPU и соответствующее ему соотношение сторон:
</p>

<pre class="ipsCode prettyprint lang-auto">
-- максимально возможное разрешение графической карты в символах
gw, gh = gpu.maxResolution()
-- соотношение сторон при максимальном разрешении в символах
ga = gw/gh
-- формулы, полученные из предыдущей, и которые пригодятся чуть позже
gw = gh*ga
gh = gw/ga
</pre>

<p>
	Для определения дальнейших действий следует вспомнить о физическом смысле соотношения сторон. Исходя из приведённых выше формул, sa и ga можно назвать коэффициентами горизонтальности. Сравнивая их, можно определить, что по горизонтали более вытянуто разрешение либо видеокарты, либо монитора. Понятно, что если монитор имеет больший коэффициент горизонтальности, то для приведения к нему коэффициента горизонтальности видеокарты следует уменьшить её разрешение по вертикали. В ином случае следует уменьшать разрешение GPU по горизонтали:
</p>

<pre class="ipsCode prettyprint lang-auto">
-- код в понятной форме, использованы формулы из предыдущего фрагмента
if sa&gt;ga then -- недостаточная горизонтальность GPU
  ga=sa -- привести горизонтальность в соответствии с экраном
  gh = gw/ga -- за счёт уменьшения высоты
else -- избыточная горизонтальность GPU
  ga=sa -- привести горизонтальность в соответствии с экраном
  gw = gh*ga -- за счёт уменьшения ширины
end
-- код после сокращения лишних операций
if sa &gt; gw/gh then
  gh = gw/sa
else
  gw = gh*sa
end</pre>

<p>
	<strong>Третий шаг: скорректировать разрешение графической карты под нужны программы</strong>
</p>

<p>
	 
</p>

<p>
	Вычисленное на предыдущем шаге разрешение может оказаться дробным, и перед использованием его следует округлить. Возможно, что перед этим разрешение должно быть приведено к желаемому масштабу, как это сделано в библиотеке <a contenteditable="false" data-ipshover="" data-ipshover-target="https://computercraft.ru/profile/14123-ecs/?do=hovercard" data-mentionid="14123" href="https://computercraft.ru/profile/14123-ecs/" rel="">@ECS</a>. Эта часть, скорее всего, не требует пояснений, и готовый код будет, например, таким:
</p>

<pre class="ipsCode prettyprint lang-auto">
-- код для автоматической подстройки разрешения графической карты под размер монитора
--  почти не оставляет чёрных полос по краям экрана
--  полное исключение полос возможно только при отсутствии округления разрешения

local component = require"component"
local gpu, screen = component.gpu, component.screen

function set_proportional_resolution( scale )
  -- коррекция допустимых пределов масштаба
  if not scale or scale &gt; 1 then
    scale = 1
  elseif scale &lt; 0.1 then
    scale = 0.1
  end
  -- соотношение сторон монитора в символах:
  local sw,sh = screen.getAspectRatio()
  local sa = (sw*2-0.5)/(sh-0.25)
  -- запрос и коррекция максимального разрешения GPU
  local gw, gh = gpu.maxResolution()
  if sa &gt; gw/gh then
    gh = gw/sa
  else
    gw = gh*sa
  end
  -- установка нового разрешения GPU с учётом заданного масштаба
  gpu.setResolution( math.floor(gw*scale), math.floor(gh*scale) )
end

-- тест работоспособности на нескольких вариантах масштаба
-- в процессе можно видеть, что на некоторых масштабах чёрные полосы имеют больший размер, чем на других
local w,h
local unicode = require"unicode"

for i=0.1, 1, 0.1 do
  set_proportional_resolution(i)
  w,h = gpu.getResolution()
  gpu.fill(1,1,w,h, unicode.char(0x2592))
  os.sleep(2)
end</pre>

<p>
	Приведённый код можно сократить ещё сильнее, например, избавившись от масштабирования, которое может отвлекать читателя от подгонки соотношения сторон.
</p>

<p>
	 
</p>

<p>
	<strong>Полное исключение чёрных полос</strong>
</p>

<p>
	 
</p>

<p>
	При выполнении этого кода можно видеть, что чёрные полосы не исчезают полностью, и на одних масштабах проявляются сильнее, чем на других. Предположим, требуется полностью избавиться от чёрных полос. Можно было бы написать код и для этого случая, но эта задача не всегда решаема. Кроме того, количество решений сильно ограничено, и не любой интерфейс можно будет подогнать под найденные решения.
</p>

<p>
	 
</p>

<p>
	<strong>Пример №1:</strong>
</p>

<p>
	Монитор максимального допустимого размера 8x6; GPU Tier3 обеспечивает максимальное разрешение 160x50.
</p>

<p>
	Условное разрешение монитора в целых символах:
</p>

<p>
	sw = 8*8-2 = 62
</p>

<p>
	sh = 6*4-1 = 23
</p>

<p>
	Допустимые разрешения GPU, которые обеспечат отсутствие полос: 62x23 и 124x46.
</p>

<p>
	 
</p>

<p>
	<strong>Пример №2:</strong>
</p>

<p>
	Монитор 6x5; GPU Tier1 обеспечивает максимальное разрешение 50x16.
</p>

<p>
	Условное разрешение монитора в целых символах:
</p>

<p>
	sw = 6*8-2 = 46
</p>

<p>
	sh = 5*4-1 = 19
</p>

<p>
	Нет разрешений GPU, обеспечивающих полное отсутствие полос.
</p>

<p>
	 
</p>

<p>
	<strong>Пример №3:</strong>
</p>

<p>
	Монитор 5x5; GPU Tier1 обеспечивает максимальное разрешение 50x16.
</p>

<p>
	Условное разрешение монитора в целых символах:
</p>

<p>
	sw = 5*8-2 = 38
</p>

<p>
	sh = 5*4-1 = 19
</p>

<p>
	Разрешения GPU 50x16 недостаточно для размещения поля символов 38x19. Но если присмотреться внимательно, и вспомнить, что нам важно соотношение, то поле символов можно сократить до 2x1, избавившись от общего делителя 19. В этом случае допустимых разрешений GPU предостаточно, начиная от 2x1 и заканчивая 32x16. Во всех этих случаях пустых чёрных полос на мониторе не будет.
</p>

<p>
	 
</p>

<p>
	Автоматизация этих вычислений вряд ли целесообразна. Скорее всего, имеет смысл примерно прикинуть необходимое разрешение для конкретного интерфейса, выбрать желаемый размер экрана, графическую плату, и выполнив приведённые выше вычисления, уже окончательно определить рабочее разрешение и затем подогнать интерфейс под него.
</p>

<p>
	 
</p>

<p>
	 
</p>

<p>
	Вот, и вся магия. То, что выглядит сложным, не всегда является таковым на самом деле.
</p>

<p>
	 
</p>

<p>
	Upd: Дополняющий гайд от <a contenteditable="false" data-ipshover="" data-ipshover-target="https://computercraft.ru/profile/14123-ecs/?do=hovercard" data-mentionid="14123" href="https://computercraft.ru/profile/14123-ecs/" rel="">@ECS</a><span>:</span>
</p>

<p>
	<span><a href="https://computercraft.ru/topic/2501-kak-ubrat-chyornye-polosy-po-krayam-ekrana-v30/" rel="">https://computercraft.ru/topic/2501-kak-ubrat-chyornye-polosy-po-krayam-ekrana-v30/</a></span>
</p>

]]></description><guid isPermaLink="false">2413</guid><pubDate>Sat, 25 Aug 2018 07:59:10 +0000</pubDate></item><item><title>&#x41A;&#x430;&#x43A; &#x443;&#x431;&#x440;&#x430;&#x442;&#x44C; &#x447;&#x451;&#x440;&#x43D;&#x44B;&#x435; &#x43F;&#x43E;&#x43B;&#x43E;&#x441;&#x44B; &#x43F;&#x43E; &#x43A;&#x440;&#x430;&#x44F;&#x43C; &#x44D;&#x43A;&#x440;&#x430;&#x43D;&#x430; v3.0</title><link>https://computercraft.ru/topic/2501-kak-ubrat-chyornye-polosy-po-krayam-ekrana-v30/</link><description><![CDATA[
<p>
	По этой теме уже существует отлаженный <a href="https://computercraft.ru/topic/2413-gayd-kak-ubrat-chyornye-polosy-po-krayam-ekrana-opencomputers/" rel="">софт</a>, успешно используемый многими игроками. Однако на днях я заметил забавную особенность местных видеокарт, позволяющую выставлять разрешение большее, нежели получаемое через <strong>gpu.maxResolution()</strong>. К примеру, если <strong>maxResolution</strong> для видеокарты третьего уровня вернет числа 160 и 50, то никто не мешает установить разрешение, скажем, в 20x158 пикселей. При этом при проверке валидности устанавливаемого разрешения соблюдается два правила:
</p>

<p>
	 
</p>

<ul>
	<li>
		Результирующее разрешение по числу пикселей не должно превышать результат умножения чисел, возвращаемых <strong>maxResolution</strong>. То есть для T3 GPU не более 160 * 50 = 8000.
	</li>
	<li>
		Каждый параметр разрешения, будь то ширина или высота, не должен численно превышать значение возвращаемой ширины. То есть для T3 GPU не более 160.
	</li>
</ul>

<p>
	 
</p>

<p>
	Не знаю, баг это или фича, однако подобное грех не использовать в своих целях. К примеру, старая версия программы при вертикально-удлиненном расположении мониторов позволяла выставить разрешение лишь в 30х50 (<span>1500</span> пикселей в итоге), заполняя тем самым "черные полосы". В то же время обновленная софтина, учитывающая описанные выше особенности, выдает 69x114 (<span>7866</span> пикселей), максимально приближаясь к предельной отметке в 8000:
</p>

<p>
	 
</p>

<p>
	<img alt="46Q5jB6.png?1" class="ipsImage" height="750" src="https://i.imgur.com/46Q5jB6.png?1" width="299">   <img alt="cIp0CPJ.png?1" class="ipsImage" height="750" src="https://i.imgur.com/cIp0CPJ.png?1" width="321">
</p>

<p>
	 
</p>

<p>
	Согласитесь, лишние пиксели на дороге не валяются, и, думаю, кому-то будет интересно узнать про реализацию подобного софта.
</p>

<p>
	 
</p>

<p>
	Прежде всего нам требуется определить точную пропорцию мультиблочного монитора: то, как относится его ширина к высоте. Взглянем на текстуру блока: она явно состоит из мелких "квадратиков" в количестве 16 штук, причем лицевая часть монитора имеет рамку толщиной в 2 "квадратика" с каждой стороны:
</p>

<p>
	 
</p>

<p>
	<img alt="WKlKAPf.png?1" class="ipsImage" height="315" src="https://i.imgur.com/WKlKAPf.png?1" width="400">
</p>

<p>
	 
</p>

<p>
	Эти "квадратики" мы и будем использовать для расчета пропорции,  так как они позволяют идеально точно получить размеры отображающей части монитора в игровом мире. А размеры "в квадратиках" можно посчитать по формуле:
</p>

<pre class="ipsCode">
число_блоков_монитора * 16 - 4</pre>

<p>
	Следовательно, пропорция монитора будет считается следующим образом:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> gpu </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">gpu
</span><span class="kwd">local</span><span class="pln"> screen </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">proxy</span><span class="pun">(</span><span class="pln">gpu</span><span class="pun">.</span><span class="pln">getScreen</span><span class="pun">())</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> blockCountByWidth</span><span class="pun">,</span><span class="pln"> blockCountByHeight </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">screen</span><span class="pun">.</span><span class="pln">getAspectRatio</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> proportion </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">16</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByHeight </span><span class="pun">*</span><span class="pln"> </span><span class="lit">16</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span></pre>

<p>
	Также не забываем, что высота каждого псевдографического пикселя при отображении в 2 раза больше его ширины, поэтому формула пропорции слегка меняется. Заодно произведем некоторые сокращения, чтобы избавиться от лишних математических операций. Все три варианта эквивалентны:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> proportion </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">16</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByHeight </span><span class="pun">*</span><span class="pln"> </span><span class="lit">16</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> proportion </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">16</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByHeight </span><span class="pun">*</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> proportion </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByHeight </span><span class="pun">-</span><span class="pln"> </span><span class="lit">0.25</span><span class="pun">)</span></pre>

<p>
	После вычисления пропорции монитора можно приступить к написанию программной логики. Для начала получим максимальное разрешение видеокарты:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> maxWidth</span><span class="pun">,</span><span class="pln"> maxHeight </span><span class="pun">=</span><span class="pln"> gpu</span><span class="pun">.</span><span class="pln">maxResolution</span><span class="pun">()</span></pre>

<p>
	Обладая этими данными, а также взглянув на условия, описанные в начале поста, мы можем составить систему неравенств для получения итогового идеального разрешения:
</p>

<p>
	 
</p>

<p>
	<img alt="p2A0tJ2.png" class="ipsImage" height="100" src="https://i.imgur.com/p2A0tJ2.png" width="428">
</p>

<p>
	 
</p>

<p>
	Помним также, что ширину мы вполне можем выразить через высоту и пропорцию монитора:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="pln">width </span><span class="pun">=</span><span class="pln"> proportion </span><span class="pun">*</span><span class="pln"> height</span></pre>

<p>
	Подставим этот вариант в систему:
</p>

<p>
	 
</p>

<p>
	<img alt="T3p1lnT.png" class="ipsImage" height="105" src="https://i.imgur.com/T3p1lnT.png" width="486">
</p>

<p>
	 
</p>

<p>
	Оставим высоту в левой части неравенств:
</p>

<p>
	 
</p>

<p>
	<img alt="45y25kQ.png" class="ipsImage" height="188" src="https://i.imgur.com/45y25kQ.png" width="401">
</p>

<p>
	 
</p>

<p>
	Подставляем имеющиеся переменные в каждое неравенство, рисуем числовую прямую и выбираем высоту, удовлетворяющую условиям неравенства для конкретного случая. Разумеется, в программировании никаких числовых прямых нет, зато есть любимые <strong>math.min()</strong> и <strong>math.max():</strong>
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
  maxWidth </span><span class="pun">/</span><span class="pln"> proportion</span><span class="pun">,</span><span class="pln">
  maxWidth</span><span class="pun">,</span><span class="pln">
  math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln">maxWidth </span><span class="pun">*</span><span class="pln"> maxHeight </span><span class="pun">/</span><span class="pln"> proportion</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="com">-- Выражаем ширину через пропорцию</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> width </span><span class="pun">=</span><span class="pln"> height </span><span class="pun">*</span><span class="pln"> proportion</span></pre>

<p>
	Все. Разумеется, полученные значения ширины и высоты нужно округлить в меньшую сторону, дабы не кормить видеокарту дробями. Заодно добавим поддержку масштабирования, чтобы выставлять половинное или, скажем, четвертичное от идеального разрешение. Сократив код, избавившись от лишних переменных, мы получаем следующее:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted">
<span class="kwd">local</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">"component"</span><span class="pun">)</span><span class="pln">

</span><span class="com">-- Получаем масштаб в качестве первого аргумента скрипта и корректируем его значение</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> scale </span><span class="pun">=</span><span class="pln"> tonumber</span><span class="pun">(</span><span class="pln">select</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> scale </span><span class="kwd">or</span><span class="pln"> scale </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
  scale </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="kwd">elseif</span><span class="pln"> scale </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0.1</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
  scale </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.1</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">

</span><span class="kwd">local</span><span class="pln"> gpu </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">gpu
</span><span class="kwd">local</span><span class="pln"> blockCountByWidth</span><span class="pun">,</span><span class="pln"> blockCountByHeight </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">proxy</span><span class="pun">(</span><span class="pln">gpu</span><span class="pun">.</span><span class="pln">getScreen</span><span class="pun">()).</span><span class="pln">getAspectRatio</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> maxWidth</span><span class="pun">,</span><span class="pln"> maxHeight </span><span class="pun">=</span><span class="pln"> gpu</span><span class="pun">.</span><span class="pln">maxResolution</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">local</span><span class="pln"> proportion </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="pln">blockCountByHeight </span><span class="pun">-</span><span class="pln"> </span><span class="lit">0.25</span><span class="pun">)</span><span class="pln">
 
</span><span class="kwd">local</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> scale </span><span class="pun">*</span><span class="pln"> math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
  maxWidth </span><span class="pun">/</span><span class="pln"> proportion</span><span class="pun">,</span><span class="pln">
  maxWidth</span><span class="pun">,</span><span class="pln">
  math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln">maxWidth </span><span class="pun">*</span><span class="pln"> maxHeight </span><span class="pun">/</span><span class="pln"> proportion</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="com">-- Выставляем полученное разрешение</span><span class="pln">
gpu</span><span class="pun">.</span><span class="pln">setResolution</span><span class="pun">(</span><span class="pln">math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="pln">height </span><span class="pun">*</span><span class="pln"> proportion</span><span class="pun">),</span><span class="pln"> math</span><span class="pun">.</span><span class="pln">floor</span><span class="pun">(</span><span class="pln">height</span><span class="pun">))</span></pre>

<p>
	Надеюсь, это микро-знание кому-то было полезно. Лично я очень доволен, что могу наконец запилить графонистый интерфейс для контроля реакторов на вертикальных мониках без осваивания профессии "глиномес", да и соответствующая либа для автопобора разрешения в оське пригодится.
</p>

]]></description><guid isPermaLink="false">2501</guid><pubDate>Tue, 01 Jan 2019 23:37:53 +0000</pubDate></item><item><title>&#x41C;&#x435;&#x442;&#x430;&#x442;&#x430;&#x431;&#x43B;&#x438;&#x446;&#x44B;, Lua</title><link>https://computercraft.ru/topic/1090-metatablitsy-lua/</link><description><![CDATA[
<p>Метатаблицы — это самые обыкновенные таблицы, содержащие функции, которые изменяют стандартное поведение операторов в Lua. Метатаблица в Lua может быть у любого значения, но только у каждой таблицы может быть своя метатаблица, у всех остальных же одна на всех. Так например у типа значения строки есть своя встроенная метатаблица, которая позволяет нам делать так:<span style="font-family:'courier new', courier, monospace;"> (<span style="color:#00ff00;">"строка"</span>):<strong><span style="color:#008000;">rep</span></strong>(<span style="color:#ff8c00;">10</span>)</span> В данной таблице присутствует поле <strong><span style="color:#008080;"><span style="font-family:'courier new', courier, monospace;">__index</span></span></strong>. А у потоков метатаблицы нет, а надо бы!!! Но обо всём по порядку.<br><br>Для установки и получения метатаблиц в Lua по стандарту существует 4 функции:</p>
<ul>
<li>
<span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">setmetatable</span></strong>(table<span style="color:rgb(105,105,105);">: table</span>, metatable: <span style="color:rgb(105,105,105);">table</span>):<span style="color:#696969;">table</span></span><span style="color:rgb(37,37,37);font-family:sans-serif;font-size:12.3199996948242px;background-color:rgb(249,249,249);"> </span>— это основная функция, которая позволяет установить таблице метатаблицу. Такая функция работает только с таблицами.</li>
<li>
<span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">getmetatable</span></strong>(value: <span style="color:#696969;">value</span>):<span style="color:#696969;">table</span> <span style="color:#8b4513;">or</span> <span style="color:#696969;">value</span></span> <span style="color:rgb(37,37,37);font-family:sans-serif;font-size:12.3199996948242px;background-color:rgb(249,249,249);">—</span> возвращает метатаблицу, если есть или значение поля <strong><span style="color:#008080;"><span style="font-family:'courier new', courier, monospace;">__metatable</span></span></strong> в метатаблице, если есть. Работает со всеми значениями.</li>
<li>
<strong><span style="font-family:'courier new', courier, monospace;"><em><span style="color:#0000ff;">debug.setmetatable</span></em></span></strong><span style="font-family:'courier new', courier, monospace;">(value: <span style="color:#696969;">value</span>):<span style="color:#696969;">boolean</span> <span style="color:#8b4513;">or</span> <span style="color:#696969;">table</span></span> — устанавливает метатаблицу любому значению и обходит метаполе <span style="font-family:'courier new', courier, monospace;"><span style="color:#008080;"><strong>__metatable</strong></span></span>. Действительно мощная штука, вот почему её убрали в Open Computers <img src="https://computercraft.ru/uploads/emoticons/default_giggle.gif" alt=":giggle:">.</li>
<li>
<strong><em><span style="color:#0000ff;"><span style="font-family:'courier new', courier, monospace;">debug.getmetatable</span></span></em></strong>(value: <span style="color:#696969;">value</span>)<span style="font-family:'courier new', courier, monospace;">:</span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">table</span><span style="font-family:'courier new', courier, monospace;"> </span><span style="font-family:'courier new', courier, monospace;color:rgb(139,69,19);">or</span><span style="font-family:'courier new', courier, monospace;"> </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span> — возвращает метатаблицу, обходя поле <span style="color:#008080;"><span style="font-family:'courier new', courier, monospace;"><strong>__metatable</strong></span></span>.​ Также отсутствует в OC.</li>
</ul>
<p>Теперь, я думаю, можно приступить к самим метаметодам. Для своего, а может быть и вашего удобства я их разделю на четыре категории:<br><br><strong><span style="font-family:'comic sans ms', cursive;"><span style="color:#daa520;"><span style="font-size:18px;">Разное</span></span></span></strong><br></p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p>Начну сразу с этой категории, т.к. здесь всё самое вкусное. <img src="https://computercraft.ru/uploads/emoticons/default_smile.png" alt=":)"></p>
<p> <br>1) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__index</span></strong>(self: <span style="color:#696969;">value</span>, key: <span style="color:#696969;">value</span>)</span> — метаметод, который вызывается при попытке индексирования значения с этим метаметодом. В качестве аргументов функция получает само значение, как первый аргумент, и индекс как второй, возвращать должна любое значение под заданным индексом. Если значение-таблица, то вызывается только тогда, когда нет поля с искомым индексом в самой таблице. Если вам необходимо проигнорировать этот метаметод, используйте <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">rawget</span></strong>(table: <span style="color:#696969;">table</span>, key: <span style="color:#696969;">value</span>):<span style="color:#696969;">value</span></span>, эта простая функция вернёт значение в самой таблице и не притронется к метаметоду. Пример:<br></p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint lang-auto">
local t = { }
setmetatable(t, { __index = _G })
t:print()

--то же самое с помощью функции
t = setmetatable(t, {
    __index = function(self, key)
        return _G[key]
    end
})
t:print()
</pre>
<p> </p>
</div>
</div>
<p> <br>2) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__newindex</span></strong>(self: <span style="color:#696969;">value</span>, key: <span style="color:#696969;">value</span>, value: <span style="color:#696969;">value</span>)</span> — делает то же что и <strong><span style="color:#008080;">__index</span></strong>, только наоборот. Этот метаметод вызывается, когда значению, присваивают что-нибудь под каким-нибудь индексом. Также можно установить вместо функции таблицу, куда будут уходить все новые значения под <u>новыми</u> индексами. Если ваше значение с метатаблицей <span style="color:rgb(37,37,37);font-family:sans-serif;font-size:12.3199996948242px;background-color:rgb(249,249,249);">—</span> таблица, то вы можете вставить поле прямо в неё, избегая метометод, с помощью <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">rawset</span></strong>(table: <span style="color:#696969;">table</span>, key: <span style="color:#696969;">value</span>, value: <span style="color:#696969;">value</span>):<span style="color:#696969;">nil</span></span>. Пример:</p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint lang-auto">
--Давайте сделаем таблицу, которую нельзя обойти стандартными итераторами
local t = { }
local private = { }
setmetatable(t, {
    __index = private;
    __newindex = private;
})
t.var = 23
t.var2 = 42

for key, value in pairs(t) do --По сути ничего неделает
    print(key, value)
end

print(t.var)
--&gt; 23

print(t.var2)
--&gt; 42 </pre>
<p> </p>
</div>
</div>
<p> <br>3) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__call</span></strong>(self: <span style="color:#696969;">value</span>, args: <span style="color:#ff8c00;">...</span> )</span> — превращает любое значение с метатаблицей в типа функцию. С ним вы можете вызвать ваше значение, как функцию. Первым аргументом всегда будет само значение, остальные — это те которые были указаны при вызове функции. Пример:</p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint lang-auto">
local t = { }
setmetatable(t, {
    __call = function(self, String)
        table.insert(self, String)
        return true
    end
})

print(t("Hello!"))
--&gt; true

print(t[1])
--&gt; Hello! </pre>
<p> </p>
</div>
</div>
<p> <br>4) <span style="font-family:'courier new', courier, monospace;"><span style="color:#008080;"><strong>__metatable</strong></span></span><span style="font-family:'courier new', courier, monospace;">: </span><span style="color:#696969;"><span style="font-family:'courier new', courier, monospace;">value</span> </span>— это не метаметод, это просто поле, которое содержит информацию, которая будет возвращаться функцией <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">getmetatable</span></strong>(value: <span style="color:#696969;">value</span>):<span style="color:#696969;">value</span></span>. Также при наличии этого поля не удастся сменить метатаблицу с помощью <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">setmetatable</span></strong>(value: value, metatable: <span style="color:#696969;">table</span>):<span style="color:#696969;">table</span></span> на другую: выскочит <a href="https://computercraft.ru/topic/978-digital-rain/?hl=%D0%B5%D0%B3%D0%B3%D0%BE%D0%B3&amp;do=findComment&amp;comment=13250" rel="">ошибка</a>. Чтобы проигнорировать этот параметр можно использовать функции из библиотеки <span style="color:#0000ff;"><strong><span style="font-family:'courier new', courier, monospace;">debug</span></strong></span>.<br> <br>5) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__tostring</span></strong>(self: <span style="color:#696969;">value</span>)</span> — при попытке перевести значение в строку будет вызван этот метаметод, использован же будет его результат. Пример:</p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint lang-auto">
local t = { }
setmetatable(t, {
    __tostring = function(self)
        return "Я - таблица!"
    end
})

print(tostring(t))
--&gt; Я - таблица!

print(t) --Да, да. Это также работает.
--&gt; Я - таблица! </pre>
<p> </p>
</div>
</div>
<p> <br>6) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__len</span></strong>(self: <span style="color:#696969;">value</span>)</span> — взаимодействует с оператором <span style="color:#ff8c00;">#</span>. Если вы хотите проигнорировать этот метаметод в значении таблица, просто используйте <span style="font-family:'courier new', courier, monospace;"><span style="color:#008000;"><strong>table.getn</strong></span>(table: <span style="color:#696969;">table</span>):<span style="color:#696969;">number</span></span>. Не знаю, что добавить, смотрите пример. Пример:</p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint lang-auto">
local t = { }
setmetatable(t, {
    __len = function(self)
        return 3 --Размер этого "массива" теперь всегда 3
    end
})

for i = 1, 8 do
    table.insert(t, i)
end
-- В массиве теперь 8 элементов,

print(#t) -- но результат всё равно 3
--&gt; 3 </pre>
<p> </p>
</div>
</div>
<p> <br>7) <span style="font-family:'courier new', courier, monospace;"><span style="color:#008080;"><strong>__pairs</strong></span>(self: <span style="color:#696969;">value</span>)</span> — заменяет собой функцию <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">pairs</span></strong>(table: <span style="color:#696969;">table</span>)</span>, должен возвращать итератор, как минимум. Проигнорировать можно, подставив стандартный итератор <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">next</span></strong>(level: <span style="color:#696969;">number</span>, table: <span style="color:#696969;">table</span>):<span style="color:#696969;">value</span>, <span style="color:#696969;">value</span></span>.<br> <br>8) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__ipairs</span></strong>(self: <span style="color:#696969;">value</span>)</span> — то же самое, но для <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">ipairs</span></strong>(table: <span style="color:#696969;">table</span>)</span>. Стандартный итератор <span style="color:rgb(37,37,37);font-family:sans-serif;font-size:12.3199996948242px;background-color:rgb(249,249,249);">—</span> <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__inext</span></strong>(level: <span style="color:#696969;">number</span>, table: <span style="color:#696969;">table</span>):<span style="color:#696969;">value</span>, <span style="color:#696969;">value</span></span> (не удивляйтесь двойному подчёркиванию, это не метаметод, а стандартная функция глобального окружения).</p>
<p> </p>
<p>9) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__name</span></strong>: <span style="color:#696969;">string</span></span> — метаполе, которое используется при возникновении ошибки. Это поле в метатаблице наверняка существует для типа userdata, но также успешно работает с таблицами. Когда срабатывает ошибка несоответствия типов данных, то Lua заменяет слово, обозначающее этот тип данных, на то, что хранится в <strong><span style="color:rgb(0,128,128);">__name</span></strong> (при условии, что <strong><span style="color:rgb(0,128,128);">__name</span></strong> — строка). Для понимания того, что вы сейчас прочитали, пример:</p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint">
t = setmetatable({}, { __name = "qwerty" }) -- Переименовываем table в qwerty
print(type(t)) -- Никак не влияет на type
--&gt; table

math.sqrt(t) -- t - не число, а из таблицы корень не получишь
--[[
    Этот код выдаст примерно следующую ошибку:
stdin:2: bad argument #1 to 'sqrt' (number expected, got qwerty)
]]
</pre>
<p> </p>
</div>
</div>
<p> </p>
<p></p>
<hr> <br>Следующие два метаметода взаимодействуют со сборщиком мусора в Lua. На разных версиях lua они немного отличаются по возможностям. Я опишу, как они работают на lua 5.3.<br> <br>10) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__gc</span></strong>(self: <span style="color:#696969;">value</span>)</span> —<span style="color:rgb(37,37,37);font-family:sans-serif;font-size:12.3199996948242px;background-color:rgb(249,249,249);"> </span>вызывается, когда сборщик мусора хочет удалить объект из памяти. По некоторым данным не работает с таблицами, но я протестировал в Lua интерпритаторе, и всё вроде как функционирует  <img src="https://computercraft.ru/uploads/emoticons/default_smile44.gif" alt=":smile44:">. Я думаю, что этот метаметод может заменить собой деструктор "<a href="https://computercraft.ru/topic/56-obektno-orientirovannoe-programmirovanie-i-lua/" rel="">класса</a>" в Lua. Пример:
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint lang-auto">
setmetatable({ }, {
    __gc = function(self)
        print(self, " был удалён с ОЗУ")
    end
})

--[[ Через какое-то время ленивый сборщик мусора удалит вашу таблицу, и вы увидите этот знаменательный момент]] </pre>
<p> </p>
</div>
</div>
<p> <br>11) <strong><span style="color:#008080;"><span style="font-family:'courier new', courier, monospace;">__mode</span></span></strong><span style="font-family:'courier new', courier, monospace;">: <span style="color:#696969;">string</span></span> —<span style="color:rgb(37,37,37);font-family:sans-serif;font-size:12.3199996948242px;background-color:rgb(249,249,249);"> </span>параметр, указывающий на то, что <u>таблица</u> не может защитить ключи или значения от безжалостного сборщика мусора. Если <strong><span style="color:#008080;"><span style="font-family:'courier new', courier, monospace;">__mode</span></span></strong> <span style="color:rgb(255,140,0);">==</span> <span style="color:rgb(0,255,0);">"k"</span>, то при не нахождении переменной содержащей, значение равное этому ключу, сборщик мусора спокойно удалит это поле и из таблицы тоже, если же <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__mode</span></strong></span> <span style="color:rgb(255,140,0);">==</span> <span style="color:rgb(0,255,0);">"v"</span>, то тоже самое он будет делать для значений в таблице. Полностью правильно это будет работать только если удаляемые ключи и значения <u>не</u> являются: строкой, boolean или числом (это связано с особенностью работы сборщика). Пример:</p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint lang-auto">
local t = setmetatable({ }, { __mode = "v" })

do
    local var = {}
    t.var = var
end

print(t.var)
--&gt; table: XXXXXXXXXXX

-- После очередного сбора мусора
print(t.var)
--&gt; nil </pre>
<p> </p>
</div>
</div>
<p><br></p>
</div>
</div>
<p> <br><strong><span style="font-family:'comic sans ms', cursive;"><span style="color:#daa520;"><span style="font-size:18px;">Математические</span></span></span></strong><br></p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p>1) <span style="font-family:'courier new', courier, monospace;"><span style="color:#008080;"><strong>__unm</strong></span>(self: <span style="color:#696969;">value</span>)</span> — унарный минус, это, когда <span style="font-family:'courier new', courier, monospace;">var <span style="color:#ff8c00;">=</span> <span style="color:#8b4513;">-</span>value</span>. В качестве аргумента получает само значение. Думаю, примеры здесь не нужны.</p>
<hr>
<p> </p>
<p>Следующие метаметоды однотипны, поэтому я опишу принцип действия для всех, а потом с какими операторами они взаимодействуют.</p>
<p>Принцип действия: сначала Lua смотрит на первое значение в действии, если оно содержит метатаблицу с метаметодом этого действия, то он вызывается, и решением этого действия становится результат метаметода (то, что он вернёт). Если не находит смотрит во втором значении и проделывает тоже самое, если ненаходит ни там ни там, то действует по стандартному алгоритму. При постановке аргументов в метаметоде использует их изначальный порядок (то есть 2 + 3 будет вызывать __add(2, 3))  Надеюсь объяснил понятно.</p>
<div>
<p> </p>
<p>2) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__add</span></strong>(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span> — операция сложения. Оператор <span style="font-family:'courier new', courier, monospace;"><span style="color:rgb(139,69,19);">+</span></span>.</p>
<div>
<p> </p>
<p>3) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__sub</span></strong></span><span style="font-family:'courier new', courier, monospace;">(op1: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">, op2: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">)</span> — операция вычитания. Оператор <span style="font-family:'courier new', courier, monospace;"><span style="color:rgb(139,69,19);">-</span></span>.</p>
<div> </div>
<div>
<p>4) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__mul</span></strong></span><span style="font-family:'courier new', courier, monospace;">(op1: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">, op2: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">)</span> — операция умножения. Оператор <span style="font-family:'courier new', courier, monospace;"><span style="color:rgb(139,69,19);">*</span></span>.</p>
<div> </div>
<div>
<p>5) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__div</span></strong></span><span style="font-family:'courier new', courier, monospace;">(op1: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">, op2: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">)</span> — операция деления. Оператор <span style="font-family:'courier new', courier, monospace;"><span style="color:rgb(139,69,19);">/</span></span>.</p>
<div> </div>
<div>
<p>6) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__mod</span></strong></span><span style="font-family:'courier new', courier, monospace;">(op1: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">, op2: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">)</span> — операция получения остатка от деления. Оператор <span style="font-family:'courier new', courier, monospace;"><span style="color:rgb(139,69,19);">%</span></span>.</p>
<p> </p>
<div>7) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__pow</span></strong></span><span style="font-family:'courier new', courier, monospace;">(op1: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">, op2: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">)</span> — операция возведения в степень. Оператор <span style="font-family:'courier new', courier, monospace;"><span style="color:rgb(139,69,19);">^</span></span>. Игнорируется функцией <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008000;">math.pow</span></strong>(op1: <span style="color:#696969;">number</span>, op2: <span style="color:#696969;">number</span>):<span style="color:#696969;">number</span></span>.</div>
<div> </div>
<div>8) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__concat</span></strong></span><span style="font-family:'courier new', courier, monospace;">(op1: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">, op2: </span><span style="font-family:'courier new', courier, monospace;color:rgb(105,105,105);">value</span><span style="font-family:'courier new', courier, monospace;">)</span> — операция конкатенации (склейки). Оператор <span style="font-family:'courier new', courier, monospace;"><span style="color:rgb(139,69,19);">..</span></span>. Игнорируется функцией <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008000;">table.concat</span></strong>(table: <span style="color:#696969;">table</span>[, insert_string: <span style="color:#808080;">string</span>, begin: <span style="color:#808080;">number</span>, end: <span style="color:#808080;">number</span>]):<span style="color:#696969;">string</span></span>.</div>
<div> </div>
<div>9) <strong><span style="font-family:'courier new', courier, monospace;"><span style="color:#008080;">__idiv</span></span></strong><span style="font-family:'courier new', courier, monospace;">(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span> — операция целочисленного деления. Оператор <span style="color:#8b4513;"><span style="font-family:'courier new', courier, monospace;">//</span></span>. Появился в Lua 5.3.</div>
<div> </div>
<div>Пример один на всех, но только с операцией сложения:<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p></p>
<pre class="ipsCode prettyprint">
local _42 = { }
setmetatable(_42, {
    __add = function(op1, op2)
        op1 = type(op1) == "table" and 42 or op1 --Если первый аргумент - таблица, то присваиваем ему значение 42, иначе его изначальное значение
        op2 = type(op2) == "table" and 42 or op2 --Проделываем то же самое
        return op1 + op2 --Складываем и возвращаем результат
    end
})

print(_42 + 8)
--&gt; 50

print(8 + _42)
--&gt; 50
print(_42 + _42)
--&gt; 84
print({} + _42)
--&gt; 84</pre>
</div>
<div>
<span style="color:rgb(0,0,0);font-size:13px;background-color:rgb(250,250,250);">Немного странный результат у последнего примера, правда? <img src="https://computercraft.ru/uploads/emoticons/default_smile.png" alt=":)"></span><span style="color:rgb(0,0,0);font-size:13px;background-color:rgb(250,250,250);"> </span><span style="color:rgb(0,0,0);font-size:13px;background-color:rgb(250,250,250);"> Попробуйте это объяснить.</span>
</div>
<div></div>
</div>
<p></p>
</div>
</div>
</div>
</div>
</div>
</div>
<p> </p>
</div>
</div>
<p> </p>
<p><strong><span style="font-family:'comic sans ms', cursive;"><span style="color:#daa520;"><span style="font-size:18px;">Сравнение</span></span></span></strong></p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p>Следующие метаметоды нотличаются от всех тех, что выше. Во-первых они могут возвращать только логическое значение (<strong>true</strong> или <strong>false</strong>), если возвращаемое значение не является таковым, то будет переделано в него (например <span style="color:#00ff00;">"return {}"</span> будет восприниматься, как <span style="color:#00ff00;">"return true"</span>). Во-вторых, они будут вызываться только, если <u>одинаковый</u> метаметод присутствует в метатаблицах обоих значений, причём сами метатаблицы могут быть разными.</p>
<p> </p>
<p>1) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__eq</span></strong>(op1: <span style="color:#696969;">value</span>, op2: <span style="color:#696969;">value</span>)</span> — операция равенства, операторы: <span style="font-family:'courier new', courier, monospace;"><span style="color:#ff8c00;">==</span></span> и <span style="color:#ff8c00;"><span style="font-family:'courier new', courier, monospace;">~=</span></span>. При использовании оператора <span style="color:#ff8c00;">~=</span> возвращаемое значение инвертируется. Порядок сравниваемых значений в аргументах соответствует их изначальной постановке. Не вызывается если значения одинаковы (например, когда мы сравниваем одну и ту же таблицу). Пример:</p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p> </p>
<pre class="ipsCode prettyprint">
local t1 = {}
local t2 = {}
local __eq = function(op1, op2)
    print "Работает"
    return op1
end
setmetatable(t1, { __eq = __eq })
setmetatable(t2, {
    __eq = function(op1, op2)
        print "Работает"
        return op1
    end
})

print(t1 == t2) --__eq не вызвался, т.к. методы в метатаблицах разные.
--&gt; false

setmetatable(t2, { __eq = __eq })
print(t1 == t2) --Метод успешно вызван
--&gt; Работает
--&gt; true

print(t1 == t1) --Не вызван, т.к. одинаковы
--&gt; true </pre>
<p> </p>
</div>
</div>
<p> </p>
<p>2) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008080;">__lt</span></strong>(op1: <span style="color:#696969;">value</span>, op2: <span style="color:#696969;">value</span>)</span> — операция меньше чем, операторы<span style="font-size:12.3199996948242px;background-color:rgb(249,249,249);">:</span> <span style="color:#ff8c00;"><span style="font-family:'courier new', courier, monospace;">&lt;</span></span> и <span style="font-family:'courier new', courier, monospace;"><span style="color:#ff8c00;">&gt;</span></span>. Сравниваемые значения расставляются в аргументах в том порядке, в каком их сравнивают, при использовании оператора <span style="font-family:'courier new', courier, monospace;"><span style="color:#ff8c00;">&lt;</span></span>. Оператор <span style="color:#ff8c00;"><span style="font-family:'courier new', courier, monospace;">&gt;</span></span> просто меняет их местами.</p>
<p> </p>
<p>3) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__le</span></strong>(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span> — операция меньше или равно, операторы: <span style="color:#ff8c00;"><span style="font-family:'courier new', courier, monospace;">&lt;=</span></span> и <span style="font-family:'courier new', courier, monospace;"><span style="color:#ff8c00;">&gt;=</span></span>. Работает также, что и метаметод выше, но с другими операторами.</p>
</div>
</div>
<p> </p>
<p> </p>
<div><span style="font-family:'comic sans ms', cursive;"><span style="color:#daa520;"><span style="font-size:18px;"><b>Битовые операторы</b></span></span></span></div>
<div>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents"><p></p></div>
<div>
<div>В Lua 5.3 появились новые операторы (о которых я даже не подозревал). Эти операторы позволяют производить побитовые операции над целыми числами. Им также соответствуют некоторые специальные поля в метатаблице. В предыдущих версиях Lua для этого использовалась отдельная стандартная библиотека <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:#008000;">bit32</span></strong></span>. Все соответствующие операторам функции в библиотеке можно использовать для обхода метаметодов в метатаблице.</div>
<div> </div>
<div>1) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__band</span></strong>(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span> — операция побитового и. Оператор <span style="color:#8b4513;">&amp;</span>.</div>
<div><div> </div></div>
<div>2) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__bor</span></strong>(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span>  — операция побитового или. Оператор <span style="color:rgb(139,69,19);">|</span>.</div>
<div> </div>
<div>3) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__bxor</span></strong>(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span>  — операция побитового исключающего или. Оператор <span style="color:rgb(139,69,19);">~</span> (бинарная версия).</div>
<div><div> </div></div>
<div>4) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__bnot</span></strong>(self: <span style="color:rgb(105,105,105);">value</span>)</span>  — операция побитового не. Оператор <span style="color:rgb(139,69,19);">~</span> (унарная версия).</div>
<div> </div>
<div>5) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__shl</span></strong>(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span>  — операция битового сдвига влево. Оператор <span style="color:rgb(139,69,19);">&lt;&lt;</span>.</div>
<div> </div>
<div>6) <span style="font-family:'courier new', courier, monospace;"><strong><span style="color:rgb(0,128,128);">__shr</span></strong>(op1: <span style="color:rgb(105,105,105);">value</span>, op2: <span style="color:rgb(105,105,105);">value</span>)</span>  — операция битового сдвига вправо. Оператор <span style="color:rgb(139,69,19);">&gt;&gt;</span>.</div>
<div> </div>
<div>Пример с операторами <span style="font-family:'courier new', courier, monospace;"><span style="color:#8b4513;">&lt;&lt;</span></span>:<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p></p>
<pre class="ipsCode prettyprint">
local meta = getmetatable(io.stdout)

function meta.__shl(ostream, data)
    return ostream:write(tostring(data))
end

local cout = io.stdout
local endl = "\n"

cout = cout &lt;&lt; "Я люблю C++!" &lt;&lt; endl
            &lt;&lt; "Число: " &lt;&lt; math.pi &lt;&lt; endl
            &lt;&lt; cout;
</pre>
</div>
<div></div>
</div>
<p></p>
</div>
</div>
</div>
<p></p>
</div>

]]></description><guid isPermaLink="false">1090</guid><pubDate>Mon, 24 Aug 2015 09:38:06 +0000</pubDate></item><item><title>&#x417;&#x430;&#x449;&#x438;&#x442;&#x430; &#x43E;&#x442; &#x438;&#x437;&#x43C;&#x435;&#x43D;&#x435;&#x43D;&#x438;&#x439; &#x432; Lua</title><link>https://computercraft.ru/topic/1758-zaschita-ot-izmeneniy-v-lua/</link><description><![CDATA[
<p>Начнём сразу с кода. Пихнём в файл <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">./lib.lua</span></p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">local a = "Hi"
local b = "World"
return {
  a = a,
  b = b
}
</pre>
<p>Вполне себе нормальный, имеющий право на жизнь, код. Не то, что бы он делал что-то полезное, но как пример нашей дискусси вполне сгодится.</p>
<p>Итак, этот небольшой файлик будет возвращает таблицу с двумя ключами. Подключим его (<span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">./test.lua</span>):</p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">local test = require("test")
print(test.a, test.b)
</pre>
<p>Выведет это "Hi      World" и успокоится. Вроде всё нормально.</p>
<p>Допишем в этот файл ещё немного кода:</p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">test.a = "Goodbye"
b = "Cruel World"
test2 = require("lib")
print(test2.a, test2.b)
</pre>
<p>Выведет это, однако, <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">Goodbye Cruel World</span>. Упс.</p>
<p>Если в таблице будет реализация бомбёжки ракетами по союзникам (а как же), изменять что-то не хотелось бы совсем. Вот об неизменяемости речь и пойдёт.</p>
<p> </p>
<p>Заметим, что в таблице либы ключам значение присваивается не напрямую, а через переменную. Локальную. Доступа к ним (проигнорим <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">debug</span>) ни у кого другого нет. С другой стороны, у Луа есть метатаблицы с метаметодом <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">__index</span>. Воспользуемся этим, прямолинейно:</p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">local a = "Hi"
local b = "World"
return setmetatable({}, {
  __index = function(self, k)
    if k == "a" then
      return a
    elseif k == "b" then
      return b
    end
  end
})
</pre>
<p> </p>
<p>Код <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">./test.lua</span> можно даже не менять. Результат всё равно будет тот же. Ибо <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">__index</span> вызывается только для несуществующих значений основной таблицы. Когда мы присвоим какое-то значение, вызываться не будет уже метаметод. Ага, значит, давайте запретим заменять таблицу. При <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">tbl.keyname = value</span> вызывается метаметод <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">__newindex</span>. Окей:</p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">local a = "Hi"
local b = "World"
return setmetatable({}, {
  __index = function(self, k)
    if k == "a" then
      return a
    else
      return b
    end
  end,
  __newindex = function(self, k, v)
    print("No way!")
  end
})
</pre>
<p>Теперь, если мы запустим код тот же, получим что-то вроде этого:</p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">Hi      World
No way!
No way!
Hi      World
</pre>
<p>Воооот, вроде бы цель достигнута. Как бы не так. Заменим файл <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">./test.lua</span> этим:</p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">local test = require("test")
print(test.a, test.b)
rawset(test, "a", "Goodbye")
rawset(test, "b", "Cruel World")
test2 = require("lib")
print(test2.a, test2.b)
</pre>
<p>Угадайте, что получится. Конечно же, большой и длинный "ууупс".</p>
<p> </p>
<pre class="ipsCode prettyprint lang-auto">Hi      World
Goodbye Cruel World
</pre>
<p>Более того, теперь эти значения сидят в обычной таблице и больше не вызывают <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">__newindex</span>. Вот печаль-то.</p>
<p> </p>
<p>Но тем не менее, именно такой код мы и оставим. Для решения проблемы нам потребуется переопределить <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">rawget</span> и <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">rawset</span>, добавив проверку на наши любимые таблицы и не давая ничего изменить. Получится это сделать только для систем с доступом к контролю над <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">_G</span>.</p>
<p> </p>
<p>Есть ещё вариант докопаться до сути: <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">getmetatable</span> и <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">setmetatable</span>. Их, как можно догадаться, тоже требуется переопределить. Туда же <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">debug.getmetatable</span> и <span style="color:#0a0a0a;font-family:'Ubuntu Mono', 'Source Code Pro', monospace;background-color:#eaeaea;padding:.15em .2em;border:1px solid #cccccc;">debug.setmetatable</span>.</p>
<p> </p>
<p>После этого можно будет, наконец, сказать. что мы полностью уверены, что наши таблицы константны.</p>
<p> </p>
<p>Как видно, Луа всеми силами пытается забрать право на забирание динамичности структур. Позволяя стандартно переопределять внутри VM стандартные функции для своих нужд, И просто так отплясаться не получится. Шмактус, однако.</p>

]]></description><guid isPermaLink="false">1758</guid><pubDate>Sat, 03 Sep 2016 20:48:57 +0000</pubDate></item><item><title>&#x41B;&#x43E;&#x433;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x438;&#x435; &#x432;&#x44B;&#x440;&#x430;&#x436;&#x435;&#x43D;&#x438;&#x44F; &#x432; lua &#x438;&#x43B;&#x438; &#x438;&#x437;&#x431;&#x430;&#x432;&#x43B;&#x44F;&#x435;&#x43C;&#x441;&#x44F; &#x43E;&#x442; &#x43B;&#x43E;&#x433;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x438;&#x445; &#x431;&#x43B;&#x43E;&#x43A;&#x43E;&#x432;</title><link>https://computercraft.ru/topic/1058-logicheskie-vyrazheniya-v-lua-ili-izbavlyaemsya-ot-logicheskih-blokov/</link><description><![CDATA[
<p>Решил написать немного о логических выражениях в Lua. Логические операции в Lua (в частности end и or) отличаются по возможностям с теми же операциями в других языках программирования. Во многом это зависит от того, что в Lua нет типов переменных (ну там всякие int, byte, short). Зная эти особенности, вы можете избавиться от ненужных логических блоков, но сначала следует разобраться, что они вообще делают и какие значения в lua истинные, а какие ложные.<br>Ложные значения - это <strong>nil</strong> и <strong>false</strong>, а всё остальное (таблицы, числа, сопрограммы, <strong>true</strong>) - истинные.</p>
<p></p>
<hr>
<p><span style="color:#008000;"><span style="font-size:18px;">OR</span></span><br></p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p><strong>Запись простого выражения:</strong></p>
<pre class="ipsCode prettyprint lang-auto">
var = znach1 or znach2
</pre>
<p><strong>Алгоритм:</strong><br>сначала оператор проверяет первое значение, если оно истинное, возвращает его, если ложное, то второе значение.<br><strong>Примеры:</strong></p>
<pre class="ipsCode prettyprint lang-auto">
local znach1 = true
local znach2 = false
local var

var = znach1 or znach2 -- Вернёт znach1, то-есть true
var = znach2 or znach1 -- Вернёт znach1, то-есть true
var = false or nil -- Вернёт nil
</pre>
<p> </p>
</div>
</div>
<p><br><span style="color:#008000;"><span style="font-size:18px;">AND</span></span></p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p><strong>Запись простого выражения:</strong></p>
<pre class="ipsCode prettyprint lang-auto">
var = znach1 or znach2</pre>
<p><strong>Алгоритм:</strong><br>сначала оператор проверяет первое значение, если оно ложное, возвращает его, если истинное, то второе значение.<br><strong>Примеры:</strong></p>
<pre class="ipsCode prettyprint lang-auto">
var = true and false -- Вернёт второе, то-есть false
var = false and true -- Вернёт znach1, то-есть true
var = true and 42 -- Вернёт второе, то-есть 42
var = nil and 42 -- Вернёт первое, то-есть nil
var = false and nil -- Вернёт false</pre>
<p> </p>
</div>
</div>
<p><br><span style="color:#008000;"><span style="font-size:18px;">NOT</span></span></p>
<div class="ipsSpoiler" data-ipsspoiler="">
<div class="ipsSpoiler_header"><span></span></div>
<div class="ipsSpoiler_contents">
<p><strong>Запись простого выражения:</strong></p>
<pre class="ipsCode prettyprint lang-auto">
var = not znach</pre>
<p><strong>Алгоритм:</strong><br>оператор проверяет значение, если истинное, возвращает <strong>false</strong>, иначе <strong>true</strong>.<br><strong>Примеры:</strong></p>
<pre class="ipsCode prettyprint lang-auto">
var = true and false -- Вернёт второе, то-есть false
var = not false -- Вернёт true
var = not true -- Вернёт false
var = not nil -- Вернёт true
var = not 42 -- Вернёт false
var = not not 42 -- Вернёт true</pre>
<p> </p>
</div>
</div>
<p></p>
<hr>
<p> </p>
<p>Теперь можно показать самые используемые выражения.</p>
<p>Наверняка у вас был случай, когда нужно, чтобы переменная приравнялась одному значению, а если его нет, то другому. Многие записали бы так:</p>
<pre class="ipsCode prettyprint">
if var == nil then
    var = 23
end
</pre>
<p>Это конечно работает, но не лучше ли записать так:</p>
<pre class="ipsCode prettyprint">
var = var or 23
</pre>
<p>Кратко и красиво, да к тому же нет лишнего логического блока. Вы также можете продолжить эту цепочку:</p>
<pre class="ipsCode prettyprint">
var = var or var2 or var3 or 23
</pre>
<p>В такой цепочке выражение вернёт первое истинное значение, при этом не трогая все те что за ним. Это значит, что вы спокойно можете сделать так:</p>
<pre class="ipsCode prettyprint">
var = var or error("Переменная var содержит ложное значение!")
</pre>
<p>И радовались бы дальше, но ведь иногда нам нужно, придать значение переменной в зависимости от истинности выражения. Не зная удобного способа, вы бы сделали так:</p>
<pre class="ipsCode prettyprint">
if var then
    var2 = 23
else
    var2 = 42
end
</pre>
<p>Но это можно записать без логического блока:</p>
<pre class="ipsCode prettyprint">
var2 = var and 23 or 42
</pre>
<p>Вы можете заменить переменную var любым выражением, но если вы плохо разбираетесь в приоритетах операторов рекомендую выделять скобками:</p>
<pre class="ipsCode prettyprint">
var2 = (var &gt; 0) and 23 or 42 -- В данном примере скобки не обязательны
</pre>
<p>Теперь давайте основываясь на узнанном, напишем функцию с проверкой аргумента:</p>
<pre class="ipsCode prettyprint">
function func(var)
    var = type(var) == "number" and var == math.floor(var) and var or error("bad argument: celoe number expected, got "..var, 2)
end
</pre>
<p>И заметьте ни одного логического блока. В результате наша функция проверит является ли аргумент целым числом, иначе вернёт ошибку.</p>
<p>Бывает случай, когда необходимо проверить существует ли поле в таблице и выполнять действия в зависимости от этого, но ведь значение может быть не таблицей, из-за этого ошибка будет не пользователя а ваша. Я не буду приводить всякие отдельные случаи просто напишу само выражение:</p>
<pre class="ipsCode prettyprint">
if not (type(table) == "table" and table.field and ...) then -- ... - ваши логические выражения
    -- Какие-то действия
end
</pre>
<p>Ещё один важный момент, когда аргумент вашей функции может быть не указан, но потом внутри самой функции обретает значение типа boolean (<strong>true</strong> либо <strong>false</strong>) через оператор <strong>or </strong>это не выполнить, т.к. <strong>false </strong>- ложное значение, но можно воспользоваться следующими выражениями, в зависимости от того, что вам нужно:</p>
<pre class="ipsCode prettyprint">
var = var ~= false -- Если var = nil, то вернёт true, если переменная типа boolean не изменит её значения
var = not not var -- То же, что и первое, но при значении nil вернёт false
</pre>
<p>Думаю, что наиболее используемые моменты осветил, но если что-то не понятно, спрашивайте.</p>
<p>[ok=Ни один смайлик не использован][/ok]</p>

]]></description><guid isPermaLink="false">1058</guid><pubDate>Tue, 11 Aug 2015 21:04:04 +0000</pubDate></item></channel></rss>
