Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Grapher, By Symmetryc
- -- Buffer
- local max_x, max_y = term.getSize()
- local function copy(_t, _loc)
- local t = _loc or {}
- for k, v in pairs(_t) do
- t[k] = type(v) == "table" and copy(v) or v
- end
- return t
- end
- local equal = function(_t1, _t2)
- for i = 1, 3 do
- if _t1[i] ~= _t2[i] then
- return false
- end
- end
- return true
- end
- local round = function(_n)
- return math.floor(_n + 0.5)
- end
- local index = function(_t)
- return function(self, key)
- self[key] = setmetatable({}, {
- __index = function(self2, key2)
- self2[key2] = copy(_t)
- return self2[key2]
- end;
- })
- return self[key]
- end
- end
- local cache, buffer
- buffer = {
- init = function(_t)
- cache = setmetatable({}, {
- __index = index(_t)
- })
- end;
- new_fn = function(_f, _color)
- return setmetatable(buffer.new(), {
- __index = function(self, key)
- self[key] = setmetatable({}, {
- __index = function(self2, key2)
- self2[key2] = setmetatable({}, {
- __index = function(self3, key3)
- return round(_f(key)) == key2 and (key3 == 1 and _color or key3 == 3 and (cache[key][key2][3] or " ")) or nil
- end;
- })
- return self2[key2]
- end;
- })
- return self[key]
- end;
- })
- end;
- new = function()
- return setmetatable(
- {
- rect = function(self, _x, _y, _x2, _y2, _color)
- for x = _x, _x2 do
- for y = _y, _y2 do
- local pixel = self[x][y]
- pixel[1] = _color
- pixel[3] = pixel[3] or " "
- end
- end
- return self
- end;
- line = function(self, _x, _y, _x2, _y2, _color, _int)
- if _x - _x2 == 0 or _y - _y2 == 0 then
- return self:rect(_x, _y, _x2, _y2, _color)
- end
- local slope = (_y - _y2) / (_x - _x2)
- local y_int = _y - (_x * slope)
- local f = function(x)
- return x * slope + y_int
- end
- return self:fn(f, _x, _x2, _color, _int or 1/slope)
- end;
- write = function(self, _x, _y, _text, _color, _back)
- local i = 0
- for x = _x, _x + #_text - 1 do
- i = i + 1
- local pixel = self[x][_y]
- pixel[1] = _back or pixel[1]
- pixel[2] = _color or pixel[2]
- pixel[3] = _text:sub(i, i)
- end
- end;
- draw = function(self)
- buffer.draw(self:render())
- return self
- end;
- render = function(self)
- local screen = setmetatable({}, {__index = index({})})
- for x = 1, max_x do
- local t1, t2, t3 = screen[x], self[x], cache[x]
- for y = 1, max_y do
- local p1, p2, p3 = t1[y], t2[y], t3[y]
- for i = 1, 3 do
- p1[i] = p2[i] or p3[i]
- end
- end
- end
- return screen
- end;
- },
- {
- __index = index({});
- }
- )
- end;
- draw = function(_t)
- local pos_x, pos_y = term.getCursorPos()
- local ins = {"setBackgroundColor", "setTextColor", "write"}
- for x = 1, max_x do
- local t1, t2 = _t[x], cache[x]
- for y = 1, max_y do
- local p1, p2 = t1[y], t2[y]
- if not equal(p1, p2) then
- term.setCursorPos(x, y)
- for i = 1, 3 do
- term[ins[i]](p1[i] or p2[i])
- p2[i] = p1[i]
- end
- end
- end
- end
- term.setCursorPos(pos_x, pos_y)
- return _t
- end;
- }
- -- General
- local x, y = term.getSize()
- buffer.init({colors.white, colors.lightGray, " "})
- term.setBackgroundColor(colors.white)
- term.clear()
- -- help Buffer
- local help = buffer.new()
- help:line(3, y - 1, x - 1, y - 1, colors.black)
- help:line(x - 1, 3, x - 1, y - 1, colors.black)
- help:rect(2, 2, x - 2, y - 2, colors.lightBlue)
- help:write(math.floor(x / 2 - 2), 3, "Help", colors.white)
- local help_text = {
- "^ + H : Help";
- "^ + Q : Quit";
- "^ + WASD : Move Grid";
- "Arrow Up / Down : Change Function Number";
- "Enter : Render Graph";
- "Scroll : Change Zoom";
- "Normal Text : Creating Functions";
- "*Note* When creating functions, you can not";
- "only use normal math i.e. \"f(01) = x ^ 2 * 3\",";
- "but you can also use any standard Lua Math";
- "Library functions by omitting the \"math.\"";
- "i.e. \"f(02) = atan2(x, x^2) + sin(abs(x))\"";
- }
- for i = 1, #help_text do
- help:write(4, i + 4, help_text[i], colors[i < 8 and "white" or "red"])
- end
- help = help:render()
- -- grid Buffer
- local grid = buffer.new()
- local chars = {{" ", "-"}, {"|", "+"}}
- for i = 1, x do
- for j = 1, y - 2 do
- grid[i][j] = {colors.white, colors.lightGray, chars[i % 2 == 0 and 1 or 2][j % 2 == 0 and 1 or 2]}
- end
- end
- grid[1][1] = {colors.white, colors.black, "#"}
- grid:write(1, y - 1, ("-"):rep(x), colors.black, colors.white)
- grid = grid:render()
- -- Setting Up Graph
- local input = buffer.new()
- local color = {
- colors.lime;
- colors.lightBlue;
- colors.orange;
- colors.magenta;
- colors.yellow;
- colors.red;
- }
- local flist = {}
- local f = 1
- for i = 1, 99 do
- flist[i] = ""
- end
- local graph = {
- new = function(self, _str, _n)
- local func = loadstring("return ".._str:gsub("(%a%w+)", "math.%1"))
- if not func then
- flist[_n] = "error!"
- self.cursor = 0
- self:update_info()
- return
- end
- self[_n] = buffer.new_fn(function(input_x)
- return setfenv(func, {
- x = (input_x + self.pos[1] - 1) / self.zoom;
- math = _G.math;
- })() * -self.zoom + self.pos[2] + 1
- end, color[_n % #color])
- self:draw()
- end;
- zoom = 1;
- pos = {0, 0};
- cursor = 0;
- cursor_pos = function(self)
- return #self:info_str() - #flist[f] + self.cursor + 1
- end;
- info_str = function(self)
- return "("..self.pos[1]..","..self.pos[2]..") | 1:"..self.zoom.." | f("..("0"):rep(2 - #(f..""))..f..")="..flist[f]
- end;
- update_info = function(self)
- local info = x - #self:info_str()
- input:write(1, y, self:info_str()..(" "):rep(info > 0 and info or 0), colors.black)
- input:draw()
- end;
- draw = function(self)
- buffer.draw(grid)
- for k, v in pairs(self) do
- if type(v) == "table" and v.draw then
- flist[k] = pcall(v.draw, v) and flist[k] or "error!"
- end
- end
- self.cursor = 0
- self:update_info()
- end;
- draw_help = function(self)
- term.setCursorBlink(false)
- buffer.draw(help)
- os.pullEvent("mouse_click")
- buffer.draw(grid)
- self:draw()
- term.setCursorBlink(true)
- end;
- }
- -- Actual Program
- graph:draw_help()
- local main = function()
- while true do
- term.setCursorPos(graph:cursor_pos(), y)
- os.queueEvent("")
- os.pullEvent()
- local event, p1, p2, p3 = os.pullEvent()
- if event == "mouse_scroll" then
- graph.zoom = graph.zoom * 2 ^ p1
- graph:draw()
- elseif event == "key" then
- os.startTimer(0)
- local e1, e2 = os.pullEvent()
- if e1 == "char" and os.pullEvent("timer") then
- flist[f] = flist[f]:sub(1, graph.cursor)..e2..flist[f]:sub(graph.cursor + 1)
- graph.cursor = graph.cursor + 1
- graph:update_info()
- else
- if p1 == keys.backspace and graph.cursor > 0 then
- flist[f] = flist[f]:sub(1, graph.cursor - 1)..flist[f]:sub(graph.cursor + 1)
- graph.cursor = graph.cursor - 1
- graph:update_info()
- elseif p1 == keys.up and f < 99 or p1 == keys.down and f > 1 then
- f = f + (p1 == keys.up and 1 or -1)
- graph.cursor = 0
- graph:update_info()
- elseif p1 == keys.enter then
- graph:new(flist[f], f)
- elseif p1 == keys.right and graph.cursor < #flist[f] or p1 == keys.left and graph.cursor > 0 then
- graph.cursor = graph.cursor + (p1 == keys.right and 1 or -1)
- elseif p1 == keys.q then
- term.setCursorBlink(false)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.lightBlue)
- local end_text = "Thank you for using Grapher!"
- term.clear()
- term.setCursorPos((x - #end_text) / 2, 1)
- print(end_text)
- break
- elseif p1 == keys.h then
- graph:draw_help()
- elseif p1 == keys.a or p1 == keys.d or p1 == keys.s or p1 == keys.w then
- graph.pos[1] = graph.pos[1] + (p1 == keys.a and -1 or p1 == keys.d and 1 or 0)
- graph.pos[2] = graph.pos[2] + (p1 == keys.s and -1 or p1 == keys.w and 1 or 0)
- graph:draw()
- end
- end
- end
- end
- end
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement