trackler 2.0.8.15 → 2.0.8.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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