Fun with Oracle SQL - Solving Checkouts in a Game of 501 Darts

AID: 3909
  • Status: Published

7614 points

  • By
  • TypeTips/Tricks
  • Posted on2010-10-07 at 15:27:44
Awards
  • Community Pick
  • Experts Exchange Approved
I like to play darts and I like SQL, so naturally I thought to myself: "How can I combine these two interests?"  It came to me while watching some professional 501 darts tournaments on TV.  As the players closed in on the finish, a little window appeared on the screen showing the player's checkout combination.  Frequently the player would choose a different strategy than what had been displayed and that's where the idea was born.

For each possible checkout score, how many checkouts are there and what are they?
Some checkouts are mathematically possible but clearly poor strategy; so I want to eliminate those and just return the list of professionally viable choices.

If this intrigues you and you'd like to give it a shot and explain your take on it, here's a forum.


First, a primer on the game of 501.



  • You start with 501 points and you race to 0.

  • Each turn you get to throw up to 3 darts.  The "checkout" is the turn where you go to exactly 0.  If you go below 0 your turn is dead and your score reverts to what it was at the beginning of your turn.

  • One dart can score anywhere from 1 to 60 (triple 20), a Bull (the most inner circle of the dart board is worth 50 and is considered a double), the ring immediately around the Bull is worth 25 and is considered a single.  Thus giving you a maximum possible score of 180 points in turn.

  • An additional caveat to this game is you must throw a double with your last dart, so the maximum possible score in a checkout is 170 (Triple-20, Triple-20 and Bull).  Similarly, the minimum score for a checkout is 2, you throw one dart for a Double-1.  Strategically it's bad to leave yourself with a D1 throw because if you accidentally miss and leave yourself a score of 1, you can't win because you can't double to hit it.

    2 and 3 are the only scores that require a D1, so I hardcoded them as special cases at the end and explicitly removed D1 from the calculations in the interesting part of the query.



So, that's the game,  the tech challenge is...



Assuming 10gR2 or higher database and using only DUAL, list all possible checkouts by the following rules:

  • Must double on final dart

  • Must use fewest number of darts (3 3 D3 is not ok, D6 is better)

  • Avoid D1 as last throw if possible

  • Avoid obviously more difficult throws for the same score
    ...don't throw doubles when a single will do  (D7 when a 14 is easier)
    ...don't throw triples when a single or double will do (T12 when D18 is easier)

  • 3-dart checkouts must be arranged so first dart is higher scoring than second dart

  • Double-25 is called a Bull

  • Final dart does determine a distinct checkout.  Thus (D19 Bull) is distinct from (Bull D19)



For presentation consistency...



  • A single-dart is represented by N, DN, TN, 25 or Bull where N is 1-20, D meaning Double, T meaning Triple

  • A multi-dart checkout consists of single darts concatenated in order of throws separated by a single space



This article started as a question but I got no takers, so the question was deleted after a month of inactivity; but I thought it was an interesting topic, so I'll try again as an article.  This is probably a better forum anyway because I'm not really interested in a "solution"; I'm more interested in the conversation and trade of ideas.

Here is my best attempt so far.

Have fun!
WITH points AS (    SELECT LEVEL p
                      FROM DUAL
                CONNECT BY LEVEL <= 20
                UNION ALL
                SELECT 25 FROM DUAL),
     ab_throws
         AS (SELECT p, m
               FROM     points
                    INNER JOIN
                        (SELECT 0 m FROM DUAL
                         UNION ALL
                         SELECT 1 FROM DUAL
                         UNION ALL
                         SELECT 2 FROM DUAL
                         UNION ALL
                         SELECT 3 FROM DUAL)
                    ON (m IN (0, 1)) OR (m = 2 AND p >= 11) 
                    OR  (m = 3 
                     AND p IN 
                             (7, 9, 11, 13, 14, 15, 16, 17, 18, 19, 20)))
