Перейти к контенту

Рекомендуемые сообщения

Тема для обсуждения скриптов всего и всех в серии игр STALKER.


Задавая вопрос (!):
1. Внимательно изучите суть вопроса. Вопрос должен соответствовать выбранной Вами темы. Это поможет сохранить порядок и читабельность темы, а также облегчит поиск и понимание сего;
2. Изучите то, что уже есть в теме (пролистайте "руками", воспользуйтесь поиском на форуме);
3. Изучите информацию которая может вам помочь:

  Информация (Показать)

4. Дабы не превращать обсуждение в "кашу" разной информативной направленности, задавайте несколько вопросов по порядку (в разных постах) после того, как получите ответ на предыдущий вопрос;
5. "Спасибо" и тому подобное - будьте так любезны в ПМ. Если не любите писать в ПМ, в конце вопроса напишите фразу: "Заранее спасибо!" - или что-то в этом духе;
6. ПОЖАЛУЙСТА! Указывайте, для какой игры Вам необходима информация (ТЧ, ЧН, ЗП), если стоит мод - укажите название мода;
7. Если Вы что-то сделали и результат не такой, какой Вами задумывался, то, пожалуйста, приводите коды которые Вы изменяли/писали целиком! Это поможет другим правильно ответить на Ваш вопрос, а также оградит Вас от лишней писанины.
8. Оформляйте сообщение. Пользуйтесь тегами для того, чтобы отделить код от текста. Пишите грамотно - ПОЛЬЗУЙТЕСЬ ЗНАКАМИ ПРЕПИНАНИЯ.
9. И помните: «Правильно заданный вопрос – половина ответа».

 

Какие вопросы следует задавать, а какие нет...

  Читать рекомендуется. (Показать)

И последнее: очень рекомендовано к прочтению Правила форума
 


  • Спасибо 1
  • Полезно 2
Ссылка на комментарий

Полагаю что это уже мелочи, учитывая сказанное мною слово "набросок".

Тем не менее ты прав в плане сравнения с нулем. Проверку с nехt делать всё равно прийдется. Например если есть и индексы от 1 до ... и не натуральные индексы.

Изменено пользователем Gun12
Ссылка на комментарий

Gun12, насчет проверки да :)

а вот насчет ключей думаю надо помнить. Тут недавно обсуждался ipairs, который тоже реагирует лишь на натуральные ключи, а в таблицах часто встречаются и другие, так что тут все же pairs...

Vita sine libertate, nihil

Vita sine litteris - mors est

Ссылка на комментарий

Gun12,

  Цитата
По поводу определения типа таблиц.

Набросок без итераторов. Проверку на пустую таблицу и скорость не делал.

function GetTabStatus(tab)
    if #tab ~= 0 and not  next(tab, #tab) then
        return 'index' -- индексирудмый массив
    else
        return 'hash' -- всё подряд
    end
end

Увы, здесь не учитывается тот случай, когда в таблице произвольного вида имеются несколько ключей, отвечающих правилам "массивов". Т.е. если есть хотя бы ключ [1], то так таблица будет распознана как массив, хотя там может быть что угодно ещё.

 

Я думаю, что здесь без полного перебора не обойтись. Что же касается исходно заявленной задачи сохранения таблиц/массивов, то очевидным решением будет делать отдельную функцию сохранения на разные варианты и не пытаться определять "тип" автоматически. В конечном счёте, конкретная таблица как правило в силу дизайна либо является массивом, либо имеет произвольный вид. Ключевой момент "в силу дизайна", т.е. программист заранее знает природу этой таблицы. Это означает, что в подавляющем большинстве случаев задача определять тип не стоит вовсе, поскольку тип и так известен заранее.

 

Если же вдруг такая задача возникла, то лучше потратить силы не на ёё решение, а на редизайн кода с тем, чтобы привести его в состояние, когда вы таки знаете определённо, что из себя представляет эта таблица.

  Полезный утиль (Показать)
Ссылка на комментарий

После if-а #t определит наличие/отсутствие ключей, начинающихся с 1 и до последнего целочисленного поступательно нарастающего.

Если есть такие, то проверяем, есть ли ещё какие-либо записи (nехt). Если есть - значит хэш, если нет, то индексный массив.

Прогоните код в SсiТЕ.

Не пойму, чего вы хотите от iраirs?

