XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Желтая пресса: обучающие статьи
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

 
adic3x

offline
Опыт: 108,439
Активность:
Равкоды - элементарные сведения
Тип integer и равкод как его представитель

Статья о том что это такое и с чем его едят. Знание jass необходимо.
Для всех примеров использован New Gen WE, его наличия обязательно.

В тексте возможно вы встетите термины, которые вам не будут ясны, я буду выделять их курсивом - ничего страшного, они не являются ключевыми, просто я привык называть вещи своими именами.

Теория



Итак, равкод - четыре чара (символа), которые указывают на тип обьекта, т.е. его характеристики в соответсвующей .slk таблице. Что бы увидить его в OE нажмите Ctrl+D.

Сразу замечу, что равкодами обладают почти все обьекты, а не только те что используются в OE: тайлсеты (tileset), молнии (lightning), погода (weather), склоны (cliffs) - все это доступно можно редактировать через правку соответсвующей слк таблицы, но к нашему рассказу это отношения не имеет=)

Теперь, в GUI (в редаторе тригеров) тип юнита/предмета/декорации и т.д. был представлен как отдельный тип, в jass такого идиотизма к счастью нет=) В jass все равкоды (ну не все, молнии - исключение) являются integer (т.е. просто число). Теперь пришла пора рассказать о других системах счисления:

В jass можно использовать следующие системы: двухсотпятидесятишестиричную (обозначается '<число>'), шестнадцатиричнуюричную (0x<число>), десятичную (самая привычная для большинства, обозначается просто <число>), и восмиричную (0<число>). Все данны представлены в компьютере в двоичном виде, поэтому испольхование систем, основанных на двоичной более уобны в некоторых случаях, к примеру при работе с чарами это тоже может быть намного удобней.

В десятичной си увелечение следующего разряда по достижению предыдущего разряда значению числа 10 (9+1=10), поэтому логично предположить что в шестнадцатиричной (иногда называется hex) - по 16. Числа от 0 до 9 обозначаются также, далее 10-A, 11-B, 12-C, 13-D, 14-E, 15-F, как пример 0x0f+0x01=0x10 (префикс 0x обозначает что число записанно в hex форме, также принято писать только четное количество байтов: 0x00, 0x000f, 0x000000a, даже если они равно 0).

Указывать числа в двоичной системе в jass нельзя, но она очень важна для понимания дальнейшего материала, поэтому и ее я опишу. В двоичной (бинарной) системе есть всего два символа, это 1 и 0, и называются они битами. Восемь бит образуют один байт. Данная система имеет тоже основание что и шестнадцатиричная (точнее наоборот, hex имеет тоже основание что и bin) и поэтому из одной системы очень легко переводить цифры в другую.

Код:
0100 1010 0101 1101
0x 4    a    5    d


Теперь запускаем обычный калькулятор Windows, ставим инженерный вид, водим любое число, и слева ставим галочку hex или bin - теперь думаю вы поняли что это такое и больше не боитесь его ;) Едем дальше...

Двумя байтами можно обозначить число от 0 до 255 или от 0x00 до 0xff. Именно это и есть двухсотпятидесятишестиричная си. Теперь смотрим эту таблицу (asc II, взял из WEU):

DEAD URL

Тут есть представление числа во всех основных си, кроме бинарной, но она нас не интересует при работе с чарами ;)

Так вот, при нашей работе с рав кодами мы остановимся именно на hex. Почему? Потому что в asc II многие символы вводить затруднительно, и она очень неудобна, а перевести число из 256 в 10 достаточно сложно, а вот в 16 можно спокойно в уме. 'A123' будет равно 'A'==0x41, '1'==0x31, '2'==0x32, '3'==0x33, теперь же просто составляем все - 'A123'==0x41313233 (в десятичной это было бы 1093743155). Еще пример 'M00x'==0x4d303078.

Снова возращаемя к нашим равкодам, теперь мы знаем что юнит 'h000' это 0x68303030, и этим числом можно делать что угодно и как угодно, я приведу несколько примеров, но сначала поясню кое что еще ;)

Все integer в war это signed long int, т.е. 32 бита, причем первый из них знаковый т.е. отвечает за то, отрицательное число или положительное. Сейчас я попробую обьяснить как это все работает, но будет намного лучше если вы попытаетесь постолрить за мной в том же WinCalc)

Да, и еще, числа от 0x00000000 до 0x7fffffff положительные от 0 до 2147483647, от 0xffffffff до 0x80000000 отрицательные от -1 до -2147483648.

Код:
знаковый бит, 0+, 1-
0101 0011 1001 0111 0000 1101 0001 0111 +
0000 0100 1111 1001 0110 0010 1000 1000 =
________________________________________________
0101 1000 1001 0000 0110 1111 1001 1111

и будет это

