RosettaCodeData/Task/Total-circles-area/Lua/total-circles-area-1.lua
2026-04-30 12:34:36 -04:00

105 lines
4.1 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- Import the Moses functional programming library
-- (provides map, min, max, include, etc.)
local moses = require("moses")
-- Helper: checks if any value in a table is truthy (i.e., not nil/false)
-- Used to test if a point lies inside *any* of the circles.
local function any(t)
return moses.include(t, function(v)
return v and true -- returns true as soon as one truthy element is found
end)
end
-- Factory function to create a circle object with centre `(x, y)` and radius `r`
local function newCircle(x, y, radius)
local c = {
x = x, -- x-coordinate of centre
y = y, -- y-coordinate of centre
r = radius -- radius
}
return c
end
-- Define a fixed set of 25 circles
local circles = {
newCircle( 1.6417233788, 1.6121789534, 0.0848270516),
newCircle(-1.4944608174, 1.2077959613, 1.1039549836),
newCircle( 0.6110294452, -0.6907087527, 0.9089162485),
newCircle( 0.3844862411, 0.2923344616, 0.2375743054),
newCircle(-0.2495892950, -0.3832854473, 1.0845181219),
newCircle( 1.7813504266, 1.6178237031, 0.8162655711),
newCircle(-0.1985249206, -0.8343333301, 0.0538864941),
newCircle(-1.7011985145, -0.1263820964, 0.4776976918),
newCircle(-0.4319462812, 1.4104420482, 0.7886291537),
newCircle( 0.2178372997, -0.9499557344, 0.0357871187),
newCircle(-0.6294854565, -1.3078893852, 0.7653357688),
newCircle( 1.7952608455, 0.6281269104, 0.2727652452),
newCircle( 1.4168575317, 1.0683357171, 1.1016025378),
newCircle( 1.4637371396, 0.9463877418, 1.1846214562),
newCircle(-0.5263668798, 1.7315156631, 1.4428514068),
newCircle(-1.2197352481, 0.9144146579, 1.0727263474),
newCircle(-0.1389358881, 0.1092805780, 0.7350208828),
newCircle( 1.5293954595, 0.0030278255, 1.2472867347),
newCircle(-0.5258728625, 1.3782633069, 1.3495508831),
newCircle(-0.1403562064, 0.2437382535, 1.3804956588),
newCircle( 0.8055826339, -0.0482092025, 0.3327165165),
newCircle(-0.6311979224, 0.7184578971, 0.2491045282),
newCircle( 1.4685857879, -0.8347049536, 1.3670667538),
newCircle(-0.6855727502, 1.6465021616, 1.0593087096),
newCircle( 0.0152957411, 0.0638919221, 0.9771215985)
}
-- Compute the axis-aligned bounding box that contains all circles
local xMin = moses.min(moses.map(circles, function(c)
return c.x - c.r -- leftmost point
end))
local xMax = moses.max(moses.map(circles, function(c)
return c.x + c.r -- rightmost point
end))
local yMin = moses.min(moses.map(circles, function(c)
return c.y - c.r -- bottommost point
end))
local yMax = moses.max(moses.map(circles, function(c)
return c.y + c.r -- topmost point
end))
-- Resolution of the grid: use a 500×500 pixel-like grid over the bounding box
local boxSide = 500
-- Width and height of each grid cell (pixel)
local dx = (xMax - xMin) / boxSide
local dy = (yMax - yMin) / boxSide
-- Count how many grid cells contain at least one point inside the union of circles
local count = 0
-- Iterate over each row (y-direction)
for r = 1, boxSide do
-- Compute y-coordinate at the *centre* of the current row's cell
-- Note: using `r * dy` places sample at top edge + dy, ...,
-- effectively sampling centres if we consider [0,1] indexing
-- (More precisely: samples at yMin + dy, yMin + 2*dx, ..., yMin + boxSide*dx = yMax)
local y = yMin + r * dy
-- Iterate over each column (x-direction)
for c = 1, boxSide do
-- Compute x-coordinate at the centre of the current column's cell
local x = xMin + c * dx
-- Check if the point (x, y) lies inside *any* circle:
-- For each circle, compute squared distance from (x,y) to centre
-- and compare to squared radius (to avoid `sqrt` for performance)
if any(moses.map(circles, function(circle)
return (x - circle.x) ^ 2 + (y - circle.y) ^ 2 <= circle.r ^ 2
end)) then
-- If inside at least one circle, count this grid cell
count = count + 1
end
end
end
-- Approximate area = (number of covered cells) × (area per cell)
-- This is a standard Monte Carlo / grid-based area estimation technique
print("Approximated area: "..(count*dx*dy))