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