0x53970d17+0x04f96288==0x58906f9f

причем!

0x00000000-0x00000001==0xffffffff


Теперь обьясню одно очень хорошое свойство чисел - это сдвиг. К примеру, если 0010 умножить на 0100 то мы получим 1000 (2*4==8) т.е. умножение как и деление на цифру (именно цифру а не число!) 10 в любой системе (двоичной, десятичной и шестнадцатиричной) просто сдвигает все числа в "сторону". Но эта операция затрагивает знаковый бит! Проблемы связанные с этим я опишу позже. А что же будет если число выйдет за свои рамки и станет занимать больше 31 бита? А собственно ничего плохого, биты которые непоместяться просто потеряются, а в пустых местах появяться нули

Код:
0101 0000 0000 0000 0000 0000 0000 1111 << умножаем на 0010
  ______________________________________________________
0 1010 0000 0000 0000 0000 0000 0001 1110

жирным я пометил один бит для того что бы
было проще отследить смещение, курсивом добавленный ноль,
зачеркнут же потерянный бит


Далее мы будет считать 2^1 сдвинет на 1 бит, 2^2 на 1, 2^n на n. Сдвиг влево и вправо позволяет получить конкретный бит или биты числа, этот вариант будет рассмотрен в задачах. То что надо помнить - что сдвиг вправо (деление на 2^n) работает вполне коректно если знаковый бит равен 0. Т.е. когда мы сдвигаем биты влево мы должны быть уверены что первый знаковый бит будет равен 0 т.к. при делении (при сдвиге вправо) знаковый бит не затронеться! Достаточно банальный метод обойти это - прибавить с знаковому биту в двоичной си 1.

Код:
есть число, в котором нас интересуют седьмой и восьмой бит (выделено жирным)
  0000 1111 0000 0000 0000 0000 0000 0000 << *0x00000020
  ________________________________________________
  1110 0000 0000 0000 0000 0000 0000 0000 
  1000 0000 0000 0000 0000 0000 0000 0000 + 0x80000000 причем! это не умножение на -1!
  ________________________________________________
1 0110 0000 0000 0000 0000 0000 0000 0000 >> /0x20000000 (знаковый бит теперь потерян)
  ________________________________________________
  0000 0000 0000 0000 0000 0000 0000 0011


Отлично! Вот мы и получили искомы биты из конкрентного числа. Причем обратите внимание что прибавление числа 0x80000000 это не умножение или деление на -1 т.к. в таком случае бы многи биты числа изменили бы свое значение, а так меняется значение только знакового бита!

Практика



Тут я выложу достаточно простые задачи, советую хоть немного поламать голову над их решением ;)

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

Золото



Есть задача - по смерти юнита добавить золото в зависимости от каких либо характеристик (ну к примеру у юнита есть предмет +50% от золота крипов), и при этом на карте существует просто куча мобов, с каждого из них может выпасть совершенно разное количество золота. Функция создающая texttag у нас есть, просто в нее нужно сообщить кол-во золота. Предложите несколько вариантов, в первом 1<=minGold<=maxGlod<80000000, во втором же 1<=minGold<=MaxGold<=75

Добавление предмета



У нас скажем карта, где есть около 60 различных типов героев. По достижению 25 уровня у ног героя должен появится предмет, какой либо артефакт, причем индивидуальных для каждого героя.

Сопостовление юниту



Есть задача - сопоставить многим юнитам в игре количество убитых им юнитов, убитых им героев, а также в которых из 5 городов на карте юнит успел побывать. Предположительно юнит не может убить больше 2 тысяч юнитов, не может убить больше 500 героев, и на карте всего 5 городов, таких юнитов которым нужно все это сопоставить может быть очень много. Главное условие задачи - нельзя использовать кешь и переменные или массивы (только локальные).

Решение задач



» Золото


Код:
globals
 real array goldMin
 real array goldMax
 // два массива в которых и
 // будет храниться информация о золоте
endglobals

function Init takes nothing returns nothing
 set array goldMin[0x00]=1
 set array goldMin[0x01]=25
 set array goldMin[0x02]=12
 set array goldMin[0x03]=85
 set array goldMin[0x04]=10
 set array goldMin[...n]=n

 set array goldMax[0x00]=5
 set array goldMax[0x01]=28
 set array goldMax[0x02]=15
 set array goldMax[0x03]=85
 set array goldMax[0x04]=12
 set array goldMax[...n]=n
endfunction


Теперь, элемент массива обозначен как 0x00, реально же это обозначение 0x75303030-0x75303030 (т.е. 'u000'-'u000'), 0x01 == 0x75303031-0x75303030 ('u001'-'u000')

Вот такой нехитрый вариант хеширования, единственное что надо следить за тем, что бы равкоды лежали близко друг к другу: <raw code>-0x75303030<8190 (размер массива, 0x75303030 в конкретном нашем случае)

