This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
MewK's profile picture

Code Snippets: formatDay(), peripheralutils.*() & tableutils.*()

Started by MewK, 10 March 2013 - 08:20 AM
MewK #1
Posted 10 March 2013 - 09:20 AM
formatDay()

You probably all know this thing:


textutils.formatTime(os.time(), true)

Yea, me too. But I thought about how I could display os.day() in a nice way. I'm currently at day 3xxx which looks kinda boring so I thought let's convert it into a "real" date string. Because I'm kinda lazy I just ported the Minix C function (nerd) to LUA but instead of the UNIX timestamp (aka "epoch") it's using minecraft days. I just assume that minecraft has leap years etc as well simply because it would be too simple to calculate otherwise. And people that want a simple approach aren't using CC, am i right? The second parameter is the format string. The order is hardcoded to match the ISO8601 notation (YYY/MM/DD).


local function formatDays(days, format)
  local function isLeapYear(year)
	return year % 4 == 0 and (year % 100 > 0 or year % 400 == 0)
  end
  local function daysInYear(year)
	if isLeapYear(year) then
	  return 366
	end
	return 365
  end
  
  local year = 0 -- change this to start in a different year
  local mon = 1

  while days >= daysInYear(year) do
	days = days - daysInYear(year);
	year = year + 1;
  end
  
  local _temp = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  if isLeapYear(year) then
	_temp[2] = 29
  end
  
  while days >= _temp[mon] do
	days = days - _temp[mon];
	mon = mon + 1;
  end

  return string.format(format, year, mon, days + 1) -- here you can change the order of the values if you want something like DD/MM/YYYY or MM/DD/YYY
end

print(formatDays(os.day(), "%04d-%02d-%02d") -- will output something like "0008-01-16"

peripheralutils.get(type) & peripheralutils.getAll(type)


peripheralutils = {
get = function(_type)
  local _side, _peripheral = nil, nil
  for i, side in ipairs(rs.getSides()) do
   if peripheral.getType(side) == _type then
	_peripheral = peripheral.wrap(side)
	_side = side
	break
   end
  end
  return _side, _peripheral
end,

getAll = function(_type)
  local _peripherals = {}
  for i, side in ipairs(rs.getSides()) do
   if peripheral.getType(side) == _type then
	_peripheral[side] = peripheral.wrap(side)
   end
  end
  return _peripherals
end
}

The functions just get you the first peripheral of the given type or all. If you have a lot of programs using peripherals you can clean up your code quite a bit.

Usage:


local modemSide, modem = peripheralutils.get("modem")
assert(modem, "Please attach a modem to this computer.")


local nuclearReaders = peripheralutils.getAll("nuclearReader")
assert(# nuclearReaders > 0, "Please attach atleast one nuclear reader to this computer.")

tableutils.copy(), tableutils.merge(), tableutils.print(), tableutils.get(), tableutils.set()

Just a bunch of functions you would probably expect in the table-namespace. Have some recursiveness! :3


tableutils = {
copy = function(t)
  local t2
  -- table
  if type(t) == 'table' then
   t2 = {}
   for k, v in next, t, nil do
	t2[tableutils.copy(k)] = tableutils.copy(v)
   end
   setmetatable(t2, tableutils.copy(getmetatable(t)))
  
   -- number, string, boolean, etc
  else
   t2 = t
  end

  return t2
end,

merge = function(t1, t2)
  for k, v in pairs(t2) do
   -- table
   if (type(v) == "table") and (type(t1[k] or false) == "table") then
	tableutils.merge(t1[k], t2[k])
  
	-- number, string, boolean, etc
   else
	t1[k] = v
   end
  end

  return t1
end,
_print = function(t, path)
  if t and type(t) == "table" then
   for name, value in pairs(t) do
	local _path = tableutils.copy(path)
	table.insert(_path, name)
	tableutils._print(t[name], _path)
   end
  else
   print(table.concat(path, ">").."="..(t or "false"))
  end
end,
print = function(t)
  tableutils._print(t, {})
end,

get = function(t, path)
  if # path == 0 then
   return t
  end
  
  local k = path[1]

  -- table
  if type(t[k] or false) == "table" then
   local _path = tableutils.copy(path)
   table.remove(_path, 1)
   return tableutils.get(t[k], _path)

  -- number, string, boolean, etc
  else
   return t[k]
  end
end,
set = function(t, path, v)
  if # path == 0 then
   return t
  end
  local k = path[1]

  if # path == 1 then
   t[k] = v
  else
   table.remove(path, 1)
   if not t[k] or not (type(t[k] or false) == "table") then
	t[k] = {}
   end
   tableutils.merge(t[k], tableutils.set(t[k], path, v))
  end

  return t
end
}

Usage:


t_copy = tableutils.copy(t_original) -- makes a deep copy
t_new = tableutils.merge(t1, t2) -- merges t2 into t1
tableutils.print(t) -- prints the content of the table. nice for debugging
v = tableutils.get(t, {a, b, c}) -- tries to return t[a][b][c] without throwing errors if of the nodes isn't existing
tableutils.set(t, {a, b, c}, "foo") -- sets t[a][b][c] to "foo". if a or b doesn't exists it will create them.

Edit: http://xkcd.com/1179/ compliant
superaxander #2
Posted 10 March 2013 - 09:23 AM
This looks a bit like ccCalendar by TOBIT(TheOriginalBit)
theoriginalbit #3
Posted 10 March 2013 - 03:13 PM
Good job! You programmed in the 400 for the leap year, a lot of people forget that one.
MewK #4
Posted 11 March 2013 - 09:34 PM
Just added a bunch of reusable code fragments. I'm including the util-namespaces like this:


local programPath = fs.combine(shell.getRunningProgram(), "..")
shell.run(programPath.."/peripheralutils")
shell.run(programPath.."/tableutils")

That way it will work fine even when the working directory isn't set to the program folder and it doesn't load the namespaces globally like os.loadAPI would do.
superaxander #5
Posted 11 March 2013 - 10:07 PM
That's real handy