trackler 2.0.8.15 → 2.0.8.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/clock/canonical-data.json +473 -425
  3. data/common/exercises/crypto-square/canonical-data.json +105 -95
  4. data/common/exercises/difference-of-squares/canonical-data.json +76 -62
  5. data/common/exercises/etl/canonical-data.json +67 -59
  6. data/common/exercises/meetup/canonical-data.json +859 -762
  7. data/common/exercises/meetup/description.md +13 -7
  8. data/common/exercises/minesweeper/canonical-data.json +21 -5
  9. data/common/exercises/nth-prime/canonical-data.json +23 -16
  10. data/common/exercises/nucleotide-count/canonical-data.json +49 -41
  11. data/common/exercises/ocr-numbers/canonical-data.json +204 -183
  12. data/common/exercises/pascals-triangle/canonical-data.json +38 -27
  13. data/common/exercises/queen-attack/canonical-data.json +125 -109
  14. data/common/exercises/rotational-cipher/canonical-data.json +1 -1
  15. data/common/exercises/triangle/canonical-data.json +103 -74
  16. data/lib/trackler/version.rb +1 -1
  17. data/tracks/csharp/docs/TESTS.md +7 -1
  18. data/tracks/csharp/exercises/{exercises.sln → Exercises.All.sln} +0 -0
  19. data/tracks/csharp/exercises/Exercises.Default.sln +1433 -0
  20. data/tracks/csharp/exercises/Exercises.Refactoring.sln +61 -0
  21. data/tracks/csharp/exercises/acronym/AcronymTest.cs +35 -11
  22. data/tracks/csharp/exercises/parallel-letter-frequency/ParallelLetterFrequencyTest.cs +2 -2
  23. data/tracks/delphi/docs/TESTS.md +2 -2
  24. data/tracks/elixir/exercises/bowling/bowling.exs +1 -1
  25. data/tracks/fsharp/docs/LEARNING.md +2 -1
  26. data/tracks/go/config.json +7 -1
  27. data/tracks/go/exercises/prime-factors/{primefactors_test.go → prime_factors_test.go} +4 -1
  28. data/tracks/go/exercises/protein-translation/protein_translation_test.go +6 -6
  29. data/tracks/go/exercises/pythagorean-triplet/example.go +2 -0
  30. data/tracks/go/exercises/pythagorean-triplet/pythagorean_triplet_test.go +8 -0
  31. data/tracks/julia/README.md +2 -0
  32. data/tracks/julia/config.json +9 -0
  33. data/tracks/julia/exercises/rotational-cipher/HINTS.md +21 -0
  34. data/tracks/julia/exercises/rotational-cipher/example.jl +16 -0
  35. data/tracks/julia/exercises/rotational-cipher/rotational-cipher.jl +0 -0
  36. data/tracks/julia/exercises/rotational-cipher/runtests.jl +51 -0
  37. data/tracks/ocaml/config.json +5 -0
  38. data/tracks/ocaml/exercises/connect/.merlin +3 -0
  39. data/tracks/ocaml/exercises/connect/Makefile +15 -0
  40. data/tracks/ocaml/exercises/connect/connect.mli +4 -0
  41. data/tracks/ocaml/exercises/connect/example.ml +80 -0
  42. data/tracks/ocaml/exercises/connect/test.ml +121 -0
  43. data/tracks/ocaml/tools/test-generator/templates/connect/template.ml +23 -0
  44. data/tracks/python/exercises/all-your-base/all_your_base_test.py +2 -0
  45. data/tracks/python/exercises/luhn/example.py +5 -8
  46. data/tracks/python/exercises/luhn/luhn_test.py +34 -24
  47. data/tracks/ruby/README.md +138 -23
  48. metadata +16 -4
