[ª  ªªªªª ªªª ªªª  ªªª 30333333333330333:ÀÀÀ ÀÀÀÌÀÀ ÀÀ >…?™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™îîîîîîîîîîîîîîîîîîîîîîîîîþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïþÌÌÿÿÿÿÿÏüÌÿÿÿÿÿÿÿÿÿÿÿÿÿïþÌÿüÏÌüÏÌüÿÿÌÌÏÌüÿÌÌÿÿÿÿïþÌÿüüÏüüÏüÌÏÿÌÏüÏÏÌÿÿÿÿÿïþÌÌÿüÏüüÏüÌÏÿÌÏüÏÿÏÌÿÿÿÿïàîîþÌÿüÏÌüÏÌüÌÿÌÌÏüÏÏÌüÿÿÿÿïîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîàÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿîîîîîîîîîîîîîîîîîîîîîîîîîÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÏÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÏÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÏÿÏÿÿÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿüÿÿÏüÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÏÏÿüÿÿÏÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÏÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÏÌÿüÿüÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿüÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿüÿüÏÏÿüÿÿÏÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÏÿÿÿÏÌÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÏÏÏÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÏüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÏüÿÿÿÌÿÿÿÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÏÿÿÿÿÿÿÿÿÿÿÿÿÿÌÿüÿüÿÿÏÏÿÏÏÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÏÿÏÏÿüÿÿÏÏÿüÏÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÏÿÿÿÿÿÿÿÿÿÿÿÿÿÏÿÏÏÿüÿÿÏÏÏÿÏÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÏÌÿÿÿÿÿÿÿÿÿÿÿÿÿÌÿüÏÌÿÿÏüÿÿÏüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî "-- title: Graphinator -- author: SirWobb79 (@admiralerkal79 via discord) -- desc: Graphing app made in TIC-80 with custom editor -- license: MIT License -- version: 1.1 -- script: lua -- This code feels held together with -- hopes and dreams in some areas width = 240 height = 136 width2 = width//2 height2 = height//2 -- existing math is ustilised from -- the convinient math module sqrt = math.sqrt --[[sin = math.sin cos = math.cos tan = math.tan asin = math.asin acos = math.acos atan = math.atan atan2 = math.atan2]] ln = math.log exp = math.exp abs = math.abs function sin(x) if convert then x = x * (pi/180) end return math.sin(x) end function cos(x) if convert then x = x * (pi/180) end return math.cos(x) end function tan(x) if convert then x = x * (pi/180) end return math.tan(x) end function asin(x) if convert then x = x * (pi/180) end return math.asin(x) end function acos(x) if convert then x = x * (pi/180) end return math.acos(x) end function atan(x) if convert then x = x * (pi/180) end return math.atan(x) end function atan2(y, x) if convert then x = x * (pi/180) y = y * (pi/180) end return math.atan2(y, x) end function log10(x) return ln(x)/ln(10) end function log2(x) return ln(x)/ln(2) end function logX(b, x) return ln(x)/ln(b) end -- Some required defining, like the -- extended trigonometry (secant, -- cosecant, cotangent, and their -- inverses) and other little things function xRoot(p, x) return x^(1/p) end function sec(x) return 1/cos(x) end function csc(x) return 1/sin(x) end function cot(x) return 1/tan(x) end function asec(x) return acos(1/x) end function acsc(x) return asin(1/x) end function acot(x) return atan(1/x) end snap = false convert = false pi = 3.1415926535897932384628 e = math.sinh(1)+math.cosh(1) index = 2 chars = { " ", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", "x", "+", "-", "*", "/", "^", "(", ")", ",", " ", "sqrt()", "xRoot()", "abs()", "sin()", "cos()", "tan()", "asin()", "acos()", "atan()", "atan2()", ",", " ", "sec()", "csc()", "cot()", "asec()", "acsc()", "acot()", " ", "ln()", "log10()", "log2()", "logX()", "ln()", "exp()", "fact()", ",", " ", "pi", "e", " ", "clear", " " } -- "(10/(1+(2*(x-3))^2))+(4/(1+exp(-100*(x-10))))+(sin(4*x)/(1+exp(-100*(x+5))))" expression = "1/x"--sin(pi^(x/5))-tan(x^2)"--"x/4+abs(sin(x))"--"(3*(x/5))" col = 1 zoom = 1.0 -- Zoom multiplier format_start = "(< >) " cut_start = 30 cam = {x=0, y=0} --enemy = {x=5, y=-1} edit = not false fire = false -- The following is an approximation -- for fractional factorials. I still -- don't fully get it either, don't -- worry g = 7 p = { 0.99999999999980993, 676.5203681218851, -1259.1392167224028, 771.32342877765313, -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7 } function gamma(z) if z < .5 then return pi / (sin(pi*z) * gamma(1-z)) end z = z - 1 local x = p[1] for i=2, #p do x = x + p[i] / (z+i-1) end local t = z+g+.5 return sqrt(2*pi) * t^(z+.5) * exp(-t) * x end function fact(x) if convert then x = x * (180/pi) end return gamma(x+1) end function checkchar(char, set) for i=1, #set do if char == set:sub(i, i) then return true end end return false -- char:match("["..set.."]") ~= nil end --trace(fact(0.5)) ok = true function setF() func, err = load("return function(x) return ("..expression..") end") ok = true --trace(err) if err ~= nil then --exit() func, err = load("return function(x) return (0) end") ok = false end end setF() function bracketMatch() local depth = 0 local i = 1 while i ~= #expression+1 do local c = expression:sub(i, i) if c == "(" then depth = depth + 1 end if c == ")" then depth = depth - 1 end i = i + 1 end return depth == 0 end function TIC() cls() if btnp(6) then if expression == "" then expression = "0" col = 1 end setF() --func, err = load("return function(x) return "..expression.." end") end if not err then bracketsMatch = bracketMatch() f = func() ok = pcall(f, 0) --trace(ok) -- Detect problem problem = not ok or not bracketsMatch-- or err -- FIx said problem if problem then function f(x) return 0 end end --[[if err ~= nil then f = function(x) return 0 end end]] else f = function(x) return 0 end end if expression == "" then f = function(x) return 0 end end --trace(f(1)) --local f0 = f(0) --if type(f0) ~= "number" or f0 == math.huge or f0 == -math.huge or f0 == 0/0 then f0 = 0 end --f0 = 0 local graph_origin_x = -cam.x * zoom + width2 local graph_origin_y = -cam.y * zoom + height2 line(width2-cam.x*zoom, 0, width2-cam.x*zoom, height, 15) line(0, height2-cam.y*zoom, width, height2-cam.y*zoom, 15) -- DRAW! for i = -width2+cam.x*zoom, width2+cam.x*zoom, 1 do -- Divide 1 by smt to get MORE LINES!! local x1 = i / zoom local x2 = (i + 1) / zoom --[[if convert then x1 = x1 * (pi/180) x2 = x2 * (pi/180) end]] local y1 = f(x1) local y2 = f(x2) if type(y1) ~= "number" then y1 = 0 end if type(y2) ~= "number" then y2 = 0 end line( i + graph_origin_x , - y1 * zoom + graph_origin_y , i + 1 + graph_origin_x , - y2 * zoom + graph_origin_y , 9-(tonumber(problem and 1 or 0)*7) ) --[[pix( i + graph_origin_x, - y1 * zoom + graph_origin_y, 12 )]] end -- Determine functionality in and -- out of edit mode if btnp(6) then edit = not edit end if edit then x = 5 y = height-30 w = width-10 h = 26 rect(x, y, w, h, 15) rectb(x, y, w, h, 14) rect(10, 100, 50, 9, 15) rectb(10, 100, 50, 9, 14) if not convert then print("Radians", 12, 102, 12) else print("Degrees", 12, 102, 12) end if btnp(7) then convert = not convert end format = expression if #format > cut_start then if col <= cut_start-5 then spr(256, 67+((col+5)*4), 106, 0) else spr(256, 67+((cut_start)*4), 106, 0) end format = format_start..format:sub(math.max(col-(cut_start-#format_start), 1), math.max(col, (cut_start-#format_start+1))) else spr(256, 71+((col-1)*4), 106, 0) end if #expression == 0 then col = 0 end print(" "..chars[index-1].."\n> "..chars[index].."\n "..chars[index+1], x+2, y+4, 12, true, 1, true) print("f(x) = "..format, x+38, y+10, 12, true, 1, true) print("col "..col.."/"..#expression, x+38, y+16, 12, true, 1, true) if btnp(0) and index ~= 2 then index = index - 1 end if btnp(1) and index <= #chars-2 then index = index + 1 end if btnp(2) and col ~= 1 then col = col - 1 end if btnp(3) and col ~= #expression+1 then col = col + 1 end if col > 0 then end if btnp(4) then if col == 0 then col = 1 end expression = expression:sub(1, col-1)..chars[index]..expression:sub(col) col = col + #chars[index] if chars[index] == "clear" then expression = "" end if chars[index] == "space" then expression = expression:sub(1, col-5).." "..expression:sub(col+1) col = col-(#chars[index]-1) end end if btnp(5) then --expression = expression:sub(1, col-1)..expression:sub(col+1) --if col ~= 1 then --col = col - 1 --end if #expression ~= 0 then --while checkchar(expression:sub(col, col), "qwertyuiopasdfghjklzxcvbnm") and #expression ~= 0 do --expression = expression:sub(1, col-1)..expression:sub(col+1) if col ~= 1 then col = col - 1 expression = expression:sub(1, col-1)..expression:sub(col+1) else expression = expression:sub(1, col-1)..expression:sub(col+1) --col = col - 1 end --end end end else print("X="..cam.x.."\nY="..-cam.y.."\nZoom: x"..zoom.."\nSnap to Y: "..tostring(snap), 1, 1, 12, false, 1, true) --pix(width2, height2, 3) spr(257, width2-3, height2-3, 0) if btn(0) and not snap then cam.y = cam.y - 1/zoom end if btn(1) and not snap then cam.y = cam.y + 1/zoom end if btn(2) then cam.x = cam.x - 1/zoom end if btn(3) then cam.x = cam.x + 1/zoom end if btnp(4) and zoom < 1e15 then zoom = zoom * 2 end if btnp(5) and zoom > 1e-320 then zoom = zoom / 2 end if btnp(7) then snap = not snap end if btnp(4) and btnp(5) then cam.x = 0 cam.y = 0 end end -- Because radians and degrees go -- hand in hand like a married -- couple --[[if convert then xUse = cam.x * (pi/180) else xUse = cam.x end]] -- Snap Y to f(X). Very useful for -- tracing a graph's path if snap then cam.y = -f(cam.x) end --print(tostring(-cam.y).."\n"..tostring(sin(-1)^sin(-1)), 32, 32) --if tostring(-cam.y) == tostring(-0/0) then cam.y = cam.y end origin = f(0) if type(origin) ~= type(0) then origin = 0 end --print(lineY, 0, 0, 12) end