Теперь исходя из нашего решения что бы получить золото мы должны действовать так
Код:
function AddGlod takes real x, real y, player p, integer gold returns nothing

 ...
 local integer i=GetUnitTypeId(GetDyingUnit())
 call AddGold(<x>, <y>, <player>, GetRandomInt(goldMin[i-0x75303030], goldMax[i-0x75303030])*<factor>)


Теперь предположим, что золото может быть обозначенно через некоторые биты в самом равкоде юнита. К примеру есть юнит 'u000' его равкод в bin:

Код:
0111 0101 0011 0000 0011 0000 0011 0000
0x 7    5    3    0    3    0    3    0

последний байт оставим для определения юнита, а вот второй и третий используем в своих целях

Код:
function AddGlod takes real x, real y, player p, integer gold returns nothing

 ...
 local integer i=GetUnitTypeId(GetDyingUnit())
 call AddGold(<x>, <y>, <player>, GetRandomInt((i-0x75300000)/0x01000000, (i-i/0x75303000)/0x00000100)*<factor>)
 // немного другой метод сдвига


т.е. для юнита 'uax9' будет выделенно от 49 до 72

Вот и все! Конечно такой вариант не везде применим, но учитывать его тоже стоит.


» Добавление предмета


Код:
call CreateItem(GetUnitTypeId(<hero>)+0x01000000, GetUnitX(<hero>), GetUnitY(<hero>))


Слишком просто? Да, это будет работать будь у нас пару сотен героев, все что нам надо - что бы равкод итема был именно на 0x01000000 больше равкода героя, т.е. для героя 'H000' будет создан предмет 'I000', для 'H005' - 'I005'.


» Сопоставление юниту
Итак, для хранения информации, мы будем использовать UserData юнита. Вопрос в том как организовать хранение всех данных в одном integer - собственно ничего сложного

Код:
0000 0000 0000 0000 0000 0000 0000 0000
x1-- ---- ---- 2--- ---- -3-- --xx xxxx

где 1 - счетчик крипов
    2 - счетчик героев
    3 - счетчик городов


Всего для хранения онной информации достаточно 25 битов, поэтому все можно спокойно уместить в одном 32 битном integer

Код:
// увеличивает счетчик убитых крипов на 1
function IncCC takes unit u returns nothing
 call SetUnitUserData(u, GetUnitUserData(u)+0x00100000)
 // 0x00100000 ==
 // 0000 0000 0001 0000 0000 0000 0000 0000
endfunction

// возращает количество убитых крипов
function GetCC takes unit u returns integer
 return GetUnitUserData(u)/0x00100000
 // сдвиг вправо
 // поскольку интересующие нас биты
 // крайнее мы учерены что все остальные биты
 // будут нулевыми
endfunction

// аналогично для героев
function IncHC takes unit u returns nothing
 call SetUnitUserData(u, GetUnitUserData(u)+0x00000800)
endfunction

// тут мы используем смену знакового бита
// если он равен 1
function GetHC takes unit u returns integer
 local integer i=GetUnitUserData(u)*0x00000800
 if i<0x00then
  set i=i+0x80000000
 endif
 return i/0x00400000
endfunction

// города имеют индексы от 0 до 4

// город посещен
function CityVisit takes unit u, integer c returns nothing
 local integer x=GetUnitUserData(u)
 local integer i=x*R2I(Pow(I2R(0x02), I2R(0x14+c)))
 if i<0x00then
  set i=i+0x80000000
 endif
 if i/0x40000000==0x00then
  call SetUnitUserData(u, x+R2I(Pow(I2R(0x02), I2R(0x0a-c))))
 endif 
endfunction

// был ли юнит в городе
function IsCityVisited takes integer c returns integer
 local integer i=GetUnitUserData(u)*R2I(Pow(I2R(0x02), I2R(0x14+c)))
 if i<0x00then
  set i=i+0x80000000
 endif
 return i/0x40000000
endfunction


Вот и все! Достаточно простое и елегантное решение поставленной задачи ;)

Отредактировано NETRAT, 16.02.2009 в 16:55.
Старый 24.03.2008, 12:40
J
expert
offline
Опыт: 48,447
Активность:
ну теория уже сто раз про существование различных си разбросана по разным статьям, а вот то что на практике, можно как упоминание подшить в факу или т.п.
Старый 24.03.2008, 15:19
adic3x

offline
Опыт: 108,439
Активность:
Цитата:
ну теория уже сто раз про существование различных си разбросана по разным статьям