@@ -0,0 +1,61 @@
1
+ Microsoft Visual Studio Solution File, Format Version 12.00
2
+ # Visual Studio 15
3
+ VisualStudioVersion = 15.0.26228.4
4
+ MinimumVisualStudioVersion = 15.0.26124.0
5
+ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TreeBuilding", "tree-building\TreeBuilding.csproj", "{B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}"
6
+ EndProject
7
+ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ledger", "ledger\Ledger.csproj", "{4CD21D4F-5DCC-4506-8BDB-292555F43E9B}"
8
+ EndProject
9
+ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Markdown", "markdown\Markdown.csproj", "{78C54755-0602-409D-8058-0AC3C339BF37}"
10
+ EndProject
11
+ Global
12
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
13
+ Debug|Any CPU = Debug|Any CPU
14
+ Debug|x64 = Debug|x64
15
+ Debug|x86 = Debug|x86
16
+ Release|Any CPU = Release|Any CPU
17
+ Release|x64 = Release|x64
18
+ Release|x86 = Release|x86
19
+ EndGlobalSection
20
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
21
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
23
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Debug|x64.ActiveCfg = Debug|Any CPU
24
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Debug|x64.Build.0 = Debug|Any CPU
25
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Debug|x86.ActiveCfg = Debug|Any CPU
26
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Debug|x86.Build.0 = Debug|Any CPU
27
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
28
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Release|Any CPU.Build.0 = Release|Any CPU
29
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Release|x64.ActiveCfg = Release|Any CPU
30
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Release|x64.Build.0 = Release|Any CPU
31
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Release|x86.ActiveCfg = Release|Any CPU
32
+ {B0E08B2C-51F8-4E11-9D7C-02F08EAFEAD1}.Release|x86.Build.0 = Release|Any CPU
33
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
35
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Debug|x64.ActiveCfg = Debug|Any CPU
36
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Debug|x64.Build.0 = Debug|Any CPU
37
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Debug|x86.ActiveCfg = Debug|Any CPU
38
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Debug|x86.Build.0 = Debug|Any CPU
39
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
40
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Release|Any CPU.Build.0 = Release|Any CPU
41
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Release|x64.ActiveCfg = Release|Any CPU
42
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Release|x64.Build.0 = Release|Any CPU
43
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Release|x86.ActiveCfg = Release|Any CPU
44
+ {4CD21D4F-5DCC-4506-8BDB-292555F43E9B}.Release|x86.Build.0 = Release|Any CPU
45
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Debug|Any CPU.Build.0 = Debug|Any CPU
47
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Debug|x64.ActiveCfg = Debug|Any CPU
48
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Debug|x64.Build.0 = Debug|Any CPU
49
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Debug|x86.ActiveCfg = Debug|Any CPU
50
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Debug|x86.Build.0 = Debug|Any CPU
51
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Release|Any CPU.ActiveCfg = Release|Any CPU
52
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Release|Any CPU.Build.0 = Release|Any CPU
53
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Release|x64.ActiveCfg = Release|Any CPU
54
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Release|x64.Build.0 = Release|Any CPU
55
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Release|x86.ActiveCfg = Release|Any CPU
56
+ {78C54755-0602-409D-8058-0AC3C339BF37}.Release|x86.Build.0 = Release|Any CPU
57
+ EndGlobalSection
58
+ GlobalSection(SolutionProperties) = preSolution
59
+ HideSolutionNode = FALSE
60
+ EndGlobalSection
61
+ EndGlobal
@@ -3,20 +3,44 @@ using Xunit;
3
3
  public class AcronymTest
