RosettaCodeData/Task/Death-Star/Lua/death-star.lua

43 lines
1.4 KiB
Lua

function V3(x,y,z) return {x=x,y=y,z=z} end
function dot(v,w) return v.x*w.x + v.y*w.y + v.z*w.z end
function norm(v) local m=math.sqrt(dot(v,v)) return V3(v.x/m, v.y/m, v.z/m) end
function clamp(n,lo,hi) return math.floor(math.min(math.max(lo,n),hi)) end
function hittest(s, x, y)
local z = s.r^2 - (x-s.x)^2 - (y-s.y)^2
if z >= 0 then
z = math.sqrt(z)
return true, s.z-z, s.z+z
end
return false, 0, 0
end
function deathstar(pos, neg, sun, k, amb)
shades = {[0]=" ",".",":","!","*","o","e","&","#","%","@"}
for y = pos.x-pos.r-0.5, pos.x+pos.r+0.5 do
for x = pos.x-pos.r-0.5, pos.x+pos.r+0.5, 0.5 do
local hitpos, pz1, pz2 = hittest(pos, x, y)
local result, hitneg, nz1, nz2 = 0
if hitpos then
hitneg, nz1, nz2 = hittest(neg, x, y)
if not hitneg or nz1 > pz1 then result = 1
elseif nz2 > pz2 then result = 0
elseif nz2 > pz1 then result = 2
else result = 1
end
end
local shade = 0
if result > 0 then
if result == 1 then
shade = clamp((1-dot(sun, norm(V3(x-pos.x, y-pos.y, pz1-pos.z)))^k+amb) * #shades, 1, #shades)
else
shade = clamp((1-dot(sun, norm(V3(neg.x-x, neg.y-y, neg.z-nz2)))^k+amb) * #shades, 1, #shades)
end
end
io.write(shades[shade])
end
io.write("\n")
end
end
deathstar({x=20, y=20, z=0, r=20}, {x=10, y=10, z=-15, r=10}, norm(V3(-2,1,3)), 2, 0.1)