trackler 2.2.1.33 → 2.2.1.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (267) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/README.md +1 -1
  4. data/problem-specifications/exercises/palindrome-products/description.md +9 -3
  5. data/tracks/c/exercises/hamming/src/example.c +9 -8
  6. data/tracks/c/exercises/hamming/src/example.h +1 -1
  7. data/tracks/c/exercises/hamming/test/test_hamming.c +31 -7
  8. data/tracks/clojure/config.json +10 -0
  9. data/tracks/clojure/exercises/collatz-conjecture/README.md +34 -0
  10. data/tracks/clojure/exercises/collatz-conjecture/project.clj +4 -0
  11. data/tracks/clojure/exercises/collatz-conjecture/src/collatz_conjecture.clj +3 -0
  12. data/tracks/clojure/exercises/collatz-conjecture/src/example.clj +13 -0
  13. data/tracks/clojure/exercises/collatz-conjecture/test/collatz_conjecture_test.clj +29 -0
  14. data/tracks/coldfusion/.gitignore +1 -0
  15. data/tracks/coldfusion/.travis.yml +16 -4
  16. data/tracks/coldfusion/CONTRIBUTING.md +10 -0
  17. data/tracks/coldfusion/README.md +85 -6
  18. data/tracks/coldfusion/config.json +195 -10
  19. data/tracks/coldfusion/config/maintainers.json +8 -1
  20. data/tracks/coldfusion/docs/ABOUT.md +8 -0
  21. data/tracks/coldfusion/docs/EXERCISE_README_INSERT.md +15 -0
  22. data/tracks/coldfusion/docs/INSTALLATION.md +35 -0
  23. data/tracks/coldfusion/docs/LEARNING.md +37 -0
  24. data/tracks/coldfusion/docs/RESOURCES.md +29 -0
  25. data/tracks/coldfusion/docs/SNIPPET.txt +8 -0
  26. data/tracks/coldfusion/docs/TESTS.md +19 -0
  27. data/tracks/coldfusion/exercises/acronym/.meta/HINTS.md +0 -0
  28. data/tracks/coldfusion/exercises/acronym/Acronym.cfc +13 -0
  29. data/tracks/coldfusion/exercises/acronym/AcronymTest.cfc +43 -0
  30. data/tracks/coldfusion/exercises/acronym/Solution.cfc +22 -0
  31. data/tracks/coldfusion/exercises/acronym/SolutionTest.cfc +7 -0
  32. data/tracks/coldfusion/exercises/acronym/TestRunner.cfc +103 -0
  33. data/tracks/coldfusion/exercises/acronym/box.json +8 -0
  34. data/tracks/coldfusion/exercises/acronym/index.cfm +37 -0
  35. data/tracks/coldfusion/exercises/atbash-cipher/.meta/HINTS.md +0 -0
  36. data/tracks/coldfusion/exercises/atbash-cipher/AtbashCipher.cfc +14 -0
  37. data/tracks/coldfusion/exercises/atbash-cipher/AtbashCipherTest.cfc +71 -0
  38. data/tracks/coldfusion/exercises/atbash-cipher/Solution.cfc +56 -0
  39. data/tracks/coldfusion/exercises/atbash-cipher/SolutionTest.cfc +7 -0
  40. data/tracks/coldfusion/exercises/atbash-cipher/TestRunner.cfc +103 -0
  41. data/tracks/coldfusion/exercises/atbash-cipher/box.json +8 -0
  42. data/tracks/coldfusion/exercises/atbash-cipher/index.cfm +37 -0
  43. data/tracks/coldfusion/exercises/diamond/.meta/HINTS.md +0 -0
  44. data/tracks/coldfusion/exercises/diamond/Diamond.cfc +13 -0
  45. data/tracks/coldfusion/exercises/diamond/DiamondTest.cfc +35 -0
  46. data/tracks/coldfusion/exercises/diamond/Solution.cfc +35 -0
  47. data/tracks/coldfusion/exercises/diamond/SolutionTest.cfc +7 -0
  48. data/tracks/coldfusion/exercises/diamond/TestRunner.cfc +103 -0
  49. data/tracks/coldfusion/exercises/diamond/box.json +8 -0
  50. data/tracks/coldfusion/exercises/diamond/index.cfm +37 -0
  51. data/tracks/coldfusion/exercises/difference-of-squares/.meta/HINTS.md +0 -0
  52. data/tracks/coldfusion/exercises/difference-of-squares/DifferenceOfSquares.cfc +18 -0
  53. data/tracks/coldfusion/exercises/difference-of-squares/DifferenceOfSquaresTest.cfc +63 -0
  54. data/tracks/coldfusion/exercises/difference-of-squares/Solution.cfc +28 -0
  55. data/tracks/coldfusion/exercises/difference-of-squares/SolutionTest.cfc +7 -0
  56. data/tracks/coldfusion/exercises/difference-of-squares/TestRunner.cfc +103 -0
  57. data/tracks/coldfusion/exercises/difference-of-squares/box.json +8 -0
  58. data/tracks/coldfusion/exercises/difference-of-squares/index.cfm +37 -0
  59. data/tracks/coldfusion/exercises/flatten-array/.meta/HINTS.md +0 -0
  60. data/tracks/coldfusion/exercises/flatten-array/FlattenArray.cfc +13 -0
  61. data/tracks/coldfusion/exercises/flatten-array/FlattenArrayTest.cfc +42 -0
  62. data/tracks/coldfusion/exercises/flatten-array/Solution.cfc +26 -0
  63. data/tracks/coldfusion/exercises/flatten-array/SolutionTest.cfc +7 -0
  64. data/tracks/coldfusion/exercises/flatten-array/TestRunner.cfc +103 -0
  65. data/tracks/coldfusion/exercises/flatten-array/box.json +8 -0
  66. data/tracks/coldfusion/exercises/flatten-array/index.cfm +37 -0
  67. data/tracks/coldfusion/exercises/gigasecond/.meta/HINTS.md +0 -0
  68. data/tracks/coldfusion/exercises/gigasecond/Gigasecond.cfc +13 -0
  69. data/tracks/coldfusion/exercises/gigasecond/GigasecondTest.cfc +39 -0
  70. data/tracks/coldfusion/exercises/gigasecond/Solution.cfc +16 -0
  71. data/tracks/coldfusion/exercises/gigasecond/SolutionTest.cfc +7 -0
  72. data/tracks/coldfusion/exercises/gigasecond/TestRunner.cfc +103 -0
  73. data/tracks/coldfusion/exercises/gigasecond/box.json +8 -0
  74. data/tracks/coldfusion/exercises/gigasecond/index.cfm +37 -0
  75. data/tracks/coldfusion/exercises/grains/.meta/HINTS.md +0 -0
  76. data/tracks/coldfusion/exercises/grains/Grains.cfc +14 -0
  77. data/tracks/coldfusion/exercises/grains/GrainsTest.cfc +63 -0
  78. data/tracks/coldfusion/exercises/grains/Solution.cfc +22 -0
  79. data/tracks/coldfusion/exercises/grains/SolutionTest.cfc +7 -0
  80. data/tracks/coldfusion/exercises/grains/TestRunner.cfc +103 -0
  81. data/tracks/coldfusion/exercises/grains/box.json +8 -0
  82. data/tracks/coldfusion/exercises/grains/index.cfm +37 -0
  83. data/tracks/coldfusion/exercises/hamming/.meta/HINTS.md +0 -0
  84. data/tracks/coldfusion/exercises/hamming/Hamming.cfc +13 -0
  85. data/tracks/coldfusion/exercises/hamming/HammingTest.cfc +75 -0
  86. data/tracks/coldfusion/exercises/hamming/Solution.cfc +25 -0
  87. data/tracks/coldfusion/exercises/hamming/SolutionTest.cfc +7 -0
  88. data/tracks/coldfusion/exercises/hamming/TestRunner.cfc +103 -0
  89. data/tracks/coldfusion/exercises/hamming/box.json +8 -0
  90. data/tracks/coldfusion/exercises/hamming/index.cfm +37 -0
  91. data/tracks/coldfusion/exercises/hello-world/HelloWorld.cfc +13 -0
  92. data/tracks/coldfusion/exercises/hello-world/HelloWorldTest.cfc +18 -0
  93. data/tracks/coldfusion/exercises/hello-world/Solution.cfc +13 -0
  94. data/tracks/coldfusion/exercises/hello-world/SolutionTest.cfc +7 -0
  95. data/tracks/coldfusion/exercises/hello-world/TestRunner.cfc +103 -0
  96. data/tracks/coldfusion/exercises/hello-world/box.json +8 -0
  97. data/tracks/coldfusion/exercises/hello-world/index.cfm +37 -0
  98. data/tracks/coldfusion/exercises/isogram/.meta/HINTS.md +0 -0
  99. data/tracks/coldfusion/exercises/isogram/Isogram.cfc +13 -0
  100. data/tracks/coldfusion/exercises/isogram/IsogramTest.cfc +55 -0
  101. data/tracks/coldfusion/exercises/isogram/Solution.cfc +23 -0
  102. data/tracks/coldfusion/exercises/isogram/SolutionTest.cfc +7 -0
  103. data/tracks/coldfusion/exercises/isogram/TestRunner.cfc +103 -0
  104. data/tracks/coldfusion/exercises/isogram/box.json +8 -0
  105. data/tracks/coldfusion/exercises/isogram/index.cfm +37 -0
  106. data/tracks/coldfusion/exercises/largest-series-product/.meta/HINTS.md +0 -0
  107. data/tracks/coldfusion/exercises/largest-series-product/LargestSeriesProduct.cfc +13 -0
  108. data/tracks/coldfusion/exercises/largest-series-product/LargestSeriesProductTest.cfc +75 -0
  109. data/tracks/coldfusion/exercises/largest-series-product/Solution.cfc +41 -0
  110. data/tracks/coldfusion/exercises/largest-series-product/SolutionTest.cfc +7 -0
  111. data/tracks/coldfusion/exercises/largest-series-product/TestRunner.cfc +103 -0
  112. data/tracks/coldfusion/exercises/largest-series-product/box.json +8 -0
  113. data/tracks/coldfusion/exercises/largest-series-product/index.cfm +37 -0
  114. data/tracks/coldfusion/exercises/leap/Leap.cfc +15 -0
  115. data/tracks/coldfusion/exercises/leap/LeapTest.cfc +39 -0
  116. data/tracks/coldfusion/exercises/leap/Solution.cfc +19 -0
  117. data/tracks/coldfusion/exercises/leap/SolutionTest.cfc +7 -0
  118. data/tracks/coldfusion/exercises/leap/TestRunner.cfc +103 -0
  119. data/tracks/coldfusion/exercises/leap/box.json +8 -0
  120. data/tracks/coldfusion/exercises/leap/index.cfm +37 -0
  121. data/tracks/coldfusion/exercises/luhn/.meta/HINTS.md +0 -0
  122. data/tracks/coldfusion/exercises/luhn/Luhn.cfc +13 -0
  123. data/tracks/coldfusion/exercises/luhn/LuhnTest.cfc +67 -0
  124. data/tracks/coldfusion/exercises/luhn/Solution.cfc +38 -0
  125. data/tracks/coldfusion/exercises/luhn/SolutionTest.cfc +7 -0
  126. data/tracks/coldfusion/exercises/luhn/TestRunner.cfc +103 -0
  127. data/tracks/coldfusion/exercises/luhn/box.json +8 -0
  128. data/tracks/coldfusion/exercises/luhn/index.cfm +37 -0
  129. data/tracks/coldfusion/exercises/nth-prime/.meta/HINTS.md +0 -0
  130. data/tracks/coldfusion/exercises/nth-prime/NthPrime.cfc +13 -0
  131. data/tracks/coldfusion/exercises/nth-prime/NthPrimeTest.cfc +35 -0
  132. data/tracks/coldfusion/exercises/nth-prime/Solution.cfc +33 -0
  133. data/tracks/coldfusion/exercises/nth-prime/SolutionTest.cfc +7 -0
  134. data/tracks/coldfusion/exercises/nth-prime/TestRunner.cfc +103 -0
  135. data/tracks/coldfusion/exercises/nth-prime/box.json +8 -0
  136. data/tracks/coldfusion/exercises/nth-prime/index.cfm +37 -0
  137. data/tracks/coldfusion/exercises/pangram/.meta/HINTS.md +0 -0
  138. data/tracks/coldfusion/exercises/pangram/Pangram.cfc +13 -0
  139. data/tracks/coldfusion/exercises/pangram/PangramTest.cfc +55 -0
  140. data/tracks/coldfusion/exercises/pangram/Solution.cfc +21 -0
  141. data/tracks/coldfusion/exercises/pangram/SolutionTest.cfc +7 -0
  142. data/tracks/coldfusion/exercises/pangram/TestRunner.cfc +103 -0
  143. data/tracks/coldfusion/exercises/pangram/box.json +8 -0
  144. data/tracks/coldfusion/exercises/pangram/index.cfm +37 -0
  145. data/tracks/coldfusion/exercises/pig-latin/.meta/HINTS.md +0 -0
  146. data/tracks/coldfusion/exercises/pig-latin/PigLatin.cfc +13 -0
  147. data/tracks/coldfusion/exercises/pig-latin/PigLatinTest.cfc +115 -0
  148. data/tracks/coldfusion/exercises/pig-latin/Solution.cfc +30 -0
  149. data/tracks/coldfusion/exercises/pig-latin/SolutionTest.cfc +7 -0
  150. data/tracks/coldfusion/exercises/pig-latin/TestRunner.cfc +103 -0
  151. data/tracks/coldfusion/exercises/pig-latin/box.json +8 -0
  152. data/tracks/coldfusion/exercises/pig-latin/index.cfm +37 -0
  153. data/tracks/coldfusion/exercises/raindrops/.meta/HINTS.md +0 -0
  154. data/tracks/coldfusion/exercises/raindrops/Raindrops.cfc +13 -0
  155. data/tracks/coldfusion/exercises/raindrops/RaindropsTest.cfc +87 -0
  156. data/tracks/coldfusion/exercises/raindrops/Solution.cfc +33 -0
  157. data/tracks/coldfusion/exercises/raindrops/SolutionTest.cfc +7 -0
  158. data/tracks/coldfusion/exercises/raindrops/TestRunner.cfc +103 -0
  159. data/tracks/coldfusion/exercises/raindrops/box.json +8 -0
  160. data/tracks/coldfusion/exercises/raindrops/index.cfm +37 -0
  161. data/tracks/coldfusion/exercises/rna-transcription/.meta/HINTS.md +0 -0
  162. data/tracks/coldfusion/exercises/rna-transcription/RnaTranscription.cfc +13 -0
  163. data/tracks/coldfusion/exercises/rna-transcription/RnaTranscriptionTest.cfc +47 -0
  164. data/tracks/coldfusion/exercises/rna-transcription/Solution.cfc +35 -0
  165. data/tracks/coldfusion/exercises/rna-transcription/SolutionTest.cfc +7 -0
  166. data/tracks/coldfusion/exercises/rna-transcription/TestRunner.cfc +103 -0
  167. data/tracks/coldfusion/exercises/rna-transcription/box.json +8 -0
  168. data/tracks/coldfusion/exercises/rna-transcription/index.cfm +37 -0
  169. data/tracks/coldfusion/exercises/saddle-points/.meta/HINTS.md +0 -0
  170. data/tracks/coldfusion/exercises/saddle-points/SaddlePoints.cfc +13 -0
  171. data/tracks/coldfusion/exercises/saddle-points/SaddlePointsTest.cfc +35 -0
  172. data/tracks/coldfusion/exercises/saddle-points/Solution.cfc +59 -0
  173. data/tracks/coldfusion/exercises/saddle-points/SolutionTest.cfc +7 -0
  174. data/tracks/coldfusion/exercises/saddle-points/TestRunner.cfc +103 -0
  175. data/tracks/coldfusion/exercises/saddle-points/box.json +8 -0
  176. data/tracks/coldfusion/exercises/saddle-points/index.cfm +37 -0
  177. data/tracks/coldfusion/exercises/scrabble-score/.meta/HINTS.md +0 -0
  178. data/tracks/coldfusion/exercises/scrabble-score/ScrabbleScore.cfc +13 -0
  179. data/tracks/coldfusion/exercises/scrabble-score/ScrabbleScoreTest.cfc +59 -0
  180. data/tracks/coldfusion/exercises/scrabble-score/Solution.cfc +50 -0
  181. data/tracks/coldfusion/exercises/scrabble-score/SolutionTest.cfc +7 -0
  182. data/tracks/coldfusion/exercises/scrabble-score/TestRunner.cfc +103 -0
  183. data/tracks/coldfusion/exercises/scrabble-score/box.json +8 -0
  184. data/tracks/coldfusion/exercises/scrabble-score/index.cfm +37 -0
  185. data/tracks/coldfusion/exercises/secret-handshake/.meta/HINTS.md +0 -0
  186. data/tracks/coldfusion/exercises/secret-handshake/SecretHandshake.cfc +13 -0
  187. data/tracks/coldfusion/exercises/secret-handshake/SecretHandshakeTest.cfc +63 -0
  188. data/tracks/coldfusion/exercises/secret-handshake/Solution.cfc +31 -0
  189. data/tracks/coldfusion/exercises/secret-handshake/SolutionTest.cfc +7 -0
  190. data/tracks/coldfusion/exercises/secret-handshake/TestRunner.cfc +103 -0
  191. data/tracks/coldfusion/exercises/secret-handshake/box.json +8 -0
  192. data/tracks/coldfusion/exercises/secret-handshake/index.cfm +37 -0
  193. data/tracks/coldfusion/exercises/space-age/.meta/HINTS.md +0 -0
  194. data/tracks/coldfusion/exercises/space-age/Solution.cfc +28 -0
  195. data/tracks/coldfusion/exercises/space-age/SolutionTest.cfc +7 -0
  196. data/tracks/coldfusion/exercises/space-age/SpaceAge.cfc +13 -0
  197. data/tracks/coldfusion/exercises/space-age/SpaceAgeTest.cfc +47 -0
  198. data/tracks/coldfusion/exercises/space-age/TestRunner.cfc +103 -0
  199. data/tracks/coldfusion/exercises/space-age/box.json +8 -0
  200. data/tracks/coldfusion/exercises/space-age/index.cfm +37 -0
  201. data/tracks/coldfusion/exercises/sum-of-multiples/.meta/HINTS.md +0 -0
  202. data/tracks/coldfusion/exercises/sum-of-multiples/Solution.cfc +27 -0
  203. data/tracks/coldfusion/exercises/sum-of-multiples/SolutionTest.cfc +7 -0
  204. data/tracks/coldfusion/exercises/sum-of-multiples/SumOfMultiples.cfc +13 -0
  205. data/tracks/coldfusion/exercises/sum-of-multiples/SumOfMultiplesTest.cfc +63 -0
  206. data/tracks/coldfusion/exercises/sum-of-multiples/TestRunner.cfc +103 -0
  207. data/tracks/coldfusion/exercises/sum-of-multiples/box.json +8 -0
  208. data/tracks/coldfusion/exercises/sum-of-multiples/index.cfm +37 -0
  209. data/tracks/coldfusion/exercises/triangle/.meta/HINTS.md +0 -0
  210. data/tracks/coldfusion/exercises/triangle/Solution.cfc +53 -0
  211. data/tracks/coldfusion/exercises/triangle/SolutionTest.cfc +7 -0
  212. data/tracks/coldfusion/exercises/triangle/TestRunner.cfc +103 -0
  213. data/tracks/coldfusion/exercises/triangle/Triangle.cfc +18 -0
  214. data/tracks/coldfusion/exercises/triangle/TriangleTest.cfc +95 -0
  215. data/tracks/coldfusion/exercises/triangle/box.json +8 -0
  216. data/tracks/coldfusion/exercises/triangle/index.cfm +37 -0
  217. data/tracks/coldfusion/tasks/GenerateTests.cfc +179 -0
  218. data/tracks/coldfusion/tasks/ScaffoldExercise.cfc +85 -0
  219. data/tracks/coldfusion/tasks/TestAllSolutions.cfc +24 -0
  220. data/tracks/coldfusion/tasks/exercise_template/.meta/HINTS.md +0 -0
  221. data/tracks/coldfusion/tasks/exercise_template/@@name@@.cfc +13 -0
  222. data/tracks/coldfusion/tasks/exercise_template/@@name@@Test.cfc +15 -0
  223. data/tracks/coldfusion/tasks/exercise_template/Solution.cfc +6 -0
  224. data/tracks/coldfusion/tasks/exercise_template/SolutionTest.cfc +7 -0
  225. data/tracks/coldfusion/tasks/exercise_template/TestRunner.cfc +103 -0
  226. data/tracks/coldfusion/tasks/exercise_template/box.json +8 -0
  227. data/tracks/coldfusion/tasks/exercise_template/index.cfm +37 -0
  228. data/tracks/common-lisp/config.json +12 -0
  229. data/tracks/common-lisp/exercises/collatz-conjecture/README.md +84 -0
  230. data/tracks/common-lisp/exercises/collatz-conjecture/collatz-conjecture-test.lisp +31 -0
  231. data/tracks/common-lisp/exercises/collatz-conjecture/collatz-conjecture.lisp +7 -0
  232. data/tracks/common-lisp/exercises/collatz-conjecture/example.lisp +14 -0
  233. data/tracks/csharp/exercises/clock/Clock.cs +20 -4
  234. data/tracks/csharp/exercises/clock/ClockTest.cs +290 -55
  235. data/tracks/csharp/exercises/clock/Example.cs +11 -8
  236. data/tracks/csharp/generators/Exercises/Clock.cs +75 -0
  237. data/tracks/csharp/generators/Output/FormattingExtensions.cs +0 -1
  238. data/tracks/csharp/generators/Program.cs +2 -1
  239. data/tracks/haskell/config.json +10 -0
  240. data/tracks/haskell/exercises/collatz-conjecture/README.md +87 -0
  241. data/tracks/haskell/exercises/collatz-conjecture/examples/success-standard/package.yaml +16 -0
  242. data/tracks/haskell/exercises/collatz-conjecture/examples/success-standard/src/CollatzConjecture.hs +9 -0
  243. data/tracks/haskell/exercises/collatz-conjecture/package.yaml +20 -0
  244. data/tracks/haskell/exercises/collatz-conjecture/src/CollatzConjecture.hs +4 -0
  245. data/tracks/haskell/exercises/collatz-conjecture/stack.yaml +1 -0
  246. data/tracks/haskell/exercises/collatz-conjecture/test/Tests.hs +52 -0
  247. data/tracks/idris/docs/SNIPPET.txt +10 -0
  248. data/tracks/rust/README.md +83 -2
  249. data/tracks/rust/config.json +24 -0
  250. data/tracks/rust/exercises/perfect-numbers/.gitignore +7 -0
  251. data/tracks/rust/exercises/perfect-numbers/Cargo.toml +5 -0
  252. data/tracks/rust/exercises/perfect-numbers/README.md +56 -0
  253. data/tracks/rust/exercises/perfect-numbers/example.rs +20 -0
  254. data/tracks/rust/exercises/perfect-numbers/src/lib.rs +0 -0
  255. data/tracks/rust/exercises/perfect-numbers/tests/perfect-numbers.rs +33 -0
  256. data/tracks/rust/exercises/poker/.gitignore +7 -0
  257. data/tracks/rust/exercises/poker/.meta/hints.md +8 -0
  258. data/tracks/rust/exercises/poker/Cargo-example.toml +8 -0
  259. data/tracks/rust/exercises/poker/Cargo.toml +6 -0
  260. data/tracks/rust/exercises/poker/README.md +54 -0
  261. data/tracks/rust/exercises/poker/example.rs +341 -0
  262. data/tracks/rust/exercises/poker/src/lib.rs +7 -0
  263. data/tracks/rust/exercises/poker/tests/poker.rs +298 -0
  264. metadata +242 -5
  265. data/tracks/coldfusion/exercises/leap/example.cfc +0 -11
  266. data/tracks/coldfusion/exercises/leap/leap.cfc +0 -5
  267. data/tracks/coldfusion/exercises/leap/leap_tests.cfc +0 -35