4
4
  {
5
5
  [Fact]
6
- public void Empty_string_abbreviated_to_empty_string()
6
+ public void Basic()
7
7
  {
8
- Assert.Equal(string.Empty, Acronym.Abbreviate(string.Empty));
8
+ Assert.Equal("PNG", Acronym.Abbreviate("Portable Network Graphics"));
9
9
  }
10
10
 
11
- [Theory(Skip = "Remove to run test")]
12
- [InlineData("Portable Network Graphics", "PNG")]
13
- [InlineData("Ruby on Rails", "ROR")]
14
- [InlineData("HyperText Markup Language", "HTML")]
15
- [InlineData("First In, First Out", "FIFO")]
16
- [InlineData("PHP: Hypertext Preprocessor", "PHP")]
17
- [InlineData("Complementary metal-oxide semiconductor", "CMOS")]
18
- public void Phrase_abbreviated_to_acronym(string phrase, string expected)
11
+ [Fact(Skip = "Remove to run test")]
12
+ public void Lowercase_words()
19
13
  {
20
- Assert.Equal(expected, Acronym.Abbreviate(phrase));
14
+ Assert.Equal("ROR", Acronym.Abbreviate("Ruby on Rails"));
15
+ }
16
+
17
+ [Fact(Skip = "Remove to run test")]
18
+ public void Camelcase()
19
+ {
20
+ Assert.Equal("HTML", Acronym.Abbreviate("HyperText Markup Language"));
21
+ }
22
+
23
+ [Fact(Skip = "Remove to run test")]
24
+ public void Punctuation()
25
+ {
26
+ Assert.Equal("FIFO", Acronym.Abbreviate("First In, First Out"));
27
+ }
28
+
29
+ [Fact(Skip = "Remove to run test")]
30
+ public void All_caps_words()
31
+ {
32
+ Assert.Equal("PHP", Acronym.Abbreviate("PHP: Hypertext Preprocessor"));
33
+ }
34
+
35
+ [Fact(Skip = "Remove to run test")]
36
+ public void NonAcronymAllCapsWord()
37
+ {
38
+ Assert.Equal("GIMP", Acronym.Abbreviate("GNU Image Manipulation Program"));
39
+ }
40
+
41
+ [Fact(Skip = "Remove to run test")]
42
+ public void Hyphenated()
43
+ {
44
+ Assert.Equal("CMOS", Acronym.Abbreviate("Complementary metal-oxide semiconductor"));
21
45
  }
22
46
  }
@@ -2,7 +2,7 @@
2
2
  using System.Linq;
3
3
  using Xunit;
4
4
 
5
- public class ParallelLetterParallelLetterFrequency
5
+ public class ParallelLetterFrequencyTest
6
6
  {
7
7
  // Poem by Friedrich Schiller. The corresponding music is the European Anthem.
8
8
  private const string OdeAnDieFreude =
@@ -118,4 +118,4 @@ public class ParallelLetterParallelLetterFrequency
118
118
  Assert.Equal(56, actual['t']);
119
119
  Assert.Equal(2, actual['ü']);
120
120
  }
121
- }
121
+ }
@@ -1,8 +1,8 @@
1
1
  ## Running The Tests
2
2
 
