# Introduction

Write a program or function that, given the coordinates of where a dart lands on a dartboard, return the score of that dart. Dart coordinates are given as two integers, x,y measured from the center of the dartboard, with millimeter precision.

## How to score a dart

Darts is a game played by throwing a dart at a circular board. The dart board is divided into 20 equally sized "wedges". Starting from the top and going clockwise, the sections have values of 20,1,18,4,13,6,10,15,2,17,3,19,7,16,8,11,14,9,12,5. If your dart lands in the black or white parts of any of the wedges, you score the value indicated on the outside of that wedge. .

However, if your dart lands in the outer green/red ring of the dartboard, you score double the points indicated on the outside of the wedge that you hit. Likewise, hitting the inner green/red ring (the one in between the two white/black sections), you score triple the number indicated on the outside of the wedge. If your dart hits the innermost circle (the red bulls-eye) you instead score 50 points and finally, if your dart hits the second-innermost circle (the green ring around the bulls-eye), you score 25 points.

The dimensions of the rings, measured from the center of the dartboard, are as follows: Bullseye (50): [0mm-6mm)
25:            [6mm-16mm)
Inner Single:  [16mm-99mm)
Triple:        [99mm-107mm)
Outer Single:  [107mm-162mm)
Double:        [162mm-170mm)
Miss (0):       170mm+


Note 1: Pictures provided are for illustration purposes only, and are not to scale.

Note 2: Measurements given are approximate, and may not be accurate to a real dartboard.

Note 3: All measurements given are [inclusive-exclusive). For the purposes of this challenge, we're not going to worry about darts hitting the wire and bouncing off. If the dart lands "on the wire" with one of the radial lines, then it is up to the answerer to decide whether to break the tie clockwise or counter-clockwise. Tie breaking direction must be consistent, and indicated.

Note 4: Dartboard is hung in the standard way with the middle of the 20 section being directly above the bullseye, and the 3 section directly below the bullseye.

# Input

Two integers representing the x,y coordinates of where the dart landed, measured in millimeters, relative to the center of the dartboard.

# Output

A single integer, for the number of points that would be awarded to a dart that landed at the given coordinates.

# Sample

0,0     -> 50
2,101   -> 60
-163,-1 -> 22
6,18    ->  1
-6,18   ->  5
45,-169 ->  0
22, 22  ->  4 (if tie-broken clock-wise)
18(if tie-broken counter-clockwise)
-150,0  ->  11
-150,-1 ->  11


## Scoring

. Fewest bytes in your source code wins.

• @Shaggy I don't see any decent reason to do so. Jun 25 '18 at 21:47
• @Shaggy Can you explain why that should be the case? Personally I would love it if my darts were always guaranteed to hit the dart board, but for the sake of the challenge, I thought it best to stick to reality over fantasy. Jun 25 '18 at 21:56
• Suggested test cases: -150,-1 and -150,0 which should both give 11 and may be an edge case on some implementations, as this is the transition between theta converging to -pi and theta = +pi in polar coordinates. (My initial answer failed on the 2nd one.) Jun 26 '18 at 8:25
• Dangit, x=y=0 is totally messing me up!! Good challenge. Jun 26 '18 at 16:22
• Hope you don't mind, I edited in a better version of the second pic. Jun 27 '18 at 15:32

# JavaScript (ES7), 137 bytes

Takes the coordinates in currying syntax (x)(y). Uses counterclockwise tie-break.

x=>y=>(r=(x*x+y*y)**.5)<6?50:r<16?25:(r<99?1:r<107?3:r<162||r<170&&2)*parseInt('b8g7j3h2fa6d4i1k5c9eb'[Math.atan2(y,x)*3.1831+10.5|0],36)


Try it online!

### How?

We translate the input Cartesian coordinates $(x,y)$ into polar coordinates $(r,\theta)$ with:

