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

some blog name

  • записей
    15
  • комментарий
    41
  • просмотра
    17 253

Робот с геосканером. Часть #1 [движения]

Doob

899 просмотров

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

Так как робот будет шахтером, то все движения должны сопровождаться разрушением блоков, он будет ползать сквозь породу, попутно захватывая руду.

Описание основной двигательной деятельности занимает всего четыре функции (можно и три, но в прошлой версии, в процессе борьбы за место, пришлось одну разделить)

Приведу базовый код, затем опишу, что он делает.

local component = require('component') -- подгрузить обертку из OpenOS
local X, Y, Z, D = 0, 0, 0, 0
local WORLD = {x = {}, y = {}, z = {}}

local function add_component(name) -- получение прокси компонента
  name = component.list(name)() -- получить адрес по имени
  if name then -- если есть адрес
    return component.proxy(name) -- вернуть прокси
  end
end

local robot = add_component('robot') -- загрузка компонента

local function step(side) -- функция движения на 1 блок
  local state, type = robot.swing(side) -- тестовый свинг
  if not state and type == 'block' then -- если блок нельзя разрушить
    print('bedrock')
    os.exit() -- временная заглушка
  else
    while robot.swing(side) do end -- копать пока возможно
  end
  if robot.move(side) then -- если робот сдвинулся, обновить координаты
    if side == 0 then
      Y = Y-1
    elseif side == 1 then
      Y = Y+1
    elseif side == 3 then
      if D == 0 then
        Z = Z+1
      elseif D == 1 then
        X = X-1
      elseif D == 2 then
        Z = Z-1
      else
        X = X+1
      end
    end
  end
  if #WORLD.x ~= 0 then -- если таблица меток не пуста
    for i = 1, #WORLD.x do -- пройти по всем позициям
      if X == WORLD.x[i] and (Y-1 <= WORLD.y[i] and Y+1 >= WORLD.y[i]) and Z == WORLD.z[i] then
        if WORLD.y[i] == Y+1 then -- добыть блок сверху, если есть
          robot.swing(1)
        elseif WORLD.y[i] == Y-1 then -- добыть блок снизу
          robot.swing(0)
        end
        table.remove(WORLD.x, i) -- удалить метку из таблицы
        table.remove(WORLD.y, i)
        table.remove(WORLD.z, i)
      end
    end
  end
end


local function turn(side) -- поворот в сторону
  side = side or false
  if robot.turn(side) then -- если робот повернулся, обновить переменную направления
    if side then
      D = (D+1)%4
    else
      D = (D-1)%4
    end
  end
end

local function smart_turn(side) -- поворот в определенную сторону света
  while D ~= side do
    turn((side-D)%4==1)
  end
end

local function go(x, y, z) -- переход по указанным координатам
  while Y ~= y do
    if Y < y then
      step(1)
    elseif Y > y then
      step(0)
    end
  end
  if X < x then
    smart_turn(3)
  elseif X > x then
    smart_turn(1)
  end
  while X ~= x do
    step(3)
  end
  if Z < z then
    smart_turn(0)
  elseif Z > z then
    smart_turn(2)
  end
  while Z ~= z do
    step(3)
  end
end

Сначала создаются переменные для локальных координат робота.

X, Y, Z - собственно, позиция робота, относительно стартовой точки.

 

D - направление, куда смотрит мордочка робота. при старте программы она относительная. Поэтому, чтобы привязать ее к сторонам света, надо будет произвести некоторое шаманство при помощи геосканера.

 

Таблица WORLD - это метки, которые будут устанавливаться в процессе сканирования. Таблица разделена на три, это смежные хранилища переменных для каждой координаты, например, сканер обнаружил блок с подходящей плотностью по координатам x15, y-10, z3, в таблицу они будут добавлены по одному индексу. Допустим, таблица была пустая, после добавления будет иметь вид WORLD.x[1] = 15, WORLD.y[1] = -10, WORLD.z[1] = 3 или WORLD = {x = {15}, y = {-10}, z = {3}}

 

Далее следует функция, упрощающая добавление компонентов. На вход получает имя нужного компонента и, если он есть, выдает прокси к нему.

 

Функция step() - основное движение робота.

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

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

Если махнул удачно - пробуем еще раз и еще, до посинения. Это своеобразная защита от лагающего гравия/песка и назойливых сущностей (в виде гномиков).

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

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

 

Функция turn() - основной поворотник (аналог robot.turn(), но с обновлением переменной направления)

Робот поворачивается, записывая результат в переменную, добавляя/отнимая единицу по модулю 4 при каждом повороте.

 

Функция smart_turn() - поворот на желаемую сторону света, с минимумом действий.

Вычисляет разницу между текущим и целевым направлением, запуская результат по модулю 4 через turn()

Функции поворота можно будет объединить, но пока оставлю так.

 

Функция go() - великий ход конем до нужных координат.

Принимает координаты целевого блока, двигается по вертикали, поворачивает на цель X, двигается до цели, поворачивает на цель Z, двигается до цели. Для поворота использует smart_turn(), т. к. оси x и z глобальные, это стороны света.

 

 

  • Нравится 4


2 комментария


Рекомендуемые комментарии

для world.x и остальных можно было бы попробовать юзать что-то наподобие world[x][z][y] = index
тогда бы не пришлось бегать по всему массиву и искать нужные коорды, но памяти бы жрало много

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

Поделиться комментарием


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

Экономия скорости не большая, по сравнению с потреблением памяти.

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

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

Поделиться комментарием


Ссылка на комментарий
Гость
Добавить комментарий...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...