3
- Exercises that have been fetched using the Exercism.io client are delivered with a minimum of three files: a `readme.md` file, a `.dpr` file, and a `.pas` file. The `.dpr` file is the Delphi project file and the `.pas` file is the test runner. Load the Delphi project by either double clicking on the `.dpr` file or by opening the project from with in Delphi. You will be responsible for creating a new `.pas` file that will contain your solution code that the tests will be run against. Refer to the `readme.md` file for instruction on how to compiles and execute your code.
3
+ Exercises that have been fetched using the Exercism.io [command line client](http://www.exercism.io/cli) are delivered with a minimum of three files: a `readme.md` file, a `.dpr` file, and a `.pas` file. The `.dpr` file is the Delphi project file and the `.pas` file is the test runner. Load the Delphi project by either double clicking on the `.dpr` file or by opening the project from with in Delphi. You will be responsible for creating a new `.pas` file that will contain your solution code that the tests will be run against. Refer to the `readme.md` file for instruction on how to compile and execute your code.
4
4
 
5
- All tests have been ignored except the first one for you to work on. To continue, just comment the ```[Ignore]``` attribute on the test to start working on it.
5
+ All tests have been ignored except the first one for you to work on. To continue, just comment the `[Ignore]` attribute on the test to start working on it.
6
6
 
7
7
  Make sure [DUnitX](https://github.com/VSoftTechnologies/DUnitX) is installed, if not already installed from the setup above.
8
8
 
@@ -10,7 +10,7 @@ defmodule Bowling do
10
10
  end
11
11
 
12
12
  @doc """
13
- Records the number of pins knocked down on a single roll. Returns `:ok`
13
+ Records the number of pins knocked down on a single roll. Returns `any`
14
14
  unless there is something wrong with the given number of pins, in which
15
15
  case it returns a helpful message.
16
16
  """
@@ -6,8 +6,9 @@
6
6
  * The [F# Foundation](http://fsharp.org/) is a non-profit organisation which aim is to promote F#. The website has lots of links to great F# content. Perhaps even more interesting is their [mentorship program](http://fsharp.org/mentorship/index.html), where you can apply to learn F# from an experienced F# mentor.
7
7
 
8
8
  ### Videos
9
- * [F# for the Practical Developer](https://www.youtube.com/watch?v=7z_q06HQLes&t=2070s) is a nice introduction to F#.
9
+ * [F# for the Practical Developer](https://www.youtube.com/watch?v=7z_q06HQLes) is a nice introduction to F#.
10
10
  * [F# - Why you should give an F](https://www.youtube.com/watch?v=kKkFabSzZvU) has Daniel Chambers give a sweet introduction into F#, neatly highlighting most F#'s features.
11
+ * In [A tour of F#](https://www.youtube.com/watch?v=15tK48Xes0k), Phillip Carter gives a great introduction to the F# language.
11
12
  * [Dr. Don Syme - Introduction to F#](https://channel9.msdn.com/Series/C9-Lectures-Dr-Don-Syme-Introduction-to-F-/C9-Lectures-Dr-Don-Syme-Introduction-to-F-1-of-3) has Don Syme, the designer of F#, give an introduction to F#.
12
13
  * If you're a C# developer, you might like [F# for C# developers](https://vimeo.com/78908217) by Phil Trelford.
13
14
  * [PluralSight](https://www.pluralsight.com/) has several [great](https://www.pluralsight.com/courses/fsintro) [introduction](https://www.pluralsight.com/courses/fsharp-jumpstart) [courses](https://www.pluralsight.com/courses/fsharp-fundamentals). The downside: PluralSight is a paid service, but you can request a [free trial](https://www.pluralsight.com/pricing).
@@ -4,7 +4,6 @@
4
4
  "repository": "https://github.com/exercism/xgo",
5
5
  "active": true,
6
6
  "deprecated": [
7
- "accumulate",
8
7
  "binary",
9
8
  "bottles",
10
9
  "counter",
@@ -80,6 +79,13 @@
80
79
  "Filtering"
81
80
  ]
82
81
  },
82
+ {
83
+ "difficulty": 1,
84
+ "slug": "accumulate",
85
+ "topics": [
86
+ "Lists"
87
+ ]
88
+ },
83
89
  {
84
90
  "difficulty": 3,
85
91
  "slug": "acronym",
@@ -26,10 +26,13 @@ var tests = []struct {
26
26
  {93819012551, []int64{11, 9539, 894119}},
27
27
  }
28
28
 
29
- func TestPrimeFactors(t *testing.T) {
29
+ func TestTestVersion(t *testing.T) {
30
30
  if testVersion != targetTestVersion {
31
31
  t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
32
32
  }
33
+ }
34
+
35
+ func TestPrimeFactors(t *testing.T) {
33
36
  for _, test := range tests {
34
37
  actual := Factors(test.input)
35
38
  if !reflect.DeepEqual(actual, test.expected) {
@@ -44,6 +44,12 @@ var proteinTestCases = []rnaCase{
44
44
  {"UGGUGUUAUUAAUGGUUU", []string{"Tryptophan", "Cysteine", "Tyrosine"}},
45
45
  }
46
46
 
47
+ func TestTestVersion(t *testing.T) {
48
+ if testVersion != targetTestVersion {
49
+ t.Fatalf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
50
+ }
51
+ }
52
+
47
53
  func TestCodon(t *testing.T) {
48
54
  for _, test := range codonTestCases {
49
55
  actual := FromCodon(test.input)
@@ -61,9 +67,3 @@ func TestProtein(t *testing.T) {
61
67
  }
62
68
  }
63
69
  }
64
-
65
- func TestTestVersion(t *testing.T) {
66
- if testVersion != targetTestVersion {
67
- t.Errorf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
68
- }
69
- }
@@ -1,5 +1,7 @@
1
1
  package pythagorean
2
2
 
3
+ const testVersion = 1
4
+
3
5
  type Triplet [3]int
4
6
 
5
7
  func pyth(a, b, c int) bool {
@@ -24,6 +24,14 @@ import (
24
24
  "testing"
25
25
  )
26
26
 
27
+ const targetTestVersion = 1
28
+
29
+ func TestTestVersion(t *testing.T) {
30
+ if testVersion != targetTestVersion {
31
+ t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
32
+ }
33
+ }
34
+
27
35
  var rangeTests = []struct {
28
36
  min, max int
29
37
  ts []Triplet
@@ -1,4 +1,6 @@
1
1
  # Exercism Julia Track
2
+
3
+ [![Join the chat at https://gitter.im/exercism/xjulia](https://badges.gitter.im/exercism/xjulia.svg)](https://gitter.im/exercism/xjulia?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2
4
  [![Build Status](https://travis-ci.org/exercism/xjulia.svg?branch=master)](https://travis-ci.org/exercism/xjulia)
3
5
 
4
6
  Exercism exercises in Julia.
@@ -215,6 +215,15 @@
215
215
  "mathematics"
216
216
  ]
217
217
  },
218
+ {
219
+ "slug": "rotational-cipher",
220
+ "difficulty": 2,
221
+ "topics": [
222
+ "string literals",
223
+ "metaprogramming",
224
+ "strings"
225
+ ]
226
+ },
218
227
  {
219
228
  "slug": "custom-set",
220
229
  "difficulty": 5,
@@ -0,0 +1,21 @@
1
+ This is a good exercise to experiment with non-standard string literals and metaprogramming.
2
+
3
+ A short introduction to non-standard string literals can be found in this [blog post](http://iaindunning.com/blog/julia-unicode.html). A detailed metaprogramming guide can be found in the [manual](http://docs.julialang.org/en/stable/manual/metaprogramming/).
4
+
5
+ You can extend your solution by adding the functionality described below. To test your solution, you have to remove the comments at the end of `runtests.jl` before running the tests as usual.
6
+
7
+ Bonus A only requires basics as outlined in the blog post. Bonus B requires significantly more knowledge of metaprogramming in Julia.
8
+
9
+ ## Bonus A
10
+ Implement a string literal that acts as `ROT13` on the string:
11
+ ```julia
12
+ R13"abcdefghijklmnopqrstuvwxyz" == "nopqrstuvwxyzabcdefghijklm"
13
+ ```
14
+
15
+ ## Bonus B
16
+ Implement string literals `R<i>`, `i = 0, ..., 26`, that shift the string for `i` values:
17
+ ```julia
18
+ R0"Hello, World!" == "Hello, World!"
19
+ R4"Testing 1 2 3 testing" == "Xiwxmrk 1 2 3 xiwxmrk"
20
+ R13"abcdefghijklmnopqrstuvwxyz" == "nopqrstuvwxyzabcdefghijklm"
21
+ ```
@@ -0,0 +1,16 @@
1
+ function rotate(n::Int, c::Char)
2
+ if c in 'a':'z'
3
+ c = 'a' + (c - 'a' + n) % 26
4
+ elseif c in 'A':'Z'
5
+ c = 'A' + (c - 'A' + n) % 26
6
+ end
7
+ return c
8
+ end
9
+
10
+ rotate(n::Int, s::String) = join(rotate(n, c) for c in s)
11
+
12
+ for n in 0:26
13
+ eval( :(macro $(Symbol(:R, n, :_str))(s::String)
14
+ :(rotate($$n, $s))
15
+ end))
16
+ end
@@ -0,0 +1,51 @@
1
+ using Base.Test
2
+
3
+ include("rotational-cipher.jl")
4
+
5
+ @testset "rotate function" begin
6
+ @testset "rotate by n" begin
7
+ @testset "no wrap" begin
8
+ @test rotate(1, "a") == "b"
9
+ @test rotate(1, 'a') == 'b'
10
+ @test rotate(13, "m") == "z"
11
+ @test rotate(13, 'm') == 'z'
12
+ end
13
+ @testset "wrap around" begin
14
+ @test rotate(13, "n") == "a"
15
+ @test rotate(13, 'n') == 'a'
16
+ end
17
+ end
18
+
19
+ @testset "full rotation" begin
20
+ @test rotate(26, "a") == "a"
21
+ @test rotate(26, 'a') == 'a'
22
+ @test rotate(0, "a") == "a"
23
+ @test rotate(0, 'a') == 'a'
24
+ end
25
+
26
+ @testset "full strings" begin
27
+ @test rotate(5, "OMG") == "TRL"
28
+ @test rotate(5, "O M G") == "T R L"
29
+ @test rotate(4, "Testing 1 2 3 testing") == "Xiwxmrk 1 2 3 xiwxmrk"
30
+ @test rotate(21, "Let's eat, Grandma!") == "Gzo'n zvo, Bmviyhv!"
31
+ @test rotate(13, "The quick brown fox jumps over the lazy dog.") == "Gur dhvpx oebja sbk whzcf bire gur ynml qbt."
32
+ end
33
+ end
34
+
35
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
36
+ # Additional exercises #
37
+ # Remove the comments for the optional bonus exercises from HINTS.md #
38
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
39
+
40
+ # Bonus A
41
+ # @testset "string literal R13" begin
42
+ # @test R13"The quick brown fox jumps over the lazy dog." == "Gur dhvpx oebja sbk whzcf bire gur ynml qbt."
43
+ # end
44
+
45
+ # Bonus B
46
+ # @testset "string literals" begin
47
+ # @test R5"OMG" == "TRL"
48
+ # @test R4"Testing 1 2 3 testing" == "Xiwxmrk 1 2 3 xiwxmrk"
49
+ # @test R21"Let's eat, Grandma!" == "Gzo'n zvo, Bmviyhv!"
50
+ # @test R13"The quick brown fox jumps over the lazy dog." == "Gur dhvpx oebja sbk whzcf bire gur ynml qbt."
51
+ # end
@@ -161,6 +161,11 @@
161
161
  "difficulty": 8,
162
162
  "topics": []
163
163
  },
164
+ {
165
+ "slug": "connect",
166
+ "difficulty": 8,
167
+ "topics": ["Search"]
168
+ },
164
169
  {
165
170
  "slug": "meetup",
166
171
  "difficulty": 9,
@@ -0,0 +1,3 @@
1
+ S *
2
+ B _build/**
3
+ PKG core oUnit
@@ -0,0 +1,15 @@
1
+ test: test.native
2
+ @./test.native
3
+
4
+ test.native: *.ml *.mli
5
+ @corebuild -r -quiet -pkg oUnit test.native
6
+
7
+ main.byte: clean
8
+ @corebuild -r -quiet main.byte
9
+
10
+ clean:
11
+ rm -rf _build
12
+ rm -f test.native
13
+ rm -f main.byte
14
+
15
+ .PHONY: clean
@@ -0,0 +1,4 @@
1
+ type player = O | X
2
+
3
+ (* Returns the winning player inside the option if there is a winner, otherwise None *)
4
+ val connect : string list -> player option
@@ -0,0 +1,80 @@
1
+ open Core.Std
2
+
3
+ type player = O | X
4
+ type cell = O | X | Empty
5
+
6
+ module IntTuple = struct
7
+ type t = int * int
8
+
9
+ let compare (x0, y0) (x1, y1) =
10
+ match Int.compare x0 x1 with
11
+ 0 -> Int.compare y0 y1
12
+ | c -> c
13
+
14
+ let t_of_sexp tuple = Tuple2.t_of_sexp Int.t_of_sexp Int.t_of_sexp tuple
15
+ let sexp_of_t tuple = Tuple2.sexp_of_t Int.sexp_of_t Int.sexp_of_t tuple
16
+ end
17
+
18
+ module IntIntSet = Set.Make(IntTuple)
19
+
20
+ let (>|>) f g = Fn.compose g f
21
+
22
+ let to_matrix (b: string list): cell array array =
23
+ let to_cell = function
24
+ | 'X' -> Some X
25
+ | 'O' -> Some O
26
+ | '.' -> Some Empty
27
+ | _ -> None in
28
+ List.map b ~f:(String.to_list >|> List.filter_map ~f:to_cell >|> Array.of_list) |> Array.of_list
29
+
30
+ let neighbouring_positions rows cols (r, c): (int * int) list =
31
+ let deltas = [
32
+ -1,0; -1,1;
33
+ 0,-1; 0,1;
34
+ 1,-1; 1,0;
35
+ ] in
36
+ List.filter_map deltas ~f:(fun (dr, dc) ->
37
+ if r + dr < 0 || r + dr >= rows || c + dc < 0 || c + dc >= cols
38
+ then None
39
+ else Some (r+dr, c+dc)
40
+ )
41
+
42
+ let neighbours board rows cols (r,c) =
43
+ let cell = board.(r).(c) in
44
+ let positions = neighbouring_positions rows cols (r,c) in
45
+ List.filter positions ~f:(fun (r1,c1) -> cell = board.(r1).(c1))
46
+
47
+ let search successors initial ~matches =
48
+ let rec go visited node =
49
+ if matches node then (true, visited)
50
+ else
51
+ if not (Set.mem visited node) then
52
+ begin
53
+ let visited = Set.add visited node in
54
+ let successor_nodes = successors node in
55
+ if List.is_empty successor_nodes
56
+ then (false, visited)
57
+ else
58
+ List.fold_left successor_nodes
59
+ ~f:(fun (fnd, v) n -> if fnd then (true, v) else go v n)
60
+ ~init:(false, visited)
61
+ end
62
+ else (false, visited)
63
+ in
64
+ Array.exists initial ~f:(go (IntIntSet.empty) >|> fst)
65
+
66
+ let connect board: player option =
67
+ let board = to_matrix board in
68
+ let rows = Array.length board in
69
+ let cols = Array.length board.(0) in
70
+ let search = search (neighbours board rows cols) in
71
+ let initials_x = Array.filter_mapi board ~f:(fun row cell -> if cell.(0) = X then Some (row, 0) else None) in
72
+ if search initials_x ~matches:(fun (r,c) -> (c = cols - 1) && board.(r).(c) = X)
73
+ then Some X
74
+ else
75
+ begin
76
+ let initials_o = Array.filter_mapi board.(0) ~f:(fun col cell -> if cell = O then Some (0, col) else None) in
77
+ if search initials_o ~matches:(fun (r,c) -> (r = rows - 1) && board.(r).(c) = O)
78
+ then Some O
79
+ else None
80
+ end