Предисловие - для кого эта статья
Статья носит скорее более теоретический характер, хотя и дает
достаточно пищи для размышлений о том, как код можно сделать намного
проще и качественней. Предполагается что читатель достаточно хорошо
знает JASS.
Теория
Тип integer в Jass это long signed int (в C) или попросту DWORD, это
значит что он имеет 32 бита: 31 бит что бы обозначить само число и один
знаковый бит. В JASS коде он может быть представлен в 8 (восьмеричная
или octimal), 10 (десятеричная или decimal, самая привычная для
большинства людей), 16 (шестнадцатеричная или hexadecimal) и 256(ASCII)
нотации (системе счисления).
Чем одна система отличается от другой? (если Вы знакомы с этими
понятиями можете пропустить этот абзац) В десятеричной системе переход
в следующий разряд происходит когда число достигает 10 (9+1=10). Точно
также и в других системах счисления: в восьмеричной системе 7+1=10
(причем 10 в ней реально равно 8 в десятеричной системе). В
шестнадцатеричной системе что бы обозначить цифры (не путайте число и
цифру, цифра - обозначение числа, поэтому разные цифры - в разных
нотациях могут указывать на одно число), так вот, что бы обозначить в
шестнадцатеричной системе цифру больше 9 мы будем использовать первые
буквы английского алфавита: A=10, B=11, ... F=15. С 256 системой
счисления дело обстоит также, ниже я выложу таблицу символов и значений
(взято из WEU документации):
Хорошо, теперь вернемся к JASS. Что бы написать цифру в восьмеричной системе счисления мы должны приставить к ней 0
local integer i=012 // 10 в десятеричной си
Цифры без префиксов считаются десятичными, hex обозначается через 0x
local integer i=0x0f // 15 в десятеричной си
256 цифры указываются обрамленными в апострофы
local integer i='A' // 65 в десятеричной си
Если Вы хотите перевести цифру в другую си - используйте WinCalc (есть
такая программа в меню "пуск") переставленный в инженерный вид. Перевод
числа из ASCII делается тоже достаточно просто: переведите каждый чар
(ну т.е. символ) в hex, и вы получите 16ричное число. К примеру:
'A0a1', 'A' = 0x41, '0' = 0x30, 'a' = 0x61, '1' = 0x31, 'A0a1' равно
0x41306131 или 1093689649.
Помните, что большинство равкодов (кроме lightning, ubersplat) в JASS
обычные integer, поэтому с ними возможны любые математические действия,
что и будет описано дальше.
В JASS невозможно указать integer в двоичной (binary) системе
счисления, но она очень важна для понимания всего материала. Как Вы
могли догадаться, в ней переход в следующий разряд происходит при
достижение 2: 1bin+1bin == 10bin (2dec). Теперь вернемся к нашему 32
битному integer
0x 7 a 9 8 0 1 f 0 0111 1010 1001 1000 0000 0001 1111 0000
Один разряд в двоичной системе называется бит, восемь разрядов или двух разрядное шестнадцатеричное число - байт.
Напомню, что первый бит числа - знаковый бит, и он определяет будет ли
оно положительным (0) или отрицательным (1). Положительные числа идут
от 0x00000000 (0dec) до 0x7fffffff (2147483647dec), отрицательные от
0xffffffff (-1dec) до 0x80000000 (-2147483648dec). Что бы изменить знак
числа надо инвертировать (где было 1 написать 0, где был 0 написать
один) все биты числа и потом к нему прибавить 1.
// в примере я использую однобайтовое число что бы было легче понять
0000 0001 // +1dec 1111 1110 // inv 1111 1111 // -1dec
Теперь, хоть в JASS и нету побитовых операций над числами, можно имитировать их с помощью умножения и деления
1000 1000 // *10bin (<<) 1 0001 0000 // /100bin (>>) 0000 0100
Биты, которые не помещаются в результате будут считаться потерянными.
Также с помощью нескольких сдвигов мы сможем получить любые биты числа,
имитировав тем самым логические побитовые операции, к примеру на нужно
узнать значение 3 и 4 бита
0110 1101 // *1000 0110 1000 // /100000 0000 0011
Отлично! Но у нас могут возникнуть некоторые проблемы с знаковым битом при таких операциях
0111 1100 // *1000 1110 0000 // 1110 0000bin = -20dec
1110 0000 // но мы можем изменить знаковый бит +1000 0000 _____ _____ 1 0110 0000
Так что мы смело можем прибавить 0x80000000, но есть еще более простой
способ использовать бит "сепавратор", который всегда будет равен 0, и
если он займет место знакового то результат все равно будет верным
0vv! vvvv
v - наши данные ! - бит сепаратор
Остается добавить, что деление или умножение на 10bin, 100bin, 1000bin
это сдвиг влево или вправо на 1, 2, 3 бита (2^1 == 2 dec == 10 bin; 2^2
== 4 dec == 100 bin; 2^3 == 8 dec == 1000 bin; 2^n == сдвиг на n бит).
Хорошо, теперь попробуем применить это все на практике.
Практика
Тут я выложу несколько простых задач, в решение которых стоит применить полученные знания.
Золото за убийство
Мы должны добавить владельцу убившего юнита золота в зависимости от
какой либо характеристики (к примеру у юнита есть способность или
предмет +50% золота от крипов). На карте есть много всяких крипов, и от
каждого должно даваться случайное количество золота, но пересчитанное
по какой либо формуле. Функция, создающая texttag и добавляющая золота
у нас есть, в нее просто надо сообщить его количество. Также сделайте
два варианта, в первом 1 <=minGold <=maxGold <=80000000, во
втором 1 <=minGold <=MaxGold <=75.
Добавление предмета
На карте существует ~60 типов различных героев. Когда какой либо герой
достигнет 50 уровня надо создать уникальный для это типа героя артефакт
возле него.
Данные юнита
Необходимо сохранить для каждого юнита в игре сколько героев и крипов
он убил, и на какой стороне он сражается (к примеру свет и тьма).
Предположительно юнит не может убить больше 2000 других юнитов, не
может убить больше чем 500 героев, и он либо темный, либо светлый.
Возможное количество таких юнитов, которым надо сопоставить эти данные
неограниченно. Также добавлю условие что нельзя использовать глобальные
переменные, массивы или кешь.
|