Dictionary - Форум


Правила форума ·

  • Страница 1 из 2
  • 1
  • 2
  • »
Форум » Warcraft III » Библиотека » Dictionary
Dictionary

SirNikolas

#1

Класс Dictionary


Что-то я в последнее время стал делать из JASS'а C++ :)



Предисловие


Данный класс - это ассоциативный массив, он является эквивалентом классов std::map в C++ и System.Collections.Generic.Dictionary в C#. Проще говоря, это массив, в качестве индексов в котором выступают не целые числа, а любые типы, которые Вы укажете.


Использование


Основное применение - создание баз данных. Скорость обращения к таким базам относительно линейного поиска тем выше, чем больше элементов в базе. Также в качестве индексов Вы можете использовать... таймеры. Да, это еще одна замена хэшу, однако применять ее стоит лишь тогда, когда одновременно существует много объектов. При малом количестве повышения производительности не будет.


Объявление типа


Думаю, можно не говорить, что следует скопировать триггер Dictionary себе в карту. Затем Вам нужно определить функции, которые будут сравнивать индексы. Создаются они по такому шаблону:[jass]library <Имя>
public function less takes <Имя типа> left, <Имя типа> right returns boolean
<Условие, если левый операнд меньше правого>
endfunction

public function equal takes <Имя типа> left, <Имя типа> right returns boolean
<Условие, если операнды равны>
endfunction
endlibrary[/jass]Разберем на конкретном примере - пусть нам нужен массив с индексатором integer:[jass]library IntegerComparison
public function less takes integer op1, integer op2 returns boolean
return op1 < op2
endfunction

public function equal takes integer op1, integer op2 returns boolean
return op1 == op2
endfunction
endlibrary[/jass]
После этого необходимо объявить массив нужного типа. Делается это с помощью следующей инструкции препроцессора:[jass]//! runtextmacro DeclareDictionary("<Тип индексатора>","<Тип значений>","<Наследуется ли индексатор от handle>","<Наследуется ли значение от handle>","<Имя библиотеки сравнения>","<Максимальный суммарный размер всех словарей данного типа>")[/jass]Например:[jass]//! runtextmacro DeclareDictionary("integer","unit","false","true","IntegerComparison","8191")[/jass]Эта инструкция объявит тип массива unit с индексом integer (integer не наследуется от handle, unit - наследуется, поэтому "false, true"). Для сравнения ключей будут использоваться функции из библиотеки IntegerComparison, размер всех словарей - 8191. Этот размер не стоит уменьшать - память Вы этим не сэкономите.
Обратите внимание: все значения макроса пишутся в кавычках; между запятыми и кавычками не должно быть пробелов!
Все необходимые приготовления сделаны, можно начинать кодить.


Работа с классом


Нужно просто объявить переменную типа Dictionary_<Тип индексатора>_<Тип значений> и инициализировать ее значением Dictionary_<Тип индексатора>_<Тип значений>.Create(), затем можно использовать ее как обычный массив:[jass]function Example1 takes nothing returns nothing
local Dictionary_integer_unit d = Dictionary_integer_unit.Create()
set d[0] = CreateUnit(...)
set d[1] = null
set d[-1] = CreateUnit(...)//Записываем по отрицательному индексу. Да, это возможно!
set d[100500] = CreateUnit(...)//И это тоже разрешено!
call KillUnit(d[0])
call RemoveUnit(d[-1])
//После использования, если массив временный, его необходимо уничтожить:
call d.Destroy()
endfunction[/jass]Однако гораздо чаще требуются словари, которые существуют всю игру и, следовательно, не требуют удаления. Их можно делать глобальными:[jass]globals
Dictionary_integer_unit MyDict
endglobals

function InitTrig_Example2 takes nothing returns nothing
set MyDict = Dictionary_integer_unit.Create()
set MyDict[0] = CreateUnit(...)
endfunction[/jass]Следует запомнить, что глобальный словарь, к сожалению, нельзя создать сразу же в globals.[jass]globals
Dictionary_integer_unit MyDict = Dictionary_integer_unit.Create()//Недопустимо!
endglobals[/jass]

Можно полностью очистить массив, не удаляя его:[jass]call MyDict.Clear()[/jass]Также есть свойство, показывающее количество элементов в данный момент:[jass]local Dictionary_integer_unit d = Dictionary_integer_unit.Create()
set d[0] = CreateUnit(...)
set d[1] = CreateUnit(...)
set d[2] = CreateUnit(...)
set d[3] = CreateUnit(...)
call BJDebugMsg(I2S(d.Count))//Выведет "4"
call d.Destroy()[/jass]После "Count" скобки не пишутся.