SELECT n, s
  FROM (SELECT DISTINCT n, s, c
          FROM (SELECT n,
                       LTRIM(
                           CASE
                               WHEN x = 0 THEN NULL
                               WHEN x = 1 THEN TO_CHAR(a)
                               WHEN x = 2 AND a = 25 THEN 'Bull'
                               WHEN x = 2 THEN 'D' || TO_CHAR(a)
                               WHEN x = 3 THEN 'T' || TO_CHAR(a)
                           END
                           || CASE
                                  WHEN y = 0 THEN NULL
                                  WHEN y = 1 THEN ' ' || TO_CHAR(b)
                                  WHEN y = 2 AND b = 25 THEN ' Bull'
                                  WHEN y = 2 THEN ' D' || TO_CHAR(b)
                                  WHEN y = 3 THEN ' T' || TO_CHAR(b)
                              END
                           || CASE
                                  WHEN c = 25 THEN ' Bull'
                                  ELSE ' D' || TO_CHAR(c)
                              END
                       )
                           s,
                       x,
                       y,
                       a,
                       b,
                       c,
                       -- Rank by number of throws, then difficulty
                       -- Exception: Throwing multiple Bulls is difficult due to blocking/deflection
                       -- Thus, a Bull is more difficult than a triple.
                       RANK()
                       OVER (
                           PARTITION BY n
                           ORDER BY
                               (SIGN(x) + SIGN(y) + 1),
                               CASE WHEN x = 2 AND a = 25 THEN 4 ELSE x END
                               + CASE WHEN y = 2 AND b = 25 THEN 4 ELSE y END
                       )
                           r
                  FROM (    SELECT LEVEL + 3 n
                              FROM DUAL
                        CONNECT BY LEVEL < 168)
                       INNER JOIN (SELECT p a, m x FROM ab_throws)
                           ON a <= n - 4 OR x = 0
                       INNER JOIN (SELECT p b, m y FROM ab_throws)
                           ON b <= n - 4 OR y = 0
                       INNER JOIN (SELECT p c
                                     FROM points
                                    WHERE p > 1) -- avoid Double-1 as your last throw
                           ON 2 * c <= n
                 WHERE ((x * a > y * b) OR (x * a = y * b AND x = y)) -- remove unsorted duplicates
                   AND (x * a + y * b + 2 * c = n) -- throws must sum to the checkout
                                                  )
         WHERE r = 1
        UNION ALL
        SELECT 2 n, 'D1' s, 2 c FROM DUAL -- 2 requires a Double-1 as the only possible checkout
        UNION ALL
        SELECT 3 n, '1 D1' s, 2 c FROM DUAL -- 3 requires a Double-1 as the only possible checkout
        ORDER BY n, c DESC, s);
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:

Select allOpen in new window

Asked On
2010-10-07 at 15:27:44ID3909
Tags

Oracle

,

SQL

,

Darts

,

Combinatorics

Topic

Oracle Database

Views
2385

Comments

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top Oracle Database Experts

  1. slightwv

    811,605

    Sage

    12,800 points yesterday

    Profile
    Rank: Genius
  2. sdstuber

    578,296

    Sage

    3,540 points yesterday

    Profile
    Rank: Genius
  3. wasimibm

    159,939

    Guru

    2,100 points yesterday

    Profile
    Rank: Guru
  4. tosse

    83,962

    Master

    1,510 points yesterday

    Profile
    Rank: Master
  5. dvz

    77,992

    Master

    900 points yesterday

    Profile
    Rank: Sage
  6. flow01

    70,666

    Master

    0 points yesterday

    Profile
    Rank: Sage
  7. OP_Zaharin

    66,395

    Master

    0 points yesterday

    Profile
    Rank: Sage
  8. Geert_Gruwez

    66,198

    Master

    800 points yesterday

    Profile
    Rank: Genius
  9. awking00

    63,850

    Master

    0 points yesterday

    Profile
    Rank: Genius
  10. MikeOM_DBA

    55,954

    Master

    10 points yesterday

    Profile
    Rank: Genius
  11. johnsone

    46,104

    0 points yesterday

    Profile
    Rank: Genius
  12. schwertner

    43,375

    0 points yesterday

    Profile
    Rank: Genius
  13. slobaray

    42,921

    20 points yesterday

    Profile
    Rank: Master
  14. Bajwa

    35,334

    1,000 points yesterday

    Profile
  15. gatorvip

    33,868

    0 points yesterday

    Profile
    Rank: Sage
  16. praveencpk

    33,355

    0 points yesterday

    Profile
    Rank: Master
  17. sujith80

    30,896

    0 points yesterday

    Profile
    Rank: Genius
  18. sventhan

    30,548

    0 points yesterday

    Profile
    Rank: Sage
  19. markgeer

    29,292

    0 points yesterday

    Profile
    Rank: Genius
  20. paquicuba

    26,860

    0 points yesterday

    Profile
    Rank: Genius
  21. HainKurt

    24,922

    0 points yesterday

    Profile
    Rank: Genius
  22. Milleniumaire

    20,300

    0 points yesterday

    Profile
    Rank: Sage
  23. ytarkan

    17,352

    0 points yesterday

    Profile
  24. mwvisa1

    15,600

    0 points yesterday

    Profile
    Rank: Genius
  25. angelIII

    14,509

    0 points yesterday

    Profile
    Rank: Elite

Hall Of Fame