Всё происходит так как и положено.

Какому-то индексу присвоили значение nil. Сборщик мусора удалил это поле. Осталось дырка в индексах. Вот он и тормознул на этом поле. Совершенно правильно работает.

Ссылка на комментарий

Не стал, чтобы не навешивать шоры, ранее давать свой двух-недельной давности набросок:

  нечто определяющее список иль нет: (Показать)
Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Может я не так понял. Может вы имеете в виду таблицы с целочисленными индексами, но произвольными? Но ведь в условии были даны варианты таблиц именно индексируемые с 1 и по порядку.Все другие варианты рассматриваются как хэш-ы. С ними нельзя работать ни оператором #, ни table.concat. Также в условии стояла задача узнать тип таблицы.

Я предложил вариант не только без пайрсов, но и без for i=1,#t.

Условия выполнены. Что не так? Не пойму.

Ссылка на комментарий

Gun12

В условии были приведены два возможных варианта таблиц-списков (а не или-или).

Да, именно с индекса 1 они должны иль могут начинаться и по порядку.

Да, именно с целочисленными, но НЕ произвольными.

Порядок индексов может быть нарушен (иметь 'дырки'), если элемет(ы) списка были занилен(ы) (=nil).

Такие 'дырки' просто исключаются из списка (таблица-список чистится).

В твоем варианте непонятно, ведь 'next(tab, #tab)' для списка всегда должен возвращать 'nil', т.е. после последнего нет следующего элемента списка просто по определению.

Может имелось ввиду 'next(tab, #tab-1) > 0', т.е. имеется последний элемент в списке => длина всей таблицы не ноль

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos, это я тебе возражу (и докажу) - т.к. в своё время всё то, о чём я говорил, неоднократно проверял, и всё это у меня и сейчас вполне так ничего себе работает :). Начнём сначала:

  Цитата
Файл 'smart_terrain_presets.ltx' является конфигом, который предназначен только для универсальных гулагов типа 'general_lager'

Для универсальных гулагов предназначен файл-пресет general_lager.ltx - а для "именных", как ты выразился :), предназначен тот, который я указал.

Далее:

респонеры NPC никаким местом не привязаны к каким-либо "гулагам". Поясняю ещё раз: любой респонер может плодить неписей для любых смарттеррейнов (или, если угодно, для "гулагов" :)), если он подходит по праметрам (повторюсь: в общем случае - группировка, ранг). Чтобы убедиться в этом, достаточно через некоторое время после начала игры (после срабатывания респонеров, это дело в разных модах реализовано совершенно по-разному) просмотреть глобальную карту (следует включить отображение всех NPC (или только сталкеров) на глобальной карте - как это сделать, пояснять, надеюсь, не потребуется?). В ярлычках неписей видно, что смарты наполнены совершенно разными респоновыми сталкерами, я имею в виду сталкерами, рождёнными совершенно разными респонерами. И не надо валить всё на алайф, "перегоняющий" сталкеров из одних смартов в другие, повторюсь: отслеживая путь любого NPC от респонера до смарта, становится очевидно, что никакие респонеры не привязаны ни к каким смартам. Единственные респонеры, срабатывающие в момент взятия NPC под гулаг (при условии, что условие для них прописано в смарте) - это респонеры, наполняющие ящики с барахлом в смартах. То есть, поменяв в конкретной секции "опытных" на "мастеров", ничего глобального ты не совершишь, т.к. в оллспоне есть куча других респонеров, которые наплодят и "опытных", и "новичков" в предостаточном количестве.

Далее:

человеку явно было нужно всего лишь заспонить и поселить на Кордоне бандоса-мастера, и для этого совершенно не хотелось лезть в оллспон (да это и ни к чему, я уже пояснял, что нужно для этого сделать, причём двумя способами :)). А если уж ты решил создать дополнительные секции спона (отдельные, для "мастеров" и т.п.), то, чтобы прописать их в существующий респонер, потребуется править оллспон.

