· 4 years ago · Jan 12, 2021, 10:52 PM
1local json = { _version = "0.1.2" }
2
3-------------------------------------------------------------------------------
4-- Encode
5-------------------------------------------------------------------------------
6
7local encode
8
9local escape_char_map = {
10 [ "\\" ] = "\\",
11 [ "\"" ] = "\"",
12 [ "\b" ] = "b",
13 [ "\f" ] = "f",
14 [ "\n" ] = "n",
15 [ "\r" ] = "r",
16 [ "\t" ] = "t",
17}
18
19local escape_char_map_inv = { [ "/" ] = "/" }
20for k, v in pairs(escape_char_map) do
21 escape_char_map_inv[v] = k
22end
23
24
25local function escape_char(c)
26 return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
27end
28
29
30local function encode_nil(val)
31 return "null"
32end
33
34
35local function encode_table(val, stack)
36 local res = {}
37 stack = stack or {}
38
39 -- Circular reference?
40 if stack[val] then error("circular reference") end
41
42 stack[val] = true
43
44 if rawget(val, 1) ~= nil or next(val) == nil then
45 -- Treat as array -- check keys are valid and it is not sparse
46 local n = 0
47 for k in pairs(val) do
48 if type(k) ~= "number" then
49 error("invalid table: mixed or invalid key types")
50 end
51 n = n + 1
52 end
53 if n ~= #val then
54 error("invalid table: sparse array")
55 end
56 -- Encode
57 for i, v in ipairs(val) do
58 table.insert(res, encode(v, stack))
59 end
60 stack[val] = nil
61 return "[" .. table.concat(res, ",") .. "]"
62
63 else
64 -- Treat as an object
65 for k, v in pairs(val) do
66 if type(k) ~= "string" then
67 error("invalid table: mixed or invalid key types")
68 end
69 table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
70 end
71 stack[val] = nil
72 return "{" .. table.concat(res, ",") .. "}"
73 end
74end
75
76
77local function encode_string(val)
78 return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
79end
80
81
82local function encode_number(val)
83 -- Check for NaN, -inf and inf
84 if val ~= val or val <= -math.huge or val >= math.huge then
85 error("unexpected number value '" .. tostring(val) .. "'")
86 end
87 return string.format("%.14g", val)
88end
89
90
91local type_func_map = {
92 [ "nil" ] = encode_nil,
93 [ "table" ] = encode_table,
94 [ "string" ] = encode_string,
95 [ "number" ] = encode_number,
96 [ "boolean" ] = tostring,
97}
98
99
100encode = function(val, stack)
101 local t = type(val)
102 local f = type_func_map[t]
103 if f then
104 return f(val, stack)
105 end
106 error("unexpected type '" .. t .. "'")
107end
108
109
110function json.encode(val)
111 return ( encode(val) )
112end
113
114
115-------------------------------------------------------------------------------
116-- Decode
117-------------------------------------------------------------------------------
118
119local parse
120
121local function create_set(...)
122 local res = {}
123 for i = 1, select("#", ...) do
124 res[ select(i, ...) ] = true
125 end
126 return res
127end
128
129local space_chars = create_set(" ", "\t", "\r", "\n")
130local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
131local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
132local literals = create_set("true", "false", "null")
133
134local literal_map = {
135 [ "true" ] = true,
136 [ "false" ] = false,
137 [ "null" ] = nil,
138}
139
140
141local function next_char(str, idx, set, negate)
142 for i = idx, #str do
143 if set[str:sub(i, i)] ~= negate then
144 return i
145 end
146 end
147 return #str + 1
148end
149
150
151local function decode_error(str, idx, msg)
152 local line_count = 1
153 local col_count = 1
154 for i = 1, idx - 1 do
155 col_count = col_count + 1
156 if str:sub(i, i) == "\n" then
157 line_count = line_count + 1
158 col_count = 1
159 end
160 end
161 error( string.format("%s at line %d col %d", msg, line_count, col_count) )
162end
163
164
165local function codepoint_to_utf8(n)
166 -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
167 local f = math.floor
168 if n <= 0x7f then
169 return string.char(n)
170 elseif n <= 0x7ff then
171 return string.char(f(n / 64) + 192, n % 64 + 128)
172 elseif n <= 0xffff then
173 return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
174 elseif n <= 0x10ffff then
175 return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
176 f(n % 4096 / 64) + 128, n % 64 + 128)
177 end
178 error( string.format("invalid unicode codepoint '%x'", n) )
179end
180
181
182local function parse_unicode_escape(s)
183 local n1 = tonumber( s:sub(1, 4), 16 )
184 local n2 = tonumber( s:sub(7, 10), 16 )
185 -- Surrogate pair?
186 if n2 then
187 return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
188 else
189 return codepoint_to_utf8(n1)
190 end
191end
192
193
194local function parse_string(str, i)
195 local res = ""
196 local j = i + 1
197 local k = j
198
199 while j <= #str do
200 local x = str:byte(j)
201
202 if x < 32 then
203 decode_error(str, j, "control character in string")
204
205 elseif x == 92 then -- `\`: Escape
206 res = res .. str:sub(k, j - 1)
207 j = j + 1
208 local c = str:sub(j, j)
209 if c == "u" then
210 local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
211 or str:match("^%x%x%x%x", j + 1)
212 or decode_error(str, j - 1, "invalid unicode escape in string")
213 res = res .. parse_unicode_escape(hex)
214 j = j + #hex
215 else
216 if not escape_chars[c] then
217 decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
218 end
219 res = res .. escape_char_map_inv[c]
220 end
221 k = j + 1
222
223 elseif x == 34 then -- `"`: End of string
224 res = res .. str:sub(k, j - 1)
225 return res, j + 1
226 end
227
228 j = j + 1
229 end
230
231 decode_error(str, i, "expected closing quote for string")
232end
233
234
235local function parse_number(str, i)
236 local x = next_char(str, i, delim_chars)
237 local s = str:sub(i, x - 1)
238 local n = tonumber(s)
239 if not n then
240 decode_error(str, i, "invalid number '" .. s .. "'")
241 end
242 return n, x
243end
244
245
246local function parse_literal(str, i)
247 local x = next_char(str, i, delim_chars)
248 local word = str:sub(i, x - 1)
249 if not literals[word] then
250 decode_error(str, i, "invalid literal '" .. word .. "'")
251 end
252 return literal_map[word], x
253end
254
255
256local function parse_array(str, i)
257 local res = {}
258 local n = 1
259 i = i + 1
260 while 1 do
261 local x
262 i = next_char(str, i, space_chars, true)
263 -- Empty / end of array?
264 if str:sub(i, i) == "]" then
265 i = i + 1
266 break
267 end
268 -- Read token
269 x, i = parse(str, i)
270 res[n] = x
271 n = n + 1
272 -- Next token
273 i = next_char(str, i, space_chars, true)
274 local chr = str:sub(i, i)
275 i = i + 1
276 if chr == "]" then break end
277 if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
278 end
279 return res, i
280end
281
282
283local function parse_object(str, i)
284 local res = {}
285 i = i + 1
286 while 1 do
287 local key, val
288 i = next_char(str, i, space_chars, true)
289 -- Empty / end of object?
290 if str:sub(i, i) == "}" then
291 i = i + 1
292 break
293 end
294 -- Read key
295 if str:sub(i, i) ~= '"' then
296 decode_error(str, i, "expected string for key")
297 end
298 key, i = parse(str, i)
299 -- Read ':' delimiter
300 i = next_char(str, i, space_chars, true)
301 if str:sub(i, i) ~= ":" then
302 decode_error(str, i, "expected ':' after key")
303 end
304 i = next_char(str, i + 1, space_chars, true)
305 -- Read value
306 val, i = parse(str, i)
307 -- Set
308 res[key] = val
309 -- Next token
310 i = next_char(str, i, space_chars, true)
311 local chr = str:sub(i, i)
312 i = i + 1
313 if chr == "}" then break end
314 if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
315 end
316 return res, i
317end
318
319
320local char_func_map = {
321 [ '"' ] = parse_string,
322 [ "0" ] = parse_number,
323 [ "1" ] = parse_number,
324 [ "2" ] = parse_number,
325 [ "3" ] = parse_number,
326 [ "4" ] = parse_number,
327 [ "5" ] = parse_number,
328 [ "6" ] = parse_number,
329 [ "7" ] = parse_number,
330 [ "8" ] = parse_number,
331 [ "9" ] = parse_number,
332 [ "-" ] = parse_number,
333 [ "t" ] = parse_literal,
334 [ "f" ] = parse_literal,
335 [ "n" ] = parse_literal,
336 [ "[" ] = parse_array,
337 [ "{" ] = parse_object,
338}
339
340
341parse = function(str, idx)
342 local chr = str:sub(idx, idx)
343 local f = char_func_map[chr]
344 if f then
345 return f(str, idx)
346 end
347 decode_error(str, idx, "unexpected character '" .. chr .. "'")
348end
349
350
351function json.decode(str)
352 if type(str) ~= "string" then
353 error("expected argument of type string, got " .. type(str))
354 end
355 local res, idx = parse(str, next_char(str, 1, space_chars, true))
356 idx = next_char(str, idx, space_chars, true)
357 if idx <= #str then
358 decode_error(str, idx, "trailing garbage")
359 end
360 return res
361end
362
363--[[
364plans:
365- mine directly up/down to y 11 on startup
366- if any surrounding blocks are diamond ore, coal ore, gold ore, emerald ore
367 - create path to find and mine all blocks
368 - return to original point when finished and continue mining forward
369 - ignore all other blocks and continue mining forward
370- convert items to blocks for more inventory space
371- when inventory is full, add all items to ender chest for easy access at base
372- when ender chest is full, keep waiting until space appears before continuing to mine
373
374issues:
375- current orientation/position cannot be accessed, must store myself upon startup
376- can't detect block in front of turtle :/
377]]
378
379local importantBlocks = {
380 "minecraft:diamond",
381 "minecraft:emerald",
382 "minecraft:coal",
383 "minecraft:iron_ore",
384 "minecraft:gold_ore",
385 "minecraft:redstone",
386 "minecraft:lapis_lazuli"
387}
388
389local inspections = {
390 {""},
391 {"Down"},
392 {"Up"},
393 {0, "", 1},
394 {1, "", 0}
395}
396
397local yPosition = 11
398local direction = 0 -- 0 to 3
399
400local function removeUnimportantBlocks()
401 for slot = 1, 16 do
402 turtle.select(slot)
403 local block = turtle.getItemDetail()
404 if block then
405 print(json.encode(block))
406 if not importantBlocks[block.name] then
407 turtle.drop()
408 end
409 end
410 end
411end
412
413local function mineBlocks()
414 for _, inspectionList in pairs(inspections) do
415 for _, instruction in pairs(inspectionList) do
416 if tonumber(instruction) then
417 if instruction == 0 then
418 turtle.turnLeft()
419 else
420 turtle.turnRight()
421 end
422 else
423 local exists, block = turtle["inspect" .. instruction]()
424 if exists then
425 turtle["dig" .. instruction]()
426 end
427 end
428 end
429 end
430end
431
432while true do
433 mineBlocks()
434 turtle.suck()
435 removeUnimportantBlocks()
436 turtle.forward()
437end