New Fetch
This commit is contained in:
parent
ba838ca4fb
commit
a9630f6ee8
52
cpp/hello-world/CMakeLists.txt
Normal file
52
cpp/hello-world/CMakeLists.txt
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Get the exercise name from the current directory
|
||||||
|
get_filename_component(exercise ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
|
||||||
|
# Basic CMake project
|
||||||
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
|
|
||||||
|
# Name the project after the exercise
|
||||||
|
project(${exercise} CXX)
|
||||||
|
|
||||||
|
# Locate Boost libraries: unit_test_framework, date_time and regex
|
||||||
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
|
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||||
|
find_package(Boost 1.59 REQUIRED COMPONENTS unit_test_framework date_time regex)
|
||||||
|
|
||||||
|
# Enable C++11 features on gcc/clang
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)")
|
||||||
|
set(CMAKE_CXX_FLAGS "-std=c++11")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configure to run all the tests?
|
||||||
|
if(${EXERCISM_RUN_ALL_TESTS})
|
||||||
|
add_definitions(-DEXERCISM_RUN_ALL_TESTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get a source filename from the exercise name by replacing -'s with _'s
|
||||||
|
string(REPLACE "-" "_" file ${exercise})
|
||||||
|
|
||||||
|
# Implementation could be only a header
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.cpp)
|
||||||
|
set(exercise_cpp ${file}.cpp)
|
||||||
|
else()
|
||||||
|
set(exercise_cpp "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Build executable from sources and headers
|
||||||
|
add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h)
|
||||||
|
|
||||||
|
# We need boost includes
|
||||||
|
target_include_directories(${exercise} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# We need boost libraries
|
||||||
|
target_link_libraries(${exercise} ${Boost_LIBRARIES})
|
||||||
|
|
||||||
|
# Tell MSVC not to warn us about unchecked iterators in debug builds
|
||||||
|
if(${MSVC})
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Run the tests on every build
|
||||||
|
add_custom_command(TARGET ${exercise} POST_BUILD COMMAND ${exercise})
|
53
cpp/hello-world/README.md
Normal file
53
cpp/hello-world/README.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Hello World
|
||||||
|
|
||||||
|
The classical introductory exercise. Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
|
||||||
|
the traditional first program for beginning programming in a new language
|
||||||
|
or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Write a function that returns the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Make sure you have read [the C++ page](http://exercism.io/languages/cpp) on
|
||||||
|
exercism.io. This covers the basic information on setting up the development
|
||||||
|
environment expected by the exercises.
|
||||||
|
|
||||||
|
## Passing the Tests
|
||||||
|
|
||||||
|
Get the first test compiling, linking and passing by following the [three
|
||||||
|
rules of test-driven development](http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd).
|
||||||
|
Create just enough structure by declaring namespaces, functions, classes,
|
||||||
|
etc., to satisfy any compiler errors and get the test to fail. Then write
|
||||||
|
just enough code to get the test to pass. Once you've done that,
|
||||||
|
uncomment the next test by moving the following line past the next test.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
```
|
||||||
|
|
||||||
|
This may result in compile errors as new constructs may be invoked that
|
||||||
|
you haven't yet declared or defined. Again, fix the compile errors minimally
|
||||||
|
to get a failing test, then change the code minimally to pass the test,
|
||||||
|
refactor your implementation for readability and expressiveness and then
|
||||||
|
go on to the next test.
|
||||||
|
|
||||||
|
Try to use standard C++11 facilities in preference to writing your own
|
||||||
|
low-level algorithms or facilities by hand. [CppReference](http://en.cppreference.com/)
|
||||||
|
is a wiki reference to the C++ language and standard library. If you
|
||||||
|
are new to C++, but have programmed in C, beware of
|
||||||
|
[C traps and pitfalls](http://www.slideshare.net/LegalizeAdulthood/c-traps-and-pitfalls-for-c-programmers).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
12
cpp/hello-world/hello_world.h
Normal file
12
cpp/hello-world/hello_world.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#if !defined(HELLO_WORLD_H)
|
||||||
|
#define HELLO_WORLD_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace hello_world {
|
||||||
|
|
||||||
|
std::string hello();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
8
cpp/hello-world/hello_world_test.cpp
Normal file
8
cpp/hello-world/hello_world_test.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "hello_world.h"
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_hello)
|
||||||
|
{
|
||||||
|
BOOST_REQUIRE_EQUAL("Hello, World!", hello_world::hello());
|
||||||
|
}
|
16
crystal/hello-world/spec/hello_world_spec.cr
Normal file
16
crystal/hello-world/spec/hello_world_spec.cr
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
require "spec"
|
||||||
|
require "../src/*"
|
||||||
|
|
||||||
|
describe "HelloWorld" do
|
||||||
|
it "no name" do
|
||||||
|
HelloWorld.hello.should eq("Hello, World!")
|
||||||
|
end
|
||||||
|
|
||||||
|
pending "sample name" do
|
||||||
|
HelloWorld.hello("Alice").should eq("Hello, Alice!")
|
||||||
|
end
|
||||||
|
|
||||||
|
pending "other sample name" do
|
||||||
|
HelloWorld.hello("Bob").should eq("Hello, Bob!")
|
||||||
|
end
|
||||||
|
end
|
1
crystal/hello-world/src/hello_world.cr
Normal file
1
crystal/hello-world/src/hello_world.cr
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Please implement your solution to hello-world in this file
|
28
csharp/sum-of-multiples/README.md
Normal file
28
csharp/sum-of-multiples/README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Sum Of Multiples
|
||||||
|
|
||||||
|
Given a number, find the sum of all the multiples of particular numbers up to
|
||||||
|
but not including that number.
|
||||||
|
|
||||||
|
If we list all the natural numbers up to but not including 20 that are
|
||||||
|
multiples of either 3 or 5, we get 3, 5, 6 and 9, 10, 12, 15, and 18.
|
||||||
|
|
||||||
|
The sum of these multiples is 78.
|
||||||
|
|
||||||
|
Given a number, find the sum of the multiples of a given set of numbers,
|
||||||
|
up to but not including that number.
|
||||||
|
|
||||||
|
## Hints
|
||||||
|
This exercise requires you to process a collection of data. You can simplify your code by using LINQ (Language Integrated Query).
|
||||||
|
For more information, see [this page](https://docs.microsoft.com/en-us/dotnet/articles/standard/using-linq).
|
||||||
|
|
||||||
|
### Submitting Exercises
|
||||||
|
|
||||||
|
Note that, when trying to submit an exercise, make sure the exercise file that you're submitting is in the `exercism/csharp/<exerciseName>` directory.
|
||||||
|
|
||||||
|
For example, if you're submitting `bob.cs` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/csharp/bob/bob.cs`.
|
||||||
|
## Source
|
||||||
|
|
||||||
|
A variation on Problem 1 at Project Euler [http://projecteuler.net/problem=1](http://projecteuler.net/problem=1)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
10
csharp/sum-of-multiples/SumOfMultiples.cs
Normal file
10
csharp/sum-of-multiples/SumOfMultiples.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public static class SumOfMultiples
|
||||||
|
{
|
||||||
|
public static int To(IEnumerable<int> multiples, int max)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("You need to implement this function.");
|
||||||
|
}
|
||||||
|
}
|
18
csharp/sum-of-multiples/SumOfMultiples.csproj
Normal file
18
csharp/sum-of-multiples/SumOfMultiples.csproj
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp1.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Example.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.2.0" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
46
csharp/sum-of-multiples/SumOfMultiplesTest.cs
Normal file
46
csharp/sum-of-multiples/SumOfMultiplesTest.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class SumOfMultiplesTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Sum_to_1()
|
||||||
|
{
|
||||||
|
Assert.Equal(0, SumOfMultiples.To(new[] { 3, 5 }, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "Remove to run test")]
|
||||||
|
public void Sum_to_3()
|
||||||
|
{
|
||||||
|
Assert.Equal(3, SumOfMultiples.To(new[] { 3, 5 }, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "Remove to run test")]
|
||||||
|
public void Sum_to_10()
|
||||||
|
{
|
||||||
|
Assert.Equal(23, SumOfMultiples.To(new[] { 3, 5 }, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "Remove to run test")]
|
||||||
|
public void Sum_to_100()
|
||||||
|
{
|
||||||
|
Assert.Equal(2318, SumOfMultiples.To(new[] { 3, 5 }, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "Remove to run test")]
|
||||||
|
public void Sum_to_1000()
|
||||||
|
{
|
||||||
|
Assert.Equal(233168, SumOfMultiples.To(new[] { 3, 5 }, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "Remove to run test")]
|
||||||
|
public void Sum_to_20()
|
||||||
|
{
|
||||||
|
Assert.Equal(51, SumOfMultiples.To(new [] { 7, 13, 17 }, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "Remove to run test")]
|
||||||
|
public void Sum_to_10000()
|
||||||
|
{
|
||||||
|
Assert.Equal(2203160, SumOfMultiples.To(new [] { 43, 47 }, 10000));
|
||||||
|
}
|
||||||
|
}
|
14
elm/hello-world/package.json
Normal file
14
elm/hello-world/package.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"description": "Exercism/Elm",
|
||||||
|
"repository": "https://github.com/exercism/elm.git",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"postinstall": "elm-package install -y",
|
||||||
|
"watch": "elm-test --watch",
|
||||||
|
"test": "elm-test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"elm": "0.18.0",
|
||||||
|
"elm-test": "0.18.3"
|
||||||
|
}
|
||||||
|
}
|
26
elm/hello-world/tests/Tests.elm
Normal file
26
elm/hello-world/tests/Tests.elm
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
module Tests exposing (..)
|
||||||
|
|
||||||
|
import Test exposing (..)
|
||||||
|
import Expect
|
||||||
|
import HelloWorld exposing (helloWorld)
|
||||||
|
|
||||||
|
|
||||||
|
tests : Test
|
||||||
|
tests =
|
||||||
|
describe "Hello, World!"
|
||||||
|
[ test "Hello with no name" <|
|
||||||
|
\() ->
|
||||||
|
Expect.equal "Hello, World!" (helloWorld Nothing)
|
||||||
|
|
||||||
|
-- Once you get the first test passing, remove the
|
||||||
|
-- `skip <|` (just leave the comma) on the next two
|
||||||
|
-- lines to continue!
|
||||||
|
, skip <|
|
||||||
|
test "Hello to a sample name" <|
|
||||||
|
\() ->
|
||||||
|
Expect.equal "Hello, Alice!" (helloWorld (Just "Alice"))
|
||||||
|
, skip <|
|
||||||
|
test "Hello to another sample name" <|
|
||||||
|
\() ->
|
||||||
|
Expect.equal "Hello, Bob!" (helloWorld (Just "Bob"))
|
||||||
|
]
|
16
elm/hello-world/tests/elm-package.json
Normal file
16
elm/hello-world/tests/elm-package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"version": "3.0.0",
|
||||||
|
"summary": "Exercism problems in Elm.",
|
||||||
|
"repository": "https://github.com/exercism/elm.git",
|
||||||
|
"license": "BSD3",
|
||||||
|
"source-directories": [
|
||||||
|
".",
|
||||||
|
".."
|
||||||
|
],
|
||||||
|
"exposed-modules": [],
|
||||||
|
"dependencies": {
|
||||||
|
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||||
|
"elm-community/elm-test": "4.0.0 <= v < 5.0.0"
|
||||||
|
},
|
||||||
|
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||||
|
}
|
11
erlang/hello-world/include/exercism.hrl
Normal file
11
erlang/hello-world/include/exercism.hrl
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
sut(Module) ->
|
||||||
|
{ok, Files} = file:list_dir("./src"),
|
||||||
|
case lists:member("example.erl", Files) of
|
||||||
|
true -> example;
|
||||||
|
false -> Module
|
||||||
|
end.
|
||||||
|
|
||||||
|
version_test() ->
|
||||||
|
?assertMatch(?TEST_VERSION, ?TESTED_MODULE:test_version()).
|
30
erlang/hello-world/rebar.config
Normal file
30
erlang/hello-world/rebar.config
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
%% Erlang compiler options
|
||||||
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
|
{deps, []}.
|
||||||
|
|
||||||
|
{dialyzer, [
|
||||||
|
{warnings, [underspecs, no_return]},
|
||||||
|
{get_warnings, true},
|
||||||
|
{plt_apps, top_level_deps}, % top_level_deps | all_deps
|
||||||
|
{plt_extra_apps, []},
|
||||||
|
{plt_location, local}, % local | "/my/file/name"
|
||||||
|
{plt_prefix, "rebar3"},
|
||||||
|
{base_plt_apps, [stdlib, kernel, crypto]},
|
||||||
|
{base_plt_location, global}, % global | "/my/file/name"
|
||||||
|
{base_plt_prefix, "rebar3"}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
%% eunit:test(Tests)
|
||||||
|
{eunit_tests, []}.
|
||||||
|
%% Options for eunit:test(Tests, Opts)
|
||||||
|
{eunit_opts, [verbose]}.
|
||||||
|
|
||||||
|
%% == xref ==
|
||||||
|
|
||||||
|
{xref_warnings, true}.
|
||||||
|
|
||||||
|
%% xref checks to run
|
||||||
|
{xref_checks, [undefined_function_calls, undefined_functions,
|
||||||
|
locals_not_used, exports_not_used,
|
||||||
|
deprecated_function_calls, deprecated_functions]}.
|
9
erlang/hello-world/src/hello_world.app.src
Normal file
9
erlang/hello-world/src/hello_world.app.src
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{application, hello_world,
|
||||||
|
[{description, "exercism.io - hello-world"},
|
||||||
|
{vsn, "0.0.1"},
|
||||||
|
{modules, []},
|
||||||
|
{registered, []},
|
||||||
|
{applications, [kernel,
|
||||||
|
stdlib]},
|
||||||
|
{env, []}
|
||||||
|
]}.
|
8
erlang/hello-world/src/hello_world.erl
Normal file
8
erlang/hello-world/src/hello_world.erl
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
-module(hello_world).
|
||||||
|
|
||||||
|
-export([hello/0, test_version/0]).
|
||||||
|
|
||||||
|
hello() ->
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
test_version() -> 2.
|
9
erlang/hello-world/test/hello_world_tests.erl
Normal file
9
erlang/hello-world/test/hello_world_tests.erl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-module(hello_world_tests).
|
||||||
|
|
||||||
|
-define(TESTED_MODULE, (sut(hello_world))).
|
||||||
|
-define(TEST_VERSION, 2).
|
||||||
|
-include("exercism.hrl").
|
||||||
|
|
||||||
|
|
||||||
|
say_hi_test() ->
|
||||||
|
?assertEqual("Hello, World!", ?TESTED_MODULE:hello()).
|
64
go/pov/README.md
Normal file
64
go/pov/README.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Pov
|
||||||
|
|
||||||
|
Reparent a graph on a selected node.
|
||||||
|
|
||||||
|
# Tree Reparenting
|
||||||
|
|
||||||
|
This exercise is all about re-orientating a graph to see things from a different
|
||||||
|
point of view. For example family trees are usually presented from the
|
||||||
|
ancestor's perspective:
|
||||||
|
|
||||||
|
```
|
||||||
|
+------0------+
|
||||||
|
| | |
|
||||||
|
+-1-+ +-2-+ +-3-+
|
||||||
|
| | | | | |
|
||||||
|
4 5 6 7 8 9
|
||||||
|
```
|
||||||
|
|
||||||
|
But the same information can be presented from the perspective of any other node
|
||||||
|
in the graph, by pulling it up to the root and dragging its relationships along
|
||||||
|
with it. So the same graph from 6's perspective would look like:
|
||||||
|
|
||||||
|
```
|
||||||
|
6
|
||||||
|
|
|
||||||
|
+-----2-----+
|
||||||
|
| |
|
||||||
|
7 +-----0-----+
|
||||||
|
| |
|
||||||
|
+-1-+ +-3-+
|
||||||
|
| | | |
|
||||||
|
4 5 8 9
|
||||||
|
```
|
||||||
|
|
||||||
|
This lets us more simply describe the paths between two nodes. So for example
|
||||||
|
the path from 6-9 (which in the first graph goes up to the root and then down to
|
||||||
|
a different leaf node) can be seen to follow the path 6-2-0-3-9
|
||||||
|
|
||||||
|
This exercise involves taking an input graph and re-orientating it from the point
|
||||||
|
of view of one of the nodes.
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
To run the tests run the command `go test` from within the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||||
|
different specs, so the results from these benchmark tests may vary.
|
||||||
|
|
||||||
|
## Further information
|
||||||
|
|
||||||
|
For more detailed information about the Go track, including how to get help if
|
||||||
|
you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
Adaptation of exercise from 4clojure [https://www.4clojure.com/](https://www.4clojure.com/)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
298
go/pov/pov_test.go
Normal file
298
go/pov/pov_test.go
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
package pov
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const targetTestVersion = 2
|
||||||
|
|
||||||
|
// POV / reparent / change root of a tree
|
||||||
|
//
|
||||||
|
// API:
|
||||||
|
// type Graph
|
||||||
|
// func New() *Graph
|
||||||
|
// func (*Graph) AddNode(nodeLabel string)
|
||||||
|
// func (*Graph) AddArc(from, to string)
|
||||||
|
// func (*Graph) ArcList() []string
|
||||||
|
// func (*Graph) ChangeRoot(oldRoot, newRoot string) *Graph
|
||||||
|
//
|
||||||
|
// The type name is Graph because you'll probably be implementing a general
|
||||||
|
// directed graph representation, although the test program will only use
|
||||||
|
// it to create a tree. The term "arc" is used here to mean a directed edge.
|
||||||
|
//
|
||||||
|
// The test program will create a graph with New, then use AddNode to add
|
||||||
|
// leaf nodes. After that it will use AddArc to construct the rest of the tree
|
||||||
|
// from the bottom up. That is, the `to` argument will aways specify a node
|
||||||
|
// that has already been added.
|
||||||
|
//
|
||||||
|
// ArcList is a dump method to let the test program see your graph. It must
|
||||||
|
// return a list of all arcs in the graph. Format each arc as a single string
|
||||||
|
// like "from -> to". The test program can then easily sort the list and
|
||||||
|
// compare it to an expected result. You do not need to bother with sorting
|
||||||
|
// the list yourself.
|
||||||
|
//
|
||||||
|
// All this graph construction and dumping must be working before you start
|
||||||
|
// on the interesting part of the exercise, so it is tested separately as
|
||||||
|
// a first test.
|
||||||
|
//
|
||||||
|
// API function ChangeRoot does the interesting part of the exercise.
|
||||||
|
// OldRoot is passed (as a convenience) and you must return a graph with
|
||||||
|
// newRoot as the root. You can modify the original graph in place and
|
||||||
|
// return it or create a new graph and return that. If you return a new
|
||||||
|
// graph you are free to consume or destroy the original graph. Of course
|
||||||
|
// it's nice to leave it unmodified.
|
||||||
|
|
||||||
|
type arc struct{ fr, to string }
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
description string
|
||||||
|
leaves []string
|
||||||
|
arcPairs []arc
|
||||||
|
root string
|
||||||
|
arcStrings []string
|
||||||
|
reRooted []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var testCases = []testCase{
|
||||||
|
{
|
||||||
|
description: "singleton",
|
||||||
|
leaves: []string{"x"},
|
||||||
|
arcPairs: nil,
|
||||||
|
root: "x",
|
||||||
|
arcStrings: nil,
|
||||||
|
reRooted: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "simple tree",
|
||||||
|
leaves: []string{"sibling", "x"},
|
||||||
|
arcPairs: []arc{
|
||||||
|
{"parent", "sibling"},
|
||||||
|
{"parent", "x"},
|
||||||
|
},
|
||||||
|
root: "parent",
|
||||||
|
arcStrings: []string{
|
||||||
|
"parent -> sibling",
|
||||||
|
"parent -> x",
|
||||||
|
},
|
||||||
|
reRooted: []string{
|
||||||
|
"parent -> sibling",
|
||||||
|
"x -> parent",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "large flat",
|
||||||
|
leaves: []string{"sib-a", "sib-b", "x", "sib-c", "sib-d"},
|
||||||
|
arcPairs: []arc{
|
||||||
|
{"parent", "sib-a"},
|
||||||
|
{"parent", "sib-b"},
|
||||||
|
{"parent", "x"},
|
||||||
|
{"parent", "sib-c"},
|
||||||
|
{"parent", "sib-d"},
|
||||||
|
},
|
||||||
|
root: "parent",
|
||||||
|
arcStrings: []string{
|
||||||
|
"parent -> sib-a",
|
||||||
|
"parent -> sib-b",
|
||||||
|
"parent -> sib-c",
|
||||||
|
"parent -> sib-d",
|
||||||
|
"parent -> x",
|
||||||
|
},
|
||||||
|
reRooted: []string{
|
||||||
|
"parent -> sib-a",
|
||||||
|
"parent -> sib-b",
|
||||||
|
"parent -> sib-c",
|
||||||
|
"parent -> sib-d",
|
||||||
|
"x -> parent",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "deeply nested",
|
||||||
|
leaves: []string{"x"},
|
||||||
|
arcPairs: []arc{
|
||||||
|
{"level-4", "x"},
|
||||||
|
{"level-3", "level-4"},
|
||||||
|
{"level-2", "level-3"},
|
||||||
|
{"level-1", "level-2"},
|
||||||
|
{"level-0", "level-1"},
|
||||||
|
},
|
||||||
|
root: "level-0",
|
||||||
|
arcStrings: []string{
|
||||||
|
"level-0 -> level-1",
|
||||||
|
"level-1 -> level-2",
|
||||||
|
"level-2 -> level-3",
|
||||||
|
"level-3 -> level-4",
|
||||||
|
"level-4 -> x",
|
||||||
|
},
|
||||||
|
reRooted: []string{
|
||||||
|
"level-1 -> level-0",
|
||||||
|
"level-2 -> level-1",
|
||||||
|
"level-3 -> level-2",
|
||||||
|
"level-4 -> level-3",
|
||||||
|
"x -> level-4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "cousins",
|
||||||
|
leaves: []string{"sib-1", "x", "sib-2", "cousin-1", "cousin-2"},
|
||||||
|
arcPairs: []arc{
|
||||||
|
{"parent", "sib-1"},
|
||||||
|
{"parent", "x"},
|
||||||
|
{"parent", "sib-2"},
|
||||||
|
{"aunt", "cousin-1"},
|
||||||
|
{"aunt", "cousin-2"},
|
||||||
|
{"grand-parent", "parent"},
|
||||||
|
{"grand-parent", "aunt"},
|
||||||
|
},
|
||||||
|
root: "grand-parent",
|
||||||
|
arcStrings: []string{
|
||||||
|
"aunt -> cousin-1",
|
||||||
|
"aunt -> cousin-2",
|
||||||
|
"grand-parent -> aunt",
|
||||||
|
"grand-parent -> parent",
|
||||||
|
"parent -> sib-1",
|
||||||
|
"parent -> sib-2",
|
||||||
|
"parent -> x",
|
||||||
|
},
|
||||||
|
reRooted: []string{
|
||||||
|
"aunt -> cousin-1",
|
||||||
|
"aunt -> cousin-2",
|
||||||
|
"grand-parent -> aunt",
|
||||||
|
"parent -> grand-parent",
|
||||||
|
"parent -> sib-1",
|
||||||
|
"parent -> sib-2",
|
||||||
|
"x -> parent",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "target with children",
|
||||||
|
leaves: []string{"child-1", "child-2", "nephew", "niece",
|
||||||
|
"2nd-cousin-1", "2nd-cousin-2", "2nd-cousin-3", "2nd-cousin-4"},
|
||||||
|
arcPairs: []arc{
|
||||||
|
{"x", "child-1"},
|
||||||
|
{"x", "child-2"},
|
||||||
|
{"sibling", "nephew"},
|
||||||
|
{"sibling", "niece"},
|
||||||
|
{"cousin-1", "2nd-cousin-1"},
|
||||||
|
{"cousin-1", "2nd-cousin-2"},
|
||||||
|
{"cousin-2", "2nd-cousin-3"},
|
||||||
|
{"cousin-2", "2nd-cousin-4"},
|
||||||
|
{"parent", "x"},
|
||||||
|
{"parent", "sibling"},
|
||||||
|
{"aunt", "cousin-1"},
|
||||||
|
{"aunt", "cousin-2"},
|
||||||
|
{"grand-parent", "parent"},
|
||||||
|
{"grand-parent", "aunt"},
|
||||||
|
},
|
||||||
|
root: "grand-parent",
|
||||||
|
arcStrings: []string{
|
||||||
|
"aunt -> cousin-1",
|
||||||
|
"aunt -> cousin-2",
|
||||||
|
"cousin-1 -> 2nd-cousin-1",
|
||||||
|
"cousin-1 -> 2nd-cousin-2",
|
||||||
|
"cousin-2 -> 2nd-cousin-3",
|
||||||
|
"cousin-2 -> 2nd-cousin-4",
|
||||||
|
"grand-parent -> aunt",
|
||||||
|
"grand-parent -> parent",
|
||||||
|
"parent -> sibling",
|
||||||
|
"parent -> x",
|
||||||
|
"sibling -> nephew",
|
||||||
|
"sibling -> niece",
|
||||||
|
"x -> child-1",
|
||||||
|
"x -> child-2",
|
||||||
|
},
|
||||||
|
reRooted: []string{
|
||||||
|
"aunt -> cousin-1",
|
||||||
|
"aunt -> cousin-2",
|
||||||
|
"cousin-1 -> 2nd-cousin-1",
|
||||||
|
"cousin-1 -> 2nd-cousin-2",
|
||||||
|
"cousin-2 -> 2nd-cousin-3",
|
||||||
|
"cousin-2 -> 2nd-cousin-4",
|
||||||
|
"grand-parent -> aunt",
|
||||||
|
"parent -> grand-parent",
|
||||||
|
"parent -> sibling",
|
||||||
|
"sibling -> nephew",
|
||||||
|
"sibling -> niece",
|
||||||
|
"x -> child-1",
|
||||||
|
"x -> child-2",
|
||||||
|
"x -> parent",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc testCase) graph() *Graph {
|
||||||
|
g := New()
|
||||||
|
for _, l := range tc.leaves {
|
||||||
|
g.AddNode(l)
|
||||||
|
}
|
||||||
|
for _, a := range tc.arcPairs {
|
||||||
|
g.AddArc(a.fr, a.to)
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc testCase) testResult(got, want []string, msg string, t *testing.T) {
|
||||||
|
if len(got)+len(want) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gs := append([]string{}, got...)
|
||||||
|
sort.Strings(gs)
|
||||||
|
if reflect.DeepEqual(gs, want) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// test has failed
|
||||||
|
t.Log(tc.description, "test case")
|
||||||
|
t.Log(msg)
|
||||||
|
t.Logf("got %d arcs:", len(got))
|
||||||
|
for _, s := range got {
|
||||||
|
t.Log(" ", s)
|
||||||
|
}
|
||||||
|
t.Logf("that result sorted:")
|
||||||
|
for _, s := range gs {
|
||||||
|
t.Log(" ", s)
|
||||||
|
}
|
||||||
|
t.Logf("want %d arcs:", len(want))
|
||||||
|
for _, s := range want {
|
||||||
|
t.Log(" ", s)
|
||||||
|
}
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTestVersion(t *testing.T) {
|
||||||
|
if testVersion != targetTestVersion {
|
||||||
|
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConstruction(t *testing.T) {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
got := tc.graph().ArcList()
|
||||||
|
want := tc.arcStrings
|
||||||
|
tc.testResult(got, want, "incorrect graph construction", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangeRoot(t *testing.T) {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
got := tc.graph().ChangeRoot(tc.root, "x").ArcList()
|
||||||
|
want := tc.reRooted
|
||||||
|
tc.testResult(got, want, "incorrect root change", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkConstructOnlyNoChange(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc.graph()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkConstructAndChangeRoot(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc.graph().ChangeRoot(tc.root, "x")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
go/transpose/README.md
Normal file
83
go/transpose/README.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Transpose
|
||||||
|
|
||||||
|
Given an input text output it transposed.
|
||||||
|
|
||||||
|
Roughly explained, the transpose of a matrix:
|
||||||
|
|
||||||
|
```
|
||||||
|
ABC
|
||||||
|
DEF
|
||||||
|
```
|
||||||
|
|
||||||
|
is given by:
|
||||||
|
|
||||||
|
```
|
||||||
|
AD
|
||||||
|
BE
|
||||||
|
CF
|
||||||
|
```
|
||||||
|
|
||||||
|
Rows become columns and columns become rows. See <https://en.wikipedia.org/wiki/Transpose>.
|
||||||
|
|
||||||
|
If the input has rows of different lengths, this is to be solved as follows:
|
||||||
|
|
||||||
|
- Pad to the left with spaces.
|
||||||
|
- Don't pad to the right.
|
||||||
|
|
||||||
|
Therefore, transposing this matrix:
|
||||||
|
|
||||||
|
```
|
||||||
|
ABC
|
||||||
|
DE
|
||||||
|
```
|
||||||
|
|
||||||
|
results in:
|
||||||
|
|
||||||
|
```
|
||||||
|
AD
|
||||||
|
BE
|
||||||
|
C
|
||||||
|
```
|
||||||
|
|
||||||
|
And transposing:
|
||||||
|
|
||||||
|
```
|
||||||
|
AB
|
||||||
|
DEF
|
||||||
|
```
|
||||||
|
|
||||||
|
results in:
|
||||||
|
|
||||||
|
```
|
||||||
|
AD
|
||||||
|
BE
|
||||||
|
F
|
||||||
|
```
|
||||||
|
|
||||||
|
In general, all characters from the input should also be present in the transposed output.
|
||||||
|
That means that if a column in the input text contains only spaces on its bottom-most row(s),
|
||||||
|
the corresponding output row should contain the spaces in its right-most column(s).
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
To run the tests run the command `go test` from within the exercise directory.
|
||||||
|
|
||||||
|
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||||
|
flag:
|
||||||
|
|
||||||
|
go test -bench .
|
||||||
|
|
||||||
|
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||||
|
different specs, so the results from these benchmark tests may vary.
|
||||||
|
|
||||||
|
## Further information
|
||||||
|
|
||||||
|
For more detailed information about the Go track, including how to get help if
|
||||||
|
you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
Reddit r/dailyprogrammer challenge #270 [Easy]. [https://www.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text](https://www.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
248
go/transpose/cases_test.go
Normal file
248
go/transpose/cases_test.go
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
package transpose
|
||||||
|
|
||||||
|
// Source: exercism/x-common
|
||||||
|
// Commit: 6dba022 transpose: Fix canonical-data.json formatting
|
||||||
|
// x-common version: 1.0.0
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
description string
|
||||||
|
input []string
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"empty string",
|
||||||
|
[]string{},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"two characters in a row",
|
||||||
|
[]string{
|
||||||
|
"A1",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"A",
|
||||||
|
"1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"two characters in a column",
|
||||||
|
[]string{
|
||||||
|
"A",
|
||||||
|
"1",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"A1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"simple",
|
||||||
|
[]string{
|
||||||
|
"ABC",
|
||||||
|
"123",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"A1",
|
||||||
|
"B2",
|
||||||
|
"C3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"single line",
|
||||||
|
[]string{
|
||||||
|
"Single line.",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"S",
|
||||||
|
"i",
|
||||||
|
"n",
|
||||||
|
"g",
|
||||||
|
"l",
|
||||||
|
"e",
|
||||||
|
" ",
|
||||||
|
"l",
|
||||||
|
"i",
|
||||||
|
"n",
|
||||||
|
"e",
|
||||||
|
".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"first line longer than second line",
|
||||||
|
[]string{
|
||||||
|
"The fourth line.",
|
||||||
|
"The fifth line.",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"TT",
|
||||||
|
"hh",
|
||||||
|
"ee",
|
||||||
|
" ",
|
||||||
|
"ff",
|
||||||
|
"oi",
|
||||||
|
"uf",
|
||||||
|
"rt",
|
||||||
|
"th",
|
||||||
|
"h ",
|
||||||
|
" l",
|
||||||
|
"li",
|
||||||
|
"in",
|
||||||
|
"ne",
|
||||||
|
"e.",
|
||||||
|
".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"second line longer than first line",
|
||||||
|
[]string{
|
||||||
|
"The first line.",
|
||||||
|
"The second line.",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"TT",
|
||||||
|
"hh",
|
||||||
|
"ee",
|
||||||
|
" ",
|
||||||
|
"fs",
|
||||||
|
"ie",
|
||||||
|
"rc",
|
||||||
|
"so",
|
||||||
|
"tn",
|
||||||
|
" d",
|
||||||
|
"l ",
|
||||||
|
"il",
|
||||||
|
"ni",
|
||||||
|
"en",
|
||||||
|
".e",
|
||||||
|
" .",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"square",
|
||||||
|
[]string{
|
||||||
|
"HEART",
|
||||||
|
"EMBER",
|
||||||
|
"ABUSE",
|
||||||
|
"RESIN",
|
||||||
|
"TREND",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"HEART",
|
||||||
|
"EMBER",
|
||||||
|
"ABUSE",
|
||||||
|
"RESIN",
|
||||||
|
"TREND",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rectangle",
|
||||||
|
[]string{
|
||||||
|
"FRACTURE",
|
||||||
|
"OUTLINED",
|
||||||
|
"BLOOMING",
|
||||||
|
"SEPTETTE",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"FOBS",
|
||||||
|
"RULE",
|
||||||
|
"ATOP",
|
||||||
|
"CLOT",
|
||||||
|
"TIME",
|
||||||
|
"UNIT",
|
||||||
|
"RENT",
|
||||||
|
"EDGE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"triangle",
|
||||||
|
[]string{
|
||||||
|
"T",
|
||||||
|
"EE",
|
||||||
|
"AAA",
|
||||||
|
"SSSS",
|
||||||
|
"EEEEE",
|
||||||
|
"RRRRRR",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"TEASER",
|
||||||
|
" EASER",
|
||||||
|
" ASER",
|
||||||
|
" SER",
|
||||||
|
" ER",
|
||||||
|
" R",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"many lines",
|
||||||
|
[]string{
|
||||||
|
"Chor. Two households, both alike in dignity,",
|
||||||
|
"In fair Verona, where we lay our scene,",
|
||||||
|
"From ancient grudge break to new mutiny,",
|
||||||
|
"Where civil blood makes civil hands unclean.",
|
||||||
|
"From forth the fatal loins of these two foes",
|
||||||
|
"A pair of star-cross'd lovers take their life;",
|
||||||
|
"Whose misadventur'd piteous overthrows",
|
||||||
|
"Doth with their death bury their parents' strife.",
|
||||||
|
"The fearful passage of their death-mark'd love,",
|
||||||
|
"And the continuance of their parents' rage,",
|
||||||
|
"Which, but their children's end, naught could remove,",
|
||||||
|
"Is now the two hours' traffic of our stage;",
|
||||||
|
"The which if you with patient ears attend,",
|
||||||
|
"What here shall miss, our toil shall strive to mend.",
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
"CIFWFAWDTAWITW",
|
||||||
|
"hnrhr hohnhshh",
|
||||||
|
"o oeopotedi ea",
|
||||||
|
"rfmrmash cn t",
|
||||||
|
".a e ie fthow ",
|
||||||
|
" ia fr weh,whh",
|
||||||
|
"Trnco miae ie",
|
||||||
|
"w ciroitr btcr",
|
||||||
|
"oVivtfshfcuhhe",
|
||||||
|
" eeih a uote ",
|
||||||
|
"hrnl sdtln is",
|
||||||
|
"oot ttvh tttfh",
|
||||||
|
"un bhaeepihw a",
|
||||||
|
"saglernianeoyl",
|
||||||
|
"e,ro -trsui ol",
|
||||||
|
"h uofcu sarhu ",
|
||||||
|
"owddarrdan o m",
|
||||||
|
"lhg to'egccuwi",
|
||||||
|
"deemasdaeehris",
|
||||||
|
"sr als t ists",
|
||||||
|
",ebk 'phool'h,",
|
||||||
|
" reldi ffd ",
|
||||||
|
"bweso tb rtpo",
|
||||||
|
"oea ileutterau",
|
||||||
|
"t kcnoorhhnatr",
|
||||||
|
"hl isvuyee'fi ",
|
||||||
|
" atv es iisfet",
|
||||||
|
"ayoior trr ino",
|
||||||
|
"l lfsoh ecti",
|
||||||
|
"ion vedpn l",
|
||||||
|
"kuehtteieadoe ",
|
||||||
|
"erwaharrar,fas",
|
||||||
|
" nekt te rh",
|
||||||
|
"ismdsehphnnosa",
|
||||||
|
"ncuse ra-tau l",
|
||||||
|
" et tormsural",
|
||||||
|
"dniuthwea'g t ",
|
||||||
|
"iennwesnr hsts",
|
||||||
|
"g,ycoi tkrttet",
|
||||||
|
"n ,l r s'a anr",
|
||||||
|
"i ef 'dgcgdi",
|
||||||
|
"t aol eoe,v",
|
||||||
|
"y nei sl,u; e",
|
||||||
|
", .sf to l ",
|
||||||
|
" e rv d t",
|
||||||
|
" ; ie o",
|
||||||
|
" f, r ",
|
||||||
|
" e e m",
|
||||||
|
" . m e",
|
||||||
|
" o n",
|
||||||
|
" v d",
|
||||||
|
" e .",
|
||||||
|
" ,",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
32
go/transpose/transpose.go
Normal file
32
go/transpose/transpose.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package transpose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const testVersion = 1
|
||||||
|
|
||||||
|
func Transpose(inp []string) []string {
|
||||||
|
// find the longest length string in the slice
|
||||||
|
lng := 0
|
||||||
|
for i := range inp {
|
||||||
|
if len(inp[i]) > lng {
|
||||||
|
lng = len(inp[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret := make([]string, lng, lng)
|
||||||
|
for i := range inp {
|
||||||
|
for j := 0; j < lng; j++ {
|
||||||
|
if len(inp[i]) > j {
|
||||||
|
ret[j] = ret[j] + string(inp[i][j])
|
||||||
|
} else {
|
||||||
|
ret[j] = ret[j] + " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(ret) > 0 {
|
||||||
|
// Trim the spaces off of the end of the last line
|
||||||
|
ret[len(ret)-1] = strings.TrimRight(ret[len(ret)-1], " ")
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
52
go/transpose/transpose_test.go
Normal file
52
go/transpose/transpose_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package transpose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const targetTestVersion = 1
|
||||||
|
|
||||||
|
func TestTestVersion(t *testing.T) {
|
||||||
|
if testVersion != targetTestVersion {
|
||||||
|
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTranspose(t *testing.T) {
|
||||||
|
for _, test := range testCases {
|
||||||
|
actual := Transpose(test.input)
|
||||||
|
if !reflect.DeepEqual(actual, test.expected) {
|
||||||
|
// check for zero length slices
|
||||||
|
if len(actual) == 0 || len(test.expected) == 0 {
|
||||||
|
t.Fatalf("\n\tTranspose(%q): %s\n\n\tExpected: %q\n\tGot: %q",
|
||||||
|
test.input, test.description, test.expected, actual)
|
||||||
|
}
|
||||||
|
// let's make the error more specific and find the row it's on
|
||||||
|
min := min(len(test.expected), len(actual))
|
||||||
|
for i := 0; i < min; i++ {
|
||||||
|
if test.expected[i] != actual[i] {
|
||||||
|
t.Fatalf("\n\tTranspose(%q): %s\n\n\tExpected: %q\n\tGot: %q\n\n\tRow %d Expected: %q Got: %q",
|
||||||
|
test.input, test.description, test.expected, actual, i, test.expected[i], actual[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function
|
||||||
|
// https://stackoverflow.com/questions/27516387/what-is-the-correct-way-to-find-the-min-between-two-integers-in-go
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTranspose(b *testing.B) {
|
||||||
|
for _, test := range testCases {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Transpose(test.input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
haskell/hello-world/README.md
Normal file
83
haskell/hello-world/README.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Hello World
|
||||||
|
|
||||||
|
The classical introductory exercise. Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
|
||||||
|
the traditional first program for beginning programming in a new language
|
||||||
|
or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Write a function that returns the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
|
||||||
|
## Hints
|
||||||
|
|
||||||
|
To complete this exercise, you need to implement the `hello` function.
|
||||||
|
|
||||||
|
You will find the type signature for `hello` already in place,
|
||||||
|
but it is up to you to define the function.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
For installation and learning resources, refer to the
|
||||||
|
[exercism help page](http://exercism.io/languages/haskell).
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
To run the test suite, execute the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
stack test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### If you get an error message like this...
|
||||||
|
|
||||||
|
```
|
||||||
|
No .cabal file found in directory
|
||||||
|
```
|
||||||
|
|
||||||
|
You are probably running an old stack version and need
|
||||||
|
to upgrade it.
|
||||||
|
|
||||||
|
#### Otherwise, if you get an error message like this...
|
||||||
|
|
||||||
|
```
|
||||||
|
No compiler found, expected minor version match with...
|
||||||
|
Try running "stack setup" to install the correct GHC...
|
||||||
|
```
|
||||||
|
|
||||||
|
Just do as it says and it will download and install
|
||||||
|
the correct compiler version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
stack setup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running *GHCi*
|
||||||
|
|
||||||
|
If you want to play with your solution in GHCi, just run the command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
stack ghci
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feedback, Issues, Pull Requests
|
||||||
|
|
||||||
|
The [exercism/haskell](https://github.com/exercism/haskell) repository on
|
||||||
|
GitHub is the home for all of the Haskell exercises.
|
||||||
|
|
||||||
|
If you have feedback about an exercise, or want to help implementing a new
|
||||||
|
one, head over there and create an issue. We'll do our best to help you!
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
20
haskell/hello-world/package.yaml
Normal file
20
haskell/hello-world/package.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: hello-world
|
||||||
|
version: 1.0.0.3
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- base
|
||||||
|
|
||||||
|
library:
|
||||||
|
exposed-modules: HelloWorld
|
||||||
|
source-dirs: src
|
||||||
|
dependencies:
|
||||||
|
# - foo # List here the packages you
|
||||||
|
# - bar # want to use in your solution.
|
||||||
|
|
||||||
|
tests:
|
||||||
|
test:
|
||||||
|
main: Tests.hs
|
||||||
|
source-dirs: test
|
||||||
|
dependencies:
|
||||||
|
- hello-world
|
||||||
|
- hspec
|
4
haskell/hello-world/src/HelloWorld.hs
Normal file
4
haskell/hello-world/src/HelloWorld.hs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
module HelloWorld (hello) where
|
||||||
|
|
||||||
|
hello :: String
|
||||||
|
hello = error "You need to implement this function."
|
1
haskell/hello-world/stack.yaml
Normal file
1
haskell/hello-world/stack.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
resolver: lts-8.21
|
11
haskell/hello-world/test/Tests.hs
Normal file
11
haskell/hello-world/test/Tests.hs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import Test.Hspec (Spec, it, shouldBe)
|
||||||
|
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)
|
||||||
|
|
||||||
|
import HelloWorld (hello)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = hspecWith defaultConfig {configFastFail = True} specs
|
||||||
|
|
||||||
|
specs :: Spec
|
||||||
|
specs = it "hello" $
|
||||||
|
hello `shouldBe` "Hello, World!"
|
99
java/two-fer/README.md
Normal file
99
java/two-fer/README.md
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# Two Fer
|
||||||
|
|
||||||
|
`Two-fer` or `2-fer` is short for two for one. One for you and one for me.
|
||||||
|
|
||||||
|
```
|
||||||
|
"One for X, one for me."
|
||||||
|
```
|
||||||
|
|
||||||
|
When X is a name or "you".
|
||||||
|
|
||||||
|
If the given name is "Alice", the result should be "One for Alice, one for me."
|
||||||
|
If no name is given, the result should be "One for you, one for me."
|
||||||
|
|
||||||
|
|
||||||
|
## Test-Driven Development
|
||||||
|
|
||||||
|
As programmers mature, they eventually want to test their code.
|
||||||
|
|
||||||
|
Here at Exercism we simulate [Test-Driven
|
||||||
|
Development](http://en.wikipedia.org/wiki/Test-driven_development) (TDD), where
|
||||||
|
you write your tests before writing any functionality. The simulation comes in
|
||||||
|
the form of a pre-written test suite, which will signal that you have solved
|
||||||
|
the problem.
|
||||||
|
|
||||||
|
It will also provide you with a safety net to explore other solutions without
|
||||||
|
breaking the functionality.
|
||||||
|
|
||||||
|
### A typical TDD workflow on Exercism:
|
||||||
|
|
||||||
|
1. Run the test file and pick one test that's failing.
|
||||||
|
2. Write some code to fix the test you picked.
|
||||||
|
3. Re-run the tests to confirm the test is now passing.
|
||||||
|
4. Repeat from step 1.
|
||||||
|
5. Submit your solution (`exercism submit /path/to/file`)
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
Submissions are encouraged to be general, within reason. Having said that, it's
|
||||||
|
also important not to over-engineer a solution.
|
||||||
|
|
||||||
|
It's important to remember that the goal is to make code as expressive and
|
||||||
|
readable as we can.
|
||||||
|
|
||||||
|
Most Java exercises include multiple test cases. These cases are structured to
|
||||||
|
support a useful process known as
|
||||||
|
[test-driven development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development).
|
||||||
|
TDD involves repeating a structured cycle that helps programmers build complex
|
||||||
|
functionality piece by piece rather than all at once. That cycle can be
|
||||||
|
described as follows:
|
||||||
|
|
||||||
|
1. Add a test that describes one piece of desired functionality your code is
|
||||||
|
currently missing.
|
||||||
|
2. Run the tests to verify that this newly-added test fails.
|
||||||
|
3. Update your existing code until:
|
||||||
|
- All the old tests continue to pass;
|
||||||
|
- The new test also passes.
|
||||||
|
4. [Clean up](https://en.wikipedia.org/wiki/Code_refactoring) your code, making
|
||||||
|
sure that all tests continue to pass. This typically involves renaming
|
||||||
|
variables, removing duplicated chunks of logic, removing leftover logging, etc.
|
||||||
|
5. Return to step 1 until all desired functionality has been built!
|
||||||
|
|
||||||
|
The test files in this track contain _all_ the tests your solution should pass
|
||||||
|
to be considered valid. That doesn't immediately seem to be compatible with the
|
||||||
|
cycle described above, in which tests are written one by one. However, the
|
||||||
|
tool that we use to write our tests, [JUnit](http://junit.org), provides an
|
||||||
|
[@Ignore](http://junit.sourceforge.net/javadoc/org/junit/Ignore.html)
|
||||||
|
[annotation](https://docs.oracle.com/javase/tutorial/java/annotations/) that
|
||||||
|
can be used to temporarily skip an already-written test. Using this annotation,
|
||||||
|
we make sure that the test files we deliver to you satisfy the following rules:
|
||||||
|
|
||||||
|
- The first test in any test file is _not_ skipped by default.
|
||||||
|
- All but the first test in any test file _are_ skipped by default.
|
||||||
|
|
||||||
|
This allows you to simulate the TDD cycle by following these slightly-modified
|
||||||
|
steps:
|
||||||
|
|
||||||
|
1. Run the tests to verify that _at most one_ test currently fails.
|
||||||
|
2. Update your existing code until all the non-skipped tests pass.
|
||||||
|
3. Clean up your code, making sure that all non-skipped tests continue to pass.
|
||||||
|
4. Remove the topmost `@Ignore` annotation in the test file.
|
||||||
|
5. Return to step 1 until no tests are skipped and all tests pass!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
To run the tests:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ gradle test
|
||||||
|
```
|
||||||
|
|
||||||
|
For more detailed info about the Java track see the [help page](http://exercism.io/languages/java).
|
||||||
|
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
This is an exercise to introduce users to basic programming constructs, just after hello World. [https://en.wikipedia.org/wiki/Two-fer](https://en.wikipedia.org/wiki/Two-fer)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
17
java/two-fer/build.gradle
Normal file
17
java/two-fer/build.gradle
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "eclipse"
|
||||||
|
apply plugin: "idea"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testCompile "junit:junit:4.12"
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
testLogging {
|
||||||
|
exceptionFormat = 'full'
|
||||||
|
events = ["passed", "failed", "skipped"]
|
||||||
|
}
|
||||||
|
}
|
5
java/two-fer/src/main/java/Twofer.java
Normal file
5
java/two-fer/src/main/java/Twofer.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
public class Twofer {
|
||||||
|
public String twofer(String name) {
|
||||||
|
throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
|
||||||
|
}
|
||||||
|
}
|
41
java/two-fer/src/test/java/TwoferTest.java
Normal file
41
java/two-fer/src/test/java/TwoferTest.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class TwoferTest {
|
||||||
|
|
||||||
|
private Twofer twofer;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
twofer = new Twofer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noNameGiven() {
|
||||||
|
String input = null;
|
||||||
|
String expected = "One for you, one for me.";
|
||||||
|
|
||||||
|
assertEquals(expected, twofer.twofer(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Remove to run test")
|
||||||
|
@Test
|
||||||
|
public void aNameGiven() {
|
||||||
|
String input = "Alice";
|
||||||
|
String expected = "One for Alice, one for me.";
|
||||||
|
|
||||||
|
assertEquals(expected, twofer.twofer(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Remove to run test")
|
||||||
|
@Test
|
||||||
|
public void anotherNameGiven() {
|
||||||
|
String input = "Bob";
|
||||||
|
String expected = "One for Bob, one for me.";
|
||||||
|
|
||||||
|
assertEquals(expected, twofer.twofer(input));
|
||||||
|
}
|
||||||
|
}
|
50
kotlin/hello-world/GETTING_STARTED.md
Normal file
50
kotlin/hello-world/GETTING_STARTED.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
----
|
||||||
|
# Quick Start Guide
|
||||||
|
|
||||||
|
This guide picks-up where [Running the Tests (in Kotlin)](http://exercism.io/languages/kotlin/tests)
|
||||||
|
left off. If you haven't reviewed those instructions, do so now.
|
||||||
|
|
||||||
|
Need more information? A **step-by-step tutorial** is available in this directory at TUTORIAL.md or you can read
|
||||||
|
the [HTML version](https://github.com/exercism/kotlin/blob/master/exercises/hello-world/TUTORIAL.md).
|
||||||
|
|
||||||
|
The following instructions work equally well on Windows, Mac OS X and Linux.
|
||||||
|
|
||||||
|
## Solve "Hello World"
|
||||||
|
|
||||||
|
Try writing a solution that passes one test at a time, running Gradle each time:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Iterate through the tests
|
||||||
|
|
||||||
|
After your first test passes, remove the `@Ignore` from the next test, and iterate on your solution,
|
||||||
|
testing after each change.
|
||||||
|
|
||||||
|
## All the tests pass? Submit your solution!
|
||||||
|
|
||||||
|
With a working solution that we've reviewed, we're ready to submit it to
|
||||||
|
exercism.io.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ exercism submit src/main/kotlin/HelloWorld.kt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
From here, there are a number of paths you can take.
|
||||||
|
|
||||||
|
1. Move on to the next exercise
|
||||||
|
2. Review (and comment on) others' submissions to this exercise
|
||||||
|
3. Submit another iteration
|
||||||
|
4. Contribute to Exercism
|
||||||
|
|
||||||
|
|
||||||
|
We sincerely hope you learn and enjoy being part of this community. If at any time you need assistance
|
||||||
|
do not hesitate to ask for help:
|
||||||
|
|
||||||
|
http://exercism.io/languages/kotlin/help
|
||||||
|
|
||||||
|
Cheers!
|
692
kotlin/hello-world/TUTORIAL.md
Normal file
692
kotlin/hello-world/TUTORIAL.md
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
NOTE: You can also view the HTML version of this file here:
|
||||||
|
https://github.com/exercism/kotlin/blob/master/exercises/hello-world/TUTORIAL.md
|
||||||
|
|
||||||
|
* [Solving "Hello, World!"](#solving-hello-world)
|
||||||
|
* [Reading Gradle output](#reading-gradle-output)
|
||||||
|
* [Fixing the first failing test](#fixing-the-first-failing-test)
|
||||||
|
* [Enabling and fixing the second test](#enabling-and-fixing-the-second-test)
|
||||||
|
* [Enabling and fixing the third test](#enabling-and-fixing-the-third-test)
|
||||||
|
* [Enabling the last test](#enabling-the-last-test)
|
||||||
|
* [Refactoring](#refactoring)
|
||||||
|
* [Submitting your first iteration](#submitting-your-first-iteration)
|
||||||
|
* [Next Steps](#next-steps)
|
||||||
|
* [Review (and comment on) others' submissions to this exercise](#review-and-comment-on-others-submissions-to-this-exercise)
|
||||||
|
* [Extend an exercise](#extend-an-exercise)
|
||||||
|
* [Contribute to Exercism](#contribute-to-exercism)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
# Solving "Hello, World!"
|
||||||
|
|
||||||
|
Welcome to the first exercise on the Kotlin track!
|
||||||
|
|
||||||
|
This is a step-by-step guide to solving this exercise.
|
||||||
|
|
||||||
|
Each exercise comes with a set of tests. The first pass through the
|
||||||
|
exercise is about getting all of the tests to pass, one at a time.
|
||||||
|
|
||||||
|
If you have not installed the Java Development Kit and Gradle, you must do
|
||||||
|
so now. For help with this, see: http://exercism.io/languages/kotlin/installing
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
This guide picks-up where [Running the Tests (in Kotlin)](http://exercism.io/languages/kotlin/tests)
|
||||||
|
left off. If you haven't reviewed those instructions, do so now.
|
||||||
|
|
||||||
|
The following instructions work equally well on Windows, Mac OS X and Linux.
|
||||||
|
|
||||||
|
## Reading Gradle output
|
||||||
|
|
||||||
|
Use Gradle to run the tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
```
|
||||||
|
|
||||||
|
This command does a lot and displays a bunch of stuff. Let's break it down...
|
||||||
|
|
||||||
|
```
|
||||||
|
:compileKotlin
|
||||||
|
w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used
|
||||||
|
:compileJava UP-TO-DATE
|
||||||
|
:copyMainKotlinClasses
|
||||||
|
:processResources UP-TO-DATE
|
||||||
|
:classes UP-TO-DATE
|
||||||
|
```
|
||||||
|
|
||||||
|
Each line that begins with a colon (like `:compileKotlin`) is Gradle telling
|
||||||
|
us that it's starting that task. The first five tasks are about compiling
|
||||||
|
the source code of our *solution*. We've done you a favor and included just
|
||||||
|
enough code for the solution that it compiles.
|
||||||
|
|
||||||
|
When a task is successful, it generally does not output anything. This is
|
||||||
|
why `:copyMainKotlinClasses` does not produce any additional output.
|
||||||
|
|
||||||
|
A task may succeed but warn of a potential problem. This is what we see from
|
||||||
|
`:compileKotlin`. The Kotlin compiler tells us that on line 1, 11 characters in
|
||||||
|
of the `HelloWorld.kt` file, there is a parameter called `name` that was
|
||||||
|
declared but never used. Usually, warnings _are_ helpful and should be heeded.
|
||||||
|
We'll address this warning soon enough, but we're okay for now.
|
||||||
|
|
||||||
|
The next five tasks are about compiling source code of the *tests*.
|
||||||
|
|
||||||
|
```
|
||||||
|
:compileTestKotlin
|
||||||
|
:compileTestJava UP-TO-DATE
|
||||||
|
:copyTestKotlinClasses
|
||||||
|
:processTestResources UP-TO-DATE
|
||||||
|
:testClasses UP-TO-DATE
|
||||||
|
```
|
||||||
|
|
||||||
|
... with both sets of source code successfully compiled, Gradle turns to
|
||||||
|
running the task you asked it to: executing the tests against the solution.
|
||||||
|
|
||||||
|
```
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName SKIPPED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName SKIPPED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName FAILED
|
||||||
|
org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]>
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||||
|
at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||||
|
|
||||||
|
4 tests completed, 1 failed, 3 skipped
|
||||||
|
:test FAILED
|
||||||
|
|
||||||
|
FAILURE: Build failed with an exception.
|
||||||
|
|
||||||
|
* What went wrong:
|
||||||
|
Execution failed for task ':test'.
|
||||||
|
> There were failing tests. See the report at: file:///Users/jtigger/exercism/exercises/kotlin/hello-world/build/reports/tests/index.html
|
||||||
|
|
||||||
|
* Try:
|
||||||
|
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
|
||||||
|
|
||||||
|
BUILD FAILED
|
||||||
|
|
||||||
|
Total time: 7.473 secs
|
||||||
|
```
|
||||||
|
|
||||||
|
Seeing the word "fail" NINE TIMES might give you the impression you've done
|
||||||
|
something horribly wrong! You haven't. It's a whole lot of noise over
|
||||||
|
a single test not passing.
|
||||||
|
|
||||||
|
Let's focus in on the important bits:
|
||||||
|
|
||||||
|
```
|
||||||
|
HelloWorldTest > helloNoName FAILED
|
||||||
|
org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]>
|
||||||
|
```
|
||||||
|
|
||||||
|
...is read: "Within the test class named `HelloWorldTest`, the test method
|
||||||
|
`helloNoName` did not pass because the solution did not satisfy an
|
||||||
|
assertion. Apparently, we expected to see the string 'Hello, World!' but
|
||||||
|
a blank string was returned instead.
|
||||||
|
|
||||||
|
The last line of the stack trace tells us exactly where this unsatisfied
|
||||||
|
assertion lives:
|
||||||
|
|
||||||
|
```
|
||||||
|
at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
|
||||||
|
```
|
||||||
|
|
||||||
|
Looks like the scene of the crime is on line 10 in the test file.
|
||||||
|
|
||||||
|
Knowing these two facts,
|
||||||
|
|
||||||
|
1. the return value was not what was expected, and
|
||||||
|
2. the failure was on line 10 of the test,
|
||||||
|
|
||||||
|
we can turn this failure into success.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Fixing the first failing test
|
||||||
|
|
||||||
|
In your favorite text editor, open `src/test/kotlin/HelloWorldTest.kt`
|
||||||
|
and go to line 10.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
assertEquals("Hello, World!", hello(""))
|
||||||
|
```
|
||||||
|
|
||||||
|
The test is expecting that `hello()`, when given an empty string (`""`),
|
||||||
|
returns "Hello, World!". Instead, `hello()` is returning `""`.
|
||||||
|
Let's fix that.
|
||||||
|
|
||||||
|
Open `src/main/kotlin/HelloWorld.kt`.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = ""): String {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's change that to return the expected string:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = ""): String {
|
||||||
|
return "Hello, World!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the file and run the tests again:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
:compileKotlin
|
||||||
|
w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used
|
||||||
|
:compileJava UP-TO-DATE
|
||||||
|
:copyMainKotlinClasses
|
||||||
|
:processResources UP-TO-DATE
|
||||||
|
:classes UP-TO-DATE
|
||||||
|
:compileTestKotlin
|
||||||
|
:compileTestJava UP-TO-DATE
|
||||||
|
:copyTestKotlinClasses UP-TO-DATE
|
||||||
|
:processTestResources UP-TO-DATE
|
||||||
|
:testClasses UP-TO-DATE
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName SKIPPED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName SKIPPED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||||
|
|
||||||
|
BUILD SUCCESSFUL
|
||||||
|
|
||||||
|
Total time: 7.318 secs
|
||||||
|
```
|
||||||
|
|
||||||
|
"BUILD SUCCESSFUL"! Woohoo! :) You can see that `helloNoName()` test is
|
||||||
|
now passing.
|
||||||
|
|
||||||
|
We still see the warning about `name` not being used; we'll get to that
|
||||||
|
next.
|
||||||
|
|
||||||
|
With one win under our belt, we can turn our focus to some other messages
|
||||||
|
that we've been ignoring: the lines ending in "`SKIPPED`".
|
||||||
|
|
||||||
|
Each test suite contains a series of tests, all of which have been marked
|
||||||
|
to be skipped/ignored except the first one. We did this to help you focus
|
||||||
|
on getting one test running at a time.
|
||||||
|
|
||||||
|
Let's tackle the next test...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Enabling and fixing the second test
|
||||||
|
|
||||||
|
Right now, that second test is being skipped/ignored. Let's enable it.
|
||||||
|
|
||||||
|
(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the second test:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
fun helloSampleName() {
|
||||||
|
assertEquals("Hello, Alice!", hello("Alice"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When the JUnit test runner sees that `@Ignore` annotation on the test
|
||||||
|
method, it knows to skip over that test. Remove that line:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Test
|
||||||
|
fun helloSampleName() {
|
||||||
|
assertEquals("Hello, Alice!", hello("Alice"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, when you run the tests, both tests run:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName FAILED
|
||||||
|
org.junit.ComparisonFailure: expected:<Hello, [Alice]!> but was:<Hello, [World]!>
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||||
|
at HelloWorldTest.helloSampleName(HelloWorldTest.kt:15)
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName SKIPPED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||||
|
|
||||||
|
4 tests completed, 1 failed, 2 skipped
|
||||||
|
```
|
||||||
|
|
||||||
|
The first test, `helloNoName()` continues to pass. We see that
|
||||||
|
`helloSampleName` -- the test we just un-`@Ignore`'d -- is now running and
|
||||||
|
failing. Yay, failing test! In fact, the "failure" message is just
|
||||||
|
describing the difference between what the program does now and what it
|
||||||
|
should do for us to call it "done."
|
||||||
|
|
||||||
|
Right now, we've hardcoded the greeting. Enabling this second test has
|
||||||
|
unleashed a new expectation: that our program incorporate a name given
|
||||||
|
into that greeting. When given the name "`Alice`", that's who should be
|
||||||
|
greeted instead of "`World`".
|
||||||
|
|
||||||
|
(Re)open `src/main/kotlin/HelloWorld.kt`.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = ""): String {
|
||||||
|
return "Hello, World!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
While `hello()` does accept a reference to a string named `name`, it is not
|
||||||
|
using it in the output. Let's change that:
|
||||||
|
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = ""): String {
|
||||||
|
return "Hello, $name!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
_(Kotlin allows you to embed expressions within strings, a feature known as
|
||||||
|
string interpolation. For more about this feature, see
|
||||||
|
https://kotlinlang.org/docs/reference/basic-types.html#string-templates )_
|
||||||
|
|
||||||
|
... and rerun the tests ...
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName SKIPPED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName FAILED
|
||||||
|
org.junit.ComparisonFailure: expected:<Hello, [World]!> but was:<Hello, []!>
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||||
|
at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||||
|
|
||||||
|
4 tests completed, 1 failed, 2 skipped
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait... didn't we just fix the test? Why is it failing? Take a closer look...
|
||||||
|
|
||||||
|
In fact, `helloSampleName()` *is* passing. It's just that at the same time,
|
||||||
|
we just inadvertently broke that first test: `helloNoName()`.
|
||||||
|
|
||||||
|
This is one tiny example of the benefit of maintaining a test suite: if we
|
||||||
|
use them to drive out our code, the second we break the program the tests
|
||||||
|
say so. Since we saw them passing just *before* our latest change,
|
||||||
|
whatever we *just* did most likely cause that regression.
|
||||||
|
|
||||||
|
Our latest change was making the greeting dependent on the name given. If
|
||||||
|
no name is given, our function defaults to an empty string. The intent is
|
||||||
|
that when `hello()` is called on no one in particular, our function greets
|
||||||
|
the whole world. Sound like a job for a default value!
|
||||||
|
|
||||||
|
`src/main/kotlin/HelloWorld.kt`:
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = "World"): String {
|
||||||
|
return "Hello, $name!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
... and re-run the tests ...
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
:compileKotlin
|
||||||
|
:compileJava UP-TO-DATE
|
||||||
|
:copyMainKotlinClasses
|
||||||
|
:processResources UP-TO-DATE
|
||||||
|
:classes UP-TO-DATE
|
||||||
|
:compileTestKotlin
|
||||||
|
:compileTestJava UP-TO-DATE
|
||||||
|
:copyTestKotlinClasses
|
||||||
|
:processTestResources UP-TO-DATE
|
||||||
|
:testClasses UP-TO-DATE
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName SKIPPED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||||
|
|
||||||
|
BUILD SUCCESSFUL
|
||||||
|
```
|
||||||
|
|
||||||
|
Excellent! Not only are both our tests passing, but that pesky warning
|
||||||
|
about not using `name` has faded into the distant past. We're now
|
||||||
|
(at least) three-fourth the way done. Just two more tests to go...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Enabling and fixing the third test
|
||||||
|
|
||||||
|
(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the penultimate test:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
fun helloBlankName() {
|
||||||
|
assertEquals("Hello, World!", hello(" "))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this test, we're trying to be tricky. It's one thing to omit a
|
||||||
|
parameter completely; it's a whole other situation when we provide a blank
|
||||||
|
string for a name. This test is telling us that we'd like to treat these
|
||||||
|
cases the same way.
|
||||||
|
|
||||||
|
... and remove it's `@Ignore` to enable it ...
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Test
|
||||||
|
fun helloBlankName() {
|
||||||
|
assertEquals("Hello, World!", hello(" "))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
... and re-run the tests ...
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName FAILED
|
||||||
|
org.junit.ComparisonFailure: expected:<Hello, [World]!> but was:<Hello, [ ]!>
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||||
|
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||||
|
at HelloWorldTest.helloBlankName(HelloWorldTest.kt:20)
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||||
|
|
||||||
|
4 tests completed, 1 failed, 1 skipped
|
||||||
|
```
|
||||||
|
|
||||||
|
Since `" "` is an actual value, Kotlin does _not_ substitute in the
|
||||||
|
default value.
|
||||||
|
|
||||||
|
(Re)open `src/main/kotlin/HelloWorld.kt`.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = "World"): String {
|
||||||
|
return "Hello, $name!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
One way to handle this case is to check to see if `name` is blank. Let's
|
||||||
|
do that:
|
||||||
|
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = "World"): String {
|
||||||
|
return "Hello, ${if (name.isBlank()) "World" else name}!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see, string templates can contain not just references to
|
||||||
|
variables, but entire expressions! This is appropriate in a case like this
|
||||||
|
where we want to apply a simple condition to a value.
|
||||||
|
|
||||||
|
... and rerun the tests ...
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||||
|
|
||||||
|
BUILD SUCCESSFUL
|
||||||
|
```
|
||||||
|
|
||||||
|
We're almost there (perhaps closer than you think)! Just _one_ more test
|
||||||
|
to pass before we have a solution we can have real confidence in.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Enabling the last test
|
||||||
|
|
||||||
|
(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the last test:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
fun helloAnotherSampleName() {
|
||||||
|
assertEquals("Hello, Bob!", hello("Bob"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
... and pop-off that `@Ignore` ...
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Test
|
||||||
|
fun helloAnotherSampleName() {
|
||||||
|
assertEquals("Hello, Bob!", hello("Bob"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
... then rerun the tests ...
|
||||||
|
|
||||||
|
```
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName PASSED
|
||||||
|
|
||||||
|
BUILD SUCCESSFUL
|
||||||
|
```
|
||||||
|
|
||||||
|
Oh, hello! Turns out, the solution we put into place didn't just apply for
|
||||||
|
"`Alice`" but for "`Bob`" equally well. In this case, the test succeeded
|
||||||
|
with no additional code on our part.
|
||||||
|
|
||||||
|
Congratulations!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Refactoring
|
||||||
|
|
||||||
|
Now that you've got all the tests passing, you might consider whether
|
||||||
|
the code is in the most readable/maintainable/efficient shape. What makes
|
||||||
|
for "good" design of software is a big topic. The pursuit of it underlies
|
||||||
|
much of what makes up the more valuable conversations on Exercism.
|
||||||
|
|
||||||
|
Kotlin is such a concise language and this exercise is so small, there is
|
||||||
|
not much room for us to make adjustments. Most would leave this code, as
|
||||||
|
is.
|
||||||
|
|
||||||
|
That said, we've taken such pains to illustrate two core parts of the
|
||||||
|
Test-Driven Development approach (i.e. "red", "green"), we'd be remiss if
|
||||||
|
we skipped the all important final part: "refactor".
|
||||||
|
|
||||||
|
More on TDD at http://www.jamesshore.com/Blog/Red-Green-Refactor.html.
|
||||||
|
|
||||||
|
The core responsibility of `hello()` is to produce a personalized greeting.
|
||||||
|
_How_ we determine whether or not a name is given (i.e. `name` is
|
||||||
|
effectively an empty string) is a lower-level detail.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = "World"): String {
|
||||||
|
return "Hello, ${if (name.isBlank()) "World" else name}!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
How would things read if we extracted that detail into a separate method?
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun hello(name: String = ""): String {
|
||||||
|
return "Hello, ${whom(name)}!"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun whom(name: String):String {
|
||||||
|
return if(name.isBlank()) "World" else name
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
By extracting that logic into the `whom()` method, we've added a little
|
||||||
|
abstraction to our program — it's not as literal as it was before. Yet,
|
||||||
|
it allows us to defer _needing_ to understand _how_ the recipient of the
|
||||||
|
greeting is determined.
|
||||||
|
|
||||||
|
If we can assume that `whom()` just works, we don't have to
|
||||||
|
downshift in our head to those details. Instead, we can remain at the same
|
||||||
|
level of thinking: what's the greeting?
|
||||||
|
|
||||||
|
_(Yes, this is considerable more lines of code; again, not a move we'd likely
|
||||||
|
make typically. The takeaway is this: when you are "done" with an exercise
|
||||||
|
ask yourself, "can I adjust the shape of this code to better tell the
|
||||||
|
story of what's going on through its shape?")_
|
||||||
|
|
||||||
|
We made a bunch of changes, let's make sure we didn't break the program!
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gradle test
|
||||||
|
:compileKotlin
|
||||||
|
:compileJava UP-TO-DATE
|
||||||
|
:copyMainKotlinClasses
|
||||||
|
:processResources UP-TO-DATE
|
||||||
|
:classes UP-TO-DATE
|
||||||
|
:compileTestKotlin
|
||||||
|
:compileTestJava UP-TO-DATE
|
||||||
|
:copyTestKotlinClasses UP-TO-DATE
|
||||||
|
:processTestResources UP-TO-DATE
|
||||||
|
:testClasses UP-TO-DATE
|
||||||
|
:test
|
||||||
|
|
||||||
|
HelloWorldTest > helloSampleName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloBlankName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloNoName PASSED
|
||||||
|
|
||||||
|
HelloWorldTest > helloAnotherSampleName PASSED
|
||||||
|
|
||||||
|
BUILD SUCCESSFUL
|
||||||
|
```
|
||||||
|
|
||||||
|
This illustrates another benefit of writing tests: you can make significant
|
||||||
|
changes to the structure of the program and very quickly restore your
|
||||||
|
confidence that the program still works. These tests are a far cry from a
|
||||||
|
"proof" of correctness, but well-written tests do a much better job of
|
||||||
|
(very quickly) giving us evidence that it is. Without them, we manually
|
||||||
|
run the program with different inputs and/or inspecting the code
|
||||||
|
line-by-line — time-consuming and error prone.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Submitting your first iteration
|
||||||
|
|
||||||
|
With a working solution that we've reviewed, we're ready to submit it to
|
||||||
|
exercism.io.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ exercism submit src/main/kotlin/HelloWorld.kt
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Next Steps
|
||||||
|
|
||||||
|
From here, there are a number of paths you can take.
|
||||||
|
|
||||||
|
|
||||||
|
## Move on to the next exercise
|
||||||
|
|
||||||
|
There are many more exercises you can practice with. Grab the next one!
|
||||||
|
|
||||||
|
```
|
||||||
|
$ exercism fetch kotlin
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Review (and comment on) others' submissions to this exercise
|
||||||
|
|
||||||
|
The heart of Exercism is the conversations about coding
|
||||||
|
practices. It's definitely fun to practice, but engaging with others
|
||||||
|
both in their attempts and your own is how you get feedback. That feedback
|
||||||
|
can help point out what you're doing well and where you might need to
|
||||||
|
improve.
|
||||||
|
|
||||||
|
Some submissions will be nearly identical to yours; others will be
|
||||||
|
completely different. Seeing both kinds can be instructive and interesting.
|
||||||
|
|
||||||
|
Note that you can only view submissions of others for exercises you have
|
||||||
|
completed yourself. This enriches the experience of reading others' code
|
||||||
|
because you'll have your own experience of trying to solve the problem.
|
||||||
|
|
||||||
|
Here's an up-to-date list of submissions on the Kotlin track:
|
||||||
|
|
||||||
|
http://exercism.io/tracks/kotlin/exercises
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Submit another iteration
|
||||||
|
|
||||||
|
You are also encouraged to consider additional "requirements" on a given
|
||||||
|
exercise.
|
||||||
|
|
||||||
|
For example, you could add a test or two that requires that the greeting
|
||||||
|
use the capitalized form on the person's name, regardless of the case they
|
||||||
|
used.
|
||||||
|
|
||||||
|
In that situation, you'd:
|
||||||
|
|
||||||
|
1. add a new test setting up that new expectation,
|
||||||
|
2. implement that in the code (the same process we just went through
|
||||||
|
together, above).
|
||||||
|
3. review your code for readability and refactor as you see fit.
|
||||||
|
|
||||||
|
Exercism practitioners who "play" with each exercise — over trying to go as
|
||||||
|
fast as they can through the stream of exercises — report deep rewards.
|
||||||
|
|
||||||
|
|
||||||
|
## Contribute to Exercism
|
||||||
|
|
||||||
|
The entire of Exercism is Open Source and is the labor of love for more
|
||||||
|
than 100 maintainers and many more contributors.
|
||||||
|
|
||||||
|
A starting point to jumping in can be found here:
|
||||||
|
|
||||||
|
https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Regardless of what you decide to do next, we sincerely hope you learn
|
||||||
|
and enjoy being part of this community. If at any time you need assistance
|
||||||
|
do not hesitate to ask for help:
|
||||||
|
|
||||||
|
http://exercism.io/languages/kotlin/help
|
||||||
|
|
||||||
|
Cheers!
|
11
lfe/leap/.gitignore
vendored
Normal file
11
lfe/leap/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
## -*- conf -*-
|
||||||
|
.rebar3
|
||||||
|
_build/
|
||||||
|
ebin/
|
||||||
|
erl_crash.dump
|
||||||
|
rebar3.crashdump
|
||||||
|
|
||||||
|
tmp
|
||||||
|
bin/configlet
|
||||||
|
bin/configlet.exe
|
||||||
|
CHECKLIST
|
6
lfe/leap/rebar.lock
Normal file
6
lfe/leap/rebar.lock
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{"1.1.0",
|
||||||
|
[{<<"lfe">>,{pkg,<<"lfe">>,<<"1.1.1">>},0}]}.
|
||||||
|
[
|
||||||
|
{pkg_hash,[
|
||||||
|
{<<"lfe">>, <<"F57D2D705AB239CE171318DD31F4E374558266A88E1435F91045C1E8A2965D9C">>}]}
|
||||||
|
].
|
18
lua/hello-world/hello-world.lua
Normal file
18
lua/hello-world/hello-world.lua
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
-- This is a "stub" file. It's a little start on your solution.
|
||||||
|
-- It's not a complete solution though; you have to write some code.
|
||||||
|
|
||||||
|
-- Table to be returned by the hello-world module.
|
||||||
|
local hello_world = {}
|
||||||
|
|
||||||
|
-- Add the hello() function to the table returned by this module.
|
||||||
|
function hello_world.hello()
|
||||||
|
-- Write some code here to pass the test suite.
|
||||||
|
|
||||||
|
-- When you have a working solution, REMOVE ALL THE STOCK COMMENTS.
|
||||||
|
-- They're here to help you get started but they only clutter a finished solution.
|
||||||
|
-- If you leave them in, reviewers will protest!
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return the hello_world table to make it accessible as a module.
|
||||||
|
return hello_world
|
5
ocaml/hello-world/.merlin
Normal file
5
ocaml/hello-world/.merlin
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
PKG findlib
|
||||||
|
PKG core
|
||||||
|
PKG ounit
|
||||||
|
S *
|
||||||
|
B *
|
11
ocaml/hello-world/Makefile
Normal file
11
ocaml/hello-world/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
test: test.native
|
||||||
|
@./test.native
|
||||||
|
|
||||||
|
test.native: *.ml *.ml
|
||||||
|
@corebuild -r -quiet -pkg oUnit test.native
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf _build
|
||||||
|
rm -f test.native
|
||||||
|
|
||||||
|
.PHONY: clean
|
61
ocaml/hello-world/README.md
Normal file
61
ocaml/hello-world/README.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Hello World
|
||||||
|
|
||||||
|
The classical introductory exercise. Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
|
||||||
|
the traditional first program for beginning programming in a new language
|
||||||
|
or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Write a function that returns the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
For installation and learning resources, refer to the
|
||||||
|
[exercism help page](http://exercism.io/languages/ocaml).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
To work on the exercises, you will need `Opam` and `Core`. Consult [opam](https://opam.ocaml.org) website for instructions on how to install `opam` for your OS. Once `opam` is installed open a terminal window and run the following command to install core:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
opam install core
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the tests you will need `OUnit`. Install it using `opam`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
opam install ounit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
A Makefile is provided with a default target to compile your solution and run the tests. At the command line, type:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Interactive Shell
|
||||||
|
`utop` is a command line program which allows you to run Ocaml code interactively. The easiest way to install it is via opam:
|
||||||
|
```bash
|
||||||
|
opam install utop
|
||||||
|
```
|
||||||
|
Consult [utop](https://github.com/diml/utop/blob/master/README.md) for more detail.
|
||||||
|
|
||||||
|
## Feedback, Issues, Pull Requests
|
||||||
|
The [exercism/ocaml](https://github.com/exercism/ocaml) repository on
|
||||||
|
GitHub is the home for all of the Ocaml exercises.
|
||||||
|
|
||||||
|
If you have feedback about an exercise, or want to help implementing a new
|
||||||
|
one, head over there and create an issue. We'll do our best to help you!
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
1
ocaml/hello-world/hello_world.ml
Normal file
1
ocaml/hello-world/hello_world.ml
Normal file
@ -0,0 +1 @@
|
|||||||
|
let hello = "Change me"
|
4
ocaml/hello-world/hello_world.mli
Normal file
4
ocaml/hello-world/hello_world.mli
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
(*
|
||||||
|
Returns "Hello, World!"
|
||||||
|
*)
|
||||||
|
val hello: string
|
14
ocaml/hello-world/test.ml
Normal file
14
ocaml/hello-world/test.ml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
(* Test/exercise version: "1.0.0" *)
|
||||||
|
|
||||||
|
open Core
|
||||||
|
open OUnit2
|
||||||
|
open Hello_world
|
||||||
|
|
||||||
|
let ae exp got _test_ctxt = assert_equal ~printer:String.to_string exp got
|
||||||
|
|
||||||
|
let tests = [
|
||||||
|
"Say Hi!" >:: ae "Hello, World!" hello;
|
||||||
|
]
|
||||||
|
|
||||||
|
let () =
|
||||||
|
run_test_tt_main ("Hello World tests" >::: tests)
|
10
perl5/hello-world/HelloWorld.pm
Normal file
10
perl5/hello-world/HelloWorld.pm
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Declare package 'HelloWorld' with version
|
||||||
|
package HelloWorld 1;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
sub hello {
|
||||||
|
# Remove the comments and write some code here to pass the test suite.
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
21
perl5/hello-world/README.md
Normal file
21
perl5/hello-world/README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Hello World
|
||||||
|
|
||||||
|
The classical introductory exercise. Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
|
||||||
|
the traditional first program for beginning programming in a new language
|
||||||
|
or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Write a function that returns the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
## Source
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
64
perl5/hello-world/hello-world.t
Normal file
64
perl5/hello-world/hello-world.t
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use FindBin;
|
||||||
|
my $dir;
|
||||||
|
use lib $dir = $FindBin::Bin; # Look for the module inside the same directory as this test file.
|
||||||
|
use JSON::PP;
|
||||||
|
|
||||||
|
my $exercise = 'HelloWorld'; # The name of this exercise.
|
||||||
|
my $test_version = 1; # The version we will be matching against the exercise.
|
||||||
|
my $module = $ENV{EXERCISM} ? 'Example' : $exercise; # $ENV{EXERCISM} is for tests not directly for the exercise, don't worry about these :)
|
||||||
|
use Test::More tests => 4; # This is how many tests we expect to run.
|
||||||
|
|
||||||
|
use_ok $module or BAIL_OUT; # Check that the module can be use-d.
|
||||||
|
|
||||||
|
# If the exercise is updated, we want to make sure other people testing
|
||||||
|
# your code don't think you've made a mistake if things have changed!
|
||||||
|
my $exercise_version = $exercise->VERSION // 0;
|
||||||
|
if ($exercise_version != $test_version) {
|
||||||
|
warn "\nExercise version mismatch. Further tests may fail!"
|
||||||
|
. "\n$exercise is v$exercise_version. "
|
||||||
|
. "Test is v$test_version.\n";
|
||||||
|
BAIL_OUT if $ENV{EXERCISM};
|
||||||
|
}
|
||||||
|
|
||||||
|
my %subs;
|
||||||
|
foreach ( qw(hello) ) {
|
||||||
|
can_ok $exercise, $_;
|
||||||
|
$subs{$_} = $exercise->can($_);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $C_DATA;
|
||||||
|
is $subs{hello}->($_->{input}), $_->{expected}, $_->{description} foreach @{$C_DATA->{cases}};
|
||||||
|
|
||||||
|
# Ignore this for your exercise! Tells Exercism folks when exercise cases become out of date.
|
||||||
|
SKIP: {
|
||||||
|
skip '', 1 unless $ENV{EXERCISM};
|
||||||
|
is_deeply eval q{
|
||||||
|
use Path::Tiny;
|
||||||
|
decode_json path("$dir/../../problem-specifications/exercises/".path($dir)->basename.'/canonical-data.json')->realpath->slurp;
|
||||||
|
}, $C_DATA, 'canonical-data';
|
||||||
|
}
|
||||||
|
|
||||||
|
done_testing; # There are no more tests after this :)
|
||||||
|
|
||||||
|
# 'INIT' is a phaser, it makes sure that the test data is available before everything else
|
||||||
|
# starts running (otherwise we'd have to shove the test data into the middle of the file!)
|
||||||
|
INIT {
|
||||||
|
$C_DATA = decode_json <<'EOF';
|
||||||
|
|
||||||
|
{
|
||||||
|
"exercise": "hello-world",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"description": "Say Hi!",
|
||||||
|
"property": "hello",
|
||||||
|
"expected": "Hello, World!"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
30
python/isogram/README.md
Normal file
30
python/isogram/README.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Isogram
|
||||||
|
|
||||||
|
Determine if a word or phrase is an isogram.
|
||||||
|
|
||||||
|
An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter.
|
||||||
|
|
||||||
|
Examples of isograms:
|
||||||
|
|
||||||
|
- lumberjacks
|
||||||
|
- background
|
||||||
|
- downstream
|
||||||
|
|
||||||
|
The word *isograms*, however, is not an isogram, because the s repeats.
|
||||||
|
|
||||||
|
### Submitting Exercises
|
||||||
|
|
||||||
|
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
|
||||||
|
For more detailed information about running tests, code style and linting,
|
||||||
|
please see the [help page](http://exercism.io/languages/python).
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
Wikipedia [https://en.wikipedia.org/wiki/Isogram](https://en.wikipedia.org/wiki/Isogram)
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
2
python/isogram/isogram.py
Normal file
2
python/isogram/isogram.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
def is_isogram():
|
||||||
|
pass
|
39
python/isogram/isogram_test.py
Normal file
39
python/isogram/isogram_test.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from isogram import is_isogram
|
||||||
|
|
||||||
|
|
||||||
|
# test cases adapted from `x-common//canonical-data.json` @ version: 1.1.0
|
||||||
|
|
||||||
|
class TestIsogram(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_empty_string(self):
|
||||||
|
self.assertTrue(is_isogram(""))
|
||||||
|
|
||||||
|
def test_isogram_with_only_lower_case_characters(self):
|
||||||
|
self.assertTrue(is_isogram("isogram"))
|
||||||
|
|
||||||
|
def test_word_with_one_duplicated_character(self):
|
||||||
|
self.assertFalse(is_isogram("eleven"))
|
||||||
|
|
||||||
|
def test_longest_reported_english_isogram(self):
|
||||||
|
self.assertTrue(is_isogram("subdermatoglyphic"))
|
||||||
|
|
||||||
|
def test_word_with_duplicated_character_in_mixed_case(self):
|
||||||
|
self.assertFalse(is_isogram("Alphabet"))
|
||||||
|
|
||||||
|
def test_hypothetical_isogrammic_word_with_hyphen(self):
|
||||||
|
self.assertTrue(is_isogram("thumbscrew-japingly"))
|
||||||
|
|
||||||
|
def test_isogram_with_duplicated_non_letter_character(self):
|
||||||
|
self.assertTrue(is_isogram("Hjelmqvist-Gryb-Zock-Pfund-Wax"))
|
||||||
|
|
||||||
|
def test_made_up_name_that_is_an_isogram(self):
|
||||||
|
self.assertTrue(is_isogram("Emily Jung Schwartzkopf"))
|
||||||
|
|
||||||
|
def test_duplicated_character_in_the_middle(self):
|
||||||
|
self.assertFalse(is_isogram("accentor"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
7
rust/hello-world/.gitignore
vendored
Normal file
7
rust/hello-world/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
|
||||||
|
Cargo.lock
|
5
rust/hello-world/src/lib.rs
Normal file
5
rust/hello-world/src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// The &'static here means the return type has a static lifetime.
|
||||||
|
// This is a Rust feature that you don't need to worry about now.
|
||||||
|
pub fn hello() -> &'static str {
|
||||||
|
"Goodbye, World!"
|
||||||
|
}
|
4
scala/hello-world/src/main/scala/HelloWorld.scala
Normal file
4
scala/hello-world/src/main/scala/HelloWorld.scala
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
object HelloWorld {
|
||||||
|
def hello() = ???
|
||||||
|
}
|
||||||
|
|
4
swift/hello-world/.gitignore
vendored
Normal file
4
swift/hello-world/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
5
swift/hello-world/Package.swift
Normal file
5
swift/hello-world/Package.swift
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "HelloWorld"
|
||||||
|
)
|
1
swift/hello-world/Sources/HelloWorld.swift
Normal file
1
swift/hello-world/Sources/HelloWorld.swift
Normal file
@ -0,0 +1 @@
|
|||||||
|
//Solution goes in Sources
|
@ -0,0 +1,34 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import HelloWorld
|
||||||
|
|
||||||
|
class HelloWorldTests: XCTestCase {
|
||||||
|
|
||||||
|
func testNoName() {
|
||||||
|
let expected = "Hello, World!"
|
||||||
|
XCTAssertEqual(HelloWorld.hello(), expected, "When given no name, we should greet the world!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSampleName() {
|
||||||
|
let expected = "Hello, Alice!"
|
||||||
|
XCTAssertEqual(HelloWorld.hello("Alice"), expected, "When given 'Alice' we should greet Alice!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOtherSampleName() {
|
||||||
|
let expected = "Hello, Bob!"
|
||||||
|
XCTAssertEqual(HelloWorld.hello("Bob"), expected, "When given 'Bob' we should greet Bob!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNoStrangeName() {
|
||||||
|
let expected = "Hello, !"
|
||||||
|
XCTAssertEqual(HelloWorld.hello(""), expected, "When given an empty string, it is strange, but should have a space and punctuation")
|
||||||
|
}
|
||||||
|
|
||||||
|
static var allTests: [(String, (HelloWorldTests) -> () throws -> Void)] {
|
||||||
|
return [
|
||||||
|
("testNoName", testNoName),
|
||||||
|
("testSampleName", testSampleName),
|
||||||
|
("testOtherSampleName", testOtherSampleName),
|
||||||
|
("testNoStrangeName", testNoStrangeName),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
6
swift/hello-world/Tests/LinuxMain.swift
Normal file
6
swift/hello-world/Tests/LinuxMain.swift
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import HelloWorldTests
|
||||||
|
|
||||||
|
XCTMain([
|
||||||
|
testCase(HelloWorldTests.allTests),
|
||||||
|
])
|
Loading…
Reference in New Issue
Block a user