trackler 2.2.1.53 → 2.2.1.54

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/nth-prime/canonical-data.json +2 -7
  4. data/problem-specifications/exercises/zebra-puzzle/canonical-data.json +16 -0
  5. data/tracks/c/config.json +11 -1
  6. data/tracks/c/docs/C_STYLE_GUIDE.md +142 -0
  7. data/tracks/c/exercises/collatz-conjecture/README.md +65 -0
  8. data/tracks/c/exercises/collatz-conjecture/makefile +15 -0
  9. data/tracks/c/exercises/collatz-conjecture/src/collatz_conjecture.h +8 -0
  10. data/tracks/c/exercises/collatz-conjecture/src/example.c +23 -0
  11. data/tracks/c/exercises/collatz-conjecture/test/test_collatz_conjecture.c +48 -0
  12. data/tracks/c/exercises/collatz-conjecture/test/vendor/unity.c +1300 -0
  13. data/tracks/c/exercises/collatz-conjecture/test/vendor/unity.h +274 -0
  14. data/tracks/c/exercises/collatz-conjecture/test/vendor/unity_internals.h +701 -0
  15. data/tracks/cfml/tasks/GenerateReadme.cfc +5 -5
  16. data/tracks/erlang/testgen/src/testgen.erl +99 -17
  17. data/tracks/erlang/testgen/src/tg_file_tools.erl +3 -3
  18. data/tracks/erlang/testgen/src/tgen.erl +15 -7
  19. data/tracks/haskell/config.json +15 -3
  20. data/tracks/java/scripts/canonical_data_check.sh +1 -1
  21. data/tracks/javascript/config.json +12 -0
  22. data/tracks/javascript/exercises/difference-of-squares/README.md +1 -1
  23. data/tracks/javascript/exercises/sum-of-multiples/README.md +1 -1
  24. data/tracks/javascript/exercises/zipper/README.md +55 -0
  25. data/tracks/javascript/exercises/zipper/example.js +100 -0
  26. data/tracks/javascript/exercises/zipper/zipper.spec.js +77 -0
  27. data/tracks/julia/config.json +12 -0
  28. data/tracks/julia/exercises/triangle/README.md +30 -0
  29. data/tracks/julia/exercises/triangle/example.jl +25 -0
  30. data/tracks/julia/exercises/triangle/runtests.jl +64 -0
  31. data/tracks/julia/exercises/triangle/triangle.jl +8 -0
  32. data/tracks/kotlin/exercises/leap/.meta/version +1 -1
  33. data/tracks/kotlin/exercises/leap/src/test/kotlin/LeapTest.kt +1 -1
  34. data/tracks/kotlin/scripts/canonical_data_check.sh +1 -1
  35. data/tracks/perl6/bin/README.md +1 -4
  36. data/tracks/perl6/bin/exercise-gen.pl6 +3 -4
  37. data/tracks/perl6/exercises/accumulate/example.yaml +2 -2
  38. data/tracks/perl6/exercises/all-your-base/example.yaml +9 -9
  39. data/tracks/perl6/exercises/allergies/example.yaml +7 -7
  40. data/tracks/perl6/exercises/anagram/example.yaml +3 -3
  41. data/tracks/perl6/exercises/atbash-cipher/example.yaml +3 -3
  42. data/tracks/perl6/exercises/bob/example.yaml +4 -4
  43. data/tracks/perl6/exercises/clock/example.yaml +6 -6
  44. data/tracks/perl6/exercises/flatten-array/example.yaml +4 -4
  45. data/tracks/perl6/exercises/grade-school/example.yaml +6 -6
  46. data/tracks/perl6/exercises/grains/example.yaml +3 -3
  47. data/tracks/perl6/exercises/hello-world/example.yaml +5 -5
  48. data/tracks/perl6/exercises/leap/example.yaml +4 -4
  49. data/tracks/perl6/exercises/linked-list/example.yaml +14 -14
  50. data/tracks/perl6/exercises/luhn/example.yaml +3 -3
  51. data/tracks/perl6/exercises/phone-number/example.yaml +3 -3
  52. data/tracks/perl6/exercises/raindrops/example.yaml +3 -3
  53. data/tracks/perl6/exercises/rna-transcription/example.yaml +3 -3
  54. data/tracks/perl6/exercises/robot-name/example.yaml +8 -8
  55. data/tracks/perl6/exercises/scrabble-score/example.yaml +3 -3
  56. data/tracks/perl6/exercises/space-age/example.yaml +8 -8
  57. data/tracks/perl6/exercises/word-count/example.yaml +3 -3
  58. data/tracks/perl6/exercises/wordy/example.yaml +3 -3
  59. data/tracks/python/config.json +14 -0
  60. data/tracks/python/config/maintainers.json +30 -0
  61. data/tracks/python/docs/EXERCISE_README_INSERT.md +1 -2
  62. data/tracks/python/exercises/accumulate/README.md +1 -5
  63. data/tracks/python/exercises/acronym/README.md +1 -3
  64. data/tracks/python/exercises/all-your-base/README.md +2 -3
  65. data/tracks/python/exercises/all-your-base/all_your_base_test.py +13 -13
  66. data/tracks/python/exercises/allergies/README.md +1 -3
  67. data/tracks/python/exercises/alphametics/README.md +3 -4
  68. data/tracks/python/exercises/anagram/README.md +1 -2
  69. data/tracks/python/exercises/atbash-cipher/README.md +3 -3
  70. data/tracks/python/exercises/beer-song/README.md +2 -3
  71. data/tracks/python/exercises/binary-search/README.md +1 -2
  72. data/tracks/python/exercises/binary/README.md +3 -2
  73. data/tracks/python/exercises/bob/README.md +1 -2
  74. data/tracks/python/exercises/book-store/README.md +6 -7
  75. data/tracks/python/exercises/bracket-push/README.md +1 -2
  76. data/tracks/python/exercises/change/README.md +2 -3
  77. data/tracks/python/exercises/circular-buffer/README.md +14 -8
  78. data/tracks/python/exercises/clock/README.md +1 -2
  79. data/tracks/python/exercises/clock/clock_test.py +2 -0
  80. data/tracks/python/exercises/collatz-conjecture/.meta/hints.md +3 -0
  81. data/tracks/python/exercises/collatz-conjecture/README.md +6 -19
  82. data/tracks/python/exercises/complex-numbers/README.md +28 -2
  83. data/tracks/python/exercises/crypto-square/README.md +11 -10
  84. data/tracks/python/exercises/diamond/README.md +7 -8
  85. data/tracks/python/exercises/difference-of-squares/README.md +1 -2
  86. data/tracks/python/exercises/diffie-hellman/.meta/hints.md +1 -1
  87. data/tracks/python/exercises/diffie-hellman/README.md +3 -2
  88. data/tracks/python/exercises/error-handling/.meta/hints.md +8 -0
  89. data/tracks/python/exercises/error-handling/README.md +10 -2
  90. data/tracks/python/exercises/error-handling/error_handling_test.py +15 -3
  91. data/tracks/python/exercises/etl/README.md +3 -2
  92. data/tracks/python/exercises/flatten-array/README.md +2 -4
  93. data/tracks/python/exercises/food-chain/README.md +3 -4
  94. data/tracks/python/exercises/forth/README.md +2 -6
  95. data/tracks/python/exercises/gigasecond/README.md +1 -2
  96. data/tracks/python/exercises/grade-school/README.md +1 -3
  97. data/tracks/python/exercises/grains/README.md +1 -3
  98. data/tracks/python/exercises/grep/README.md +13 -14
  99. data/tracks/python/exercises/hamming/README.md +1 -2
  100. data/tracks/python/exercises/hamming/hamming_test.py +6 -6
  101. data/tracks/python/exercises/hello-world/README.md +1 -2
  102. data/tracks/python/exercises/hexadecimal/README.md +1 -2
  103. data/tracks/python/exercises/hexadecimal/example.py +6 -6
  104. data/tracks/python/exercises/house/README.md +2 -4
  105. data/tracks/python/exercises/isogram/README.md +3 -3
  106. data/tracks/python/exercises/kindergarten-garden/README.md +14 -15
  107. data/tracks/python/exercises/largest-series-product/README.md +1 -2
  108. data/tracks/python/exercises/leap/README.md +2 -3
  109. data/tracks/python/exercises/linked-list/README.md +11 -12
  110. data/tracks/python/exercises/list-ops/README.md +1 -2
  111. data/tracks/python/exercises/luhn/README.md +8 -9
  112. data/tracks/python/exercises/markdown/README.md +1 -6
  113. data/tracks/python/exercises/matrix/README.md +7 -6
  114. data/tracks/python/exercises/meetup/README.md +2 -4
  115. data/tracks/python/exercises/minesweeper/README.md +1 -2
  116. data/tracks/python/exercises/nth-prime/README.md +1 -2
  117. data/tracks/python/exercises/nucleotide-count/README.md +9 -24
  118. data/tracks/python/exercises/ocr-numbers/README.md +6 -7
  119. data/tracks/python/exercises/octal/README.md +7 -4
  120. data/tracks/python/exercises/palindrome-products/README.md +16 -18
  121. data/tracks/python/exercises/pangram/README.md +2 -3
  122. data/tracks/python/exercises/pascals-triangle/README.md +2 -3
  123. data/tracks/python/exercises/perfect-numbers/README.md +3 -4
  124. data/tracks/python/exercises/phone-number/README.md +4 -4
  125. data/tracks/python/exercises/pig-latin/README.md +1 -2
  126. data/tracks/python/exercises/point-mutations/README.md +1 -2
  127. data/tracks/python/exercises/poker/README.md +1 -2
  128. data/tracks/python/exercises/prime-factors/README.md +1 -2
  129. data/tracks/python/exercises/protein-translation/README.md +5 -7
  130. data/tracks/python/exercises/proverb/README.md +12 -11
  131. data/tracks/python/exercises/pythagorean-triplet/README.md +4 -5
  132. data/tracks/python/exercises/queen-attack/README.md +2 -3
  133. data/tracks/python/exercises/rail-fence-cipher/README.md +13 -9
  134. data/tracks/python/exercises/raindrops/README.md +1 -2
  135. data/tracks/python/exercises/rectangles/README.md +8 -9
  136. data/tracks/python/exercises/rectangles/example.py +3 -3
  137. data/tracks/python/exercises/rna-transcription/README.md +1 -2
  138. data/tracks/python/exercises/rna-transcription/rna_transcription_test.py +4 -3
  139. data/tracks/python/exercises/robot-name/README.md +1 -2
  140. data/tracks/python/exercises/robot-simulator/README.md +1 -2
  141. data/tracks/python/exercises/roman-numerals/README.md +2 -3
  142. data/tracks/python/exercises/rotational-cipher/README.md +3 -3
  143. data/tracks/python/exercises/run-length-encoding/README.md +5 -6
  144. data/tracks/python/exercises/run-length-encoding/example.py +2 -2
  145. data/tracks/python/exercises/saddle-points/README.md +2 -3
  146. data/tracks/python/exercises/say/README.md +1 -2
  147. data/tracks/python/exercises/scale-generator/README.md +1 -3
  148. data/tracks/python/exercises/scrabble-score/README.md +4 -3
  149. data/tracks/python/exercises/secret-handshake/README.md +2 -3
  150. data/tracks/python/exercises/series/README.md +1 -2
  151. data/tracks/python/exercises/sieve/README.md +1 -2
  152. data/tracks/python/exercises/simple-cipher/README.md +3 -4
  153. data/tracks/python/exercises/space-age/README.md +2 -3
  154. data/tracks/python/exercises/space-age/space_age_test.py +18 -29
  155. data/tracks/python/exercises/strain/README.md +1 -2
  156. data/tracks/python/exercises/sublist/README.md +1 -2
  157. data/tracks/python/exercises/sum-of-multiples/README.md +1 -5
  158. data/tracks/python/exercises/tournament/README.md +6 -7
  159. data/tracks/python/exercises/transpose/README.md +8 -9
  160. data/tracks/python/exercises/tree-building/README.md +25 -0
  161. data/tracks/python/exercises/tree-building/example.py +46 -0
  162. data/tracks/python/exercises/tree-building/tree_building.py +50 -0
  163. data/tracks/python/exercises/tree-building/tree_building_test.py +183 -0
  164. data/tracks/python/exercises/triangle/README.md +10 -8
  165. data/tracks/python/exercises/trinary/README.md +2 -3
  166. data/tracks/python/exercises/twelve-days/README.md +2 -3
  167. data/tracks/python/exercises/two-bucket/README.md +4 -5
  168. data/tracks/python/exercises/two-bucket/two_bucket_test.py +2 -0
  169. data/tracks/python/exercises/two-fer/README.md +4 -5
  170. data/tracks/python/exercises/two-fer/two_fer_test.py +5 -2
  171. data/tracks/python/exercises/variable-length-quantity/README.md +7 -9
  172. data/tracks/python/exercises/word-count/README.md +2 -4
  173. data/tracks/python/exercises/word-search/README.md +2 -3
  174. data/tracks/python/exercises/wordy/README.md +1 -7
  175. data/tracks/python/exercises/wordy/example.py +8 -8
  176. data/tracks/python/exercises/wordy/wordy_test.py +36 -32
  177. data/tracks/python/exercises/zebra-puzzle/README.md +1 -2
  178. data/tracks/python/requirements-travis.txt +1 -1
  179. data/tracks/ruby/config.json +11 -0
  180. data/tracks/ruby/docs/TESTS.md +6 -0
  181. data/tracks/ruby/exercises/pangram/.meta/.version +1 -1
  182. data/tracks/ruby/exercises/pangram/.meta/solutions/pangram.rb +1 -1
  183. data/tracks/ruby/exercises/pangram/pangram_test.rb +11 -4
  184. data/tracks/ruby/exercises/two-fer/.meta/.version +1 -0
  185. data/tracks/ruby/exercises/two-fer/.meta/generator/two_fer_case.rb +12 -0
  186. data/tracks/ruby/exercises/two-fer/.meta/solutions/two_fer.rb +9 -0
  187. data/tracks/ruby/exercises/two-fer/README.md +69 -0
  188. data/tracks/ruby/exercises/two-fer/two_fer_test.rb +42 -0
  189. data/tracks/rust/config.json +12 -0
  190. data/tracks/rust/exercises/binary-search/.meta/hints.md +38 -0
  191. data/tracks/rust/exercises/binary-search/Cargo.lock +4 -0
  192. data/tracks/rust/exercises/binary-search/Cargo.toml +6 -0
  193. data/tracks/rust/exercises/binary-search/README.md +113 -0
  194. data/tracks/rust/exercises/binary-search/example.rs +29 -0
  195. data/tracks/rust/exercises/binary-search/src/lib.rs +0 -0
  196. data/tracks/rust/exercises/binary-search/tests/binary-search.rs +96 -0
  197. data/tracks/typescript/common/package.json +6 -6
  198. data/tracks/typescript/common/yarn.lock +929 -610
  199. data/tracks/typescript/exercises/acronym/package.json +6 -6
  200. data/tracks/typescript/exercises/acronym/yarn.lock +929 -610
  201. data/tracks/typescript/exercises/anagram/package.json +6 -6
  202. data/tracks/typescript/exercises/anagram/yarn.lock +929 -610
  203. data/tracks/typescript/exercises/beer-song/package.json +6 -6
  204. data/tracks/typescript/exercises/beer-song/yarn.lock +929 -610
  205. data/tracks/typescript/exercises/binary-search-tree/package.json +6 -6
  206. data/tracks/typescript/exercises/binary-search-tree/yarn.lock +929 -610
  207. data/tracks/typescript/exercises/binary-search/package.json +6 -6
  208. data/tracks/typescript/exercises/binary-search/yarn.lock +929 -610
  209. data/tracks/typescript/exercises/bob/package.json +6 -6
  210. data/tracks/typescript/exercises/bob/yarn.lock +929 -610
  211. data/tracks/typescript/exercises/circular-buffer/package.json +6 -6
  212. data/tracks/typescript/exercises/circular-buffer/yarn.lock +929 -610
  213. data/tracks/typescript/exercises/clock/package.json +6 -6
  214. data/tracks/typescript/exercises/clock/yarn.lock +929 -610
  215. data/tracks/typescript/exercises/difference-of-squares/package.json +6 -6
  216. data/tracks/typescript/exercises/difference-of-squares/yarn.lock +929 -610
  217. data/tracks/typescript/exercises/etl/package.json +6 -6
  218. data/tracks/typescript/exercises/etl/yarn.lock +929 -610
  219. data/tracks/typescript/exercises/food-chain/package.json +6 -6
  220. data/tracks/typescript/exercises/food-chain/yarn.lock +929 -610
  221. data/tracks/typescript/exercises/gigasecond/package.json +6 -6
  222. data/tracks/typescript/exercises/gigasecond/yarn.lock +929 -610
  223. data/tracks/typescript/exercises/grade-school/package.json +6 -6
  224. data/tracks/typescript/exercises/grade-school/yarn.lock +929 -610
  225. data/tracks/typescript/exercises/hamming/package.json +6 -6
  226. data/tracks/typescript/exercises/hamming/yarn.lock +929 -610
  227. data/tracks/typescript/exercises/hello-world/README.md +354 -0
  228. data/tracks/typescript/exercises/hello-world/package.json +6 -6
  229. data/tracks/typescript/exercises/hello-world/yarn.lock +929 -610
  230. data/tracks/typescript/exercises/largest-series-product/package.json +6 -6
  231. data/tracks/typescript/exercises/largest-series-product/yarn.lock +929 -610
  232. data/tracks/typescript/exercises/leap/package.json +6 -6
  233. data/tracks/typescript/exercises/leap/yarn.lock +929 -610
  234. data/tracks/typescript/exercises/linked-list/package.json +6 -6
  235. data/tracks/typescript/exercises/linked-list/yarn.lock +929 -610
  236. data/tracks/typescript/exercises/nth-prime/package.json +6 -6
  237. data/tracks/typescript/exercises/nth-prime/yarn.lock +929 -610
  238. data/tracks/typescript/exercises/pangram/package.json +6 -6
  239. data/tracks/typescript/exercises/pangram/yarn.lock +929 -610
  240. data/tracks/typescript/exercises/pascals-triangle/package.json +6 -6
  241. data/tracks/typescript/exercises/pascals-triangle/yarn.lock +929 -610
  242. data/tracks/typescript/exercises/phone-number/package.json +6 -6
  243. data/tracks/typescript/exercises/phone-number/yarn.lock +929 -610
  244. data/tracks/typescript/exercises/prime-factors/package.json +6 -6
  245. data/tracks/typescript/exercises/prime-factors/yarn.lock +929 -610
  246. data/tracks/typescript/exercises/raindrops/package.json +6 -6
  247. data/tracks/typescript/exercises/raindrops/yarn.lock +929 -610
  248. data/tracks/typescript/exercises/rna-transcription/package.json +6 -6
  249. data/tracks/typescript/exercises/rna-transcription/yarn.lock +929 -610
  250. data/tracks/typescript/exercises/robot-name/package.json +6 -6
  251. data/tracks/typescript/exercises/robot-name/yarn.lock +929 -610
  252. data/tracks/typescript/exercises/robot-simulator/package.json +6 -6
  253. data/tracks/typescript/exercises/robot-simulator/yarn.lock +929 -610
  254. data/tracks/typescript/exercises/rotational-cipher/package.json +6 -6
  255. data/tracks/typescript/exercises/rotational-cipher/yarn.lock +929 -610
  256. data/tracks/typescript/exercises/say/package.json +6 -6
  257. data/tracks/typescript/exercises/say/yarn.lock +929 -610
  258. data/tracks/typescript/exercises/scrabble-score/package.json +6 -6
  259. data/tracks/typescript/exercises/scrabble-score/yarn.lock +929 -610
  260. data/tracks/typescript/exercises/series/package.json +6 -6
  261. data/tracks/typescript/exercises/series/yarn.lock +929 -610
  262. data/tracks/typescript/exercises/space-age/package.json +6 -6
  263. data/tracks/typescript/exercises/space-age/yarn.lock +929 -610
  264. data/tracks/typescript/exercises/strain/package.json +6 -6
  265. data/tracks/typescript/exercises/strain/yarn.lock +929 -610
  266. data/tracks/typescript/exercises/sum-of-multiples/package.json +6 -6
  267. data/tracks/typescript/exercises/sum-of-multiples/yarn.lock +929 -610
  268. data/tracks/typescript/exercises/triangle/package.json +6 -6
  269. data/tracks/typescript/exercises/triangle/yarn.lock +929 -610
  270. data/tracks/typescript/exercises/word-count/package.json +6 -6
  271. data/tracks/typescript/exercises/word-count/yarn.lock +929 -610
  272. data/tracks/typescript/exercises/wordy/package.json +6 -6
  273. data/tracks/typescript/exercises/wordy/yarn.lock +929 -610
  274. metadata +37 -2
@@ -33,13 +33,12 @@ Keep your hands off that filter/reject/whatchamacallit functionality
33
33
  provided by your standard library! Solve this one yourself using other
34
34
  basic tools instead.
35
35
 
36
- ### Submitting Exercises
36
+ ## Submitting Exercises
37
37
 
38
38
  Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
39
39
 
40
40
  For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
41
41
 
42
-
43
42
  For more detailed information about running tests, code style and linting,
44
43
  please see the [help page](http://exercism.io/languages/python).
45
44
 
@@ -17,13 +17,12 @@ Examples:
17
17
  * A = [1, 2, 3, 4, 5], B = [2, 3, 4], A is a superlist of B
18
18
  * A = [1, 2, 4], B = [1, 2, 3, 4, 5], A is not a superlist of, sublist of or equal to B
19
19
 
20
- ### Submitting Exercises
20
+ ## Submitting Exercises
21
21
 
22
22
  Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
23
23
 
24
24
  For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
25
25
 
26
-
27
26
  For more detailed information about running tests, code style and linting,
28
27
  please see the [help page](http://exercism.io/languages/python).
29
28
 
@@ -8,16 +8,12 @@ multiples of either 3 or 5, we get 3, 5, 6 and 9, 10, 12, 15, and 18.
8
8
 
9
9
  The sum of these multiples is 78.
10
10
 
11
- Given a number, find the sum of the multiples of a given set of numbers,
12
- up to but not including that number.
13
-
14
- ### Submitting Exercises
11
+ ## Submitting Exercises
15
12
 
16
13
  Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
17
14
 
18
15
  For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
19
16
 
20
-
21
17
  For more detailed information about running tests, code style and linting,
22
18
  please see the [help page](http://exercism.io/languages/python).
23
19
 
@@ -5,7 +5,7 @@ Tally the results of a small football competition.
5
5
  Based on an input file containing which team played against which and what the
6
6
  outcome was, create a file with a table like this:
7
7
 
8
- ```
8
+ ```text
9
9
  Team | MP | W | D | L | P
10
10
  Devastating Donkeys | 3 | 2 | 1 | 0 | 7
11
11
  Allegoric Alaskans | 3 | 2 | 0 | 1 | 6
@@ -31,7 +31,7 @@ Input
31
31
 
32
32
  Your tallying program will receive input that looks like:
33
33
 
34
- ```
34
+ ```text
35
35
  Allegoric Alaskans;Blithering Badgers;win
36
36
  Devastating Donkeys;Courageous Californians;draw
37
37
  Devastating Donkeys;Allegoric Alaskans;win
@@ -42,7 +42,7 @@ Allegoric Alaskans;Courageous Californians;win
42
42
 
43
43
  The result of the match refers to the first team listed. So this line
44
44
 
45
- ```
45
+ ```text
46
46
  Allegoric Alaskans;Blithering Badgers;win
47
47
  ```
48
48
 
@@ -50,7 +50,7 @@ Means that the Allegoric Alaskans beat the Blithering Badgers.
50
50
 
51
51
  This line:
52
52
 
53
- ```
53
+ ```text
54
54
  Courageous Californians;Blithering Badgers;loss
55
55
  ```
56
56
 
@@ -58,19 +58,18 @@ Means that the Blithering Badgers beat the Courageous Californians.
58
58
 
59
59
  And this line:
60
60
 
61
- ```
61
+ ```text
62
62
  Devastating Donkeys;Courageous Californians;draw
63
63
  ```
64
64
 
65
65
  Means that the Devastating Donkeys and Courageous Californians tied.
66
66
 
67
- ### Submitting Exercises
67
+ ## Submitting Exercises
68
68
 
69
69
  Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
70
70
 
71
71
  For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
72
72
 
73
-
74
73
  For more detailed information about running tests, code style and linting,
75
74
  please see the [help page](http://exercism.io/languages/python).
76
75
 
@@ -4,14 +4,14 @@ Given an input text output it transposed.
4
4
 
5
5
  Roughly explained, the transpose of a matrix:
6
6
 
7
- ```
7
+ ```text
8
8
  ABC
9
9
  DEF
10
10
  ```
11
11
 
12
12
  is given by:
13
13
 
14
- ```
14
+ ```text
15
15
  AD
16
16
  BE
17
17
  CF
@@ -26,14 +26,14 @@ If the input has rows of different lengths, this is to be solved as follows:
26
26
 
27
27
  Therefore, transposing this matrix:
28
28
 
29
- ```
29
+ ```text
30
30
  ABC
31
31
  DE
32
32
  ```
33
33
 
34
34
  results in:
35
35
 
36
- ```
36
+ ```text
37
37
  AD
38
38
  BE
39
39
  C
@@ -41,30 +41,29 @@ C
41
41
 
42
42
  And transposing:
43
43
 
44
- ```
44
+ ```text
45
45
  AB
46
46
  DEF
47
47
  ```
48
48
 
49
49
  results in:
50
50
 
51
- ```
51
+ ```text
52
52
  AD
53
53
  BE
54
54
  F
55
55
  ```
56
56
 
57
57
  In general, all characters from the input should also be present in the transposed output.
58
- That means that if a column in the input text contains only spaces on its bottom-most row(s),
58
+ That means that if a column in the input text contains only spaces on its bottom-most row(s),
59
59
  the corresponding output row should contain the spaces in its right-most column(s).
60
60
 
61
- ### Submitting Exercises
61
+ ## Submitting Exercises
62
62
 
63
63
  Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
64
64
 
65
65
  For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
66
66
 
67
-
68
67
  For more detailed information about running tests, code style and linting,
69
68
  please see the [help page](http://exercism.io/languages/python).
70
69
 
@@ -0,0 +1,25 @@
1
+ Refactor a tree building algorithm.
2
+
3
+ Some web-forums have a tree layout, so posts are presented as a tree. However
4
+ the posts are typically stored in a database as an unsorted set of records. Thus
5
+ when presenting the posts to the user the tree structure has to be
6
+ reconstructed.
7
+
8
+ Your job will be to refactor a working but slow and ugly piece of code that
9
+ implements the tree building logic for highly abstracted records. The records
10
+ only contain an ID number and a parent ID number. The ID number is always
11
+ between 0 (inclusive) and the length of the record list (exclusive). All records
12
+ have a parent ID lower than their own ID, except for the root record, which has
13
+ a parent ID that's equal to its own ID.
14
+
15
+ An example tree:
16
+
17
+ ```text
18
+ root (ID: 0, parent ID: 0)
19
+ |-- child1 (ID: 1, parent ID: 0)
20
+ | |-- grandchild1 (ID: 2, parent ID: 1)
21
+ | +-- grandchild2 (ID: 4, parent ID: 1)
22
+ +-- child2 (ID: 3, parent ID: 0)
23
+ | +-- grandchild3 (ID: 6, parent ID: 3)
24
+ +-- child3 (ID: 5, parent ID: 0)
25
+ ```
@@ -0,0 +1,46 @@
1
+ class Record():
2
+ def __init__(self, record_id, parent_id):
3
+ self.record_id = record_id
4
+ self.parent_id = parent_id
5
+
6
+ def equal_id(self):
7
+ return self.record_id == self.parent_id
8
+
9
+
10
+ class Node():
11
+ def __init__(self, node_id):
12
+ self.node_id = node_id
13
+ self.children = []
14
+
15
+
16
+ def validateRecord(record):
17
+ if record.equal_id() and record.record_id != 0:
18
+ # only root(id=0) should have equal id
19
+ raise ValueError
20
+ elif not record.equal_id() and record.parent_id >= record.record_id:
21
+ # non-root node id should be smaller than its parent_id
22
+ raise ValueError
23
+
24
+
25
+ def BuildTree(records):
26
+ parent_dict = {}
27
+ node_dict = {}
28
+ ordered_id = sorted((i.record_id for i in records))
29
+ for record in records:
30
+ validateRecord(record)
31
+ parent_dict[record.record_id] = record.parent_id
32
+ node_dict[record.record_id] = Node(record.record_id)
33
+
34
+ root_id = 0
35
+ root = None
36
+
37
+ for index, record_id in enumerate(ordered_id):
38
+ if index != record_id:
39
+ raise ValueError
40
+ if record_id == root_id:
41
+ root = node_dict[record_id]
42
+ else:
43
+ parent_id = parent_dict[record_id]
44
+ node_dict[parent_id].children.append(node_dict[record_id])
45
+
46
+ return root
@@ -0,0 +1,50 @@
1
+ class Record():
2
+ def __init__(self, record_id, parent_id):
3
+ self.record_id = record_id
4
+ self.parent_id = parent_id
5
+
6
+
7
+ class Node():
8
+ def __init__(self, node_id):
9
+ self.node_id = node_id
10
+ self.children = []
11
+
12
+
13
+ def BuildTree(records):
14
+ root = None
15
+ records.sort(key=lambda x: x.record_id)
16
+ ordered_id = [i.record_id for i in records]
17
+ if records:
18
+ if ordered_id[-1] != len(ordered_id) - 1:
19
+ raise ValueError
20
+ if ordered_id[0] != 0:
21
+ raise ValueError
22
+ trees = []
23
+ parent = {}
24
+ for i in range(len(ordered_id)):
25
+ for j in records:
26
+ if ordered_id[i] == j.record_id:
27
+ if j.record_id == 0:
28
+ if j.parent_id != 0:
29
+ raise ValueError
30
+ if j.record_id < j.parent_id:
31
+ raise ValueError
32
+ if j.record_id == j.parent_id:
33
+ if j.record_id != 0:
34
+ raise ValueError
35
+ trees.append(Node(ordered_id[i]))
36
+ for i in range(len(ordered_id)):
37
+ for j in trees:
38
+ if i == j.node_id:
39
+ parent = j
40
+ for j in records:
41
+ if j.parent_id == i:
42
+ for k in trees:
43
+ if k.node_id == 0:
44
+ continue
45
+ if j.record_id == k.node_id:
46
+ child = k
47
+ parent.children.append(child)
48
+ if len(trees) > 0:
49
+ root = trees[0]
50
+ return root
@@ -0,0 +1,183 @@
1
+ import unittest
2
+
3
+ from tree_building import Record, BuildTree
4
+
5
+
6
+ class TestBuildingTest(unittest.TestCase):
7
+ """
8
+ Record(record_id, parent_id): records given to be processed
9
+ Node(node_id): Node in tree
10
+ BuildTree(records): records as argument and returns tree
11
+ BuildTree should raise ValueError if given records are invalid
12
+ """
13
+
14
+ def test_empty_list_input(self):
15
+ records = []
16
+ root = BuildTree(records)
17
+ self.assertIsNone(root)
18
+
19
+ def test_one_node(self):
20
+ records = [
21
+ Record(0, 0)
22
+ ]
23
+ root = BuildTree(records)
24
+
25
+ self.assert_node_is_leaf(root, node_id=0)
26
+
27
+ def test_three_nodes_in_order(self):
28
+ records = [
29
+ Record(0, 0),
30
+ Record(1, 0),
31
+ Record(2, 0)
32
+ ]
33
+ root = BuildTree(records)
34
+
35
+ self.assert_node_is_branch(root, node_id=0, children_count=2)
36
+ self.assert_node_is_leaf(root.children[0], node_id=1)
37
+ self.assert_node_is_leaf(root.children[1], node_id=2)
38
+
39
+ def test_three_nodes_in_reverse_order(self):
40
+ records = [
41
+ Record(2, 0),
42
+ Record(1, 0),
43
+ Record(0, 0)
44
+ ]
45
+ root = BuildTree(records)
46
+
47
+ self.assert_node_is_branch(root, node_id=0, children_count=2)
48
+ self.assert_node_is_leaf(root.children[0], node_id=1)
49
+ self.assert_node_is_leaf(root.children[1], node_id=2)
50
+
51
+ def test_more_than_two_children(self):
52
+ records = [
53
+ Record(0, 0),
54
+ Record(1, 0),
55
+ Record(2, 0),
56
+ Record(3, 0)
57
+ ]
58
+ root = BuildTree(records)
59
+
60
+ self.assert_node_is_branch(root, node_id=0, children_count=3)
61
+ self.assert_node_is_leaf(root.children[0], node_id=1)
62
+ self.assert_node_is_leaf(root.children[1], node_id=2)
63
+ self.assert_node_is_leaf(root.children[2], node_id=3)
64
+
65
+ def test_binary_tree(self):
66
+ records = [
67
+ Record(6, 2),
68
+ Record(0, 0),
69
+ Record(3, 1),
70
+ Record(2, 0),
71
+ Record(4, 1),
72
+ Record(5, 2),
73
+ Record(1, 0)
74
+ ]
75
+ root = BuildTree(records)
76
+
77
+ self.assert_node_is_branch(root, 0, 2)
78
+ self.assert_node_is_branch(root.children[0], 1, 2)
79
+ self.assert_node_is_branch(root.children[1], 2, 2)
80
+ self.assert_node_is_leaf(root.children[0].children[0], 3)
81
+ self.assert_node_is_leaf(root.children[0].children[1], 4)
82
+ self.assert_node_is_leaf(root.children[1].children[0], 5)
83
+ self.assert_node_is_leaf(root.children[1].children[1], 6)
84
+
85
+ def test_unbalanced_tree(self):
86
+ records = [
87
+ Record(0, 0),
88
+ Record(1, 0),
89
+ Record(2, 0),
90
+ Record(3, 1),
91
+ Record(4, 1),
92
+ Record(5, 1),
93
+ Record(6, 2),
94
+ ]
95
+ root = BuildTree(records)
96
+
97
+ self.assert_node_is_branch(root, 0, 2)
98
+ self.assert_node_is_branch(root.children[0], 1, 3)
99
+ self.assert_node_is_branch(root.children[1], 2, 1)
100
+ self.assert_node_is_leaf(root.children[0].children[0], 3)
101
+ self.assert_node_is_leaf(root.children[0].children[1], 4)
102
+ self.assert_node_is_leaf(root.children[0].children[2], 5)
103
+ self.assert_node_is_leaf(root.children[1].children[0], 6)
104
+
105
+ def test_root_node_has_parent(self):
106
+ records = [
107
+ Record(0, 1),
108
+ Record(1, 0)
109
+ ]
110
+ # Root parent_id should be equal to record_id(0)
111
+ with self.assertRaises(ValueError):
112
+ BuildTree(records)
113
+
114
+ def test_no_root_node(self):
115
+ records = [
116
+ Record(1, 0),
117
+ Record(2, 0)
118
+ ]
119
+ # Record with record_id 0 (root) is missing
120
+ with self.assertRaises(ValueError):
121
+ BuildTree(records)
122
+
123
+ def test_non_continuous(self):
124
+ records = [
125
+ Record(2, 0),
126
+ Record(4, 2),
127
+ Record(1, 0),
128
+ Record(0, 0)
129
+ ]
130
+ # Record with record_id 3 is missing
131
+ with self.assertRaises(ValueError):
132
+ BuildTree(records)
133
+
134
+ def test_cycle_directly(self):
135
+ records = [
136
+ Record(5, 2),
137
+ Record(3, 2),
138
+ Record(2, 2),
139
+ Record(4, 1),
140
+ Record(1, 0),
141
+ Record(0, 0),
142
+ Record(6, 3)
143
+ ]
144
+ # Cycle caused by Record 2 with parent_id pointing to itself
145
+ with self.assertRaises(ValueError):
146
+ BuildTree(records)
147
+
148
+ def test_cycle_indirectly(self):
149
+ records = [
150
+ Record(5, 2),
151
+ Record(3, 2),
152
+ Record(2, 6),
153
+ Record(4, 1),
154
+ Record(1, 0),
155
+ Record(0, 0),
156
+ Record(6, 3)
157
+ ]
158
+ # Cycle caused by Record 2 with parent_id(6) greater than record_id(2)
159
+ with self.assertRaises(ValueError):
160
+ BuildTree(records)
161
+
162
+ def test_higher_id_parent_of_lower_id(self):
163
+ records = [
164
+ Record(0, 0),
165
+ Record(2, 0),
166
+ Record(1, 2)
167
+ ]
168
+ # Record 1 have parent_id(2) greater than record_id(1)
169
+ with self.assertRaises(ValueError):
170
+ BuildTree(records)
171
+
172
+ def assert_node_is_branch(self, node, node_id, children_count):
173
+ self.assertEqual(node.node_id, node_id)
174
+ self.assertNotEqual(len(node.children), 0)
175
+ self.assertEqual(len(node.children), children_count)
176
+
177
+ def assert_node_is_leaf(self, node, node_id):
178
+ self.assertEqual(node.node_id, node_id)
179
+ self.assertEqual(len(node.children), 0)
180
+
181
+
182
+ if __name__ == '__main__':
183
+ unittest.main()