Далее: ты, видимо, не знаком с тем фактом, что для любой работы в скриптовых файлах гулагов (тот же gulag_escape.script) можно создать условия "приёма на работу" (я частично уже отписывал, по каким параметрам это можно сделать - там ещё много чего можно "наусловить" :)). Эти условия называются predicate, и их, повторяю, можно применить к любой работе гулага. Если нужен конкретный пример - не поленись, загляни в этот файл (gulag_escape.script), и посмотри, как это реализовано для работы Волка или Фаната в смарте "лагерь новичков" (esc_lager). Таким образом, на работу "пахана" в смарте бандитов на АТП можно поставить условие, человеческим языком описываемое как "на работу принимается (назначается) только NPC с группировкой "бандит", с именем профиля "sim_bandit_master", и с рангом, равным 900 и более". Интересный факт: таким образом, кстати, можно обойти ограничение, выставленное для смартов Кордона в ltx-файле (конкретно smart_terrain_presets.ltx). Можно ещё кучу условий добавить :).

Заключение: в указанный смарт (esc_fabrika_bandit) в оригинальной игре принимаются NPC с группировкой "бандит", с рангами "новичок" (ранг менее 300), и "опытный" (ранг более 300 и менее 600). Никакие "мастера", заспоненные каким-то "назначенным именно для этого гулага" респонером под гулаг в смарте браться не будут. Чтобы изменить статус-кво, см. мой предыдущий пост - там всё для этого есть.

Ссылка на комментарий

=VENOM=

Для чего такой запал? :D Нередко в пылу запала пропускается суть иль видятся фантомы ...

  ответная реплика (Показать)
Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Gun12,

  Цитата
Не пойму, чего вы хотите от iраirs?

Всё происходит так как и положено.

Какому-то индексу присвоили значение nil. Сборщик мусора удалил это поле. Осталось дырка в индексах. Вот он и тормознул на этом поле. Совершенно правильно работает.

Сборщик мусора удаляет не ссылки, а значения. Между тем в таблице собственно хранятся именно ссылки. Будет ли удалена из таблицы ссылка зависит от ряда обстоятельств. Вот пример различного поведения:

t = {1, nil, 2, 3} -- завёл массив с "дыркой посередине"

