Перейти к содержимому

eu_tomat

Модераторы
  • Публикации

    2 666
  • Зарегистрирован

  • Посещение

  • Победитель дней

    331

Все публикации пользователя eu_tomat

  1. "Ничего не получается" — это бесполезная формулировка, не несущая никакой новой информации. Эта программа по крайней мере запускается и сообщает о несовпадении количества реакторов и контроллеров красного камня. А что значит "менял подключения"?
  2. Да, есть много разных программ, в том числе и на этом форуме. Поэтому следует сразу уточнять, о какой программе идёт речь. Иначе помощи можно и не дождаться. Что касается именно этой программы, то она сообщает о том, что не совпадет количество реакторов и контроллеров красного камня, а также предлагает проверить подключения. Что показала проверка? Всё подключено верно?
  3. @OMGSEMA О какой программе идёт речь?
  4. Никакой это не отбрасыватель. В данном случае _ является таким же именем переменной, как x и y. Добро пожаловать на сервер ComputerCraft.RU в Discord!
  5. eu_tomat

    OpenGlasses 2 AE 2

    @Oleshe Штука, похоже, нужная. Только описание мутноватое. Что значит обойти? Для чего его обходить? И как? Что за фразы? Зачем их менять? На что они влияют? Что за худо? О чём идёт речь? Что за фильтр? На что он влияет? Что здесь называется объектом?
  6. Алгоритм стал предельно ясным после выбора модели входящих данных. Модель выбрана такая: изменения в списке игроков маловероятны. Поэтому нет смысла использовать какие-либо сложные оптимизации алгоритма. Достаточно выполнять линейное сравнение записей в двух отсортированных таблицах. При обнаружении различий в очередной паре строк нет смысла в использовании сложных алгоритмов поиска совпадения. Достаточно сдвинуть одну из таблиц на одну строку и двигаться дальше. С большой вероятностью следующая пара строк совпадёт. После всех этих упрощений у меня получился такой код: -- старый и новый списки строк local old, new = {}, {} -- текущие позиции в списках и их размер local o, n, oo, nn = 0,0, 0,0 -- списки добавленных и удалённых строк local add, rmv = {}, {} -- и их фактические размеры local a, r while true do -- обновить список игроков old, oo = new, nn new = genNextTable() nn = #new table.sort(new) -- установить на первую запись текущие позиции в старом и новом списках o, n = 1, 1 -- очистить списки добавленных и удалённых записей. a, r = 0, 0 -- основной цикл обработки таблиц ::_continue:: -- Если исчерпан старый список, весь остаток записей из нового копируем в добавленные if o > oo then for n = n, nn do a = a + 1 add[a] = new[n] end goto _break end -- Если исчерпан новый список, весь остаток записей из старого копируем в удалённые if n > nn then for o = o, oo do r = r + 1 rmv[r] = old[o] end goto _break end -- Если текущие записи в старом и новом списках совпали, пропускаем их обработку if old[o] == new[n] then o = o + 1 n = n + 1 goto _continue end -- Если запись в старом списке меньше чем в новом, то её следует скопировать в удалённые if old[o] < new[n] then r = r + 1 rmv[r] = old[o] o = o + 1 goto _continue -- Если запись в новом списке меньше чем в старом, то ее следует скопировать в добавленные else a = a + 1 add[a] = new[n] n = n + 1 goto _continue end ::_break:: end Переход на линейный алгоритм сравнения таблиц, а также различные мелкие оптимизации позволили ускорить вычисления в 1.5-2 раза, а по итогу (в сравнении с реализацией от @Anon) в 5-6 раз. Для таблиц размером 20 записей. @prop Вот теперь имеющийся потенциал полностью растанцован, и оснований для дальнейшего значимого улучшения я уже не вижу даже смутно. Возможно, получится сделать ещё какие-либо мелкие оптимизации. Но сейчас у меня глаз замылен, поэтому я с радостью выслушаю любые предложения. @prop Судя по всему, ты лучше меня разбираешься в теме алгоритмической сложности. Растолкуй, как её правильно посчитать применительно к моему коду.
  7. Нормальные метрики хорошо работают для универсальных ЯП. Lua же является скриптовым языком, и поэтому эффективность написанных на нём программ сильно зависит от использования внутренних возможностей языка. Работа с хэш-таблицами реализована на языке низкого уровня и хорошо оптимизирована. Поэтому циклический перебор элементов массива всегда будет работать медленнее, нежели использование ассоциативных свойств таблицы. Нет, не так. Доступ по ключу требует операций побольше чем O(n). Ускорение мы получили как за счёт уже оптимизированных алгоритмов поиска по хэш-таблицам, так и за счёт их реализации на языке низкого уровня. Какая там фактическая метрика, проверять я не планирую. Увы, я не нашёл ничего лучше сравнительных замеров нагрузки на CPU. А нормальные метрики применительно к реализациям на скриптовых языках имеют смысл лишь для очень приблизительной оценки. Нет. Это чисто умозрительная оценка. В эксперименте будет меньшее количество. Скорее всего, в 2 раза, т.к. автор кода останавливает поиск после обнаружения нужного значения. Судя по коду от @Anon, среднее количество составит 20*20/2*2. То есть, 400 сравнений, а не 800. Это я лишку хватил. Это я тебя не понял, поэтому возникла путаница. Согласен, копирование таблицы в алгоритме @Anon излишне. Да, замечание верное. Но это мелкая оптимизация и, возможно, даже преждевременная. А танцевать, мне кажется, можно гораздо дальше. Нужен другой алгоритм. Алгоритмически, аналитически... Вбрасывая какую-либо идею на форуме, я далеко не всегда погружаюсь в глубокий анализ. Например, когда я делал замечания по коду товарища @Anon, я не имел какого-либо кода. В мыслях у меня был не алгоритм и не код, а нечто смутное вроде: этот процесс заменяем другим и получаем ускорение. И анализа в его привычном смысле также не было. Было стойкое чувство, основанное на опыте использования ассоциативных массивов в Lua. Говоря же про имеющийся потенциал, я не то что не мог провести анализ, я даже алгоритм не сформулировал. У меня была лишь смутная картинка в виде пляшущих строк из двух таблиц, пытающихся совместиться друг с другом. И видеть эту картинку я мог, лишь находясь в состоянии полусна, когда аналитическое мышление притупляется, но память ещё позволяет что-то запомнить. За сутки эта смутная картинка превратилась в более-менее оформленный набор тезисов. Если ты готов к спокойному восприятию этой ещё не до конца сформулированной идеи, слушай: В большинстве случаев сравниваемые списки будут полностью идентичны друг другу. И для подтверждения этого факта в случае среднего онлайна 20 игроков будет достаточно выполнить лишь 20 сравнений строк. Правда, при наличии сортировки в таблицах. Скорее всего, ещё быстрее будет работать проверка количества игроков и тупое сравнение результатов table.concat. Но даже если таблицы отличаются, то в большинстве случаев не сильно. При обнаружении отличия надо лишь определить, строки какой из двух таблиц следует сдвинуть, и на сколько. А после вычисления размера сдвига можно продолжить линейное сравнение. Задача чем-то похожа на вывод различий строк двух текстовых файлов. Она, наверное, даже проще, т.к. в текстовые файлы могут быть добавлены огромные блоки строк, а списки игроков не успевают меняться настолько интенсивно. Что нам может помочь? Для начала надо проверить, не отсортированы ли уже списки игроков, возвращаемые отладочной платой. Даже если сортировка отсутствует, можно воспользоваться встроенной сортировкой Lua. Предполагаю, что она будет выполняться заметно быстрее, чем используемое мной формирование ассоциативного массива в цикле. А он в новом алгоритме не потребуется. Уже хороший размен.
  8. Вот более эффективный вариант сравнения таблиц игроков. При среднем онлайне 20 игроков такой способ сравнения выполняется в 3-4 раза быстрее твоего решения в лоб. ---------- конвертация предыдущего списка lastPlayers = {} for i=1, #players do lastPlayers[players[i]] = true end ---------- получение текущего списка players = getPlayers() difference = { removed={}, added={} } ---------- поиск игроков, зашедших на сервер for i, player in ipairs(players) do if lastPlayers[player] then lastPlayers[player] = nil else table.insert( difference.added, player ) end end ---------- поиск игроков, покинувших сервер for player in pairs(lastPlayers) do table.insert( difference.removed, player ) end Это, скорее всего, не предел. Чисто алгоритмически потенциал для дальнейшего ускорения имеется, но удастся ли реализовать его именно на языке Lua, на вскидку я сказать не могу.
  9. Вызов component.debug.getPlayers выполняется за один такт времени. И за это время список пользователей может измениться. То есть, действуя таким образом, мы можем терять события.
  10. Теперь стало понятнее. Для поиска ошибки надо задаться вопросом, что делает каждая из операций. #rad >= 2 проверяет количество игроков в зоне действия радара. Но что делает rad.distance <= 7? Ведь поле .distance не существует в таблице rad. Если ты хочешь проверить удалённость игрока от радара, то это надо делать для каждого из игроков. То есть, надо перебрать игроков в таблице (возможно, всех), проверить удалённость каждого из них и посчитать их количество, набрав хотя бы двух. Готовый код может выглядеть, например, таким образом: -- получаем список игроков в зоне действия радара local players = radar.getPlayers() -- вычисляем количество игроков в комнате local playersInRange = 0 -- имеет смысл считать, если найдено не менее двух игроков if #players >= 2 then -- перебираем всех найденных игроков for _,player in ipairs(players) do -- считаем только игроков в комнате if player.distance <= 7 then playersInRange = playersInRange + 1 -- останавливаем пребор, если значение счётчика достаточно для срабатывания условия if playersInRange >= 2 then break end end end end -- принимаем окончательное решение и выводим его на экран if playersInRange >= 2 then ... else ... end Работоспособность кода я не проверял, т.к. основной моей целью было показать именно алгоритм.
  11. Да, лагать там нечему. Было бы, если бы на игровом сервере не было других компьютеров, конкурирующих за общие ресурсы. А на практике одновременного работают десятки и сотни игровых компьютеров и роботов, разделяя общий поток на сервере. И если какой-то из этих компьютеров нагружает сервер необязательными вычислениями, то другой в это время, возможно, пропускает важное событие или, например, не успевает вовремя заменить теплоотводы в ядерном реакторе. Автор вопроса вообще не ставил никаких задач, он просто спросил, возможно ли это сделать. Я ответил, что теоретических ограничений нет. Ты продемонстрировал, что это возможно практически. Тут всё чётко. Но до тех пор, пока кому-нибудь не придёт в голову установить эту программу на публичный сервер. Потенциальные пользователи должны знать, что это лагодром. Программы нет потому, что писать её я и не собирался. А для тех, кто вдруг соберётся, я и дал свои замечания. Я допускаю, что недостаточно чётко сформулировал свои мысли. Скажи, что именно тебе не ясно. Как избавиться от двух проходов при сравнении списков, или как уменьшить количество сравнений за счёт использования ассоциативных свойств таблиц? Что из этого нуждается в иллюстрации кодом?
  12. В первом приближении, конечно, подойдёт. Но, судя по коду, это лагодром: В лог пишется время с точностью до секунды, хотя программа зачем-то уточняет список игроков 20 раз в секунду. Время сервера зачем-то запрашивается при каждом вызове функции log, хотя она при очередном обновлении списка может вызываться более одного раза. Сравнение списков реализовано крайне неэффективно. При онлайне 20 игроков для оценки изменений в списке потребуется 800 сравнений строк, хотя достаточно было бы лишь 20 раз запросить поле таблицы. Во-первых, два прохода списков не требуются, всё можно сделать за один проход. Во-вторых, ассоциативные свойства таблиц позволяют отказаться от перебора одной из таблиц в длинном цикле, тем самым ускорив поиск нужного значения.
  13. Зависит от того, как это преподнести. Если это какой-то коммерческий проект, то админ заинтересован в повышении онлайна. Если благодаря новой настройке ты и другие игроки начнёте строить какие-то полезные механизмы, которые сделают игровой мир более интересным, то админ будет рад пойти игрокам на встречу. В реальности всё может оказаться сложнее, поэтому все последствия надо рассматривать в комплексе. Возможно, игроки понастроят лагодромов с таким радаром, что сделает игру на сервере некомфортной. Возможно, эта механика сильно упростит добычу какого-то ресурса, что сломает игровой баланс. Поэтому я предлагаю поставить себя на место админа, понять его интересы и опасения, оценить интересы других игроков и сделать предложение, выгодное большинству участников.
  14. Он находится в каталоге config. А тот находится либо в локальном каталоге игры, либо в каталоге соответствующего сервера.
  15. А какое это имеет значение? Радиус действия радара задаётся в том же файле.
  16. На сервере точно таким же образом меняется.
  17. В файле config/computronics.cfg есть такие строки: radar { # The maximum range of the Radar. [range: 0 ~ 256, default: 8] I:maxRange=8 По умолчанию радиус действия радара задан равным 8 блокам, но здесь можно указать любое значение в диапазоне от 0 до 256.
  18. Теоретически возможно. Практически же ответ зависит от доступных модов и разрешённых на сервере крафтов.
  19. eu_tomat

    Робот и сундук

    Это разные таблицы. Посмотреть их содержимое можно, например, так: for k,v in pairs(tbl) do print(k,v) end if inv.getStackInInternalSlot(i) == 0x7efff97d9b210 then Этот код работать не будет. Во-первых, при каждом запуске программы адреса таблиц будут новыми. Во-вторых, сравнение таблиц по их адресам в большинстве случаев не имеет смысла, т.к. в первую очередь нас интересует содержимое таблиц, а не их адреса. Желательно максимально отказаться от дублирования тяжёлых вычисления или длительных запросов. getStackInInternalSlot работает медленнно. И совершая этот запрос по два раза, мы в два раза замедляем работу программу. inv.dropIntoSlot(i,7) Тут аргументы набросаны как попало. Первым аргументом должна быть указана сторона робота, с которой относительно его находится реактор. А тут зачем-то указан номер внутреннего слота робота. Код можно написать, например, таким образом: for i = 1, rob.inventorySize() do stack = inv.getStackInInternalSlot(i)) if stack.name == "IC2:reactorVentDiamond" and stack.damage==1 rob.select(i) inv.dropIntoSlot(3,i) end end В поле stack.damage хранятся метаданные или износ предмета. Применительно к теплоотводам — их температура, поэтому часть проверки можно выбросить. Достаточно проверять их по имени.
  20. Это оффтопик. Но раз ты считаешь, что он заслуживает внимания, я отвечу. Ранее от использования интернет-платы ты отказался сам: Поэтому я не понимаю, чем тебя заинтересовала идея упростить взаимодействие с банком, выбросив сетевой слой и оставив лишь API банка. Продолжая эту логику, можно вообще выбросить слой компов. Пусть игроки работают с банком консольными командами. На крайний случай сбегают на спавн и воспользуются стоящим там компом. Но зачем нам это? Подобные системы и так успешно функционируют. И к заявленной теме отношения они не имеют. Зачем нам вообще нужна эта сеть? Практического смысла в ней не было изначально, а вся эта сложность потребовалась лишь для создания игровой атмосферы, желательно с максимальной опорой на уже существующие игровые механики без добавления новых сущностей.
  21. eu_tomat

    Робот и сундук

    Вот оно что, значит! С этого и надо было начинать, а не повторять в каждом сообщении, что надо как-то обойтись без robot.select. Зачем морочить голову себе и другим? Тогда задача упрощается: с помощью контроллера инвентаря запрашиваем информацию о предметах в каждом из слотов робота. Анализируем информацию. Если обнаружили нужный компонент реактора, то выбираем нужный слот робота, и с помощью контроллера инвентаря переносим предмет в нужный слот реактора. Для этого потребуется: inventory_controller.getStackInInternalSlot(slot:number) для получения информации о предмете. robot.select(slot:number) для выбора этого слота inventory_controller.dropIntoSlot(side:number, slot:number[, count:number]) для перемещения предмета из текущего слота в нужный слот реактора.
  22. eu_tomat

    Робот и сундук

    @_bongo_ Ты специально что ли не отвечаешь на мой вопрос? Я задал его три раза: Но ты отвечаешь мне что угодно: какую-то общеизвестную информацию про метаданые, про рандомные компоненты реактора. Я спрошу иначе и последний раз. Если не хочешь, не отвечай, я тоже не буду пытаться понять. Что плохого случится при использовании robot.select?
  23. eu_tomat

    Робот и сундук

    Это я понял. Но почему без испольозвания robot.select?
  24. eu_tomat

    Робот и сундук

    Что значит, выбрать нужный предмет? Робот может выбрать слот, содержащий нужный предмет — это мне понятно. Я представляю действие, которое стоит за этим, там зелёненький курсор перемещается в нужный слот. Но как должен выглядеть выбор предмета без выбора содержащего его слота? И почему именно без robot.select? Какова цель всего этого? Постарайся сделать хорошо. Иначе с ответами тоже будет плохо.
×
×
  • Создать...