Darts (Draft)
Steps
- Construct a set of geometries representing a dartboard with individual sector scores
- Develop a model of the dart trajectory with probability density distribution
- Use integration over each geometry to determine the probabilities of particular outcomes
- Calculate expected value for the throw, repeat for other distributions to compare strategies
Note: can use @setup darts
block to hide some implementation code
# using Distributions
using Meshes
using MeshIntegrals
using Unitful
using Unitful.DefaultSymbols: mm, m
Modeling the Dartboard
Define a dartboard coordinate system
dartboard_center = Point(0m, 0m, 1.5m)
dartboard_plane = Plane(dartboard_center, Meshes.Vec(1, 0, 0))
function point(r::Unitful.Length, ϕ)
t = ustrip(r, m)
dartboard_plane(t * sin(ϕ), t * cos(ϕ))
end
point (generic function with 1 method)
Model the bullseye region
bullseye_inner = (geometry = Circle(dartboard_plane, 6.35mm), points = 50)
bullseye_outer = (geometry = Circle(dartboard_plane, 16mm), points = 25)
# TODO subtract center circle region from outer circle region -- or replace with another annular geometry
(geometry = Circle(plane: Plane(p: (x: 0.0 m, y: 0.0 m, z: 1.5 m), u: (-0.0 m, 1.0 m, -0.0 m), v: (-0.0 m, -0.0 m, 1.0 m)), radius: 16.0 mm), points = 25)
Model the sectors
# Scores on the Board
ring1 = [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5]
ring2 = 3 .* ring1
ring3 = ring1
ring4 = 2 .* ring1
board_points = hcat(ring1, ring2, ring3, ring4)
# Locations
sector_width = 2π/20
phis_a = range(0, 2π, 20) .- sector_width/2
phis_b = range(0, 2π, 20) .+ sector_width/2
phis = Iterators.zip(phis_a, phis_b)
rs = [ (16mm, 99mm), (99mm, 107mm), (107mm, 162mm), (162mm, 170mm) ]
grid = Iterators.product(phis, rs)
Base.Iterators.ProductIterator{Tuple{Base.Iterators.Zip{Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}}, Vector{Tuple{Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}}, Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}}}}}}((zip(-0.15707963267948966:0.3306939635357677:6.126105674500097, 0.15707963267948966:0.3306939635357677:6.440264939859076), Tuple{Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}}, Unitful.Quantity{Int64, 𝐋, Unitful.FreeUnits{(mm,), 𝐋, nothing}}}[(16 mm, 99 mm), (99 mm, 107 mm), (107 mm, 162 mm), (162 mm, 170 mm)]))
Define a struct to manage sector data
struct Sector{L, A}
r_inner::L
r_outer::L
phi_a::A
phi_b::A
points::Int64
end
function to_ngon(sector::Sector; N=8)
ϕs = range(sector.phi_a, sector.phi_b, length=N)
arc_o = [point(sector.r_outer, ϕ) for ϕ in ϕs]
arc_i = [point(sector.r_inner, ϕ) for ϕ in reverse(ϕs)]
return Ngon(arc_o..., arc_i...)
end
to_ngon (generic function with 1 method)
Modeling the Dart Trajectory
Define a probability distribution for where the dart will land
dist = MvNormal(μs, σs)
Integrand function is the distribution's PDF value at any particular point
function integrand(p::Point)
v_error = dist_center - p
pdf(dist, v_error)
end