Compare commits
8 Commits
package_ma
...
master
Author | SHA1 | Date |
---|---|---|
Andrew Lalis | 661972da77 | |
Andrew Lalis | 6c04533dbb | |
Andrew Lalis | ecb18cd501 | |
Andrew Lalis | 401c1fe65d | |
Andrew Lalis | f145f5a17e | |
Andrew Lalis | f9f2be629a | |
Andrew Lalis | 80be066744 | |
Andrew Lalis | 4f1db31164 |
|
@ -0,0 +1,27 @@
|
||||||
|
# movescript.lua
|
||||||
|
A more convenient way to move a robot.
|
||||||
|
|
||||||
|
## Pastebin
|
||||||
|
[4c2AN8Jw](https://pastebin.com/4c2AN8Jw)
|
||||||
|
|
||||||
|
## Module Requirements
|
||||||
|
*None*
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
Simply run `pastebin get 4c2AN8Jw /lib/movescript.lua` to install movescript to the local computer. Then you can begin writing movescripts to tell your robots how to move. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
local ms = require("movescript")
|
||||||
|
|
||||||
|
local my_script = "FFURFFL"
|
||||||
|
ms.execute(my_script)
|
||||||
|
```
|
||||||
|
|
||||||
|
The above code will make the robot move forward twice, then up once, then turn right, then move forward twice, and finally turn left.
|
||||||
|
|
||||||
|
It is also possible to specify the amount of times to perform an action, by giving an integer value before the character for the movement you want. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
local my_long_script = "10D2R5B3U"
|
||||||
|
ms.execute(my_long_script)
|
||||||
|
```
|
|
@ -0,0 +1,129 @@
|
||||||
|
--[[
|
||||||
|
Author: Andrew Lalis
|
||||||
|
File: movescript.lua
|
||||||
|
Version: 1.0
|
||||||
|
Last Modified: 27-09-2018
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This library enables string representation of robot movement, for easier
|
||||||
|
robotic control without repeating functions many times.
|
||||||
|
|
||||||
|
Begin a script with "d_" to tell the robot to attempt to destroy blocks in the
|
||||||
|
way of the path of movement.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local r = require("robot")
|
||||||
|
|
||||||
|
local movescript = {}
|
||||||
|
|
||||||
|
local destructive = true
|
||||||
|
|
||||||
|
local function doUntilSuccess(f)
|
||||||
|
local success = f()
|
||||||
|
while (not success) do
|
||||||
|
success = f()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function up()
|
||||||
|
while (destructive and r.detectUp()) do
|
||||||
|
r.swingUp()
|
||||||
|
end
|
||||||
|
doUntilSuccess(r.up)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function down()
|
||||||
|
while (destructive and r.detectDown()) do
|
||||||
|
r.swingDown()
|
||||||
|
end
|
||||||
|
doUntilSuccess(r.down)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function forward()
|
||||||
|
while (destructive and r.detect()) do
|
||||||
|
r.swing()
|
||||||
|
end
|
||||||
|
doUntilSuccess(r.forward)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function back()
|
||||||
|
if (destructive) then
|
||||||
|
r.turnAround()
|
||||||
|
while (r.detect()) do
|
||||||
|
r.swing()
|
||||||
|
end
|
||||||
|
r.turnAround()
|
||||||
|
end
|
||||||
|
doUntilSuccess(r.back)
|
||||||
|
end
|
||||||
|
|
||||||
|
local functionMap = {
|
||||||
|
["U"] = up,
|
||||||
|
["D"] = down,
|
||||||
|
["L"] = r.turnLeft,
|
||||||
|
["R"] = r.turnRight,
|
||||||
|
["F"] = forward,
|
||||||
|
["B"] = back,
|
||||||
|
["P"] = r.place,
|
||||||
|
["S"] = r.swing
|
||||||
|
}
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Determines if a string starts with a certain string.
|
||||||
|
str - string: The string to check the prefix of.
|
||||||
|
start - string: The prefix to look for.
|
||||||
|
--]]
|
||||||
|
local function starts_with(str, start)
|
||||||
|
return str:sub(1, #start) == start
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Executes a single instruction once.
|
||||||
|
c - character: One uppercase character to translate into movement.
|
||||||
|
--]]
|
||||||
|
local function executeChar(c)
|
||||||
|
local f = functionMap[c]
|
||||||
|
if (f == nil) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
f()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Executes a single instruction, such as '15D'
|
||||||
|
instruction - string: An integer followed by an uppercase character.
|
||||||
|
--]]
|
||||||
|
local function executeInstruction(instruction)
|
||||||
|
local count = string.match(instruction, "%d+")
|
||||||
|
local char = string.match(instruction, "%u")
|
||||||
|
if (count == nil) then
|
||||||
|
count = 1
|
||||||
|
end
|
||||||
|
if (char == nil) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for i=1,count do
|
||||||
|
executeChar(char)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Executes a given script.
|
||||||
|
script - string: The script to execute.
|
||||||
|
--]]
|
||||||
|
function movescript.execute(script)
|
||||||
|
if (starts_with(script, "d_")) then
|
||||||
|
destructive = true
|
||||||
|
script = string.sub(script, 3)
|
||||||
|
else
|
||||||
|
destructive = false
|
||||||
|
end
|
||||||
|
while (script ~= nil and script ~= "") do
|
||||||
|
-- Matches the next instruction, possibly prefixed by an integer value.
|
||||||
|
local next_instruction = string.match(script, "%d*%u")
|
||||||
|
executeInstruction(next_instruction)
|
||||||
|
script = string.sub(script, string.len(next_instruction) + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return movescript
|
|
@ -0,0 +1,41 @@
|
||||||
|
# harvest.lua
|
||||||
|
Script for smart harvesting of rectangular farms of multiple crops.
|
||||||
|
|
||||||
|
## Pastebin
|
||||||
|
[ytYCVGsc](https://pastebin.com/ytYCVGsc)
|
||||||
|
|
||||||
|
## Module Requirements
|
||||||
|
* geolyzer
|
||||||
|
* inventory_controller
|
||||||
|
* *equipped hoe*
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
To operate the program, you simply need to run the program. If no `harvest.conf` config file exists, the program will guide you through the creation of it. For it, you'll need the following information:
|
||||||
|
|
||||||
|
* On what side does the robot start harvesting (left or right)?
|
||||||
|
* How many rows are in the field?
|
||||||
|
* How many columns are in the field?
|
||||||
|
* What crops will be grown?
|
||||||
|
|
||||||
|
For each crop that will be grown, you will need the following pieces of information:
|
||||||
|
|
||||||
|
1. The crop's block name (can be found using the `geolyzer` component.
|
||||||
|
2. The floating point value at which the crop is ready to be harvested. Can also be found with the `geolyzer`.
|
||||||
|
3. The name of the item used to replant the crop. This can be found in the minecraft inventory after pressing `F3 + H` to enable more detailed information for displayed items.
|
||||||
|
|
||||||
|
Once all this information is entered, running the program will harvest the defined area, and drop all gathered items into a chest below the robot's resting point.
|
||||||
|
|
||||||
|
### Diagram of setup
|
||||||
|
The below diagram shows how farms should be set up: the robot faces into the first row, and has a charger behind it to replenish energy after each harvest. A chest or hopper can be placed below the robot for item collection.
|
||||||
|
|
||||||
|
```
|
||||||
|
CR---------
|
||||||
|
---------
|
||||||
|
---------
|
||||||
|
---------
|
||||||
|
---------
|
||||||
|
---------
|
||||||
|
---------
|
||||||
|
---------
|
||||||
|
---------
|
||||||
|
```
|
|
@ -0,0 +1,261 @@
|
||||||
|
-- Harvest Program for robots. Uses a hoe and geolyzer for optimal harvesting.
|
||||||
|
--[[
|
||||||
|
Author: Andrew Lalis
|
||||||
|
File: harvest.lua
|
||||||
|
Version: 1.0
|
||||||
|
Last Modified: 27-09-2018
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This script enables a robot to harvest fields of crops quickly and efficiently.
|
||||||
|
The robot will traverse the field and only harvest crops considered 'done' by
|
||||||
|
their crop definition.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local robot = require("robot")
|
||||||
|
local component = require("component")
|
||||||
|
local fs = component.filesystem
|
||||||
|
local serial = require("serialization")
|
||||||
|
local geolyzer = component.geolyzer
|
||||||
|
local ic = component.inventory_controller
|
||||||
|
local sides = require("sides")
|
||||||
|
|
||||||
|
local CONFIG_FILE = "harvest.conf"
|
||||||
|
|
||||||
|
local LEFT = 1
|
||||||
|
local RIGHT = 0
|
||||||
|
|
||||||
|
-- List of crops which will be harvested.
|
||||||
|
local crop_definitions = {}
|
||||||
|
|
||||||
|
-- Repeats the given function until it returns true.
|
||||||
|
local function doUntilSuccess(func)
|
||||||
|
local success = func()
|
||||||
|
while (not success) do
|
||||||
|
success = func()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pre-defined path from turtle docking bay to start of harvest area (first crop).
|
||||||
|
local function goToStart(rows, columns)
|
||||||
|
doUntilSuccess(robot.forward)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pre-defined path back to the turtle docking bay.
|
||||||
|
local function goBack(rows, columns)
|
||||||
|
for i=1,(columns-1) do
|
||||||
|
doUntilSuccess(robot.back)
|
||||||
|
end
|
||||||
|
robot.turnRight()
|
||||||
|
for i=1,(rows-1) do
|
||||||
|
doUntilSuccess(robot.back)
|
||||||
|
end
|
||||||
|
robot.turnLeft()
|
||||||
|
doUntilSuccess(robot.back)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Select an item, given its name and damage value.
|
||||||
|
item_name - string: The id string for an item.
|
||||||
|
item_data - number: The damage value, or variation of an item. Defaults to zero.
|
||||||
|
return - boolean: True if at least one slot contains the item. That slot is now
|
||||||
|
selected.
|
||||||
|
--]]
|
||||||
|
local function selectItemByName(item_name, item_data)
|
||||||
|
for i=1,16 do
|
||||||
|
local stack = ic.getStackInInternalSlot(i)
|
||||||
|
if (stack ~= nil and stack.name == item_name and stack.damage == item_data) then
|
||||||
|
robot.select(i)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Checks if the hoe is equipped. Meant to be done before starting a harvest.
|
||||||
|
return - boolean: True if a hoe is equipped, or false if not.
|
||||||
|
--]]
|
||||||
|
local function isHoeEquipped()
|
||||||
|
for i=1,16 do
|
||||||
|
local item_stack = ic.getStackInInternalSlot(i)
|
||||||
|
if (item_stack == nil) then
|
||||||
|
robot.select(i)
|
||||||
|
ic.equip()
|
||||||
|
new_item_stack = ic.getStackInInternalSlot(i)
|
||||||
|
if (new_item_stack ~= nil and string.match(new_item_stack.name, "_hoe")) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Tries to harvest a plant, if it is one of the crops defined in the crop
|
||||||
|
definitions table above.
|
||||||
|
return - boolean: True if a plant was harvested, false otherwise.
|
||||||
|
--]]
|
||||||
|
local function harvestPlant()
|
||||||
|
local plant_data = geolyzer.analyze(sides.bottom)
|
||||||
|
local crop_definition = crop_definitions[plant_data.name]
|
||||||
|
if (crop_definition == nil) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if (plant_data.growth >= crop_definition.growth_limit) then
|
||||||
|
robot.swingDown()
|
||||||
|
selectItemByName(crop_definition.item_name, 0)
|
||||||
|
robot.placeDown()
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Harvests one row of crops.
|
||||||
|
length - int: The number of plants in this row.
|
||||||
|
return - int: The number of crops that were harvested.
|
||||||
|
--]]
|
||||||
|
local function harvestRow(length)
|
||||||
|
local harvests = 0
|
||||||
|
for i=1,length do
|
||||||
|
if (i > 1) then
|
||||||
|
doUntilSuccess(robot.forward)
|
||||||
|
end
|
||||||
|
if (harvestPlant()) then
|
||||||
|
harvests = harvests + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return harvests
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
At the end of the row, the robot must rotate into the next row, and this is
|
||||||
|
dependent on where the start location is.
|
||||||
|
current_row_index - int: The row the robot is on prior to turning.
|
||||||
|
start_location - int: Whether the robot starts at the left or right.
|
||||||
|
--]]
|
||||||
|
local function turnToNextRow(current_row_index, start_location)
|
||||||
|
if (current_row_index % 2 == start_location) then
|
||||||
|
robot.turnRight()
|
||||||
|
else
|
||||||
|
robot.turnLeft()
|
||||||
|
end
|
||||||
|
doUntilSuccess(robot.forward)
|
||||||
|
if (current_row_index % 2 == start_location) then
|
||||||
|
robot.turnRight()
|
||||||
|
else
|
||||||
|
robot.turnLeft()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Harvests a two dimensional area defined by rows and columns. The robot starts
|
||||||
|
by moving forward down the first row.
|
||||||
|
rows - int: The number of rows to harvest.
|
||||||
|
columns - int: The number of columns to harvest.
|
||||||
|
start_location - int: 1 for LEFT, 0 for RIGHT.
|
||||||
|
return - int: The total number of crops harvested.
|
||||||
|
--]]
|
||||||
|
local function harvestField(rows, columns, start_location)
|
||||||
|
goToStart(rows, columns)
|
||||||
|
-- Begin harvesting.
|
||||||
|
robot.select(1)
|
||||||
|
local harvests = 0
|
||||||
|
for i=1,rows do
|
||||||
|
harvests = harvests + harvestRow(columns)
|
||||||
|
-- Do not turn to the next row on the last row.
|
||||||
|
if (i < rows) then
|
||||||
|
turnToNextRow(i, start_location)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
goBack(rows, columns)
|
||||||
|
return harvests
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Drops all carried items into an inventory below the robot.
|
||||||
|
return - int: The number of items dropped.
|
||||||
|
--]]
|
||||||
|
local function dropItems()
|
||||||
|
local item_count = 0
|
||||||
|
for i=1,16 do
|
||||||
|
robot.select(i)
|
||||||
|
local stack = ic.getStackInInternalSlot(i)
|
||||||
|
if (stack ~= nil) then
|
||||||
|
doUntilSuccess(robot.dropDown)
|
||||||
|
item_count = item_count + stack.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return item_count
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Reads config from a file.
|
||||||
|
filename - string: The string path/filename.
|
||||||
|
return - table|nil: The table defined in config, or nil if the file does not
|
||||||
|
exist or another error occurs.
|
||||||
|
--]]
|
||||||
|
local function loadConfig(filename)
|
||||||
|
-- Config file exists.
|
||||||
|
local f = io.open(filename, "r")
|
||||||
|
if (f == nil) then
|
||||||
|
print("No config file " .. filename .. " exists. Please create it before continuing.")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local t = serial.unserialize(f:read())
|
||||||
|
f:close()
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Guides the user in creating a new config.
|
||||||
|
return - table: The config created.
|
||||||
|
--]]
|
||||||
|
local function createConfig(filename)
|
||||||
|
local config = {}
|
||||||
|
print("Does your robot start on the left or right of the field?")
|
||||||
|
local input = io.read()
|
||||||
|
if (input == "left") then
|
||||||
|
config.START_LOCATION_RELATIVE = LEFT
|
||||||
|
elseif (input == "right") then
|
||||||
|
config.START_LOCATION_RELATIVE = RIGHT
|
||||||
|
else
|
||||||
|
print("Invalid choice. Should be either left or right.")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
print("Enter number of rows.")
|
||||||
|
config.ROWS = tonumber(io.read())
|
||||||
|
print("Enter number of columns.")
|
||||||
|
config.COLS = tonumber(io.read())
|
||||||
|
|
||||||
|
print("How many crops are being harvested?")
|
||||||
|
config.crop_definitions = {}
|
||||||
|
for i=1,tonumber(io.read()) do
|
||||||
|
print("Crop "..i..": What is the block name? (Use geolyzer to analyze it)")
|
||||||
|
local name = io.read()
|
||||||
|
config.crop_definitions[name] = {}
|
||||||
|
print(" What is the growth threshold for harvesting?")
|
||||||
|
config.crop_definitions[name].growth_limit = tonumber(io.read())
|
||||||
|
print(" What is the item name of this crop?")
|
||||||
|
config.crop_definitions[name].item_name = io.read()
|
||||||
|
end
|
||||||
|
file = io.open(filename, "w")
|
||||||
|
file:write(serial.serialize(config))
|
||||||
|
file:close()
|
||||||
|
return config
|
||||||
|
end
|
||||||
|
|
||||||
|
local function main()
|
||||||
|
local config = loadConfig(CONFIG_FILE)
|
||||||
|
if (config == nil) then
|
||||||
|
config = createConfig(CONFIG_FILE)
|
||||||
|
end
|
||||||
|
crop_definitions = config.crop_definitions
|
||||||
|
local harvest_count = harvestField(config.ROWS, config.COLS, config.START_LOCATION_RELATIVE)
|
||||||
|
local drop_count = dropItems()
|
||||||
|
print(harvest_count..", "..drop_count)
|
||||||
|
end
|
||||||
|
|
||||||
|
main()
|
|
@ -0,0 +1,41 @@
|
||||||
|
# lumber_farm.lua
|
||||||
|
Automatically chop an array of spruce trees.
|
||||||
|
|
||||||
|
## Pastebin
|
||||||
|
[dB0XwcAY](https://pastebin.com/dB0XwcAY)
|
||||||
|
|
||||||
|
## Module Requirements
|
||||||
|
* tractor_beam
|
||||||
|
* inventory_controller
|
||||||
|
* movescript library [4c2AN8Jw](https://pastebin.com/4c2AN8Jw)
|
||||||
|
* A lumber axe of obscenely high durability, or unbreakable.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
First, install *movescript* to `/lib/movescript.lua`.
|
||||||
|
|
||||||
|
Then, download this script, and `edit` the downloaded file to set some constants.
|
||||||
|
|
||||||
|
* `ROWS`: The number of rows in the farm.
|
||||||
|
* `COLS`: The number of columns in the farm.
|
||||||
|
* `TREE_SPACING`: The number of blocks between trees.
|
||||||
|
* `DELAY`: The time, in tens of seconds, to wait between chopping and picking up items.
|
||||||
|
* `move_to_start`: A *movescript* describing how to get from the robot's base station to the first tree.
|
||||||
|
* `return_from_start`: A *movescript* describing how to get back to the robot's base station from the first tree. Should usually be the opposite of `move_to_start`.
|
||||||
|
|
||||||
|
Make sure you have a very powerful lumber axe, or one which is unbreakable, and give it to the robot.
|
||||||
|
|
||||||
|
### Farm Setup
|
||||||
|
The construction of the farm should be as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
R-1 R-2 R-3
|
||||||
|
| [T] | [T] | [T] | Column 1
|
||||||
|
| [T] | [T] | [T] | Column 2
|
||||||
|
| [T] | [T] | [T] | Column 3
|
||||||
|
| [T] | [T] | [T] | Column 4
|
||||||
|
X
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `[T]` denotes a 2x2 tree, `X` denotes the starting location for the robot.
|
||||||
|
|
||||||
|
Each tree should be separated from those adjacent to it by `TREE_SPACING` blocks.
|
|
@ -0,0 +1,180 @@
|
||||||
|
--[[
|
||||||
|
Author: Andrew Lalis
|
||||||
|
File: TreeFarm.lua
|
||||||
|
Version: 1.0
|
||||||
|
Last Modified: 12-06-2018
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This script lets a robot, equipped with a tractor_beam and inventory controller
|
||||||
|
module, chop trees with a Tinker's Construct lumber axe. It will automatically
|
||||||
|
stop when it runs out of saplings or bonemeal, or when its axe is close to
|
||||||
|
breaking. It also can either chop a certain number of trees, or simply chop
|
||||||
|
until its resources are depleted.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--Require statements and componenent definitions.
|
||||||
|
local robot = require("robot")
|
||||||
|
local component = require("component")
|
||||||
|
local tractor_beam = component.tractor_beam
|
||||||
|
local ic = component.inventory_controller
|
||||||
|
|
||||||
|
--Runtime Constants defined for this robot.
|
||||||
|
local SAPLING_NAME = "minecraft:sapling"
|
||||||
|
local SAPLING_DATA = 0
|
||||||
|
local BONEMEAL_NAME = "minecraft:dye"
|
||||||
|
local BONEMEAL_DATA = 15
|
||||||
|
|
||||||
|
--Global configuration variables.
|
||||||
|
--Flag for if program should run until out of resources.
|
||||||
|
local continuous = false
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Exits the program.
|
||||||
|
--]]
|
||||||
|
local function quit()
|
||||||
|
print("#--------------------------------#")
|
||||||
|
print("# Tree Chopping Program exited. #")
|
||||||
|
os.exit()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Select an item, given its name and damage value.
|
||||||
|
item_name - string: The id string for an item.
|
||||||
|
item_data - number: The damage value, or variation of an item. Defaults to zero.
|
||||||
|
return - boolean: True if at least one slot contains the item. That slot is now
|
||||||
|
selected.
|
||||||
|
--]]
|
||||||
|
local function selectItemByName(item_name, item_data)
|
||||||
|
for i=1,16 do
|
||||||
|
local stack = ic.getStackInInternalSlot(i)
|
||||||
|
if (stack ~= nil and stack.name == item_name and stack.damage == item_data) then
|
||||||
|
robot.select(i)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Select an item, similar to selectItemByName, but if the item cannot be found,
|
||||||
|
the user will be prompted to add it to the robot's inventory and press enter to
|
||||||
|
continue.
|
||||||
|
item_name - string: The id string for an item.
|
||||||
|
item_data - number: The damage value, or variation of an item. Defaults to zero.
|
||||||
|
return - nil: If set to be continuous, then if the item cannot be found, then
|
||||||
|
the program will exit. If not, it will loop until the item is provided by the
|
||||||
|
user.
|
||||||
|
--]]
|
||||||
|
local function selectSafely(item_name, item_data)
|
||||||
|
local success = selectItemByName(item_name, item_data)
|
||||||
|
if continuous and not success then
|
||||||
|
print("Out of "..item_name..", exiting.")
|
||||||
|
quit()
|
||||||
|
end
|
||||||
|
while not success do
|
||||||
|
print("Cannot find "..item_name.." in inventory. Please add some, and press enter.")
|
||||||
|
io.read()
|
||||||
|
success = selectItemByName(item_name, item_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Plants a sapling, and if it can't place one at first, loops until it is
|
||||||
|
possible.
|
||||||
|
--]]
|
||||||
|
local function plantSapling()
|
||||||
|
selectSafely(SAPLING_NAME, SAPLING_DATA)
|
||||||
|
local success = robot.place()
|
||||||
|
while not success do
|
||||||
|
print("Unable to place the sapling. Please remove any blocks in front of the robot, and press enter.")
|
||||||
|
io.read()
|
||||||
|
success = robot.place()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Repeatedly applies bonemeal to the sapling until either the sapling has grown,
|
||||||
|
or the robot runs out of bonemeal.
|
||||||
|
--]]
|
||||||
|
local function applyBonemeal()
|
||||||
|
local success, block_type = robot.detect()
|
||||||
|
while block_type ~= "solid" do
|
||||||
|
selectSafely(BONEMEAL_NAME, BONEMEAL_DATA)
|
||||||
|
robot.place()
|
||||||
|
success, block_type = robot.detect()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Uses the robot's axe to chop a tree, and quits if the lumber axe provided has
|
||||||
|
less than 10% durability.
|
||||||
|
--]]
|
||||||
|
local function chopTree()
|
||||||
|
local durability = robot.durability()
|
||||||
|
if continuous and (durability == nil or durability < 0.1) then
|
||||||
|
print("Inadequate tool to chop trees, exiting.")
|
||||||
|
quit()
|
||||||
|
end
|
||||||
|
while (durability == nil) or (durability < 0.1) do
|
||||||
|
print("Please ensure that a lumber axe with at least 10% durability is equipped in the tool slot, and press enter.")
|
||||||
|
io.read()
|
||||||
|
durability = robot.durability()
|
||||||
|
end
|
||||||
|
robot.swing()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Uses the tractor_beam module to repeatedly pick up items until there are no
|
||||||
|
more to pick up.
|
||||||
|
--]]
|
||||||
|
local function pickupItems()
|
||||||
|
local success = tractor_beam.suck()
|
||||||
|
while success do
|
||||||
|
success = tractor_beam.suck()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Grows a tree by planting a sapling and applying bonemeal until it is grown.
|
||||||
|
--]]
|
||||||
|
local function growTree()
|
||||||
|
plantSapling()
|
||||||
|
applyBonemeal()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
The entire cycle of the farm. Grows a tree, harvests the wood, and picks up
|
||||||
|
the items.
|
||||||
|
--]]
|
||||||
|
local function farmTree()
|
||||||
|
growTree()
|
||||||
|
chopTree()
|
||||||
|
os.sleep(2)
|
||||||
|
pickupItems()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Main function in which the iterations of the cycle are performed.
|
||||||
|
--]]
|
||||||
|
local function main()
|
||||||
|
print("# Andrew's Tree Chopping Program #")
|
||||||
|
print("# Copyright 2018 Andrew Lalis #")
|
||||||
|
print("#--------------------------------#")
|
||||||
|
print("Please enter the number of trees to chop, or -1 to chop until out of resources.")
|
||||||
|
local choice = tonumber(io.read())
|
||||||
|
if (choice == nil or choice == -1) then
|
||||||
|
continuous = true
|
||||||
|
print(" Chopping trees until out of resources.")
|
||||||
|
while continuous do
|
||||||
|
farmTree()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print(" Chopping "..choice.." trees.")
|
||||||
|
for i=1,choice do
|
||||||
|
farmTree()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
quit()
|
||||||
|
end
|
||||||
|
|
||||||
|
main()
|
|
@ -0,0 +1,216 @@
|
||||||
|
--[[
|
||||||
|
Author: Andrew Lalis
|
||||||
|
File: lumber_farm.lua
|
||||||
|
Version: 2.0
|
||||||
|
Last Modified: 04-11-2018
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This script will automate the farming of large spruce trees, and will chop and
|
||||||
|
replant them, but not pick up items, since there are many mod items available
|
||||||
|
which can do this more efficiently.
|
||||||
|
|
||||||
|
The robot should be given an 'unbreakable' tool with 5 reinforced upgrades.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--Require statements and componenent definitions.
|
||||||
|
local robot = require("robot")
|
||||||
|
local component = require("component")
|
||||||
|
local ms = require("movescript")
|
||||||
|
local ic = component.inventory_controller
|
||||||
|
|
||||||
|
local move_to_start = "5F"
|
||||||
|
local return_from_start = "5B"
|
||||||
|
|
||||||
|
local ROWS = 3
|
||||||
|
local COLS = 2
|
||||||
|
local TREE_SPACING = 3
|
||||||
|
|
||||||
|
-- Global counter.
|
||||||
|
local TREES_CHOPPED = 0
|
||||||
|
|
||||||
|
--Runtime Constants defined for this robot.
|
||||||
|
local SAPLING_NAME = "minecraft:sapling"
|
||||||
|
local SAPLING_DATA = 1
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Select an item, given its name and damage value.
|
||||||
|
item_name - string: The id string for an item.
|
||||||
|
item_data - number: The damage value, or variation of an item. Defaults to zero.
|
||||||
|
min_count - number: The minimum number of items to have.
|
||||||
|
return - boolean: True if at least one slot contains the item. That slot is now
|
||||||
|
selected.
|
||||||
|
--]]
|
||||||
|
local function selectItemByName(item_name, item_data, min_count)
|
||||||
|
for i=1,16 do
|
||||||
|
local stack = ic.getStackInInternalSlot(i)
|
||||||
|
if (stack ~= nil and stack.name == item_name and stack.damage == item_data and stack.size >= min_count) then
|
||||||
|
robot.select(i)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Select an item, similar to selectItemByName, but if the item cannot be found,
|
||||||
|
the user will be prompted to add it to the robot's inventory and press enter to
|
||||||
|
continue.
|
||||||
|
item_name - string: The id string for an item.
|
||||||
|
item_data - number: The damage value, or variation of an item. Defaults to zero.
|
||||||
|
min_count - number: The minimum number of items to have.
|
||||||
|
--]]
|
||||||
|
local function selectSafely(item_name, item_data, min_count)
|
||||||
|
local success = selectItemByName(item_name, item_data, min_count)
|
||||||
|
while not success do
|
||||||
|
print("Cannot find "..min_count.."x "..item_name.." in inventory. Please add some, and press enter.")
|
||||||
|
io.read()
|
||||||
|
success = selectItemByName(item_name, item_data, min_count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Gets the total number of items with the given data.
|
||||||
|
item_name - string: The id string for an item.
|
||||||
|
item_data - number: The damage value, or variation of an item. Defaults to zero.
|
||||||
|
--]]
|
||||||
|
local function getItemCount(item_name, item_data)
|
||||||
|
local count = 0
|
||||||
|
for i=1,16 do
|
||||||
|
local stack = ic.getStackInInternalSlot(i)
|
||||||
|
if (stack ~= nil and stack.name == item_name and stack.damage == item_data) then
|
||||||
|
count = count + stack.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
return - bool: True if the tree is grown, false otherwise.
|
||||||
|
--]]
|
||||||
|
local function isTreeGrown()
|
||||||
|
local success, str = robot.detect()
|
||||||
|
return (success and str == "solid")
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Plants a sapling, and if it can't place one at first, loops until it is
|
||||||
|
possible. Assumes the robot is at the starting position:
|
||||||
|
OO
|
||||||
|
OO
|
||||||
|
R
|
||||||
|
Where O=dirt, R=robot.
|
||||||
|
--]]
|
||||||
|
local function plantTree()
|
||||||
|
local success, str = robot.detect()
|
||||||
|
if (success and (str == "passable" or str == "solid" or str == "replaceable")) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local saplings_needed = 4
|
||||||
|
if (getItemCount(SAPLING_NAME, SAPLING_DATA) < saplings_needed) then
|
||||||
|
print("Not enough saplings. Needed: "..saplings_needed..". Add some and press ENTER.")
|
||||||
|
io.read()
|
||||||
|
end
|
||||||
|
selectSafely(SAPLING_NAME, SAPLING_DATA, 1)
|
||||||
|
ms.execute("2FRP")
|
||||||
|
selectSafely(SAPLING_NAME, SAPLING_DATA, 1)
|
||||||
|
ms.execute("LBP")
|
||||||
|
selectSafely(SAPLING_NAME, SAPLING_DATA, 1)
|
||||||
|
ms.execute("RP")
|
||||||
|
selectSafely(SAPLING_NAME, SAPLING_DATA, 1)
|
||||||
|
ms.execute("LBP")
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Uses the robot's axe to chop a tree, and quits if the lumber axe provided has
|
||||||
|
less than 10% durability.
|
||||||
|
return - integer: 1 if the tree was chopped, 0 otherwise.
|
||||||
|
--]]
|
||||||
|
local function chopTree()
|
||||||
|
if (isTreeGrown()) then
|
||||||
|
ms.execute("S")
|
||||||
|
plantTree()
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Moves to the next tree in a row.
|
||||||
|
current_col - integer: The current column.
|
||||||
|
col_count - integer: The total number of columns.
|
||||||
|
--]]
|
||||||
|
local function moveToNextTree(current_col, col_count)
|
||||||
|
if (current_col < col_count) then
|
||||||
|
ms.execute("d_LFR3FRFL"..(TREE_SPACING - 1).."F")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Moves to the next row.
|
||||||
|
current_row - integer: The row that was just finished.
|
||||||
|
row_count - integer: The total number of rows.
|
||||||
|
col_count - integer: The total number of columns.
|
||||||
|
--]]
|
||||||
|
local function moveToNextRow(current_row, row_count, col_count)
|
||||||
|
local script = "d_LFL"..((TREE_SPACING + 2) * (col_count - 1)).."FLF"
|
||||||
|
if (current_row < row_count) then
|
||||||
|
script = script..(TREE_SPACING + 2).."FL"
|
||||||
|
else
|
||||||
|
script = script.."L"
|
||||||
|
end
|
||||||
|
ms.execute(script)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Moves back to the start of the orchard.
|
||||||
|
row_count - integer: The total number of rows.
|
||||||
|
--]]
|
||||||
|
local function moveToOrchardStart(row_count)
|
||||||
|
ms.execute("d_L"..((TREE_SPACING + 2) * (row_count - 1)).."FR")
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Performs a function at each tree in the orchard.
|
||||||
|
rows - integer: The total number of rows.
|
||||||
|
cols - integer: The total number of columns.
|
||||||
|
func - function: The function to execute at each position.
|
||||||
|
--]]
|
||||||
|
local function doForEachTree(rows, cols, func)
|
||||||
|
ms.execute(move_to_start)
|
||||||
|
for i=1,rows do
|
||||||
|
for k=1,cols do
|
||||||
|
func()
|
||||||
|
moveToNextTree(k, cols)
|
||||||
|
end
|
||||||
|
moveToNextRow(i, rows, cols)
|
||||||
|
end
|
||||||
|
moveToOrchardStart(rows)
|
||||||
|
ms.execute(return_from_start)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Chops an array of trees. The robot starts facing the first row.
|
||||||
|
--]]
|
||||||
|
local function chopOrchard(rows, cols)
|
||||||
|
doForEachTree(rows, cols, chopTree)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Reads any given arguments and uses them for program constants instead of
|
||||||
|
default values.
|
||||||
|
args - table: the arguments passed to the program.
|
||||||
|
--]]
|
||||||
|
local function getSettingsFromArgs(args)
|
||||||
|
ROWS = tonumber(args[1])
|
||||||
|
COLS = tonumber(args[2])
|
||||||
|
TREE_SPACING = tonumber(args[3])
|
||||||
|
move_to_start = args[4]
|
||||||
|
return_from_start = args[5]
|
||||||
|
end
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
if (#args == 5) then
|
||||||
|
getSettingsFromArgs(args)
|
||||||
|
end
|
||||||
|
|
||||||
|
chopOrchard(ROWS, COLS)
|
Loading…
Reference in New Issue