@@ -167,6 +167,16 @@
167
167
  "loop"
168
168
  ]
169
169
  },
170
+ {
171
+ "uuid": "20e7d347-b80a-4656-ac34-0825126939ff",
172
+ "slug": "perfect-numbers",
173
+ "core": false,
174
+ "unlocked_by": null,
175
+ "difficulty": 4,
176
+ "topics": [
177
+ "Mathematics"
178
+ ]
179
+ },
170
180
  {
171
181
  "uuid": "543a3ca2-fb9b-4f20-a873-ff23595d41df",
172
182
  "slug": "clock",
@@ -623,6 +633,20 @@
623
633
  "topics": [
624
634
  ]
625
635
  },
636
+ {
637
+ "uuid": "0a33f3ac-cedd-4a40-a132-9d044b0e9977",
638
+ "slug": "poker",
639
+ "core": false,
640
+ "unlocked_by": null,
641
+ "difficulty": 6,
642
+ "topics": [
643
+ "lifetimes",
644
+ "struct",
645
+ "string parsing",
646
+ "enum",
647
+ "traits"
648
+ ]
649
+ },
626
650
  {
627
651
  "uuid": "f3172997-91f5-4941-a76e-91c4b8eed401",
628
652
  "slug": "anagram",
@@ -0,0 +1,7 @@
1
+ # Generated by Cargo
2
+ # will have compiled files and executables
3
+ /target/
4
+
5
+ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6
+ # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
7
+ Cargo.lock
@@ -0,0 +1,5 @@
1
+ [package]
2
+ name = "perfect_numbers"
3
+ version = "1.0.1"
4
+
5
+ [dependencies]
@@ -0,0 +1,56 @@
1
+ # Perfect Numbers
2
+
3
+ Determine if a number is perfect, abundant, or deficient based on
4
+ Nicomachus' (60 - 120 CE) classification scheme for natural numbers.
5
+
6
+ The Greek mathematician [Nicomachus](https://en.wikipedia.org/wiki/Nicomachus) devised a classification scheme for natural numbers, identifying each as belonging uniquely to the categories of **perfect**, **abundant**, or **deficient** based on their [aliquot sum](https://en.wikipedia.org/wiki/Aliquot_sum). The aliquot sum is defined as the sum of the factors of a number not including the number itself. For example, the aliquot sum of 15 is (1 + 3 + 5) = 9
7
+
8
+ - **Perfect**: aliquot sum = number
9
+ - 6 is a perfect number because (1 + 2 + 3) = 6
10
+ - 28 is a perfect number because (1 + 2 + 4 + 7 + 14) = 28
11
+ - **Abundant**: aliquot sum > number
12
+ - 12 is an abundant number because (1 + 2 + 3 + 4 + 6) = 16
13
+ - 24 is an abundant number because (1 + 2 + 3 + 4 + 6 + 8 + 12) = 36
14
+ - **Deficient**: aliquot sum < number
15
+ - 8 is a deficient number because (1 + 2 + 4) = 7
16
+ - Prime numbers are deficient
17
+
18
+ Implement a way to determine whether a given number is **perfect**. Depending on your language track, you may also need to implement a way to determine whether a given number is **abundant** or **deficient**.
19
+
20
+ ## Rust Installation
21
+
22
+ Refer to the [exercism help page][help-page] for Rust installation and learning
23
+ resources.
24
+
25
+ ## Writing the Code
26
+
27
+ Execute the tests with:
28
+
29
+ ```bash
30
+ $ cargo test
31
+ ```
32
+
33
+ All but the first test have been ignored. After you get the first test to
34
+ pass, remove the ignore flag (`#[ignore]`) from the next test and get the tests
35
+ to pass again. The test file is located in the `tests` directory. You can
36
+ also remove the ignore flag from all the tests to get them to run all at once
37
+ if you wish.
38
+
39
+ Make sure to read the [Crates and Modules](https://doc.rust-lang.org/stable/book/crates-and-modules.html) chapter if you
40
+ haven't already, it will help you with organizing your files.
41
+
42
+ ## Feedback, Issues, Pull Requests
43
+
44
+ The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the [rust track team](https://github.com/orgs/exercism/teams/rust) are happy to help!
45
+
46
+ If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md).
47
+
48
+ [help-page]: http://exercism.io/languages/rust
49
+ [crates-and-modules]: http://doc.rust-lang.org/stable/book/crates-and-modules.html
50
+
51
+ ## Source
52
+
53
+ Taken from Chapter 2 of Functional Thinking by Neal Ford. [http://shop.oreilly.com/product/0636920029687.do](http://shop.oreilly.com/product/0636920029687.do)
54
+
55
+ ## Submitting Incomplete Solutions
56
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,20 @@
1
+ pub fn classify(num: u64) -> Result<Classification, & 'static str> {
2
+ if num == 0 {
3
+ return Err("Number must be positive");
4
+ }
5
+ let sum: u64 = (1..num).filter(|i| num%i == 0).sum();
6
+ if sum == num {
7
+ Ok(Classification::Perfect)
8
+ } else if sum < num {
9
+ Ok(Classification::Deficient)
10
+ } else {
11
+ Ok(Classification::Abundant)
12
+ }
13
+ }
14
+
15
+ #[derive(Debug, PartialEq, Eq)]
16
+ pub enum Classification {
17
+ Abundant,
18
+ Perfect,
19
+ Deficient
20
+ }
File without changes
@@ -0,0 +1,33 @@
1
+ extern crate perfect_numbers;
2
+
3
+ use perfect_numbers::{Classification, classify};
4
+
5
+ #[test]
6
+ fn basic() {
7
+ assert_eq!(classify(0), Err("Number must be positive"));
8
+ }
9
+
10
+ #[test]
11
+ #[ignore]
12
+ fn test_all() {
13
+ struct TestClassification {
14
+ num: u64,
15
+ result: perfect_numbers::Classification
16
+ }
17
+ let test_table: Vec<TestClassification> = vec![
18
+ TestClassification { num: 6, result: Classification::Perfect },
19
+ TestClassification { num: 28, result: Classification::Perfect },
20
+ TestClassification { num: 33550336, result: Classification::Perfect },
21
+ TestClassification { num: 12, result: Classification::Abundant },
22
+ TestClassification { num: 30, result: Classification::Abundant },
23
+ TestClassification { num: 33550335, result: Classification::Abundant },
24
+ TestClassification { num: 2, result: Classification::Deficient },
25
+ TestClassification { num: 4, result: Classification::Deficient },
26
+ TestClassification { num: 32, result: Classification::Deficient },
27
+ TestClassification { num: 33550337, result: Classification::Deficient },
28
+ TestClassification { num: 1, result: Classification::Deficient },
29
+ ];
30
+ for t in test_table {
31
+ assert_eq!(classify(t.num), Ok(t.result));
32
+ }
33
+ }
@@ -0,0 +1,7 @@
1
+ # Generated by Cargo
2
+ # will have compiled files and executables
3
+ /target/
4
+
5
+ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6
+ # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
7
+ Cargo.lock
@@ -0,0 +1,8 @@
1
+ ## Hints
2
+
3
+ - Ranking a list of poker hands can be considered a sorting problem.
4
+ - Rust provides the [sort](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort) method for `Vec<T> where T: Ord`.
5
+ - [`Ord` types](https://doc.rust-lang.org/std/cmp/trait.Ord.html) are form a [total order](https://en.wikipedia.org/wiki/Total_order): exactly one of `a < b`, `a == b`, or `a > b` must be true.
6
+ - Poker hands do not conform to a total order: it is possible for two hands to be non-equal but have equal sort order. Example: `3S 4S 5D 6H JH"`, `"3H 4H 5C 6C JD"`.
7
+ - Rust provides the [`PartialOrd` trait](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) to handle the case of sortable things which do not have a total order. However, it doesn't provide a standard `sort` method for `Vec<T> where T: PartialOrd`. The standard idiom to sort a vector in this case is `your_vec.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::{Less|Equal|Greater}));`, depending on your needs. `
8
+ - You might consider implementing a type representing a poker hand which implements `PartialOrd`.
@@ -0,0 +1,8 @@
1
+ [package]
2
+ name = "poker"
3
+ version = "1.0.0"
4
+ authors = ["Peter Goodspeed-Niklaus <peter.r.goodspeedniklaus@gmail.com>"]
5
+
6
+ [dependencies]
7
+ try_opt = "0.1.1"
8
+ counter = "0.1.0"
@@ -0,0 +1,6 @@
1
+ [package]
2
+ name = "poker"
3
+ version = "1.0.0"
4
+ authors = ["Peter Goodspeed-Niklaus <peter.r.goodspeedniklaus@gmail.com>"]
5
+
6
+ [dependencies]
@@ -0,0 +1,54 @@
1
+ # Poker
2
+
3
+ Pick the best hand(s) from a list of poker hands.
4
+
5
+ See [wikipedia](https://en.wikipedia.org/wiki/List_of_poker_hands) for an
6
+ overview of poker hands.
7
+
8
+ ## Hints
9
+
10
+ - Ranking a list of poker hands can be considered a sorting problem.
11
+ - Rust provides the [sort](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort) method for `Vec<T> where T: Ord`.
12
+ - [`Ord` types](https://doc.rust-lang.org/std/cmp/trait.Ord.html) are form a [total order](https://en.wikipedia.org/wiki/Total_order): exactly one of `a < b`, `a == b`, or `a > b` must be true.
13
+ - Poker hands do not conform to a total order: it is possible for two hands to be non-equal but have equal sort order. Example: `3S 4S 5D 6H JH"`, `"3H 4H 5C 6C JD"`.
14
+ - Rust provides the [`PartialOrd` trait](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) to handle the case of sortable things which do not have a total order. However, it doesn't provide a standard `sort` method for `Vec<T> where T: PartialOrd`. The standard idiom to sort a vector in this case is `your_vec.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::{Less|Equal|Greater}));`, depending on your needs. `
15
+ - You might consider implementing a type representing a poker hand which implements `PartialOrd`.
16
+
17
+
18
+ ## Rust Installation
19
+
20
+ Refer to the [exercism help page][help-page] for Rust installation and learning
21
+ resources.
22
+
23
+ ## Writing the Code
24
+
25
+ Execute the tests with:
26
+
27
+ ```bash
28
+ $ cargo test
29
+ ```
30
+
31
+ All but the first test have been ignored. After you get the first test to
32
+ pass, remove the ignore flag (`#[ignore]`) from the next test and get the tests
33
+ to pass again. The test file is located in the `tests` directory. You can
34
+ also remove the ignore flag from all the tests to get them to run all at once
35
+ if you wish.
36
+
37
+ Make sure to read the [Crates and Modules](https://doc.rust-lang.org/stable/book/crates-and-modules.html) chapter if you
38
+ haven't already, it will help you with organizing your files.
39
+
40
+ ## Feedback, Issues, Pull Requests
41
+
42
+ The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the [rust track team](https://github.com/orgs/exercism/teams/rust) are happy to help!
43
+
44
+ If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md).
45
+
46
+ [help-page]: http://exercism.io/languages/rust
47
+ [crates-and-modules]: http://doc.rust-lang.org/stable/book/crates-and-modules.html
48
+
49
+ ## Source
50
+
51
+ Inspired by the training course from Udacity. [https://www.udacity.com/course/viewer#!/c-cs212/](https://www.udacity.com/course/viewer#!/c-cs212/)
52
+
53
+ ## Submitting Incomplete Solutions
54
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,341 @@
1
+ use std::fmt;
2
+ use std::cmp::Ordering;
3
+
4
+ #[macro_use]
5
+ extern crate try_opt;
6
+
7
+ extern crate counter;
8
+ use counter::Counter;
9
+
10
+ /// Given a list of poker hands, return a list of those hands which win.
11
+ ///
12
+ /// Note the type signature: this function should return _the same_ reference to
13
+ /// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
14
+ pub fn winning_hands<'a>(hands: &[&'a str]) -> Option<Vec<&'a str>> {
15
+ let mut hands = try_opt!(
16
+ hands
17
+ .iter()
18
+ .map(|source| Hand::try_from(source))
19
+ .collect::<Option<Vec<Hand>>>()
20
+ );
21
+ hands.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
22
+ hands.last().map(|last| {
23
+ hands
24
+ .iter()
25
+ .rev()
26
+ .take_while(|&item| item.partial_cmp(last) == Some(Ordering::Equal))
27
+ .map(|hand| hand.source)
28
+ .collect()
29
+ })
30
+ }
31
+
32
+ #[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy, Hash)]
33
+ enum Suit {
34
+ Spades,
35
+ Clubs,
36
+ Diamonds,
37
+ Hearts,
38
+ }
39
+
40
+ impl Suit {
41
+ fn try_from(source: &str) -> Option<Suit> {
42
+ use Suit::*;
43
+ match source {
44
+ "S" => Some(Spades),
45
+ "C" => Some(Clubs),
46
+ "D" => Some(Diamonds),
47
+ "H" => Some(Hearts),
48
+ _ => None,
49
+ }
50
+ }
51
+ }
52
+
53
+ impl fmt::Display for Suit {
54
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55
+ use Suit::*;
56
+ write!(
57
+ f,
58
+ "{}",
59
+ match *self {
60
+ Spades => "S",
61
+ Clubs => "C",
62
+ Diamonds => "D",
63
+ Hearts => "H",
64
+ }
65
+ )
66
+ }
67
+ }
68
+
69
+ #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
70
+ enum Rank {
71
+ Number(u8),
72
+ Jack,
73
+ Queen,
74
+ King,
75
+ Ace,
76
+ }
77
+
78
+ impl Rank {
79
+ fn try_from(source: &str) -> Option<Rank> {
80
+ use Rank::*;
81
+ match source {
82
+ "A" => Some(Ace),
83
+ "K" => Some(King),
84
+ "Q" => Some(Queen),
85
+ "J" => Some(Jack),
86
+ "10" => Some(Number(10)),
87
+ "9" => Some(Number(9)),
88
+ "8" => Some(Number(8)),
89
+ "7" => Some(Number(7)),
90
+ "6" => Some(Number(6)),
91
+ "5" => Some(Number(5)),
92
+ "4" => Some(Number(4)),
93
+ "3" => Some(Number(3)),
94
+ "2" => Some(Number(2)),
95
+ _ => None,
96
+ }
97
+ }
98
+
99
+ fn value(&self) -> usize {
100
+ use Rank::*;
101
+ match *self {
102
+ Ace => 14,
103
+ King => 13,
104
+ Queen => 12,
105
+ Jack => 11,
106
+ Number(n) => n as usize,
107
+ }
108
+ }
109
+ }
110
+
111
+ impl fmt::Display for Rank {
112
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113
+ use Rank::*;
114
+ let num_str; // early declaration to placate NLL of Number case
115
+ write!(
116
+ f,
117
+ "{}",
118
+ match *self {
119
+ Ace => "A",
120
+ King => "K",
121
+ Queen => "Q",
122
+ Jack => "J",
123
+ Number(n) => {
124
+ num_str = n.to_string();
125
+ &num_str
126
+ }
127
+ }
128
+ )
129
+ }
130
+ }
131
+
132
+ impl PartialOrd for Rank {
133
+ fn partial_cmp(&self, other: &Rank) -> Option<Ordering> {
134
+ Some(self.value().cmp(&other.value()))
135
+ }
136
+ }
137
+
138
+ #[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
139
+ struct Card {
140
+ rank: Rank,
141
+ suit: Suit,
142
+ }
143
+
144
+ impl Card {
145
+ fn try_from_split(source: &str, split: usize) -> Option<Card> {
146
+ Some(Card {
147
+ rank: try_opt!(Rank::try_from(&source[..split])),
148
+ suit: try_opt!(Suit::try_from(&source[split..])),
149
+ })
150
+ }
151
+
152
+ fn try_from(source: &str) -> Option<Card> {
153
+ match source.len() {
154
+ 3 => Card::try_from_split(source, 2),
155
+ 2 => Card::try_from_split(source, 1),
156
+ _ => None,
157
+ }
158
+ }
159
+ }
160
+
161
+ impl fmt::Display for Card {
162
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163
+ write!(f, "{}{}", self.rank, self.suit)
164
+ }
165
+ }
166
+
167
+ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
168
+ enum PokerHand {
169
+ HighCard,
170
+ OnePair,
171
+ TwoPair,
172
+ ThreeOfAKind,
173
+ Straight,
174
+ Flush,
175
+ FullHouse,
176
+ FourOfAKind,
177
+ StraightFlush,
178
+ }
179
+
180
+ impl PokerHand {
181
+ fn is_ace_low_straight(cards: &[Card]) -> bool {
182
+ // special case: ace-low straight
183
+ // still depends on the sorted precondition
184
+ cards[0].rank.value() == 2 && cards[4].rank == Rank::Ace &&
185
+ cards
186
+ .windows(2)
187
+ .take(3) // (0, 1), (1, 2), (2, 3) --> skips 4, ace
188
+ .map(|pair| pair[1].rank.value() - pair[0].rank.value())
189
+ .all(|diff| diff == 1)
190
+ }
191
+
192
+ fn analyze(cards: &[Card]) -> Option<PokerHand> {
193
+ if cards.len() == 5 {
194
+ let suit_counter = Counter::init(cards.iter().map(|c| c.suit));
195
+ let is_flush = suit_counter
196
+ .most_common()
197
+ .map(|(_suit, count)| count)
198
+ .next() == Some(5);
199
+ // Note that `is_straight` depends on a precondition: it only works
200
+ // if the input `cards` are sorted by rank value ascending.
201
+ let is_straight = cards
202
+ .windows(2)
203
+ .map(|pair| pair[1].rank.value() - pair[0].rank.value())
204
+ .all(|diff| diff == 1) ||
205
+ PokerHand::is_ace_low_straight(cards);
206
+
207
+ if is_flush && is_straight {
208
+ return Some(PokerHand::StraightFlush);
209
+ }
210
+
211
+ let rank_counter = Counter::init(cards.iter().map(|c| c.rank));
212
+ let mut rc_iter = rank_counter.most_common().map(|(_rank, count)| count);
213
+ let rc_most = rc_iter.next();
214
+ let rc_second = rc_iter.next();
215
+
216
+ if rc_most == Some(4) {
217
+ return Some(PokerHand::FourOfAKind);
218
+ }
219
+ if rc_most == Some(3) && rc_second == Some(2) {
220
+ return Some(PokerHand::FullHouse);
221
+ }
222
+ if is_flush {
223
+ return Some(PokerHand::Flush);
224
+ }
225
+ if is_straight {
226
+ return Some(PokerHand::Straight);
227
+ }
228
+ if rc_most == Some(3) {
229
+ return Some(PokerHand::ThreeOfAKind);
230
+ }
231
+ if rc_most == Some(2) && rc_second == Some(2) {
232
+ return Some(PokerHand::TwoPair);
233
+ }
234
+ if rc_most == Some(2) {
235
+ return Some(PokerHand::OnePair);
236
+ }
237
+ Some(PokerHand::HighCard)
238
+ } else {
239
+ None
240
+ }
241
+ }
242
+ }
243
+
244
+ #[derive(Debug, PartialEq, Eq)]
245
+ struct Hand<'a> {
246
+ source: &'a str,
247
+ cards: [Card; 5],
248
+ hand_type: PokerHand,
249
+ }
250
+
251
+ impl<'a> Hand<'a> {
252
+ fn try_from(source: &'a str) -> Option<Hand> {
253
+ let mut cards = try_opt!(
254
+ source
255
+ .split_whitespace()
256
+ .map(|s| Card::try_from(s))
257
+ .collect::<Option<Vec<Card>>>()
258
+ );
259
+ cards.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
260
+ if cards.len() == 5 {
261
+ Some(Hand {
262
+ source: source,
263
+ cards: [cards[0], cards[1], cards[2], cards[3], cards[4]],
264
+ hand_type: try_opt!(PokerHand::analyze(&cards)),
265
+ })
266
+ } else {
267
+ None
268
+ }
269
+ }
270
+
271
+ fn cmp_high_card(&self, other: &Hand, card: usize) -> Ordering {
272
+ let mut ordering = self.cards[card].rank.value().cmp(
273
+ &other.cards[card].rank.value(),
274
+ );
275
+ if card != 0 {
276
+ ordering = ordering.then_with(|| self.cmp_high_card(other, card - 1));
277
+ }
278
+ ordering
279
+ }
280
+
281
+ fn value_by_frequency(&self) -> (Option<Rank>, Option<Rank>, Option<Rank>) {
282
+ let rank_counter = Counter::init(self.cards.iter().map(|c| c.rank));
283
+ let mut rc_iter = rank_counter
284
+ .most_common_tiebreaker(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Less))
285
+ .map(|(rank, _count)| rank);
286
+ (rc_iter.next(), rc_iter.next(), rc_iter.next())
287
+ }
288
+
289
+ fn cmp_cascade_by_freq(&self, other: &Hand) -> Ordering {
290
+ let (s1, s2, s3) = self.value_by_frequency();
291
+ let (o1, o2, o3) = other.value_by_frequency();
292
+ s1.partial_cmp(&o1)
293
+ .map(|c| {
294
+ c.then(
295
+ s2.partial_cmp(&o2)
296
+ .map(|c2| c2.then(s3.partial_cmp(&o3).unwrap_or(Ordering::Equal)))
297
+ .unwrap_or(Ordering::Equal),
298
+ )
299
+ })
300
+ .unwrap_or(Ordering::Equal)
301
+ }
302
+
303
+ fn cmp_straight(&self, other: &Hand) -> Ordering {
304
+ let s = if PokerHand::is_ace_low_straight(&self.cards) {
305
+ 5
306
+ } else {
307
+ self.cards[4].rank.value()
308
+ };
309
+ let o = if PokerHand::is_ace_low_straight(&other.cards) {
310
+ 5
311
+ } else {
312
+ other.cards[4].rank.value()
313
+ };
314
+ s.cmp(&o)
315
+ }
316
+ }
317
+
318
+ impl<'a> fmt::Display for Hand<'a> {
319
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320
+ write!(f, "{}", self.source)
321
+ }
322
+ }
323
+
324
+ impl<'a> PartialOrd for Hand<'a> {
325
+ fn partial_cmp(&self, other: &Hand) -> Option<Ordering> {
326
+ Some(self.hand_type.cmp(&other.hand_type).then_with(|| {
327
+ use PokerHand::*;
328
+ match self.hand_type {
329
+ HighCard => self.cmp_high_card(other, 4),
330
+ OnePair => self.cmp_cascade_by_freq(other),
331
+ TwoPair => self.cmp_cascade_by_freq(other),
332
+ ThreeOfAKind => self.cmp_cascade_by_freq(other),
333
+ Straight => self.cmp_straight(other),
334
+ Flush => self.cmp_high_card(other, 4),
335
+ FullHouse => self.cmp_cascade_by_freq(other),
336
+ FourOfAKind => self.cmp_cascade_by_freq(other),
337
+ StraightFlush => self.cmp_straight(other),
338
+ }
339
+ }))
340
+ }
341
+ }