угу угу, даже знаю по каким, но там кста не так подробно=/ точнее там только про обозначения и все, имхо пусть тут лежит, если что будем отсілать сюдой
Старый 24.03.2008, 21:35
FellGuard
Losyash
offline
Опыт: 39,547
Активность:
nice, теперь есть куда перенаправлять) Ура)
Вот кстати про slk, молнии и прочее добавил бы и можно заливать; так как оно щас есть слишком узко заточено под джасс, нам бы еще научиться в базах с равами работать.
Старый 25.03.2008, 00:49
adic3x

offline
Опыт: 108,439
Активность:
Цитата:
Вот кстати про slk, молнии и прочее добавил бы и можно заливать

думаю отдельная тема имхо; про погоду кста есть перевед
Цитата:
узко заточено под джасс

так и планировал)
Цитата:
нам бы еще научиться в базах с равами работать

другая тема) я ща кста этим занимаюсь (заполняю слк) вобщем ое втопку терь) в слк есть поиск и отмена последнего изменения, это уже исключает любые сравнения по удобство с ое, про возможности промолчу
Старый 25.03.2008, 16:19
ScorpioT1000
Работаем
offline
Опыт: отключен
Норм, тока вот, думаю, неопытные непоймут.

ScorpioT1000 добавил:
Поэтому после перенаправления начнет размножаться флуд, уже не в пределах темы, в которой задали вопрос..
Старый 25.03.2008, 22:12
adic3x

offline
Опыт: 108,439
Активность:
ща дополню + переработаю, есть еще интересный материал
Старый 26.03.2008, 19:23
adic3x

offline
Опыт: 108,439
Активность:
обещанное обновление
если где опичатка говорите
опять же хотя и первую систему счисления (десятичную) как правило начинают учить в подготовительной группе дет сада, тем не менне материал некоторыми лицами может быть неусвоен. если такое произойдет - дайте мне знать, я постараюсь доработать материал
Старый 27.03.2008, 12:18
ZLOBICH
Kicked by XimikS
offline
Опыт: 4,727
Активность:
0101 0011 1001 0111 0000 1101 0001 0111 +
0000 0100 1111 1001 0110 0010 1000 1000 =
0101 1000 1001 0000 0110 1111 1001 1111
вроде..
Старый 28.03.2008, 14:47
adic3x

offline
Опыт: 108,439
Активность:
угу, пофиксил, спс)
Старый 28.03.2008, 15:56
J
expert
offline
Опыт: 48,447
Активность:
Цитата:
Потому что в asc II многие символы вводить затруднительно, и она очень неудобна, а перевести число из 256 в 10 достаточно сложно, а вот в 16 можно спокойно в уме

хм... может мне написать вам маленькую програмку по переводу из ascii в 10?
Старый 28.03.2008, 21:59
adic3x

offline
Опыт: 108,439
Активность:
а смысл?
винкал тогда
из асц2 в хекс в уме
из хекса в дец в винкалке
Старый 28.03.2008, 22:08
J
expert
offline
Опыт: 48,447
Активность:
а обратно в асц2? кстате нераз задавали уже вопросы на тему перевода рав кода в строку асц2
Старый 28.03.2008, 22:12
adic3x

offline
Опыт: 108,439
Активность:
винкалк: из дец в хекс
из хекс в асц в уме
Старый 28.03.2008, 22:31
J
expert
offline
Опыт: 48,447
Активность:
все с тобой понятно...
Старый 28.03.2008, 22:34
adic3x

offline
Опыт: 108,439
Активность:
утютю, по окончанию аргументов более или менее относящихся к теме мы переходим на аргументы которые относяться к личности=/
Старый 28.03.2008, 22:39
J
expert
offline
Опыт: 48,447
Активность:
так получается) ну вот посмотри, разве неудобно?
Прикрепленные файлы
Тип файла: rar Convert.rar (5.3 Кбайт, 69 просмотров )

Отредактировано Jon, 28.03.2008 в 23:18.
Старый 28.03.2008, 22:49
Toadcop

offline
Опыт: 54,313
Активность:
вот отличный список 255 чаров =) (открывать через норм редактор напр Notepad++ и т.п.)
список я скачал с Кампов из поста MindWorX'a =)
Прикрепленные файлы
Тип файла: txt bin ascii.txt (256 байт, 74 просмотров )
Старый 28.03.2008, 22:59
J
expert
offline
Опыт: 48,447
Активность:
я знаю этот список...

Jon добавил:
но в предыдущем посте я если при конвектировании используются смволы недоступные вару, руские буквы и т.п., то чтобы он считатся неконвектировавшимся
Старый 28.03.2008, 23:06
Toadcop

offline
Опыт: 54,313
Активность:
Jon что бы там небыло оно у меня на Вин ХР СП2 не запускаетьса =).

+ написать прогу не проблема. проблема что они у меня весят 100500 кб =) почему то... т.е. ясно что комилятор говна накидывает. =) ну это уже другая тема =)
Старый 28.03.2008, 23:08

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



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