$$r=\sqrt{x^2+y^2}$$ $$\theta=\arctan_2(y,x)$$

We use $r$ to determine whether the dart is located over the Bullseye, 25, Inner Single, Triple, Outer Single, Double or if the shot is a Miss.

If we're located over a Single, Double or Triple, we use $\theta$ to determine in which sector $s$ we are with:

$$s=\left\lfloor\frac{\theta+\pi}{2\pi}\times20+\frac{1}{2}\right\rfloor=\left\lfloor\theta\times\frac{10}{\pi}+10+\frac{1}{2}\right\rfloor$$

For a $340\times340$ area, we need 4 decimal places of $10/\pi$ to get enough precision, which gives:

$$\frac{10}{\pi}\approx3.1831$$

The base scores are stored counterclockwise in a base-36 encoded string of 21 entries, starting and ending at $11$:

$$11,8,16,7,19,3,17,2,15,10,6,13,4,18,1,20,5,12,9,14,11$$

We need to repeat $11$ because half of this sector belongs to the first slice (where $\theta$ is close to $-\pi$), while the other half belongs to the last slice (where $\theta$ is close to $+\pi$).

### Graphical output

The following ES6 code snippet draws the dartboard using the same logic as in the golfed code.

for(ctx = c.getContext('2d'), y = -180; y < 180; y++) {
for(x = -180; x < 180; x++) {
r = Math.pow(x * x + y * y, 0.5);
s = Math.atan2(y, x) * 3.1831 + 10.5 | 0;

ctx.fillStyle = [ '#000', '#fff', '#be3628', '#487f45', '#bbb', '#ddd' ][
r < 6 ? 2 : r < 16 ? 3 :
(r < 99 ? 1 : r < 107 ? 3 : r < 162 ? 1 : r < 170 ? 3 : 4) ^ (s & 1)
];
ctx.fillRect(x + 180, y + 180, 1, 1);
}
}
<canvas id=c width=360 height=360 style="width:360px;height:360px" />

## JavaScript (ES6) + SVG(HTML5), 53 + 523 51 + 519 507 = 576570 558 bytes

