Робот с геосканером. Часть #1 [движения]
Чтобы программа могла контролировать движения робота, добавим систему координат и функционал связанный с ней.
Так как робот будет шахтером, то все движения должны сопровождаться разрушением блоков, он будет ползать сквозь породу, попутно захватывая руду.
Описание основной двигательной деятельности занимает всего четыре функции (можно и три, но в прошлой версии, в процессе борьбы за место, пришлось одну разделить)
Приведу базовый код, затем опишу, что он делает.
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 комментария
Рекомендуемые комментарии