При попытке получить из словаря значение, которое не было туда помещено, будет возвращено значение по умолчанию. Вы также можете просто узнать, есть ли оно там:[jass]local Dictionary_integer_unit d = Dictionary_integer_unit.Create()
set d[0] = CreateUnit(...)
call BJDebugMsg(I2S(GetHandleId(d[2])))//d[2] пуст, поэтому будет возвращен юнит null, ID которого равен 0
if not d.Exists[2] then
call BJDebugMsg("По индексу 2 ничего не записано")
endif
call d.Destroy()[/jass]Если Вы делаете большую базу данных, которая не меняется всю игру, и Вам нужно ее максимальное быстродействие, Вам может оказаться полезным метод Rebuild, перестраивающий словарь для наиболее быстрого доступа к элементам. Следует учесть, что он достаточно медленный, поэтому после каждого обновления его вызывать не стоит.[jass]//! runtextmacro DeclareDictionary("integer","string","false","false","IntegerComparison","8191")

globals
Dictionary_integer_string SpellData
endglobals

function Trig_Spells_Actions takes nothing returns boolean
local string s = SpellData[GetSpellAbilityId()]
if s != null then
call ExecuteFunc(s)
endif
return false
endfunction

function InitTrig_Spells takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT,  null)
exitwhen i == 15
set i = i + 1
endloop
call TriggerAddCondition(trig, Condition(function Trig_Spells_Actions))
set trig = null

set SpellData = Dictionary_integer_string.Create()
set SpellData['A000'] = "Trig_FireStorm_Actions"
set SpellData['A001'] = "Trig_IceWall_Actions"
set SpellData['A002'] = "Trig_PoisonTouch_Actions"
set SpellData['A003'] = "Trig_HandOfGod_Actions"
set SpellData['A004'] = "Trig_Timeback_Actions"
//...
call SpellData.Rebuild()
endfunction[/jass]Еще один способ применения, который я упомянул ранее - создание MUI-спеллов.[jass]//! runtextmacro DeclareDictionary("timer","TimebackStruct","true","false","HandleComparison","8191")

library HandleComparison
public function less takes handle op1, handle op2 returns boolean
return GetHandleId(op1) < GetHandleId(op2)
endfunction

public function equal takes handle op1, handle op2 returns boolean
return op1 == op2
endfunction
endlibrary

globals
Dictionary_timer_TimebackStruct TimebackDict
endglobals

struct TimebackStruct
unit u
real x
real y
endstruct

function Trig_Timeback_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local TimebackStruct s = TimebackDict[t]
call SetUnitX(s.u, s.x)
call SetUnitY(s.u, s.y)
set TimebackDict[t] = 0
call DestroyTimer(t)
call s.destroy()
set t = null
endfunction

function Trig_Timeback_Actions takes nothing returns nothing
local TimebackStruct s = TimebackStruct.create()
local timer t = CreateTimer()
set s.u = GetSpellTargetUnit()
set s.x = GetWidgetX(s.u)
set s.y = GetWidgetY(s.u)
set TimebackDict[t] = s
call TimerStart(t, 5., false, function Trig_Timeback_Timer)
set t = null
endfunction

function InitTrig_Timeback takes nothing returns nothing
set TimebackDict = Dictionary_timer_TimebackStruct.Create()
endfunction[/jass]Важный момент - в таких случаях необходимо ВСЕГДА обнулять данные массивов, даже если это integer или real.


Взгляд изнутри


Этот раздел посвящен тем, кто хочет разобраться, как именно (и почему smile ) данная система работает.

Класс Dictionary сделан на основе бинарного древа, так что доступ к элементам осуществляется с логарифмической скоростью. При перестроении дерево раскладывается в массив, который сортируется методом расчески и снова собирается в дерево. Код не влез в размеры сообщения, но его можно скачать отдельно.


Если возникнут вопросы, задавайте, не стесняйтесь. smile

Сообщение отредактировал SirNikolas - Сб, 07.01.12, 20:19
"I will make this the first approved cJass-only resource here on the Hive" - Bribe about ALL.

H_A_PK

#3
Quote (SirNikolas)
Проще говоря, это массив, в качестве индексов в котором выступают не целые числа, а любые типы, которые Вы укажете.

например ид хендла я могу туда записать ? или строку ?
помойму аля хеш-таблицы
Ползут 2 пирожка.
Первый: Я тебя щас трахну.
Второй: Почему?
Первый: Потому что я с яйцами :D

Ty3uK

#4
Нарк, расческа сортирует что угодно, главное знать как. И хэшом тут и не пахнет

Добавлено (21.12.11, 14:50)
---------------------------------------------
Хэшем*