print(#t) -- его длина 4

t[3] = nil -- занулил элемент со значением 2

print(#t) -- длина по прежнему 4

 

t = {} -- исходно пустая таблица

t[3] = 1 -- заполняем с конца, здесь оператор длины даёт 0

t[2] = 2 -- здесь тоже 0

t[1] = 3

print(#t) -- имеем 3

-- типа получили массив? Как бы не так!

t[2] = nil -- зануляем элемент посередине

print(#t) -- получаем 1

Я хочу обратить внимание, что эта разница поведения не имеет ни малейшего отношения к сборщику мусора. Сборщик ссылки не трогает, а собирает только значения. Ссылки же существуют либо в стеке функции и удаляются по завершении работы функции или блока или они существуют в таблице (и ещё раз, в таблице физически есть только ссылки). И вот здесь и имеем неприятность, поскольку, как видим, в этом случае поведение зависит от истории создания. В одном случае (массив с самого начала) ссылка не удаляется, в другом (исходно таблица общего вида) - ссылка удаляется, как и положено удалять элементы ассоциативного массива.

 

Это бы всё не стоило обсуждения (работает так и работает, надо только знать), но в документации Lua декларируется, что таблицы - это всегда ассоциативные массивы, а разница массив/не массив - это только детали внутренней оптимизации, которые как-бы не должны сказываться на поведении. К примеру, то, что там внутри используется для реализации ассоциативного массива, в принципе не должно быть важно. Хеш, ну и хорошо. Могло быть и что-то другое, бинарные деревья к примеру. А в реальности выходит, что детали реализации и подробности внутренней оптимизации очень даже важны и заслуживают обсуждения.

 

Возьмём iраirs. В соответствии с мануалом перебор с её помощью и оператор взятия длины работают по одному алгоритму. Если почитать, то в документации на язык таки упоминается, что оператор длины должен измерять длину не только до первой дырки в целочисленных ключах, но и до первого значения nil. Так что выходит, что пример выше показывает фактически ошибочное или нестандартное поведение.

 

Но опять же если думать над этим дальше, то такое нестандартное поведение - единственная возможность перебирать по порядку аргументы функции, используя конструкцию args = {...}. Если всё будет работать в точном соответствии со спецификацией языка, то дальше первого пустого аргумента мы не уйдём.

 

Добавлено через 12 мин.:

Artos,

  Цитата
2. Делаю все же универсальный вариант и для тех кто порой не понимает разницы в типах таблиц (т.е. не готов определять директивный аргумент) и ... порой таблицы могут иметь различный тип ... упаковка 't должна быть всегда и по возможности максимально экономная.

Рискну заметить, что это не самая лучшая идея сама по себе, а в соединении с теми, кто "порой не понимает разницы в типах таблиц" идея приобретает совершенно разрушительную мощь. Если функция заранее знает, какого типа аргумент будет на входе, то можно будет сделать проверки и остановить работу с вразумительным сообщением. Если на входе возможные варианты, то функция уже никак не сможет сказать, а что на самом деле хотел сделать программист. Здесь ошибка в данных, или это неправильно использованный вызов или что-то ещё? Вариантов становится слишком много, проверить их все уже невозможно. Остаётся только довериться программисту, но ведь программист подразумевается такой, что "порой не понимает разницы в типах таблиц". Такому только доверься... Это готовый бардак в коде, испорченные сейвы, практическая невозможность отлаживать и вообще сопровождать код. IMHO, не стоит этого делать.

  Полезный утиль (Показать)
Ссылка на комментарий

Выкладываю предварительный (рабочий!) вариант упаковки и распаковки таблиц в строку и обратно.

Предназначен для модернизации/замены варианта из АМК-мода v.1.4.x (pack_array_to_string/unpack_array_from_string) при сохранении в сэйвы.

Совместим с прежними сэйвами из модов, использовавшими прежний формат упаковки.

  экономный (рас)паковщик таблиц в строку: (Показать)
Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos

 

Что-то мы говорим на разных языках.

Попробую ещё раз.

  Цитата
Вопрос-1: Как оптимально определить тип таблицы 'список' (list), т.е. типа: {"a","b","c","d"} или {1,5,2,4,3}?

 

По типу построения между этими таблицами нет никакой разницы. На самом деле они же выглядят так :

{[1]='a', [2]='b', [3]='c', [4]='d'}
и
{[1]=1, [2]=5, [3]=2, [4]=4, [5]=3}

Т.е. оператор # определит ВСЕ! поля этих таблиц.

  Цитата
...определение именно списка, а не иного типа массива.

Если добавить в любой из списков поле, не соответствующее продолжению "списка", например {[1]='a', [2]='b', [3]='c', [4]='d', [7]='e'}, либо 'занилить' значение, после чего поле удалиться из списка {[1]='a', [2]='b', [3]=nil, [4]='d'}, то список перестанет быть таковым и станет хэшем на общих основаниях.

Теперь оператор # определит в первом случае из 6-ти фактических полей только 5 (от индекса 1 до индекса 5). Во втором случае только 2 (т.к. поле с индексом 3 исчезло, и следующий индекс после 2 будет индекс 4), вместо фактических 3-х.

!!! Для того, чтобы не нарушать строение таблицы как списка (который работает быстрее чем любой другой тип таблиц) нужно пользоваться специально созданными для этого функциями table.insert и table.remove, а не заниливанием и непонятно каким добавлением.

  Цитата
...и не полный перебор списка на поиск 'дыр' в индексах

Теперь о 'дырах' и собственно моем варианте без перебора.

Имеется 3 типа таблиц :

t1 = {a='p', k=6, [12]='s'} 
t2 = {'a', 'b', k=6}
t3 = {'a', 8, 'c'}

Хотя в таблице t2 и есть элеметы списка, но и она, и таблица t1 не являются списками. Это комбинированые хэш-таблицы.

Получается что для списка нужно определить, равна ли длина таблицы фактическому количеству полей.

Вот я и пошел таким путем.

if #tаb~=0

Определяю, есть ли в таблице элементы списка (индексов от 1 и до упора).

Если нет, то это уже не список. Ответ - хэш.

Если есть такие элементы, то последний из них по любому найдется.

И теперь проверяя nехt(tаb,#tаB) смотрю, есть ли за этим последним элементом списка ещё поля, характерные для хэша?

Если нет (nil), то фактическая длина таблицы равна количеству полей, что означает одно - таблица является списком.

Ну а если есть ещё поля, то это смешанная таблица, а по сути НЕ список.

 

Добавлено через 48 мин.:

В варианте с заниливанием внутри таблицы ([3]=nil) допустил неточность. Читать 'заниливанием извне', например t[3] = nil

Ссылка на комментарий

Как сделать так, чтоб другие Сталкеры курили?

Там по моему, нужен такой код:

kurit sidya_ 0

?

Изменено пользователем Кивач
Ссылка на комментарий

Кивач

Для ответа на твой вопрос потребно написать очень о многом. Это и добавление вырезанных анимаций в коды игры и о редактировании/добавлении события "курит" в нужные схемы (например для посиделок у костра), и о добавлении нужных моделей текстур, иконок для сигарет и их пачек ...

Если имеешь опыт редактирования конфигов и скриптов - не проще ли поиском отыскать готовые наработки по этой теме и взглянуть как и что там сделано?

 

Gun12

  Раскрывающийся текст (Показать)
Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos, я добавил сигареты и попытался на основе колбасы сделать. Но они упорно отказываются курить (Может не хотят начинать курить? :D:huh: ). Но вылетов нет. Там по моему нужны (для добавления события "курит") фалы скриптов: state_lib, state_mgr_animation, state_mgr_animation_list и xr_kamp. Модель и в стандартном игре есть.

Топик все же не для погадалок ... Так можно гадать до бесконечности.

Если что-то сделал и не получается - поясняешь и/или выкладываешь сделанное - и можно будет искать ошибки или подсказать недоделки.

Если же ничего не сделано, а только похотелка - читаем шапк темы, читаем статьи на вика сайтах по теме, ... и тогда задаем конкретные вопросы о недопонятом и/или ненайденном.

--/ Artos

Изменено пользователем Artos
Ссылка на комментарий

Gun12,

  Цитата
Теперь о 'дырах' и собственно моем варианте без перебора...

...

Вот я и пошел таким путем.

if #tаb~=0

Определяю, есть ли в таблице элементы списка (индексов от 1 и до упора).

Если нет, то это уже не список. Ответ - хэш.

Если есть такие элементы, то последний из них по любому найдется.

И теперь проверяя nехt(tаb,#tаB)

Вообще говоря, перебор там таки есть, хотя и внутри операции размера. Эта операция для получения размера как раз и перебирает все элементы. Где-то я об этом в мануале читал. Хотя это разумеется не скриптовый перебор и не так уж затратно.

Дальше, первая часть алгоритма так и не сможет определить наличие дырок в массиве в случае, как я приводил выше. В принципе не критично. Надо только не пользоваться ipairs и проверять на эти дырки при сохранении.

Ну и наконец, идея с next целиком полагается на допущение, что при индексации часть таблицы с хешем проверяется после проверки части с линейным массивом. Иначе, как можно утверждать, что после последнего элемента массива идут элементы с хешем? А вдруг они в общей последовательности идут впереди? Понятно, что из общих соображения код сделан так, что сначала проверяется менее затратный линейный массив. Однако, при переборе ассоциативного массива в общем случае нельзя делать допущения о порядке элементов.

 

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

  Полезный утиль (Показать)
Ссылка на комментарий

malandrinus

(хотя и оффтопик, но все же касательно темы)

  Раскрывающийся текст (Показать)

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий
  malandrinus писал(а):
Иначе, как можно утверждать, что после последнего элемента массива идут элементы с хешем? А вдруг они в общей последовательности идут впереди? ...Однако, при переборе ассоциативного массива в общем случае нельзя делать допущения о порядке элементов.
Изменено пользователем Artos
Ссылка на комментарий

Gun12

Что же в итоге?

Такой вариант достаточен для селекции в игре таблиц, для которых не требуется сохранять индексы элементов?:

 local iCnt = #tTbl --/ длина индексированной части таблицы
local bList = iCnt > 0 and iIdx == 1 and not next(tTbl,iCnt) --/ флаг: tTbl является списком (true)

- т.е. проверка: имеются элементы 'списка', 1-й индекс начинается с 1 и за 'списком' отсутствует хеш-элемент

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Gun12,

  Цитата
Наверное ты всё-таки прав. Не нужно высовываться

Где я такое сказал?

 

Artos,

мне интересно, что ты будешь делать с этой функцией дальше. Вот ты проверил, что это массив. Но ведь это только говорит об упорядоченности ключей. А что насчёт значений? Ведь в качестве значений может быть что угодно: числа, строки, таблицы, пользовательские объекты. До какой степени ты будешь пытаться автоматизировать обработку?

 

 

  Полезный утиль (Показать)
Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...