darts-value.el 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. ;;; darts-value.el --- Library for dealing with darts
  2. ;; Copyright © 2012-2014 Alex Kost
  3. ;; Author: Alex Kost <alezost@gmail.com>
  4. ;; Created: 25 Jul 2012
  5. ;; URL: https://gitlab.com/alezost-emacs/darts-value
  6. ;; This program is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; This program is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This file may be useful only for those strange people (like me) who
  18. ;; play darts and do something with their darts results using Emacs.
  19. ;; The most useful function is probably `darts-throw-string-to-points',
  20. ;; which can be used like this:
  21. ;;
  22. ;; (darts-throw-string-to-points "20 + 5 + T19") ; => 82
  23. ;; (darts-throw-string-to-points "25+t20+50") ; => 135
  24. ;; (darts-throw-string-to-points "T19" t) ; => 171
  25. ;;; Code:
  26. (require 'cl-lib)
  27. ;;; Darts
  28. (defun darts-dart-value (sector &optional segment)
  29. "Return dart value by the dart SECTOR and SEGMENT.
  30. SECTOR is a number in the range [1..20, 25].
  31. SEGMENT is a number in the range [1..3] (1 is default)."
  32. (or segment (setq segment 1))
  33. (or (and (>= segment 1) (<= segment 3))
  34. (error "%d is a wrong segment value" segment))
  35. (or (and (= sector 25) (/= segment 3))
  36. (and (>= sector 1) (<= sector 20))
  37. (error "%d is a wrong sector value" sector))
  38. (cons segment sector))
  39. (defun darts-dart-segment (dart)
  40. "Return dart segment by DART value."
  41. (car dart))
  42. (defun darts-dart-sector (dart)
  43. "Return dart sector by DART value."
  44. (cdr dart))
  45. (defun darts-dart-points (dart)
  46. "Return number of points for DART value."
  47. (* (darts-dart-segment dart)
  48. (darts-dart-sector dart)))
  49. (defun darts-darts-points (darts)
  50. "Return number of points for DARTS
  51. DARTS is a list of dart values."
  52. (apply #'+ (mapcar #'darts-dart-points darts)))
  53. (defun darts-dart-code (dart)
  54. "Return code value of DART."
  55. (+ (* 100 (darts-dart-segment dart))
  56. (darts-dart-sector dart)))
  57. (defun darts-dart-string-to-value (string)
  58. "Return dart value by STRING denoting a dart.
  59. STRING should be either \"50\" or be in a form:
  60. \"<letter><number>\", where:
  61. <segment> should be one of the following:
  62. \"\" (empty) or \"s\" - single,
  63. \"d\" - double,
  64. \"t\" - treble;
  65. <sector> should be a number in the range [1..20, 25]
  66. (\"t25\" is invalid).
  67. Examples of valid STRING values: \"12\", \"d20\", \"50\", \"T7\".
  68. Return nil if STRING contains an invalid value."
  69. (let* ((string (if (string= string "50")
  70. "d25"
  71. (downcase string)))
  72. (first-char (aref string 0))
  73. (segment (cl-case first-char
  74. (?s 1) (?d 2) (?t 3)))
  75. (sector (string-to-number
  76. (if segment (substring string 1) string)))
  77. (segment (or segment 1)))
  78. (darts-dart-value sector segment)))
  79. (defun darts-dart-string-to-points (string)
  80. "Return points of a dart STRING.
  81. See `darts-dart-string-to-value' for the meaning of STRING."
  82. (darts-dart-points (darts-dart-string-to-value string)))
  83. (defun darts-dart-string-to-code (string)
  84. "Return code value of a dart STRING.
  85. See `darts-dart-string-to-value' for the meaning of STRING."
  86. (darts-dart-code (darts-dart-string-to-value string)))
  87. ;;; Throws
  88. (defvar darts-special-throws
  89. '(("180" . "t20+t20+t20")
  90. ("177" . "t20+t20+t19")
  91. ("174" . "t20+t19+t19")
  92. ("171" . "t20+t19+t18"))
  93. "Alist of special strings for identifying throws.")
  94. (defun darts-special-throw-string (string)
  95. "Convert special throw STRING into a normal throw string.
  96. Return nil if STRING is not special."
  97. (cdr (assoc string darts-special-throws)))
  98. (defun darts-throw-value (&rest darts)
  99. "Return throw value for a throw consisting of DARTS."
  100. darts)
  101. (defun darts-throw-darts (throw)
  102. "Return darts of a THROW."
  103. throw)
  104. (defun darts-throw-points (throw)
  105. "Return number of points for THROW value."
  106. (darts-darts-points (darts-throw-darts throw)))
  107. (defun darts-throw-code (throw)
  108. "Return code value of THROW."
  109. (let* ((darts (darts-throw-darts throw))
  110. (dart-codes (mapcar #'darts-dart-code darts))
  111. (dart-codes (sort dart-codes #'>)))
  112. (mapconcat #'number-to-string dart-codes "")))
  113. (defun darts-throw-string-to-value (string &optional duplicate)
  114. "Return throw value by STRING denoting a throw.
  115. STRING should consist of 1, 2 or 3 darts (see
  116. `darts-dart-string-to-value') separated by \"+\". Also STRING
  117. may be one of special values from `darts-special-throws'.
  118. Examples: \"T17\", \"t20+t19+d7\", \"25+50\", \"177\".
  119. If DUPLICATE is non-nil and STRING consists of only one dart, it
  120. should be duplicated - i.e., the current throw is considered to
  121. consist of 3 such darts."
  122. (let* ((string (replace-regexp-in-string " " "" string)) ; remove spaces
  123. (string (or (darts-special-throw-string string)
  124. string))
  125. (dart-strings (split-string string "+"))
  126. (dart-count (length dart-strings)))
  127. (or (<= dart-count 3)
  128. (error "A throw should consist of 3 darts or less"))
  129. (let ((darts (mapcar #'darts-dart-string-to-value dart-strings)))
  130. (apply #'darts-throw-value
  131. (if (and duplicate (= 1 dart-count))
  132. (make-list 3 (car darts))
  133. darts)))))
  134. (defun darts-throw-string-to-points (string &optional duplicate)
  135. "Return points of a throw STRING.
  136. See `darts-throw-string-to-value' for the meaning of arguments."
  137. (darts-throw-points (darts-throw-string-to-value string duplicate)))
  138. (defun darts-throw-string-to-code (string &optional duplicate)
  139. "Return code value of a throw STRING.
  140. See `darts-throw-string-to-value' for the meaning of arguments."
  141. (darts-throw-code (darts-throw-string-to-value string duplicate)))
  142. (provide 'darts-value)
  143. ;;; darts-value.el ends here