document.write<svg width=345 height=345>;i=b=Math.PI/10;s=Math.sin(a=-b/2);c=Math.cos(a);f=(r,f,n)=>document.write(<path d=M172,172L${[172+r*s,172+r*c]}A${[r,r,0,0,1,172+r*t,172+r*d]}z fill=#${f} n=${n} />);g=(q,r,m,n,i)=>f(q,i?474:b32,n*m)+f(r,i?fff:000,n);[3,17,2,15,10,6,13,4,18,1,20,5,12,9,14,11,8,16,7,19].map(n=>{t=s;d=c;s=Math.sin(a+=b);c=Math.cos(a);g(170,162,2,n,i=!i);g(107,99,3,n,i);});document.write<circle cx=172 cy=172 r=16 fill=#474 n=25 /><circle cx=172 cy=172 r=6 fill=#b32 n=50
<body onclick=alert(+event.target.getAttributen)>

Input is via mouse click, output via alert. Edit: Saved 12 bytes by using slightly more approximate colours as suggested by @Arnauld.

• I guess nobody's going to blame you if you use b33 and 474 for red and green. :-) Jun 28 '18 at 11:43
• @Arnauld Fair enough, although b33 is bb3333 so b22 (aka bb3322) is closer to your original be3628.
– Neil
Jun 28 '18 at 12:04

# Intel 8086/8087 assembly, 180144142 138 bytes

This uses the 8087 math co-processor for all of the trig and floating-point arithmetic. All calculations are done in hardware with 80-bit floating-point precision.

df06 b101 d8c8 df06 af01 d8c8 dec1 d9fa df1e b301 8b16 b301
33c0 81fa aa00 7c03 eb53 9083 fa06 7d05 b032 eb49 9083 fa10
7d05 b019 eb3f 90df 06b7 01df 06b5 01d9 f3df 06b1 01dd d2d9
ebde f9de c9de c1df 1eb3 01a1 b301 bb9c 01d7 83fa 6b7d 0a83
fa63 7c05 b303 eb09 9081 faa2 007c 04b3 02f6 e30b 0810 0713
0311 020f 0a06 0d04 1201 1405 0c09 0e0b 0a00


Written as a MASM MACRO (basically a function), takes X and Y as coordinates and returns the calculated score in AX. The tie is broken clockwise.

MAX_BULL EQU 6
MAX_25   EQU 16
MIN_3X   EQU 99
MAX_3X   EQU 107
MIN_2X   EQU 162
MAX_2X   EQU 170

; ST = sqrt( X^2 + Y^2 )
; input: X,Y (mem16,mem16)
FILD  Y         ; ST[] = Y
FMUL  ST,ST     ; ST = y^2
FILD  X         ; ST[] = X
FMUL  ST,ST     ; ST = x^2
FADD            ; ST = ST + ST1
FSQRT           ; ST = SQRT(ST)
FISTP R         ; R = ROUND(ST)
ENDM

; cartesian coordinates to sector #
; input: X,Y (mem16,mem16)
; output: Sector (mem16)
FCSEC   MACRO X, Y, S
FILD  Y         ; ST[] = Y
FILD  X         ; ST[] = X
FPATAN          ; ST = atan2(Y,X)
FILD  CTEN      ; ST[] = 10
FST   ST(2)     ; ST(2) = 10
FLDPI           ; ST[] = pi
FDIV            ; ST = 10 / pi
FMUL            ; ST = A * ST
FADD            ; ST = ST + 10
FISTP S         ; S = ROUND(ST)
ENDM

; score the dart throw
; input: X / Y coordinates (mem16)
; output: Score (AX)
SCORE   MACRO X, Y
LOCAL IS_BULL, IS_25, IS_3X, IS_2X, MUL_SCORE, DONE
MOV  DX, FDW            ; DX = FDW = radius
XOR  AX, AX             ; score is initially 0
CMP  DX, MAX_2X         ; >= 170 (miss)
JL   IS_BULL            ; if not, check for bullseye
JMP  DONE
IS_BULL:
CMP  DX, MAX_BULL       ; < 6 (inner bullseye)
JGE  IS_25              ; if not, check for 25
MOV  AL, 50             ; score is 50
JMP  DONE
IS_25:
CMP  DX, MAX_25         ; < 16 (outer bullseye)
JGE  IS_3X              ; if not, check for triple
MOV  AL, 25             ; score is 25
JMP  DONE
IS_3X:
FCSEC X, Y, FDW         ; FDW = sector(X,Y)
MOV  AX, FDW            ; load sector # into AX
MOV  BX, OFFSET SCR     ; load base score table
XLAT                    ; put base score into AL
CMP  DX, MAX_3X         ; < 107 (triple upper bounds)
JGE  IS_2X              ; if not, check for double
CMP  DX, MIN_3X         ; >= 99 (triple lower bounds)
JL   IS_2X              ; if not, check for double
MOV  BL, 3              ; this is triple score
JMP  MUL_SCORE          ; go forth and multiply
IS_2X:
CMP  DX, MIN_2X         ; >= 162 (double lower bounds) (> 170 already checked)
JL   DONE               ; if not, single score
MOV  BL, 2              ; this is double score
MUL_SCORE:
MUL  BL                 ; multiply score either 2x or 3x
DONE:
ENDM

; DATA (place in appropriate segment)
SCR     DB  11,8,16,7,19,3,17,2,15,10,6  ; score table
DB  13,4,18,1,20,5,12,9,14,11
CTEN    DW  10      ; constant 10 to load into FPU
FDW     DW  ?       ; temp DW variable for CPU/FPU data transfer


INCLUDE DART.ASM            ; the above file
INCLUDE INDEC.ASM           ; generic I/O routines - input int
INCLUDE OUTDEC.ASM          ; generic I/O routines - output int

FINIT                   ; reset 8087

MOV  AH, 2              ; display "X" prompt
MOV  DL, 'X'
INT  21H
CALL INDEC              ; read decimal for X into AX
MOV  X, AX

MOV  AH, 2              ; display "Y" prompt
MOV  DL, 'Y'
INT  21H
CALL INDEC              ; read decimal for Y into AX
MOV  Y, AX

SCORE X, Y              ; AX = SCORE( X, Y )

CALL OUTDEC             ; display score

X   DW  ?
Y   DW  ?


## Output

Example usage of above test program. Actual IBM PC with 8087, DOSBox or your favorite emulator required.

A>DARTTEST.COM
X: 0
Y: 0
50
A>DARTTEST.COM
X: 2
Y: 101
60
A>DARTTEST.COM
X: -163
Y: -1
22
A>DARTTEST.COM
X: 6
Y: 18
1
A>DARTTEST.COM
X: -6
Y: 18
5
A>DARTTEST.COM
X: 45
Y: -169
0
A>DARTTEST.COM
X: 22
Y: 22
4
A>DARTTEST.COM
X: -150
Y: 0
11
A>DARTTEST.COM
X: -150
Y: 0
11
A>DARTTEST.COM
X: -150
Y: -1
11
A>DARTTEST.COM
X: -7
Y: -6
25
A>DARTTEST.COM
X: -90
Y: 138
24


*Edits:

• -36 bytes by removing truncate-rounding statement and 10.5 constant. Tie now broken clockwise.
• -2 bytes by removing no longer necessary FRNDINT
• -4 bytes, FMUL use same source/destination

# Jelly, 56 bytes

æA/Æ°_9:18ị“!@umÞẓẓS’Œ?¤
ḅıA<“©Ñckɱȥ‘TṂị“2ı¢¤¢£¡‘¹×>3?Ç  A monadic link accepting the pair as a list [x,y] which yields the score. Uses clockwise tie-breaking. Try it online! Or see the test-suite ### How? æA/Æ°_9:18ị“!@umÞẓẓS’Œ?¤ - Link 1, segment score: pair [x, y] / - reduce by: æA - arc tangent Æ° - convert from radians to degrees _9 - subtract 9 (align 0 with boundary between 1 & 20) :18 - integer divide by 18 (yields a segment index from 0 to 19) ¤ - nilad followed by link(s) as a nilad: “!@umÞẓẓS’ - base 250 number = 2091180117530057584 Œ? - shortest permutation of natural numbers [1..N] which - would reside at that index in a list of all permutations of - those same numbers ordered lexicographically. - = [18,4,13,6,10,15,2,17,3,19,7,16,8,11,14,9,12,5,20,1] ị - index into (yields the score associated with the segment) ḅıA<“©Ñckɱȥ‘TṂị“2ı¢¤¢£¡‘¹×>3?Ç - Main Link: segment score: pair [x, y]
ı                              - √(-1)
ḅ                               - convert from base = x+iy
A                             - absolute value = √(x²+y²)
“©Ñckɱȥ‘                    - code-page index list = [6,16,99,107,162,170]
$- ...condition: last two links as a monad: > - (override OR multiplier) greater than? 3 - three ¹ - ...then: identity (keep override as is) × - ...else: multiply (by multiplier)  # TI-Basic (TI-84 Plus CE), 147 146 bytes Prompt X,Y abs(X+iY→R int(E-12+11.5+10π-1R▸Pθ(X,Y→θ {11,8,16,7,19,3,17,2,15,10,6,13,4,18,1,20,5,12,9,14,11 25((R<6)+(R<16))+Ans(θ)(R≥16 and R<170)(1+(R≥162)+2(R≥99 and R<107  Prompts for X and Y on separate lines. Tie-breaks counter-clockwise. TI-Basic is a tokenized language; all tokens used here are one byte. Explanation: Prompt X,Y # 5 bytes, Prompt for X and Y abs(X+iY→R # 8 bytes, store distance from origin in R int(E-12+11.5+10π-1R▸Pθ(X,Y→θ # 22 bytes, store index in list of point values by polar angle in θ {11,8,16,7,19,3,17,2,15,10,6,13,4,18,1,20,5,12,9,14,11 # 55 bytes, list of point values 25((R<6)+(R<16))+Ans(θ)(R≥16 and R<170)(1+(R≥162)+2(R≥99 and R<107 # 57 56 bytes, calculate the score  Utilizes the fact that TI-Basic boolean comparisons return 0 or 1 by adding them up and multiplying by point values. # T-SQL, 392 374 366 bytes UPDATE t SET x=1WHERE x=0 SELECT TOP 1IIF(r<16,f,b*f) FROM(SELECT r=SQRT(x*x+y*y),w=FLOOR(10*ATN2(y,x)/PI()+.5)FROM t)p, (VALUES(10,11),(9,14),(8,9),(7,12),(6,5),(5,20),(4,1),(3,18),(2,4),(1,13),(0,6), (-1,10),(-2,15),(-3,2),(-4,17),(-5,3),(-6,19),(-7,7),(-8,16),(-9,8),(-10,11))s(a,b), (VALUES(6,50),(16,25),(99,1),(107,3),(162,1),(170,2),(999,0))d(e,f) WHERE a=w AND r<e  Line breaks are for readability. The initial UPDATE takes care of the x=y=0 problem that would otherwise throw an error with ATN2(), but doesn't change the score. Input is taken via pre-existing table t, per our IO guidelines. Due to using TOP 1, this table should contain only a single row. Basically I'm joining 3 tables: • Table p: The x and y from input table t are converted to polar r and a "wedge" value w representing a number from -11 to positive 11, for the scoring wedge the dart fell into. "Tie breaker" is counter-clockwise. (I tried ROUND(), which was slightly shorter, but it gave an inconsistent tie breaker.) • Table s: This is a lookup table to convert a "wedge" value a into a score b. • Table d: This is a lookup table the returns the score calculation based on the distance from the center. e is the distance and joins to r, and returns only a single row based on the TOP 1. The value f is either a fixed score (for a bulls-eye) or a multiplier for the wedge score. EDIT: Dropped the ORDER BY, it seems to work properly without it, at least on SQL 2017. I also dropped the AND y=0 on the update condition; I tested for all integer y values, changing x=0 to x=1 never changes the score. EDIT 2: Removed column g from table d, replaced it with an IIF() statement that either returns f directly (for a bulls-eye), or f*b, saved 8 bytes. Also removed the space after TOP 1. # Haskell, 198 bytes p=pure a#b=(!!(sum[1|k<-a,k<=b])) a!b=([6,16,99,107,162,170]#(sqrt$a*a+b*b))[p 50,p 25,id,(*3),id,(*2),p 0]$([pi/20,3*pi/20..6]#(pi+atan2 b a))[11,8,16,7,19,3,17,2,15,10,6,13,4,18,1,20,5,12,9,14,11]  Tie breaks counter-clockwise. (#) is a lookup function. The polar angle is used to index from the list of numbers, starting at the atan2 cutoff point at 11. The distance is used to index from the list of functions [const 50, const 25, id, (*3), id, (*2), const 0] and at last this function is applied to the number we previously got. Try it online! # Perl 5-MMath::Trig':pi' -MMath::Trig':radial' -apl, 166 bytes ($d,$a)=cartesian_to_cylindrical@F;$_=(1+($d>161||$d<6)+($d<107&&$d>98)*2)*($d<170)*($d<16?25:("6 134 181 205 129 14118 167 193 172 1510"=~/../g)[(\$a/pi*10+41/2)%20])