Аниме - такая вещь, которая балансирует на грани "надоевшего" и "нового" из-за Наруто в основном. © [DUOS]
GUI Must Die v1.1 | Arena Multiboard

H_A_PK

#5
Ty3uK, как не пахнет ? Ты нюхай чательней. Данная система позволяет указывать в массиве не только целое число, а прочую хрень, что возможно и в Хеше, ну только там я присобачиваю к адресу таблицу, а тут к переменной с массивом.
Ползут 2 пирожка.
Первый: Я тебя щас трахну.
Второй: Почему?
Первый: Потому что я с яйцами :D

Ty3uK

#6
Тщательнее, так промежду прочим. В основе системы лежит расческа, которая используется для сортировки данных
Аниме - такая вещь, которая балансирует на грани "надоевшего" и "нового" из-за Наруто в основном. © [DUOS]
GUI Must Die v1.1 | Arena Multiboard

H_A_PK

#7
Quote (Ty3uK)
которая используется для сортировки данных

ну и она сортирует данные.
Стоп что ? Она сортирует данные ? типа вау, но, кроме как производительности в долю секунду мне больше ничего это не даст например). Но как уже сказал автор, что система безполезна в картах с малым количеством объектов.
Только я вот не пойму, мало это сколько ? 1400-1500 ?
Ползут 2 пирожка.
Первый: Я тебя щас трахну.
Второй: Почему?
Первый: Потому что я с яйцами :D

Ty3uK

#8
Да ну? А сортировка данных по типу очков, статов и прочих плюшек без танцев с бубном, при помощи алгоритма, который сделал себе имя в других языках, не? Не подходит?
Аниме - такая вещь, которая балансирует на грани "надоевшего" и "нового" из-за Наруто в основном. © [DUOS]
GUI Must Die v1.1 | Arena Multiboard

H_A_PK

#9
Quote (Ty3uK)
Не подходит

мне.
Quote (Ty3uK)
А сортировка данных по типу очков, статов и прочих плюшек без танцев с бубном

что мне мешает сделать это на ХТ ? wacko извините меня
Ползут 2 пирожка.
Первый: Я тебя щас трахну.
Второй: Почему?
Первый: Потому что я с яйцами :D

Ty3uK

#10
Я сейчас не говорил за массивы и vjass. И отсутствие хт. Я и сам делаю это на хэше. Я сказал про сам алгоритм

Добавлено (21.12.11, 15:30)
---------------------------------------------
Прощаю, не стоит извиняться smile не хочу обидеть Николаса, но сам склоняюсь в сторону хт и жасс2 happy

Аниме - такая вещь, которая балансирует на грани "надоевшего" и "нового" из-за Наруто в основном. © [DUOS]
GUI Must Die v1.1 | Arena Multiboard

H_A_PK

#11
Quote (Ty3uK)
Я сказал про сам алгоритм

bye алгоритм сортировки, о да, то что нужно. По мойму такое нужно ну уж совсем людям у которых бардак в голове)
Ползут 2 пирожка.
Первый: Я тебя щас трахну.
Второй: Почему?
Первый: Потому что я с яйцами :D

Ty3uK

#12
Пхах. Но автоматическая сортировка, например, очков - очень удобная вещь
Аниме - такая вещь, которая балансирует на грани "надоевшего" и "нового" из-за Наруто в основном. © [DUOS]
GUI Must Die v1.1 | Arena Multiboard

H_A_PK

#13
закрепил все 3 системы в оглавлении
Ползут 2 пирожка.
Первый: Я тебя щас трахну.
Второй: Почему?
Первый: Потому что я с яйцами :D

SirNikolas

#14
Ty3uK, суть не в расческе. Суть в том, что эта штука построена на бинарном древе => поиск элементов куда быстрее линейного.
Quote (H_A_PK)
Только я вот не пойму, мало - это сколько? 1400 - 1500?
При 1024 элементах худший случай - когда искомое значение находится в самом конце, на 1023 месте. Линейный поиск найдет его на 1024 шаге, бинарный же - на 10. Есть разница? smile

BTW, автоматической сортировки тут нет, зря ты это написал. Древо сортируется при вызове метода .Rebuild(). Это массив с произвольным индексированием.
"I will make this the first approved cJass-only resource here on the Hive" - Bribe about ALL.

Ty3uK

#15
Ну так автоматическая сортировка будет происходить при нужном событии, например, при смерти. Надо только ее вызвать happy
Аниме - такая вещь, которая балансирует на грани "надоевшего" и "нового" из-за Наруто в основном. © [DUOS]
GUI Must Die v1.1 | Arena Multiboard
Форум » Warcraft III » Библиотека » Dictionary
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск: