trackler 2.0.8.19 → 2.0.8.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/phone-number/canonical-data.json +2 -2
  3. data/lib/trackler/version.rb +1 -1
  4. data/tracks/c/config.json +7 -0
  5. data/tracks/c/exercises/react/makefile +16 -0
  6. data/tracks/c/exercises/react/src/example.c +185 -0
  7. data/tracks/c/exercises/react/src/react.h +29 -0
  8. data/tracks/c/exercises/react/test/test_react.c +324 -0
  9. data/tracks/c/exercises/react/test/vendor/unity.c +1300 -0
  10. data/tracks/c/exercises/react/test/vendor/unity.h +274 -0
  11. data/tracks/c/exercises/react/test/vendor/unity_internals.h +701 -0
  12. data/tracks/csharp/.travis.yml +2 -9
  13. data/tracks/csharp/appveyor.yml +3 -3
  14. data/tracks/csharp/build.cake +13 -4
  15. data/tracks/csharp/build.ps1 +56 -164
  16. data/tracks/csharp/build.sh +33 -78
  17. data/tracks/csharp/circle.yml +2 -4
  18. data/tracks/csharp/config.json +2 -1
  19. data/tracks/csharp/exercises/leap/LeapTest.cs +8 -8
  20. data/tracks/csharp/generators/CanonicalData.cs +19 -0
  21. data/tracks/csharp/generators/CanonicalDataCase.cs +24 -0
  22. data/tracks/csharp/generators/CanonicalDataCaseJsonConverter.cs +32 -0
  23. data/tracks/csharp/generators/CanonicalDataCasesJsonConverter.cs +30 -0
  24. data/tracks/csharp/generators/CanonicalDataParser.cs +28 -0
  25. data/tracks/csharp/generators/ExerciseCollection.cs +23 -0
  26. data/tracks/csharp/generators/Exercises/Exercise.cs +14 -0
  27. data/tracks/csharp/generators/Exercises/LeapExercise.cs +35 -0
  28. data/tracks/csharp/generators/Generators.csproj +12 -0
  29. data/tracks/csharp/generators/Generators.csproj.user +6 -0
  30. data/tracks/csharp/generators/Generators.sln +22 -0
  31. data/tracks/csharp/generators/Program.cs +59 -0
  32. data/tracks/csharp/generators/TestClass.cs +13 -0
  33. data/tracks/csharp/generators/TestClassRenderer.cs +36 -0
  34. data/tracks/csharp/generators/TestMethod.cs +9 -0
  35. data/tracks/csharp/generators/TestMethodNameTransformer.cs +11 -0
  36. data/tracks/csharp/generators/TestMethodRenderer.cs +18 -0
  37. data/tracks/csharp/generators/To.cs +7 -0
  38. data/tracks/csharp/generators/generate.ps1 +2 -0
  39. data/tracks/csharp/generators/generate.sh +4 -0
  40. data/tracks/delphi/config.json +8 -0
  41. data/tracks/delphi/exercises/phone-number/uPhoneNumberExample.pas +6 -6
  42. data/tracks/delphi/exercises/phone-number/uPhoneNumberTests.pas +28 -17
  43. data/tracks/delphi/exercises/roman-numerals/RomanNumerals.dpr +60 -0
  44. data/tracks/delphi/exercises/roman-numerals/uRomanNumeralsExample.pas +49 -0
  45. data/tracks/delphi/exercises/roman-numerals/uRomanNumeralsTest.pas +216 -0
  46. data/tracks/elixir/config.json +22 -0
  47. data/tracks/elixir/exercises/poker/example.exs +136 -0
  48. data/tracks/elixir/exercises/poker/poker.exs +34 -0
  49. data/tracks/elixir/exercises/poker/poker_test.exs +217 -0
  50. data/tracks/elixir/exercises/protein-translation/example.exs +62 -0
  51. data/tracks/elixir/exercises/protein-translation/protein_translation.exs +34 -0
  52. data/tracks/elixir/exercises/protein-translation/protein_translation_test.exs +87 -0
  53. data/tracks/elixir/exercises/say/example.exs +139 -0
  54. data/tracks/elixir/exercises/say/say.exs +8 -0
  55. data/tracks/elixir/exercises/say/say_test.exs +85 -0
  56. data/tracks/go/exercises/robot-name/example.go +2 -0
  57. data/tracks/go/exercises/robot-name/robot_name_test.go +9 -1
  58. data/tracks/go/exercises/roman-numerals/roman_numerals_test.go +4 -1
  59. data/tracks/go/exercises/saddle-points/saddle_points_test.go +6 -6
  60. data/tracks/php/config.json +7 -0
  61. data/tracks/php/exercises/grade-school/example.php +35 -0
  62. data/tracks/php/exercises/grade-school/grade-school_test.php +84 -0
  63. metadata +43 -2
@@ -27,6 +27,14 @@
27
27
  "string processing"
28
28
  ]
29
29
  },
30
+ {
31
+ "slug": "protein-translation",
32
+ "difficulty": 2,
33
+ "topics": [
34
+ "pattern matching",
35
+ "string processing"
36
+ ]
37
+ },
30
38
  {
31
39
  "slug": "space-age",
32
40
  "difficulty": 2,
@@ -400,6 +408,13 @@
400
408
  "topics": [
401
409
  ]
402
410
  },
411
+ {
412
+ "slug": "poker",
413
+ "difficulty": 7,
414
+ "topics": [
415
+ "sorting"
416
+ ]
417
+ },
403
418
  {
404
419
  "slug": "bowling",
405
420
  "difficulty": 8,
@@ -442,6 +457,13 @@
442
457
  "Strings",
443
458
  "Enumerations"
444
459
  ]
460
+ },
461
+ {
462
+ "slug": "say",
463
+ "difficulty": 3,
464
+ "topics": [
465
+ "Pattern Matching"
466
+ ]
445
467
  }
446
468
  ],
447
469
  "deprecated": [
@@ -0,0 +1,136 @@
1
+ defmodule Poker do
2
+ @doc """
3
+ Given a list of poker hands, return a list containing the highest scoring hand.
4
+
5
+ If two or more hands tie, return the list of tied hands in the order they were received.
6
+
7
+ The basic rules and hand rankings for Poker can be found at:
8
+
9
+ https://en.wikipedia.org/wiki/List_of_poker_hands
10
+
11
+ For this exercise, we'll consider the game to be using no Jokers,
12
+ so five-of-a-kind hands will not be tested. We will also consider
13
+ the game to be using multiple decks, so it is possible for multiple
14
+ players to have identical cards.
15
+
16
+ Aces can be used in low (A 2 3 4 5) or high (10 J Q K A) straights, but do not count as
17
+ a high card in the former case.
18
+
19
+ For example, (A 2 3 4 5) will lose to (2 3 4 5 6).
20
+
21
+ You can also assume all inputs will be valid, and do not need to perform error checking
22
+ when parsing card values. All hands will be a list of 5 strings, containing a number
23
+ (or letter) for the rank, followed by the suit.
24
+
25
+ Ranks (lowest to highest): 2 3 4 5 6 7 8 9 10 J Q K A
26
+ Suits (order doesn't matter): C D H S
27
+
28
+ Example hand: ~w(4S 5H 4C 5D 4H) # Full house, 5s over 4s
29
+ """
30
+ @spec best_hand(list(list(String.t()))) :: list(list(String.t()))
31
+ def best_hand(hands) do
32
+ sorted_hands = hands
33
+ |> Enum.map(&score_hand/1)
34
+ |> Enum.sort(&sort_scored_hands/2)
35
+
36
+ [{_, highest_score, highest_extra} | _] = sorted_hands
37
+
38
+ highest_args = {highest_score, highest_extra}
39
+
40
+ sorted_hands
41
+ |> Enum.group_by(fn {_hand, score, extra} -> {score, extra} end)
42
+ |> Map.get(highest_args)
43
+ |> Enum.map(fn {hand, _score, _extra} -> hand end)
44
+ end
45
+
46
+ @ranks ~w(2 3 4 5 6 7 8 9 10 J Q K A)
47
+ @suits ~w(clubs diamonds hearts spades)a
48
+ @scores ~w(straight_flush four_of_a_kind full_house flush straight three_of_a_kind two_pair pair high_card)a
49
+
50
+ for {rank, value} <- Enum.with_index(@ranks, 2), suit <- @suits do
51
+ suit_char = suit |> to_string |> String.upcase |> String.first
52
+
53
+ defp card(<< unquote(rank), unquote(suit_char) >>), do: {unquote(value), unquote(suit)}
54
+ end
55
+
56
+ defp score_hand(hand) do
57
+ {ranks, suits} = hand
58
+ |> Enum.map(&card/1)
59
+ |> Enum.sort(&sort_rank_asc/2)
60
+ |> Enum.unzip
61
+
62
+ flush = suits |> Enum.uniq |> length |> Kernel.==(1)
63
+
64
+ ranks
65
+ |> Enum.group_by(fn x -> x end)
66
+ |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
67
+ |> Enum.sort(&sort_count_then_rank_asc/2)
68
+ |> score_hand(ranks, flush)
69
+ |> Tuple.insert_at(0, hand)
70
+ end
71
+
72
+ defp score_hand(_, [2, 3, 4, 5, 14], true), do: {:straight_flush, {5}}
73
+ defp score_hand(_, [2, 3, 4, 5, 14], _), do: {:straight, {5}}
74
+ defp score_hand(counts, [low, _, _, _, high], true) when length(counts) == 5 and high-low == 4, do: {:straight_flush, {high}}
75
+ defp score_hand(counts, [low, _, _, _, high], _) when length(counts) == 5 and high-low == 4, do: {:straight, {high}}
76
+ defp score_hand(_, ranks, true), do: {:flush, {ranks |> Enum.sort |> Enum.reverse}}
77
+ defp score_hand([{kicker, 1}, {high, 4}], _, _), do: {:four_of_a_kind, {high, kicker}}
78
+ defp score_hand([{pair, 2}, {triplet, 3}], _, _), do: {:full_house, {triplet, pair}}
79
+ defp score_hand([{kicker1, 1}, {kicker2, 1}, {triplet, 3}], _, _), do: {:three_of_a_kind, {triplet, [ kicker1, kicker2 ] |> Enum.sort |> Enum.reverse}}
80
+ defp score_hand([{kicker, 1}, {low_pair, 2}, {high_pair, 2}], _, _), do: {:two_pair, {high_pair, low_pair, kicker}}
81
+ defp score_hand([{kicker1, 1}, {kicker2, 1}, {kicker3, 1}, {pair, 2}], _, _), do: {:pair, {pair, [ kicker1, kicker2, kicker3 ] |> Enum.sort |> Enum.reverse}}
82
+ defp score_hand(_, ranks, _), do: {:high_card, {ranks |> Enum.sort |> Enum.reverse}}
83
+
84
+ defp sort_rank_asc({rank1, _}, {rank2, _}), do: rank1 <= rank2
85
+ defp sort_count_then_rank_asc({rank1, count1}, {rank2, count2}), do: count1 <= count2 and rank1 <= rank2
86
+
87
+ # Compare different scores against each other first
88
+ for {score, index} <- @scores |> Enum.with_index(1) do
89
+ for other_score <- @scores |> Enum.drop(index) do
90
+ defp sort_scored_hands({_, unquote(score), _}, {_, unquote(other_score), _} ), do: true
91
+ defp sort_scored_hands({_, unquote(other_score), _}, {_, unquote(score), _} ), do: false
92
+ end
93
+ end
94
+
95
+ # Additional rules for tiebreakers
96
+
97
+ # Straight flush tie determined by high card
98
+ defp sort_scored_hands({_, :straight_flush, {high_a}}, {_, :straight_flush, {high_b}}), do: high_a >= high_b
99
+
100
+ # 4-of-a-kind tie determined by rank, then by kicker
101
+ defp sort_scored_hands({_, :four_of_a_kind, {rank_a, _}}, {_, :four_of_a_kind, {rank_b, _}}) when rank_a > rank_b, do: true
102
+ defp sort_scored_hands({_, :four_of_a_kind, {rank_a, _}}, {_, :four_of_a_kind, {rank_b, _}}) when rank_a < rank_b, do: false
103
+ defp sort_scored_hands({_, :four_of_a_kind, {_, kicker_a}}, {_, :four_of_a_kind, {_, kicker_b}}), do: kicker_a >= kicker_b
104
+
105
+ # Full house tie determined by triplet, then pair
106
+ defp sort_scored_hands({_, :full_house, {triplet_a, _}}, {_, :full_house, {triplet_b, _}}) when triplet_a > triplet_b, do: true
107
+ defp sort_scored_hands({_, :full_house, {triplet_a, _}}, {_, :full_house, {triplet_b, _}}) when triplet_a < triplet_b, do: false
108
+ defp sort_scored_hands({_, :full_house, {_, pair_a}}, {_, :full_house, {_, pair_b}}), do: pair_a >= pair_b
109
+
110
+ # Flush tie determined by high card, comparing all 5 if necessary
111
+ defp sort_scored_hands({_, :flush, {ranks_a}}, {_, :flush, {ranks_b}}), do: ranks_a >= ranks_b
112
+
113
+ # Straight tie determined by high card
114
+ defp sort_scored_hands({_, :straight, {high_a}}, {_, :straight, {high_b}}), do: high_a >= high_b
115
+
116
+ # 3-of-a-kind tie determined by triplet, then by high card, comparing both if necessary
117
+ defp sort_scored_hands({_, :three_of_a_kind, {triplet_a, _}}, {_, :three_of_a_kind, {triplet_b, _}}) when triplet_a > triplet_b, do: true
118
+ defp sort_scored_hands({_, :three_of_a_kind, {triplet_a, _}}, {_, :three_of_a_kind, {triplet_b, _}}) when triplet_a < triplet_b, do: false
119
+ defp sort_scored_hands({_, :three_of_a_kind, {_, ranks_a}}, {_, :three_of_a_kind, {_, ranks_b}}), do: ranks_a >= ranks_b
120
+
121
+ # Two-pair tie determined by high pair, then low pair, then by kicker
122
+ defp sort_scored_hands({_, :two_pair, {high_a, _, _}}, {_, :two_pair, {high_b, _, _}}) when high_a > high_b, do: true
123
+ defp sort_scored_hands({_, :two_pair, {high_a, _, _}}, {_, :two_pair, {high_b, _, _}}) when high_a < high_b, do: false
124
+ defp sort_scored_hands({_, :two_pair, {_, low_a, _}}, {_, :two_pair, {_, low_b, _}}) when low_a > low_b, do: true
125
+ defp sort_scored_hands({_, :two_pair, {_, low_a, _}}, {_, :two_pair, {_, low_b, _}}) when low_a < low_b, do: false
126
+ defp sort_scored_hands({_, :two_pair, {_, _, kicker_a}}, {_, :two_pair, {_, _, kicker_b}}), do: kicker_a >= kicker_b
127
+
128
+ # Pair tie determined by pair rank, then by high card, comparing all 3 if necessary
129
+ defp sort_scored_hands({_, :pair, {pair_a, _}}, {_, :pair, {pair_b, _}}) when pair_a > pair_b, do: true
130
+ defp sort_scored_hands({_, :pair, {pair_a, _}}, {_, :pair, {pair_b, _}}) when pair_a < pair_b, do: false
131
+ defp sort_scored_hands({_, :pair, {_, kickers_a}}, {_, :pair, {_, kickers_b}}), do: kickers_a >= kickers_b
132
+
133
+ # High-card tie determined by high card, comparing all 5 if necessary
134
+ defp sort_scored_hands({_, :high_card, {ranks_a}}, {_, :high_card, {ranks_b}}), do: ranks_a >= ranks_b
135
+ end
136
+
@@ -0,0 +1,34 @@
1
+ defmodule Poker do
2
+ @doc """
3
+ Given a list of poker hands, return a list containing the highest scoring hand.
4
+
5
+ If two or more hands tie, return the list of tied hands in the order they were received.
6
+
7
+ The basic rules and hand rankings for Poker can be found at:
8
+
9
+ https://en.wikipedia.org/wiki/List_of_poker_hands
10
+
11
+ For this exercise, we'll consider the game to be using no Jokers,
12
+ so five-of-a-kind hands will not be tested. We will also consider
13
+ the game to be using multiple decks, so it is possible for multiple
14
+ players to have identical cards.
15
+
16
+ Aces can be used in low (A 2 3 4 5) or high (10 J Q K A) straights, but do not count as
17
+ a high card in the former case.
18
+
19
+ For example, (A 2 3 4 5) will lose to (2 3 4 5 6).
20
+
21
+ You can also assume all inputs will be valid, and do not need to perform error checking
22
+ when parsing card values. All hands will be a list of 5 strings, containing a number
23
+ (or letter) for the rank, followed by the suit.
24
+
25
+ Ranks (lowest to highest): 2 3 4 5 6 7 8 9 10 J Q K A
26
+ Suits (order doesn't matter): C D H S
27
+
28
+ Example hand: ~w(4S 5H 4C 5D 4H) # Full house, 5s over 4s
29
+ """
30
+ @spec best_hand(list(list(String.t()))) :: list(list(String.t()))
31
+ def best_hand(hands) do
32
+ end
33
+ end
34
+
@@ -0,0 +1,217 @@
1
+ if !System.get_env("EXERCISM_TEST_EXAMPLES") do
2
+ Code.load_file("poker.exs", __DIR__)
3
+ end
4
+
5
+ ExUnit.start
6
+ ExUnit.configure exclude: :pending, trace: true
7
+
8
+ defmodule PokerTest do
9
+ use ExUnit.Case
10
+
11
+ #@tag :pending
12
+ test "single hand always wins" do
13
+ high_of_jack = ~w(4S 5S 7H 8D JC)
14
+ assert Poker.best_hand([high_of_jack]) == [high_of_jack]
15
+ end
16
+
17
+ @tag :pending
18
+ test "highest card out of all hands wins" do
19
+ high_of_8 = ~w(4D 5S 6S 8D 3C)
20
+ high_of_10 = ~w(2S 4C 7S 9H 10H)
21
+ high_of_jack = ~w(3S 4S 5D 6H JH)
22
+ assert Poker.best_hand([high_of_8, high_of_10, high_of_jack]) == [high_of_jack]
23
+ end
24
+
25
+ @tag :pending
26
+ test "a tie has multiple winners" do
27
+ high_of_8 = ~w(4D 5S 6S 8D 3C)
28
+ high_of_10 = ~w(2S 4C 7S 9H 10H)
29
+ high_of_jack = ~w(3S 4S 5D 6H JH)
30
+ another_high_of_jack = ~w(3H 4H 5C 6C JD)
31
+
32
+ hands = [high_of_8, high_of_10, high_of_jack, another_high_of_jack]
33
+ assert Poker.best_hand(hands) == [high_of_jack, another_high_of_jack]
34
+ end
35
+
36
+ @tag :pending
37
+ test "multiple hands with the same high cards, tie compares next highest ranked, down to last card" do
38
+ high_of_8_low_of_3 = ~w(3S 5H 6S 8D 7H)
39
+ high_of_8_low_of_2 = ~w(2S 5D 6D 8C 7S)
40
+ assert Poker.best_hand([high_of_8_low_of_3, high_of_8_low_of_2]) == [high_of_8_low_of_3]
41
+ end
42
+
43
+ @tag :pending
44
+ test "one pair beats high card" do
45
+ high_of_king = ~w(4S 5H 6C 8D KH)
46
+ pair_of_4 = ~w(2S 4H 6S 4D JH)
47
+ assert Poker.best_hand([high_of_king, pair_of_4]) == [pair_of_4]
48
+ end
49
+
50
+ @tag :pending
51
+ test "highest pair wins" do
52
+ pair_of_2 = ~w(4S 2H 6S 2D JH)
53
+ pair_of_4 = ~w(2S 4H 6C 4D JD)
54
+ assert Poker.best_hand([pair_of_2, pair_of_4]) == [pair_of_4]
55
+ end
56
+
57
+ @tag :pending
58
+ test "two pairs beats one pair" do
59
+ pair_of_8 = ~w(2S 8H 6S 8D JH)
60
+ fives_and_fours = ~w(4S 5H 4C 8C 5C)
61
+ assert Poker.best_hand([pair_of_8, fives_and_fours]) == [fives_and_fours]
62
+ end
63
+
64
+ @tag :pending
65
+ test "both hands have two pairs, highest ranked pair wins" do
66
+ eights_and_twos = ~w(2S 8H 2D 8D 3H)
67
+ fives_and_fours = ~w(4S 5H 4C 8S 5D)
68
+ assert Poker.best_hand([eights_and_twos, fives_and_fours]) == [eights_and_twos]
69
+ end
70
+
71
+ @tag :pending
72
+ test "both hands have two pairs, with the same highest ranked pair, tie goes to low pair" do
73
+ queens_and_twos = ~w(2S QS 2C QD JH)
74
+ queens_and_jacks = ~w(JD QH JS 8D QC)
75
+ assert Poker.best_hand([queens_and_twos, queens_and_jacks]) == [queens_and_jacks]
76
+ end
77
+
78
+ @tag :pending
79
+ test "both hands have two identically ranked pairs, tie goes to remaining card (kicker)" do
80
+ queens_jacks_and_8 = ~w(JD QH JS 8D QC)
81
+ queens_jacks_and_2 = ~w(JS QS JC 2D QD)
82
+ assert Poker.best_hand([queens_jacks_and_8, queens_jacks_and_2]) == [queens_jacks_and_8]
83
+ end
84
+
85
+ @tag :pending
86
+ test "three of a kind beats two pair" do
87
+ eights_and_twos = ~w(2S 8H 2H 8D JH)
88
+ three_fours = ~w(4S 5H 4C 8S 4H)
89
+ assert Poker.best_hand([eights_and_twos, three_fours]) == [three_fours]
90
+ end
91
+
92
+ @tag :pending
93
+ test "both hands have three of a kind, tie goes to highest ranked triplet" do
94
+ three_twos = ~w(2S 2H 2C 8D JH)
95
+ three_aces = ~w(4S AH AS 8C AD)
96
+ assert Poker.best_hand([three_twos, three_aces]) == [three_aces]
97
+ end
98
+
99
+ @tag :pending
100
+ test "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards" do
101
+ three_aces_7_high = ~w(4S AH AS 7C AD)
102
+ three_aces_8_high = ~w(4S AH AS 8C AD)
103
+ assert Poker.best_hand([three_aces_7_high, three_aces_8_high]) == [three_aces_8_high]
104
+
105
+ three_aces_8_high_5_low = ~w(5S AH AS 8C AD)
106
+ assert Poker.best_hand([three_aces_8_high_5_low, three_aces_8_high]) == [three_aces_8_high_5_low]
107
+ end
108
+
109
+ @tag :pending
110
+ test "a straight beats three of a kind" do
111
+ three_fours = ~w(4S 5H 4C 8D 4H)
112
+ straight = ~w(3S 4D 2S 6D 5C)
113
+ assert Poker.best_hand([three_fours, straight]) == [straight]
114
+ end
115
+
116
+ @tag :pending
117
+ test "aces can be end a straight (10 J Q K A)" do
118
+ three_fours = ~w(4S 5H 4C 8D 4H)
119
+ straight_to_ace = ~w(10D JH QS KD AC)
120
+ assert Poker.best_hand([three_fours, straight_to_ace]) == [straight_to_ace]
121
+ end
122
+
123
+ @tag :pending
124
+ test "aces can be start a straight (A 2 3 4 5)" do
125
+ three_fours = ~w(4S 5H 4C 8D 4H)
126
+ straight_to_5 = ~w(4D AH 3S 2D 5C)
127
+ assert Poker.best_hand([three_fours, straight_to_5]) == [straight_to_5]
128
+ end
129
+
130
+ @tag :pending
131
+ test "both hands with a straight, tie goes to highest ranked card" do
132
+ straight_to_8 = ~w(4S 6C 7S 8D 5H)
133
+ straight_to_9 = ~w(5S 7H 8S 9D 6H)
134
+ assert Poker.best_hand([straight_to_8, straight_to_9]) == [straight_to_9]
135
+ end
136
+
137
+ @tag :pending
138
+ test "even though an ace is usually high, a 5-high straight is the lowest-scoring straight" do
139
+ straight_to_6 = ~w(2H 3C 4D 5D 6H)
140
+ straight_to_5 = ~w(4S AH 3S 2D 5H)
141
+ assert Poker.best_hand([straight_to_6, straight_to_5]) == [straight_to_6]
142
+ end
143
+
144
+ @tag :pending
145
+ test "straight beats a flush" do
146
+ straight_to_8 = ~w(4C 6H 7D 8D 5H)
147
+ flush_to_7 = ~w(2S 4S 5S 6S 7S)
148
+ assert Poker.best_hand([straight_to_8, flush_to_7]) == [flush_to_7]
149
+ end
150
+
151
+ @tag :pending
152
+ test "both hands have a flush, tie goes to high card, down to the last one if necessary" do
153
+ flush_to_9 = ~w(4H 7H 8H 9H 6H)
154
+ flush_to_7 = ~w(2S 4S 5S 6S 7S)
155
+ assert Poker.best_hand([flush_to_9, flush_to_7]) == [flush_to_9]
156
+
157
+ flush_to_9_with_4_matches = ~w(3S 6S 7S 8S 9S)
158
+ assert Poker.best_hand([flush_to_9, flush_to_9_with_4_matches]) == [flush_to_9]
159
+ end
160
+
161
+ @tag :pending
162
+ test "full house beats a flush" do
163
+ flush_to_8 = ~w(3H 6H 7H 8H 5H)
164
+ full = ~w(4S 5H 4C 5D 4H)
165
+ assert Poker.best_hand([flush_to_8, full]) == [full]
166
+ end
167
+
168
+ @tag :pending
169
+ test "both hands have a full house, tie goes to highest-ranked triplet" do
170
+ full_of_4_by_9 = ~w(4H 4S 4D 9S 9D)
171
+ full_of_5_by_8 = ~w(5H 5S 5D 8S 8D)
172
+ assert Poker.best_hand([full_of_4_by_9, full_of_5_by_8]) == [full_of_5_by_8]
173
+ end
174
+
175
+ @tag :pending
176
+ test "with multiple decks, both hands have a full house with the same triplet, tie goes to the pair" do
177
+ full_of_5_by_9 = ~w(5H 5S 5D 9S 9D)
178
+ full_of_5_by_8 = ~w(5H 5S 5D 8S 8D)
179
+ assert Poker.best_hand([full_of_5_by_9, full_of_5_by_8]) == [full_of_5_by_9]
180
+ end
181
+
182
+ @tag :pending
183
+ test "four of a kind beats a full house" do
184
+ full = ~w(4S 5H 4D 5D 4H)
185
+ four_3s = ~w(3S 3H 2S 3D 3C)
186
+ assert Poker.best_hand([four_3s, full]) == [four_3s]
187
+ end
188
+
189
+ @tag :pending
190
+ test "both hands have four of a kind, tie goes to high quad" do
191
+ four_2s = ~w(2S 2H 2C 8D 2D)
192
+ four_5s = ~w(4S 5H 5S 5D 5C)
193
+ assert Poker.best_hand([four_2s, four_5s]) == [four_5s]
194
+ end
195
+
196
+ @tag :pending
197
+ test "with multiple decks, both hands with identical four of a kind, tie determined by kicker" do
198
+ four_3s_and_2 = ~w(3S 3H 2S 3D 3C)
199
+ four_3s_and_4 = ~w(3S 3H 4S 3D 3C)
200
+ assert Poker.best_hand([four_3s_and_2, four_3s_and_4]) == [four_3s_and_4]
201
+ end
202
+
203
+ @tag :pending
204
+ test "straight flush beats four of a kind" do
205
+ four_5s = ~w(4S 5H 5S 5D 5C)
206
+ straight_flush_to_10 = ~w(7S 8S 9S 6S 10S)
207
+ assert Poker.best_hand([four_5s, straight_flush_to_10]) == [straight_flush_to_10]
208
+ end
209
+
210
+ @tag :pending
211
+ test "both hands have straight flush, tie goes to highest-ranked card" do
212
+ straight_flush_to_8 = ~w(4H 6H 7H 8H 5H)
213
+ straight_flush_to_9 = ~w(5S 7S 8S 9S 6S)
214
+ assert Poker.best_hand([straight_flush_to_8, straight_flush_to_9]) == [straight_flush_to_9]
215
+ end
216
+ end
217
+
@@ -0,0 +1,62 @@
1
+ defmodule ProteinTranslation do
2
+ @doc """
3
+ Given an RNA string, return a list of proteins specified by codons, in order.
4
+ """
5
+ @spec of_rna(String.t()) :: { atom, list(String.t()) }
6
+ def of_rna(rna) do
7
+ translate_rna(rna, [])
8
+ end
9
+
10
+ @doc """
11
+ Given a codon, return the corresponding protein
12
+
13
+ UGU -> Cysteine
14
+ UGC -> Cysteine
15
+ UUA -> Leucine
16
+ UUG -> Leucine
17
+ AUG -> Methionine
18
+ UUU -> Phenylalanine
19
+ UUC -> Phenylalanine
20
+ UCU -> Serine
21
+ UCC -> Serine
22
+ UCA -> Serine
23
+ UCG -> Serine
24
+ UGG -> Tryptophan
25
+ UAU -> Tyrosine
26
+ UAC -> Tyrosine
27
+ UAA -> STOP
28
+ UAG -> STOP
29
+ UGA -> STOP
30
+ """
31
+ @spec of_codon(String.t()) :: { atom, String.t() }
32
+ def of_codon(codon) do
33
+ translate_codon(codon)
34
+ end
35
+
36
+ @codons %{
37
+ "Methionine" => ~w(AUG),
38
+ "Phenylalanine" => ~w(UUU UUC),
39
+ "Leucine" => ~w(UUA UUG),
40
+ "Serine" => ~w(UCU UCC UCA UCG),
41
+ "Tyrosine" => ~w(UAU UAC),
42
+ "Cysteine" => ~w(UGU UGC),
43
+ "Tryptophan" => ~w(UGG),
44
+ }
45
+ @stop ~w(UAA UAG UGA)
46
+
47
+ defp translate_rna("", results), do: { :ok, Enum.reverse(results) }
48
+
49
+ for codon <- @stop do
50
+ defp translate_rna(unquote(codon) <> _rest, results), do: { :ok, Enum.reverse(results) }
51
+ defp translate_codon(unquote(codon)), do: { :ok, "STOP" }
52
+ end
53
+
54
+ for { protein, codons } <- @codons, codon <- codons do
55
+ defp translate_rna(unquote(codon) <> rest, results), do: translate_rna(rest, [unquote(protein) | results])
56
+ defp translate_codon(unquote(codon)), do: { :ok, unquote(protein) }
57
+ end
58
+
59
+ defp translate_rna(_, _), do: { :error, "invalid RNA"}
60
+ defp translate_codon(_), do: { :error, "invalid codon"}
61
+ end
62
+