commit 50f4a86fd8910c3e905f8b4b4254c268025f6194 Author: Brian Buller Date: Sat Aug 13 18:20:14 2016 -0500 Initial Commit diff --git a/clojure/bob/README.md b/clojure/bob/README.md new file mode 100644 index 0000000..286c6dd --- /dev/null +++ b/clojure/bob/README.md @@ -0,0 +1,35 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question. + +He answers 'Whoa, chill out!' if you yell at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +## Instructions + +Run the test file, and fix each of the errors in turn. When you get the +first test to pass, go to the first pending or skipped test, and make +that pass as well. When all of the tests are passing, feel free to +submit. + +Remember that passing code is just the first step. The goal is to work +towards a solution that is as readable and expressive as you can make +it. + +Please make your solution as general as possible. Good code doesn't just +pass the test suite, it works with any input that fits the +specification. + +Have fun! + + + +## Source + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=06) diff --git a/clojure/bob/bob_test.clj b/clojure/bob/bob_test.clj new file mode 100644 index 0000000..42bbd18 --- /dev/null +++ b/clojure/bob/bob_test.clj @@ -0,0 +1,48 @@ +(ns bob-test + (:require [clojure.test :refer :all])) + +(load-file "bob.clj") + +(deftest responds-to-something + (is (= "Whatever." (bob/response-for "Tom-ay-to, tom-aaaah-to.")))) + +(deftest responds-to-shouts + (is (= "Whoa, chill out!" (bob/response-for "WATCH OUT!")))) + +(deftest responds-to-questions + (is (= "Sure." (bob/response-for "Does this cryogenic chamber make me look fat?")))) + +(deftest responds-to-forceful-talking + (is (= "Whatever." (bob/response-for "Let's go make out behind the gym!")))) + +(deftest responds-to-acronyms + (is (= "Whatever." (bob/response-for "It's OK if you don't want to go to the DMV.")))) + +(deftest responds-to-forceful-questions + (is (= "Whoa, chill out!" (bob/response-for "WHAT THE HELL WERE YOU THINKING?")))) + +(deftest responds-to-shouting-with-special-characters + (is (= "Whoa, chill out!" (bob/response-for "ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!")))) + +(deftest responds-to-shouting-numbers + (is (= "Whoa, chill out!" (bob/response-for "1, 2, 3 GO!")))) + +(deftest responds-to-shouting-with-no-exclamation-mark + (is (= "Whoa, chill out!" (bob/response-for "I HATE YOU")))) + +(deftest responds-to-statement-containing-question-mark + (is (= "Whatever." (bob/response-for "Ending with ? means a question.")))) + +(deftest responds-to-silence + (is (= "Fine. Be that way!" (bob/response-for "")))) + +(deftest responds-to-prolonged-silence + (is (= "Fine. Be that way!" (bob/response-for " ")))) + +(deftest responds-to-only-numbers + (is (= "Whatever." (bob/response-for "1, 2, 3")))) + +(deftest responds-to-number-question + (is (= "Sure." (bob/response-for "4?")))) + +(run-tests) diff --git a/clojure/bob/project.clj b/clojure/bob/project.clj new file mode 100644 index 0000000..803ad74 --- /dev/null +++ b/clojure/bob/project.clj @@ -0,0 +1,6 @@ +(defproject bob "0.1.0-SNAPSHOT" + :description "bob exercise." + :url "https://github.com/exercism/xclojure/tree/master/bob" + :source-paths [""] + :test-paths [""] + :dependencies [[org.clojure/clojure "1.7.0"]]) diff --git a/clojure/current b/clojure/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/clojure/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/clojure/hello-world/README.md b/clojure/hello-world/README.md new file mode 100644 index 0000000..39433db --- /dev/null +++ b/clojure/hello-world/README.md @@ -0,0 +1,82 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +* * * * + +For learning resources and help with installation, refer to the +[Exercism help page][]. + +To run the tests provided, you will need to install [Leiningen][]. + +To install Leiningen on Mac OS X using [Homebrew][], run the following command: + + brew install leiningen + +For help installing on Linux, Windows or without Homebrew see: +[Leiningen installation][]. + +[Exercism help page]: http://exercism.io/languages/clojure +[Leiningen]: http://leiningen.org +[Homebrew]: http://brew.sh +[Leiningen installation]: https://github.com/technomancy/leiningen#installation + +In an exercise directory, create a `src` directory and a file therein to hold +your solution. The name of the file should be the exercise name with dashes `-` +replaced by underscores `_`. For example, if the exercise is called +`hello-world`, name the solution file `hello_world.clj`. + +Your resulting file tree should look something like this: + + /path/to/hello-world + ├── project.clj + ├── src + │   └── hello_world.clj + └── test + └── hello_world_test.clj + + +To run the tests, navigate to the exercise directory and run the following +command: + + lein test + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/clojure/hello-world/project.clj b/clojure/hello-world/project.clj new file mode 100644 index 0000000..cac88b4 --- /dev/null +++ b/clojure/hello-world/project.clj @@ -0,0 +1,4 @@ +(defproject hello-world "0.1.0-SNAPSHOT" + :description "hello-world exercise." + :url "https://github.com/exercism/xclojure/tree/master/hello-world" + :dependencies [[org.clojure/clojure "1.7.0"]]) diff --git a/clojure/hello-world/test/hello_world_test.clj b/clojure/hello-world/test/hello_world_test.clj new file mode 100644 index 0000000..65e456e --- /dev/null +++ b/clojure/hello-world/test/hello_world_test.clj @@ -0,0 +1,12 @@ +(ns hello-world-test + (:require [clojure.test :refer [deftest is]] + hello-world)) + +(deftest hello-world-test + (is (= "Hello, World!" (hello-world/hello)))) + +(deftest hello-alice-test + (is (= "Hello, Alice!" (hello-world/hello "Alice")))) + +(deftest hello-bob-test + (is (= "Hello, Bob!" (hello-world/hello "Bob")))) diff --git a/coffeescript/current b/coffeescript/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/coffeescript/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/coffeescript/hello-world/README.md b/coffeescript/hello-world/README.md new file mode 100644 index 0000000..9c2b2c5 --- /dev/null +++ b/coffeescript/hello-world/README.md @@ -0,0 +1,48 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +Refer to the [Exercism help page](http://help.exercism.io/getting-started-with-coffeescript.html) for getting started with CoffeeScript. + +In order to run the test, you can run the test file from the exercise directory. For example, if the test suite is called hello_world.spec.coffee, you can run the following command: + jasmine-node --coffee hello_world.spec.coffee + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/coffeescript/hello-world/hello_world.spec.coffee b/coffeescript/hello-world/hello_world.spec.coffee new file mode 100644 index 0000000..12f1e52 --- /dev/null +++ b/coffeescript/hello-world/hello_world.spec.coffee @@ -0,0 +1,16 @@ +HelloWorld = require "./hello_world" + +describe "HelloWorld", -> + hello_world = new HelloWorld() + + it "given no name", -> + result = hello_world.hello() + expect(result).toEqual "Hello, World!" + + it "given the name 'Alice'", -> + result = hello_world.hello 'Alice' + expect(result).toEqual "Hello, Alice!" + + it "given the name 'Bob'", -> + result = hello_world.hello 'Bob' + expect(result).toEqual "Hello, Bob!" diff --git a/cpp/bob/CMakeLists.txt b/cpp/bob/CMakeLists.txt new file mode 100644 index 0000000..95c7011 --- /dev/null +++ b/cpp/bob/CMakeLists.txt @@ -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.55 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}) diff --git a/cpp/bob/README.md b/cpp/bob/README.md new file mode 100644 index 0000000..a48841b --- /dev/null +++ b/cpp/bob/README.md @@ -0,0 +1,66 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question. + +He answers 'Whoa, chill out!' if you yell at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +## Instructions + +Run the test file, and fix each of the errors in turn. When you get the +first test to pass, go to the first pending or skipped test, and make +that pass as well. When all of the tests are passing, feel free to +submit. + +Remember that passing code is just the first step. The goal is to work +towards a solution that is as readable and expressive as you can make +it. + +Please make your solution as general as possible. Good code doesn't just +pass the test suite, it works with any input that fits the +specification. + +Have fun! + + +## Getting Started + +Make sure you have read the [getting started with C++](http://help.exercism.io/getting-started-with-cpp.html) +page on the [exercism help site](http://help.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 + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=06) diff --git a/cpp/bob/bob_test.cpp b/cpp/bob/bob_test.cpp new file mode 100644 index 0000000..ac31d9c --- /dev/null +++ b/cpp/bob/bob_test.cpp @@ -0,0 +1,90 @@ +#include "bob.h" +#define BOOST_TEST_MAIN +#include + +BOOST_AUTO_TEST_CASE(stating_something) +{ + BOOST_REQUIRE_EQUAL("Whatever.", bob::hey("Tom-ay-to, tom-aaaah-to.")); +} + +#if defined(EXERCISM_RUN_ALL_TESTS) +BOOST_AUTO_TEST_CASE(shouting) +{ + BOOST_REQUIRE_EQUAL("Whoa, chill out!", bob::hey("WATCH OUT!")); +} + +BOOST_AUTO_TEST_CASE(asking_a_question) +{ + BOOST_REQUIRE_EQUAL("Sure.", bob::hey("Does this cryogenic chamber make me look fat?")); +} + +BOOST_AUTO_TEST_CASE(talking_forcefully) +{ + BOOST_REQUIRE_EQUAL("Whatever.", bob::hey("Let's go make out behind the gym!")); +} + +BOOST_AUTO_TEST_CASE(using_acronyms_in_regular_speech) +{ + BOOST_REQUIRE_EQUAL("Whatever.", bob::hey("It's OK if you don't want to go to the DMV.")); +} + +BOOST_AUTO_TEST_CASE(forceful_questions) +{ + BOOST_REQUIRE_EQUAL("Whoa, chill out!", bob::hey("WHAT THE HELL WERE YOU THINKING?")); +} + +BOOST_AUTO_TEST_CASE(shouting_numbers) +{ + BOOST_REQUIRE_EQUAL("Whoa, chill out!", bob::hey("1, 2, 3 GO!")); +} + +BOOST_AUTO_TEST_CASE(only_numbers) +{ + BOOST_REQUIRE_EQUAL("Whatever.", bob::hey("1, 2, 3")); +} + +BOOST_AUTO_TEST_CASE(question_with_only_numbers) +{ + BOOST_REQUIRE_EQUAL("Sure.", bob::hey("4?")); +} + +BOOST_AUTO_TEST_CASE(shouting_with_special_characters) +{ + BOOST_REQUIRE_EQUAL("Whoa, chill out!", bob::hey("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!")); +} + +BOOST_AUTO_TEST_CASE(shouting_with_no_exclamation_mark) +{ + BOOST_REQUIRE_EQUAL("Whoa, chill out!", bob::hey("I HATE YOU")); +} + +BOOST_AUTO_TEST_CASE(statement_containing_question_mark) +{ + BOOST_REQUIRE_EQUAL("Whatever.", bob::hey("Ending with a ? means a question.")); +} + +BOOST_AUTO_TEST_CASE(prattling_on) +{ + BOOST_REQUIRE_EQUAL("Sure.", bob::hey("Wait! Hang on. Are you going to be OK?")); +} + +BOOST_AUTO_TEST_CASE(question_with_trailing_whitespace) +{ + BOOST_REQUIRE_EQUAL("Sure.", bob::hey("Are you ok? ")); +} + +BOOST_AUTO_TEST_CASE(silence) +{ + BOOST_REQUIRE_EQUAL("Fine. Be that way!", bob::hey("")); +} + +BOOST_AUTO_TEST_CASE(prolonged_silence) +{ + BOOST_REQUIRE_EQUAL("Fine. Be that way!", bob::hey(" ")); +} + +BOOST_AUTO_TEST_CASE(not_all_silence) +{ + BOOST_REQUIRE_EQUAL("Whatever.", bob::hey(" A bit of silence can be nice. ")); +} +#endif diff --git a/cpp/current b/cpp/current new file mode 120000 index 0000000..2529de8 --- /dev/null +++ b/cpp/current @@ -0,0 +1 @@ +bob \ No newline at end of file diff --git a/csharp/current b/csharp/current new file mode 120000 index 0000000..b905e3b --- /dev/null +++ b/csharp/current @@ -0,0 +1 @@ +leap \ No newline at end of file diff --git a/csharp/leap/LeapTest.cs b/csharp/leap/LeapTest.cs new file mode 100644 index 0000000..3356310 --- /dev/null +++ b/csharp/leap/LeapTest.cs @@ -0,0 +1,32 @@ +using NUnit.Framework; + +[TestFixture] +public class LeapTest +{ + [Test] + public void Valid_leap_year() + { + Assert.That(Year.IsLeap(1996), Is.True); + } + + [Ignore] + [Test] + public void Invalid_leap_year() + { + Assert.That(Year.IsLeap(1997), Is.False); + } + + [Ignore] + [Test] + public void Turn_of_the_20th_century_is_not_a_leap_year() + { + Assert.That(Year.IsLeap(1900), Is.False); + } + + [Ignore] + [Test] + public void Turn_of_the_25th_century_is_a_leap_year() + { + Assert.That(Year.IsLeap(2400), Is.True); + } +} \ No newline at end of file diff --git a/csharp/leap/README.md b/csharp/leap/README.md new file mode 100644 index 0000000..ec08d7c --- /dev/null +++ b/csharp/leap/README.md @@ -0,0 +1,33 @@ +# Leap + +Write a program that will take a year and report if it is a leap year. + +The tricky thing here is that a leap year occurs: + +```plain +on every year that is evenly divisible by 4 + except every year that is evenly divisible by 100 + unless the year is also evenly divisible by 400 +``` + +For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap +year, but 2000 is. + +If your language provides a method in the standard library that does +this look-up, pretend it doesn't exist and implement it yourself. + +## Notes + +For a delightful, four minute explanation of the whole leap year +phenomenon, go watch [this youtube video][video]. + +[video]: http://www.youtube.com/watch?v=xX96xng7sAE + +### Submitting Exercises + +Note that, when trying to submit an exercise, make sure you're exercise file you're submitting is in the `exercism/csharp/` directory. + +For example, if you're submitting `bob.cs` for the Bob exercise, the submit command would be something like `exercism submit /csharp/bob/bob.cs`. +## Source + +JavaRanch Cattle Drive, exercise 3 [view source](http://www.javaranch.com/leap.jsp) diff --git a/ecmascript/current b/ecmascript/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/ecmascript/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/ecmascript/hello-world/README.md b/ecmascript/hello-world/README.md new file mode 100644 index 0000000..58eef3f --- /dev/null +++ b/ecmascript/hello-world/README.md @@ -0,0 +1,82 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +## Setup + +Go through the setup instructions for ECMAScript to +install the necessary dependencies: + +http://help.exercism.io/getting-started-with-ecmascript.html + +## Requirements + +They are already described in the link above, but just as a +quick reference: + +Install globally a tool to run [Gulp](http://gulpjs.com) if +it is not installed yet: + +```bash +$ npm install -g gulp-cli +``` + +Install assignment dependencies: + +```bash +$ npm install +``` + +## Making the test suite pass + +Execute the tests with: + +```bash +$ gulp test +``` + +In many test suites all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +changing `xit` to `it`. + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/ecmascript/hello-world/gulpfile.js b/ecmascript/hello-world/gulpfile.js new file mode 100644 index 0000000..1a379c9 --- /dev/null +++ b/ecmascript/hello-world/gulpfile.js @@ -0,0 +1,42 @@ +function getInputDirectory(argv) { + if (argv.input) { + return argv.input; + } + return '.'; +} + +function getOutputDirectory(argv) { + if (argv.output) { + return argv.output; + } + return 'babel-output'; +} + +var gulp = require('gulp'), + jasmine = require('gulp-jasmine'), + babel = require('gulp-babel'), + polyfill = require('babel/polyfill'), + del = require('del'), + argv = require('yargs').argv, + inputDir = getInputDirectory(argv), + outputDir = getOutputDirectory(argv); + +// Gulp tasks definition + +gulp.task('default', [ 'test' ]); + +gulp.task('test', [ 'babel' ], function () { + return gulp.src([ outputDir + '/*.spec.js' ]) + .pipe(jasmine()); +}); + +gulp.task('babel', function () { + return gulp.src([ inputDir + '/*.js' ]) + .pipe(babel()) + .pipe(gulp.dest(outputDir)); +}); + +gulp.task('clean', function (cb) { + del([ outputDir ], cb); +}); + diff --git a/ecmascript/hello-world/hello-world.js b/ecmascript/hello-world/hello-world.js new file mode 100644 index 0000000..d76df9b --- /dev/null +++ b/ecmascript/hello-world/hello-world.js @@ -0,0 +1,15 @@ +// +// This is only a SKELETON file for the 'Hello World' exercise. It's been provided as a +// convenience to get you started writing code faster. +// + +class HelloWorld { + hello(name) { + // + // YOUR CODE GOES HERE + // + } +} + +export default HelloWorld; + diff --git a/ecmascript/hello-world/hello-world.spec.js b/ecmascript/hello-world/hello-world.spec.js new file mode 100644 index 0000000..d4f07f4 --- /dev/null +++ b/ecmascript/hello-world/hello-world.spec.js @@ -0,0 +1,18 @@ +import HelloWorld from './hello-world'; + +describe('Hello World', () => { + const helloWorld = new HelloWorld(); + + it('says hello world with no name', () => { + expect(helloWorld.hello('')).toEqual('Hello, World!'); + }); + + xit('says hello to bob', () => { + expect(helloWorld.hello('Bob')).toEqual('Hello, Bob!'); + }); + + xit('says hello to sally', () => { + expect(helloWorld.hello('Sally')).toEqual('Hello, Sally!'); + }); +}); + diff --git a/ecmascript/hello-world/package.json b/ecmascript/hello-world/package.json new file mode 100644 index 0000000..c4ed38c --- /dev/null +++ b/ecmascript/hello-world/package.json @@ -0,0 +1,25 @@ +{ + "name": "assignment", + "version": "0.0.1", + "description": "Exercism ECMAScript assignment", + "scripts": { + "test": "gulp test" + }, + "repository": { + "type": "git", + "url": "https://github.com/exercism/xecmascript" + }, + "bugs": { + "url": "https://github.com/exercism/xecmascript/issues" + }, + "homepage": "https://github.com/exercism/xecmascript", + "devDependencies": { + "gulp": "~3.9.0", + "gulp-jasmine": "~2.0.1", + "gulp-clean": "~0.3.1", + "del": "~2.0.2", + "yargs": "~3.27.0", + "gulp-babel": "~5.3.0", + "babel": "~5.8.29" + } +} diff --git a/elisp/current b/elisp/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/elisp/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/elisp/hello-world/README.md b/elisp/hello-world/README.md new file mode 100644 index 0000000..d9a535b --- /dev/null +++ b/elisp/hello-world/README.md @@ -0,0 +1,44 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/elisp/hello-world/hello-world-test.el b/elisp/hello-world/hello-world-test.el new file mode 100644 index 0000000..cceb0f4 --- /dev/null +++ b/elisp/hello-world/hello-world-test.el @@ -0,0 +1,18 @@ +;;; hello-world-test.el --- Tests for Hello World (exercism) + +;;; Commentary: + +;;; Code: + +(load-file "hello-world.el") + +(ert-deftest no-args () + (should (equal (hello) "Hello, World!"))) + +(ert-deftest with-args () + (should (equal (hello "Emacs") "Hello, Emacs!")) + (should (equal (hello "Exercism") "Hello, Exercism!"))) + +(provide 'hello-world-test) + +;;; hello-world-test.el ends here diff --git a/elisp/hello-world/hello-world.el b/elisp/hello-world/hello-world.el new file mode 100644 index 0000000..b775d59 --- /dev/null +++ b/elisp/hello-world/hello-world.el @@ -0,0 +1,9 @@ +;;; hello-world.el --- Hello World Exercise (exercism) + +;;; Commentary: + +;;; Code: + + +(provide 'hello-world) +;;; hello-world.el ends here diff --git a/elixir/bob/README.md b/elixir/bob/README.md new file mode 100644 index 0000000..1fc96ea --- /dev/null +++ b/elixir/bob/README.md @@ -0,0 +1,42 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question. + +He answers 'Whoa, chill out!' if you yell at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +## Instructions + +Run the test file, and fix each of the errors in turn. When you get the +first test to pass, go to the first pending or skipped test, and make +that pass as well. When all of the tests are passing, feel free to +submit. + +Remember that passing code is just the first step. The goal is to work +towards a solution that is as readable and expressive as you can make +it. + +Please make your solution as general as possible. Good code doesn't just +pass the test suite, it works with any input that fits the +specification. + +Have fun! + + +## Running tests + +```bash +$ elixir bob_test.exs +``` + +(Replace `bob_test.exs` with the name of the test file.) + +## Source + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=06) diff --git a/elixir/bob/bob.exs b/elixir/bob/bob.exs new file mode 100644 index 0000000..0256871 --- /dev/null +++ b/elixir/bob/bob.exs @@ -0,0 +1,8 @@ +defmodule Teenager do + def hey(input) do + cond do + true -> raise "Your implementation goes here" + + end + end +end diff --git a/elixir/bob/bob_test.exs b/elixir/bob/bob_test.exs new file mode 100644 index 0000000..fd387f6 --- /dev/null +++ b/elixir/bob/bob_test.exs @@ -0,0 +1,82 @@ +if System.get_env("EXERCISM_TEST_EXAMPLES") do + Code.load_file("example.exs") +else + Code.load_file("bob.exs") +end + +ExUnit.start +ExUnit.configure(exclude: :pending) + +defmodule TeenagerTest do + use ExUnit.Case, async: true + + test "stating something" do + assert Teenager.hey("Tom-ay-to, tom-aaaah-to.") == "Whatever." + end + + @tag :pending + test "shouting" do + assert Teenager.hey("WATCH OUT!") == "Whoa, chill out!" + end + + @tag :pending + test "asking a question" do + assert Teenager.hey("Does this cryogenic chamber make me look fat?") == "Sure." + end + + @tag :pending + test "talking forcefully" do + assert Teenager.hey("Let's go make out behind the gym!") == "Whatever." + end + + @tag :pending + test "talking in capitals" do + assert Teenager.hey("This Isn't Shouting!") == "Whatever." + end + + @tag :pending + test "shouting numbers" do + assert Teenager.hey("1, 2, 3 GO!") == "Whoa, chill out!" + end + + @tag :pending + test "shouting with special characters" do + assert Teenager.hey("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!") == "Whoa, chill out!" + end + + @tag :pending + test "shouting with no exclamation mark" do + assert Teenager.hey("I HATE YOU") == "Whoa, chill out!" + end + + @tag :pending + test "statement containing question mark" do + assert Teenager.hey("Ending with ? means a question.") == "Whatever." + end + + @tag :pending + test "silence" do + assert Teenager.hey("") == "Fine. Be that way!" + end + + @tag :pending + test "prolonged silence" do + assert Teenager.hey(" ") == "Fine. Be that way!" + end + + @tag :pending + test "only numbers" do + assert Teenager.hey("1, 2, 3") == "Whatever." + end + + @tag :pending + test "question with numbers" do + assert Teenager.hey("4?") == "Sure." + end + + @tag :pending + test "shouting in Russian" do + # Hopefully this is Russian for "GET OUT" + assert Teenager.hey("УХОДИТЬ") == "Whoa, chill out!" + end +end diff --git a/elixir/current b/elixir/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/elixir/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/elixir/hello-world/README.md b/elixir/hello-world/README.md new file mode 100644 index 0000000..4237640 --- /dev/null +++ b/elixir/hello-world/README.md @@ -0,0 +1,51 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +## Running tests + +```bash +$ elixir bob_test.exs +``` + +(Replace `bob_test.exs` with the name of the test file.) + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/elixir/hello-world/hello_world.exs b/elixir/hello-world/hello_world.exs new file mode 100644 index 0000000..29362e8 --- /dev/null +++ b/elixir/hello-world/hello_world.exs @@ -0,0 +1,7 @@ +defmodule HelloWorld do + def hello(name) do + + "Your implementation goes here" + + end +end diff --git a/elixir/hello-world/hello_world_test.exs b/elixir/hello-world/hello_world_test.exs new file mode 100644 index 0000000..be2d16b --- /dev/null +++ b/elixir/hello-world/hello_world_test.exs @@ -0,0 +1,27 @@ +if System.get_env("EXERCISM_TEST_EXAMPLES") do + Code.load_file("example.exs") +else + Code.load_file("hello_world.exs") +end + +ExUnit.start +ExUnit.configure exclude: :pending, trace: true + +defmodule HelloWorldTest do + use ExUnit.Case, async: true + + test "says hello with no name" do + assert HelloWorld.hello() == "Hello, World!" + end + + @tag :pending + test "says hello sample name" do + assert HelloWorld.hello("Alice") == "Hello, Alice!" + end + + @tag :pending + test "says hello other sample name" do + assert HelloWorld.hello("Bob") == "Hello, Bob!" + end + +end diff --git a/erlang/current b/erlang/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/erlang/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/erlang/hello-world/README.md b/erlang/hello-world/README.md new file mode 100644 index 0000000..d9a535b --- /dev/null +++ b/erlang/hello-world/README.md @@ -0,0 +1,44 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/erlang/hello-world/hello_world_tests.erl b/erlang/hello-world/hello_world_tests.erl new file mode 100644 index 0000000..f04a230 --- /dev/null +++ b/erlang/hello-world/hello_world_tests.erl @@ -0,0 +1,19 @@ +% To run tests: +% erl -make +% erl -noshell -eval "eunit:test(hello_world, [verbose])" -s init stop +% + +-module(hello_world_tests). +-include_lib("eunit/include/eunit.hrl"). + +no_name_test() -> + ?assertEqual("Hello, World!", hello_world:greet()). + +alice_test() -> + ?assertEqual("Hello, Alice!", hello_world:greet("Alice")). + +bob_test() -> + ?assertEqual("Hello, Bob!", hello_world:greet("Bob")). + +strange_test() -> + ?assertEqual("Hello, !", hello_world:greet("")). diff --git a/erlang/leap/README.md b/erlang/leap/README.md new file mode 100644 index 0000000..ecd30d2 --- /dev/null +++ b/erlang/leap/README.md @@ -0,0 +1,29 @@ +# Leap + +Write a program that will take a year and report if it is a leap year. + +The tricky thing here is that a leap year occurs: + +```plain +on every year that is evenly divisible by 4 + except every year that is evenly divisible by 100 + unless the year is also evenly divisible by 400 +``` + +For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap +year, but 2000 is. + +If your language provides a method in the standard library that does +this look-up, pretend it doesn't exist and implement it yourself. + +## Notes + +For a delightful, four minute explanation of the whole leap year +phenomenon, go watch [this youtube video][video]. + +[video]: http://www.youtube.com/watch?v=xX96xng7sAE + + +## Source + +JavaRanch Cattle Drive, exercise 3 [view source](http://www.javaranch.com/leap.jsp) diff --git a/erlang/leap/leap_tests.erl b/erlang/leap/leap_tests.erl new file mode 100644 index 0000000..651d5c3 --- /dev/null +++ b/erlang/leap/leap_tests.erl @@ -0,0 +1,20 @@ +% To run tests: +% erl -make +% erl -noshell -eval "eunit:test(leap, [verbose])" -s init stop +% + +-module(leap_tests). + +-include_lib("eunit/include/eunit.hrl"). + +leap_year_test() -> + ?assert(leap:leap_year(1996)). + +non_leap_year_test() -> + ?assertNot(leap:leap_year(1997)). + +century_test() -> + ?assertNot(leap:leap_year(1900)). + +fourth_century_test() -> + ?assert(leap:leap_year(2400)). diff --git a/fsharp/current b/fsharp/current new file mode 120000 index 0000000..bfcf9aa --- /dev/null +++ b/fsharp/current @@ -0,0 +1 @@ +sum-of-multiples \ No newline at end of file diff --git a/fsharp/sum-of-multiples/README.md b/fsharp/sum-of-multiples/README.md new file mode 100644 index 0000000..5d76d76 --- /dev/null +++ b/fsharp/sum-of-multiples/README.md @@ -0,0 +1,16 @@ +# Sum Of Multiples + +Write a program that, given a number, can 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 15 that are +multiples of either 3 or 5, we get 3, 5, 6 and 9, 10, and 12. + +The sum of these multiples is 45. + +Write a program that can find the sum of the multiples of a given set of +numbers. + + +## Source + +A variation on Problem 1 at Project Euler [view source](http://projecteuler.net/problem=1) diff --git a/fsharp/sum-of-multiples/SumOfMultiplesTest.fs b/fsharp/sum-of-multiples/SumOfMultiplesTest.fs new file mode 100644 index 0000000..18c8e65 --- /dev/null +++ b/fsharp/sum-of-multiples/SumOfMultiplesTest.fs @@ -0,0 +1,32 @@ +module SumOfMultiplesTest + +open NUnit.Framework +open SumOfMultiples + +[] +type SumOfMultiplesTest() = + let mutable sumOfMultiples = SumOfMultiples() + + [] + member tc.Sum_to_1() = + Assert.That(sumOfMultiples.To(0), Is.EqualTo(0)) + + [] + [] + member tc.Sum_to_3() = + Assert.That(sumOfMultiples.To(3), Is.EqualTo(0)) + + [] + [] + member tc.Sum_to_10() = + Assert.That(sumOfMultiples.To(10), Is.EqualTo(23)) + + [] + [] + member tc.Configurable_7_13_17_to_20() = + Assert.That(SumOfMultiples([7; 13; 17]).To(20), Is.EqualTo(51)) + + [] + [] + member tc.Configurable_43_47_to_10000() = + Assert.That(SumOfMultiples([43; 47]).To(10000), Is.EqualTo(2203160)) \ No newline at end of file diff --git a/go/allergies/README.md b/go/allergies/README.md new file mode 100644 index 0000000..c513e94 --- /dev/null +++ b/go/allergies/README.md @@ -0,0 +1,39 @@ +# Allergies + +Write a program that, given a person's allergy score, can tell them whether or not they're allergic to a given item, and their full list of allergies. + +An allergy test produces a single numeric score which contains the +information about all the allergies the person has (that they were +tested for). + +The list of items (and their value) that were tested are: + +* eggs (1) +* peanuts (2) +* shellfish (4) +* strawberries (8) +* tomatoes (16) +* chocolate (32) +* pollen (64) +* cats (128) + +So if Tom is allergic to peanuts and chocolate, he gets a score of 34. + +Now, given just that score of 34, your program should be able to say: + +- Whether Tom is allergic to any one of those allergens listed above. +- All the allergens Tom is allergic to. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +Jumpstart Lab Warm-up [view source](http://jumpstartlab.com) diff --git a/go/allergies/allergies.go b/go/allergies/allergies.go new file mode 100644 index 0000000..5629f48 --- /dev/null +++ b/go/allergies/allergies.go @@ -0,0 +1,44 @@ +package allergies + +// Allergies takes a score and returns all of the +// things that the score is allergic to. +func Allergies(score int) []string { + var ret []string + + for _, v := range getAllAllergens() { + if AllergicTo(score, v) { + ret = append(ret, v) + } + } + return ret +} + +// AllergicTo takes a score and an allergen and returns if +// That score is allergic to that thing. +func AllergicTo(score int, tst string) bool { + return score&getScoreForAllergen(tst) == getScoreForAllergen(tst) +} + +func getAllAllergens() []string { + return []string{ + "eggs", + "peanuts", + "shellfish", + "strawberries", + "tomatoes", + "chocolate", + "pollen", + "cats", + } +} + +func getScoreForAllergen(tst string) int { + ret := 1 + for _, v := range getAllAllergens() { + if tst == v { + return ret + } + ret *= 2 + } + return -1 +} diff --git a/go/allergies/allergies_test.go b/go/allergies/allergies_test.go new file mode 100644 index 0000000..5120035 --- /dev/null +++ b/go/allergies/allergies_test.go @@ -0,0 +1,79 @@ +package allergies + +import ( + "fmt" + "testing" +) + +var allergiesTests = []struct { + expected []string + input int +}{ + {[]string{}, 0}, + {[]string{"eggs"}, 1}, + {[]string{"peanuts"}, 2}, + {[]string{"strawberries"}, 8}, + {[]string{"eggs", "peanuts"}, 3}, + {[]string{"eggs", "shellfish"}, 5}, + {[]string{"strawberries", "tomatoes", "chocolate", "pollen", "cats"}, 248}, + {[]string{"eggs", "peanuts", "shellfish", "strawberries", "tomatoes", "chocolate", "pollen", "cats"}, 255}, + {[]string{"eggs", "shellfish", "strawberries", "tomatoes", "chocolate", "pollen", "cats"}, 509}, +} + +func TestAllergies(t *testing.T) { + for _, test := range allergiesTests { + actual := Allergies(test.input) + if fmt.Sprintf("%s", actual) != fmt.Sprintf("%s", test.expected) { + t.Fatalf("FAIL: Allergies(%d): expected %s, actual %s", test.input, test.expected, actual) + } else { + t.Logf("PASS: Allergic to %v", test.expected) + } + } +} + +func BenchmarkAllergies(b *testing.B) { + b.StopTimer() + for _, test := range allergicToTests { + b.StartTimer() + + for i := 0; i < b.N; i++ { + Allergies(test.i) + } + b.StopTimer() + } +} + +var allergicToTests = []struct { + expected bool + i int + allergen string +}{ + {false, 0, "peanuts"}, + {false, 0, "cats"}, + {false, 0, "strawberries"}, + {true, 1, "eggs"}, + {true, 5, "eggs"}, +} + +func TestAllergicTo(t *testing.T) { + for _, test := range allergicToTests { + actual := AllergicTo(test.i, test.allergen) + if actual != test.expected { + t.Fatalf("FAIL: AllergicTo(%d, %s): expected %t, actual %t", test.i, test.allergen, test.expected, actual) + } else { + t.Logf("PASS: AllergicTo(%d, %s) %t", test.i, test.allergen, actual) + } + } +} + +func BenchmarkAllergicTo(b *testing.B) { + b.StopTimer() + for _, test := range allergicToTests { + b.StartTimer() + + for i := 0; i < b.N; i++ { + AllergicTo(test.i, test.allergen) + } + b.StopTimer() + } +} diff --git a/go/anagram/README.md b/go/anagram/README.md new file mode 100644 index 0000000..9608b6f --- /dev/null +++ b/go/anagram/README.md @@ -0,0 +1,21 @@ +# Anagram + +Write a program that, given a word and a list of possible anagrams, selects the correct sublist. + +Given `"listen"` and a list of candidates like `"enlists" "google" +"inlets" "banana"` the program should return a list containing +`"inlets"`. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +Inspired by the Extreme Startup game [view source](https://github.com/rchatley/extreme_startup) diff --git a/go/anagram/anagram.go b/go/anagram/anagram.go new file mode 100644 index 0000000..7f9b452 --- /dev/null +++ b/go/anagram/anagram.go @@ -0,0 +1,28 @@ +package anagram + +import "strings" + +// Detect returns all candidates that are anagrams of subject +func Detect(subject string, candidates []string) []string { + var ret []string + for i := range candidates { + if isAnagram(subject, candidates[i]) { + ret = append(ret, strings.ToLower(candidates[i])) + } + } + return ret +} + +func isAnagram(s, c string) bool { + s = strings.ToLower(s) + c = strings.ToLower(c) + if s == c || len(s) != len(c) { + return false + } + for _, v := range strings.Split(s, "") { + if strings.Count(s, v) != strings.Count(c, v) { + return false + } + } + return true +} diff --git a/go/anagram/anagram_test.go b/go/anagram/anagram_test.go new file mode 100644 index 0000000..3a8c0fc --- /dev/null +++ b/go/anagram/anagram_test.go @@ -0,0 +1,172 @@ +package anagram + +import ( + "fmt" + "sort" + "testing" +) + +var testCases = []struct { + subject string + candidates []string + expected []string + description string +}{ + { + subject: "diaper", + candidates: []string{ + "hello", + "world", + "zombies", + "pants", + }, + expected: []string{}, + description: "no matches", + }, + { + subject: "ant", + candidates: []string{ + "tan", + "stand", + "at", + }, + expected: []string{"tan"}, + description: "simple anagram", + }, + { + subject: "listen", + candidates: []string{ + "enlists", + "google", + "inlets", + "banana", + }, + expected: []string{"inlets"}, + description: "another simple anagram", + }, + { + subject: "master", + candidates: []string{ + "stream", + "pigeon", + "maters", + }, + expected: []string{"maters", "stream"}, + description: "multiple anagrams", + }, + { + subject: "allergy", + candidates: []string{ + "gallery", + "ballerina", + "regally", + "clergy", + "largely", + "leading", + }, + expected: []string{"gallery", "largely", "regally"}, + description: "multiple anagrams (again)", + }, + { + subject: "galea", + candidates: []string{ + "eagle", + }, + expected: []string{}, + description: "does not confuse different duplicates", + }, + { + subject: "corn", + candidates: []string{ + "corn", + "dark", + "Corn", + "rank", + "CORN", + "cron", + "park", + }, + expected: []string{"cron"}, + description: "identical word is not anagram", + }, + { + subject: "mass", + candidates: []string{ + "last", + }, + expected: []string{}, + description: "eliminate anagrams with same checksum", + }, + { + subject: "good", + candidates: []string{ + "dog", + "goody", + }, + expected: []string{}, + description: "eliminate anagram subsets", + }, + { + subject: "Orchestra", + candidates: []string{ + "cashregiser", + "carthorse", + "radishes", + }, + expected: []string{"carthorse"}, + description: "subjects are case insensitive", + }, + { + subject: "orchestra", + candidates: []string{ + "cashregiser", + "Carthorse", + "radishes", + }, + expected: []string{"carthorse"}, + description: "candidates are case insensitive", + }, +} + +func equal(a []string, b []string) bool { + if len(b) != len(a) { + return false + } + + sort.Strings(a) + sort.Strings(b) + return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b) +} + +func TestDetectAnagrams(t *testing.T) { + for _, tt := range testCases { + actual := Detect(tt.subject, tt.candidates) + if !equal(tt.expected, actual) { + msg := `FAIL: %s + Subject %s + Candidates %v + Expected %v + Got %v + ` + t.Fatalf(msg, tt.description, tt.subject, tt.candidates, tt.expected, actual) + } else { + t.Logf("PASS: %s", tt.description) + } + } +} + +func BenchmarkDetectAnagrams(b *testing.B) { + + b.StopTimer() + + for _, tt := range testCases { + b.StartTimer() + + for i := 0; i < b.N; i++ { + Detect(tt.subject, tt.candidates) + } + + b.StopTimer() + } + +} diff --git a/go/bank-account/README.md b/go/bank-account/README.md new file mode 100644 index 0000000..985ea3c --- /dev/null +++ b/go/bank-account/README.md @@ -0,0 +1,40 @@ +# Bank Account + +Bank accounts can be accessed in different ways at the same time. + +A bank account can be accessed in multiple ways. Clients can make +deposits and withdrawals using the internet, mobile phones, etc. Shops +can charge against the account. + +Create an account that can be accessed from multiple threads/processes +(terminology depends on your programming language). + +It should be possible to close an account; operations against a closed +account must fail. + +## Instructions + +Run the test file, and fix each of the errors in turn. When you get the +first test to pass, go to the first pending or skipped test, and make +that pass as well. When all of the tests are passing, feel free to +submit. + +Remember that passing code is just the first step. The goal is to work +towards a solution that is as readable and expressive as you can make +it. + +Have fun! + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + + [view source]() diff --git a/go/bank-account/account.go b/go/bank-account/account.go new file mode 100644 index 0000000..55da376 --- /dev/null +++ b/go/bank-account/account.go @@ -0,0 +1,58 @@ +package account + +import "sync" + +// Account just represents a user's account +type Account struct { + sync.RWMutex + balance int + closed bool +} + +// Open returns a new account +func Open(amt int) *Account { + a := new(Account) + _, ok := a.Deposit(amt) + if ok { + return a + } + return nil +} + +// Close returns the payout amount and an 'ok' flag +func (a *Account) Close() (int, bool) { + a.Lock() + ret := a.balance + if a.closed { + a.Unlock() + return 0, false + } + a.closed = true + a.balance = 0 + a.Unlock() + return ret, true +} + +// Balance returns the current account balance +// and an 'ok' flag +func (a *Account) Balance() (int, bool) { + if a.closed { + return 0, false + } + return a.balance, true +} + +// Deposit takes an amount (can be a withdrawal) +// and returns the new balance and an 'ok' flag +func (a *Account) Deposit(amount int) (int, bool) { + var ret int + var ok bool + a.Lock() + if !a.closed && a.balance+amount >= 0 { + a.balance += amount + ret = a.balance + ok = true + } + a.Unlock() + return ret, ok +} diff --git a/go/bank-account/bank_account_test.go b/go/bank-account/bank_account_test.go new file mode 100644 index 0000000..82d8ea3 --- /dev/null +++ b/go/bank-account/bank_account_test.go @@ -0,0 +1,289 @@ +// API: +// +// Open(initalDeposit int64) *Account +// (Account) Close() (payout int64, ok bool) +// (Account) Balance() (balance int64, ok bool) +// (Account) Deposit(amount uint64) (newBalance int64, ok bool) +// +// If Open is given a negative initial deposit, it must return nil. +// Deposit must handle a negative amount as a withdrawal. +// If any Account method is called on an closed account, it must not modify +// the account and must return ok = false. + +package account + +import ( + "runtime" + "sync" + "sync/atomic" + "testing" + "time" +) + +func TestSeqOpenBalanceClose(t *testing.T) { + // open account + const amt = 10 + a := Open(amt) + if a == nil { + t.Fatalf("Open(%d) = nil, want non-nil *Account.", amt) + } + t.Logf("Account 'a' opened with initial balance of %d.", amt) + + // verify balance after open + switch b, ok := a.Balance(); { + case !ok: + t.Fatal("a.Balance() returned !ok, want ok.") + case b != amt: + t.Fatalf("a.Balance() = %d, want %d", b, amt) + } + + // close account + switch p, ok := a.Close(); { + case !ok: + t.Fatalf("a.Close() returned !ok, want ok.") + case p != amt: + t.Fatalf("a.Close() returned payout = %d, want %d.", p, amt) + } + t.Log("Account 'a' closed.") + + // verify balance no longer accessible + if b, ok := a.Balance(); ok { + t.Log("Balance still available on closed account.") + t.Fatalf("a.Balance() = %d, %t. Want ok == false", b, ok) + } +} + +func TestSeqOpenDepositClose(t *testing.T) { + // open account + const openAmt = 10 + a := Open(openAmt) + if a == nil { + t.Fatalf("Open(%d) = nil, want non-nil *Account.", openAmt) + } + t.Logf("Account 'a' opened with initial balance of %d.", openAmt) + + // deposit + const depAmt = 20 + const newAmt = openAmt + depAmt + switch b, ok := a.Deposit(depAmt); { + case !ok: + t.Fatalf("a.Deposit(%d) returned !ok, want ok.", depAmt) + case b != openAmt+depAmt: + t.Fatalf("a.Deposit(%d) = %d, want new balance = %d", depAmt, b, newAmt) + } + t.Logf("Deposit of %d accepted to account 'a'", depAmt) + + // close account + switch p, ok := a.Close(); { + case !ok: + t.Fatalf("a.Close() returned !ok, want ok.") + case p != newAmt: + t.Fatalf("a.Close() returned payout = %d, want %d.", p, newAmt) + } + t.Log("Account 'a' closed.") + + // verify deposits no longer accepted + if b, ok := a.Deposit(1); ok { + t.Log("Deposit accepted on closed account.") + t.Fatalf("a.Deposit(1) = %d, %t. Want ok == false", b, ok) + } +} + +func TestMoreSeqCases(t *testing.T) { + // open account 'a' as before + const openAmt = 10 + a := Open(openAmt) + if a == nil { + t.Fatalf("Open(%d) = nil, want non-nil *Account.", openAmt) + } + t.Logf("Account 'a' opened with initial balance of %d.", openAmt) + + // open account 'z' with zero balance + z := Open(0) + if z == nil { + t.Fatal("Open(0) = nil, want non-nil *Account.") + } + t.Log("Account 'z' opened with initial balance of 0.") + + // attempt to open account with negative opening balance + if Open(-10) != nil { + t.Fatal("Open(-10) seemed to work, " + + "want nil result for negative opening balance.") + } + + // verify both balances a and z still there + switch b, ok := a.Balance(); { + case !ok: + t.Fatal("a.Balance() returned !ok, want ok.") + case b != openAmt: + t.Fatalf("a.Balance() = %d, want %d", b, openAmt) + } + switch b, ok := z.Balance(); { + case !ok: + t.Fatal("z.Balance() returned !ok, want ok.") + case b != 0: + t.Fatalf("z.Balance() = %d, want 0", b) + } + + // withdrawals + const wAmt = 3 + const newAmt = openAmt - wAmt + switch b, ok := a.Deposit(-wAmt); { + case !ok: + t.Fatalf("a.Deposit(%d) returned !ok, want ok.", -wAmt) + case b != newAmt: + t.Fatalf("a.Deposit(%d) = %d, want new balance = %d", -wAmt, b, newAmt) + } + t.Logf("Withdrawal of %d accepted from account 'a'", wAmt) + if _, ok := z.Deposit(-1); ok { + t.Fatal("z.Deposit(-1) returned ok, want !ok.") + } + + // verify both balances + switch b, ok := a.Balance(); { + case !ok: + t.Fatal("a.Balance() returned !ok, want ok.") + case b != newAmt: + t.Fatalf("a.Balance() = %d, want %d", b, newAmt) + } + switch b, ok := z.Balance(); { + case !ok: + t.Fatal("z.Balance() returned !ok, want ok.") + case b != 0: + t.Fatalf("z.Balance() = %d, want 0", b) + } + + // close just z + switch p, ok := z.Close(); { + case !ok: + t.Fatalf("z.Close() returned !ok, want ok.") + case p != 0: + t.Fatalf("z.Close() returned payout = %d, want 0.", p) + } + t.Log("Account 'z' closed.") + + // verify 'a' balance one more time + switch b, ok := a.Balance(); { + case !ok: + t.Fatal("a.Balance() returned !ok, want ok.") + case b != newAmt: + t.Fatalf("a.Balance() = %d, want %d", b, newAmt) + } +} + +func TestConcClose(t *testing.T) { + if runtime.NumCPU() < 2 { + t.Skip("Multiple CPU cores required for concurrency tests.") + } + if runtime.GOMAXPROCS(0) < 2 { + runtime.GOMAXPROCS(2) + } + + // test competing close attempts + for rep := 0; rep < 1000; rep++ { + const openAmt = 10 + a := Open(openAmt) + if a == nil { + t.Fatalf("Open(%d) = nil, want non-nil *Account.", openAmt) + } + var start sync.WaitGroup + start.Add(1) + const closeAttempts = 10 + res := make(chan string) + for i := 0; i < closeAttempts; i++ { + go func() { // on your mark, + start.Wait() // get set... + switch p, ok := a.Close(); { + case !ok: + if p != 0 { + t.Errorf("a.Close() = %d, %t. "+ + "Want payout = 0 for unsuccessful close", p, ok) + res <- "fail" + } else { + res <- "already closed" + } + case p != openAmt: + t.Errorf("a.Close() = %d, %t. "+ + "Want payout = %d for successful close", p, ok, openAmt) + res <- "fail" + default: + res <- "close" // exactly one goroutine should reach here + } + }() + } + start.Done() // ...go + var closes, fails int + for i := 0; i < closeAttempts; i++ { + switch <-res { + case "close": + closes++ + case "fail": + fails++ + } + } + switch { + case fails > 0: + t.FailNow() // error already logged by other goroutine + case closes == 0: + t.Fatal("Concurrent a.Close() attempts all failed. " + + "Want one to succeed.") + case closes > 1: + t.Fatalf("%d concurrent a.Close() attempts succeeded, "+ + "each paying out %d!. Want just one to succeed.", + closes, openAmt) + } + } +} + +func TestConcDeposit(t *testing.T) { + if runtime.NumCPU() < 2 { + t.Skip("Multiple CPU cores required for concurrency tests.") + } + if runtime.GOMAXPROCS(0) < 2 { + runtime.GOMAXPROCS(2) + } + a := Open(0) + if a == nil { + t.Fatal("Open(0) = nil, want non-nil *Account.") + } + const amt = 10 + const c = 1000 + var negBal int32 + var start, g sync.WaitGroup + start.Add(1) + g.Add(3 * c) + for i := 0; i < c; i++ { + go func() { // deposit + start.Wait() + a.Deposit(amt) // ignore return values + g.Done() + }() + go func() { // withdraw + start.Wait() + for { + if _, ok := a.Deposit(-amt); ok { + break + } + time.Sleep(time.Microsecond) // retry + } + g.Done() + }() + go func() { // watch that balance stays >= 0 + start.Wait() + if p, _ := a.Balance(); p < 0 { + atomic.StoreInt32(&negBal, 1) + } + g.Done() + }() + } + start.Done() + g.Wait() + if negBal == 1 { + t.Fatal("Balance went negative with concurrent deposits and " + + "withdrawals. Want balance always >= 0.") + } + if p, ok := a.Balance(); !ok || p != 0 { + t.Fatalf("After equal concurrent deposits and withdrawals, "+ + "a.Balance = %d, %t. Want 0, true", p, ok) + } +} diff --git a/go/binary/README.md b/go/binary/README.md new file mode 100644 index 0000000..32feaca --- /dev/null +++ b/go/binary/README.md @@ -0,0 +1,43 @@ +# Binary + +Write a program that will convert a binary number, represented as a string (e.g. '101010'), to its decimal equivalent using first principles + +Implement binary to decimal conversion. Given a binary input +string, your program should produce a decimal output. The +program should handle invalid inputs. + +## Note +- Implement the conversion yourself. + Do not use something else to perform the conversion for you. + +## About Binary (Base-2) +Decimal is a base-10 system. + +A number 23 in base 10 notation can be understood +as a linear combination of powers of 10: + +- The rightmost digit gets multiplied by 10^0 = 1 +- The next number gets multiplied by 10^1 = 10 +- ... +- The *n*th number gets multiplied by 10^*(n-1)*. +- All these values are summed. + +So: `23 => 2*10^1 + 3*10^0 => 2*10 + 3*1 = 23 base 10` + +Binary is similar, but uses powers of 2 rather than powers of 10. + +So: `101 => 1*2^2 + 0*2^1 + 1*2^0 => 1*4 + 0*2 + 1*1 => 4 + 1 => 5 base 10`. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +All of Computer Science [view source](http://www.wolframalpha.com/input/?i=binary&a=*C.binary-_*MathWorld-) diff --git a/go/binary/binary.go b/go/binary/binary.go new file mode 100644 index 0000000..89804ef --- /dev/null +++ b/go/binary/binary.go @@ -0,0 +1,22 @@ +package binary + +import "fmt" + +// ParseBinary takes a binary string and returns the +// integer representation of it. +func ParseBinary(bin string) (int, error) { + var ret int + currSpot := 1 + for len(bin) > 0 { + v := bin[len(bin)-1] + if v != '0' && v != '1' { + return 0, fmt.Errorf("Invalid String") + } + if v == '1' { + ret = ret + currSpot + } + currSpot = currSpot * 2 + bin = bin[:len(bin)-1] + } + return ret, nil +} diff --git a/go/binary/binary_test.go b/go/binary/binary_test.go new file mode 100644 index 0000000..d58fa4c --- /dev/null +++ b/go/binary/binary_test.go @@ -0,0 +1,55 @@ +package binary + +import ( + "testing" +) + +// You must implement the function, +// +// func ParseBinary(string) (int, error) +// +// It is standard for Go functions to return error values to report error conditions. +// The test cases below are all valid binary numbers however. For this exercise you +// may simply return nil for the error value in all cases. +// +// For bonus points though, what errors might be possible when parsing a number? +// Can you add code to detect error conditions and return appropriate error values? + +var testCases = []struct { + binary string + expected int +}{ + {"1", 1}, + {"10", 2}, + {"11", 3}, + {"100", 4}, + {"1001", 9}, + {"11010", 26}, + {"10001101000", 1128}, + {"0", 0}, +} + +func TestParseBinary(t *testing.T) { + for _, tt := range testCases { + actual, err := ParseBinary(tt.binary) + // We don't expect errors for any of the test cases. + if err != nil { + t.Fatalf("ParseBinary(%v) returned error %q. Error not expected.", + tt.binary, err) + } + // Well, we don't expect wrong answers either. + if actual != tt.expected { + t.Fatalf("ParseBinary(%v): actual %d, expected %v", + tt.binary, actual, tt.expected) + } + } +} + +// Benchmark combined time for all tests +func BenchmarkBinary(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, tt := range testCases { + ParseBinary(tt.binary) + } + } +} diff --git a/go/bob/README.md b/go/bob/README.md new file mode 100644 index 0000000..0a62710 --- /dev/null +++ b/go/bob/README.md @@ -0,0 +1,44 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question. + +He answers 'Whoa, chill out!' if you yell at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +## Instructions + +Run the test file, and fix each of the errors in turn. When you get the +first test to pass, go to the first pending or skipped test, and make +that pass as well. When all of the tests are passing, feel free to +submit. + +Remember that passing code is just the first step. The goal is to work +towards a solution that is as readable and expressive as you can make +it. + +Please make your solution as general as possible. Good code doesn't just +pass the test suite, it works with any input that fits the +specification. + +Have fun! + + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=06) diff --git a/go/bob/bob.go b/go/bob/bob.go new file mode 100644 index 0000000..87684f9 --- /dev/null +++ b/go/bob/bob.go @@ -0,0 +1,19 @@ +package bob + +import "strings" + +// TestVersion is an exercism thing +const TestVersion = 1 + +// Hey provokes a response from Bob +func Hey(inp string) string { + inp = strings.TrimSpace(inp) + if inp == "" { + return "Fine. Be that way!" + } else if inp == strings.ToUpper(inp) && inp != strings.ToLower(inp) { + return "Whoa, chill out!" + } else if strings.HasSuffix(inp, "?") { + return "Sure." + } + return "Whatever." +} diff --git a/go/bob/bob_test.go b/go/bob/bob_test.go new file mode 100644 index 0000000..9bae61d --- /dev/null +++ b/go/bob/bob_test.go @@ -0,0 +1,33 @@ +package bob + +import "testing" + +const testVersion = 1 + +// Retired testVersions +// (none) 4a9e144a3c5dc0d9773f4cf641ffe3efe48641d8 + +func TestHeyBob(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + for _, tt := range testCases { + actual := Hey(tt.input) + if actual != tt.expected { + msg := ` + ALICE (%s): %q + BOB: %s + + Expected Bob to respond: %s` + t.Fatalf(msg, tt.description, tt.input, actual, tt.expected) + } + } +} + +func BenchmarkBob(b *testing.B) { + for _, tt := range testCases { + for i := 0; i < b.N; i++ { + Hey(tt.input) + } + } +} diff --git a/go/bob/cases_test.go b/go/bob/cases_test.go new file mode 100644 index 0000000..825d11d --- /dev/null +++ b/go/bob/cases_test.go @@ -0,0 +1,141 @@ +package bob + +// Source: exercism/x-common +// Commit: 945d08e Merge pull request #50 from soniakeys/master + +var testCases = []struct { + description string + input string + expected string +}{ + { + "stating something", + "Tom-ay-to, tom-aaaah-to.", + "Whatever.", + }, + { + "shouting", + "WATCH OUT!", + "Whoa, chill out!", + }, + { + "shouting gibberish", + "FCECDFCAAB", + "Whoa, chill out!", + }, + { + "asking a question", + "Does this cryogenic chamber make me look fat?", + "Sure.", + }, + { + "asking a numeric question", + "You are, what, like 15?", + "Sure.", + }, + { + "asking gibberish", + "fffbbcbeab?", + "Sure.", + }, + { + "talking forcefully", + "Let's go make out behind the gym!", + "Whatever.", + }, + { + "using acronyms in regular speech", + "It's OK if you don't want to go to the DMV.", + "Whatever.", + }, + { + "forceful question", + "WHAT THE HELL WERE YOU THINKING?", + "Whoa, chill out!", + }, + { + "shouting numbers", + "1, 2, 3 GO!", + "Whoa, chill out!", + }, + { + "only numbers", + "1, 2, 3", + "Whatever.", + }, + { + "question with only numbers", + "4?", + "Sure.", + }, + { + "shouting with special characters", + "ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!", + "Whoa, chill out!", + }, + { + "shouting with umlauts", + "ÜMLÄÜTS!", + "Whoa, chill out!", + }, + { + "calmly speaking with umlauts", + "ÜMLäÜTS!", + "Whatever.", + }, + { + "shouting with no exclamation mark", + "I HATE YOU", + "Whoa, chill out!", + }, + { + "statement containing question mark", + "Ending with ? means a question.", + "Whatever.", + }, + { + "non-letters with question", + ":) ?", + "Sure.", + }, + { + "prattling on", + "Wait! Hang on. Are you going to be OK?", + "Sure.", + }, + { + "silence", + "", + "Fine. Be that way!", + }, + { + "prolonged silence", + " ", + "Fine. Be that way!", + }, + { + "alternate silence", + "\t\t\t\t\t\t\t\t\t\t", + "Fine. Be that way!", + }, + { + "multiple line question", + "\nDoes this cryogenic chamber make me look fat?\nno", + "Whatever.", + }, + { + "starting with whitespace", + " hmmmmmmm...", + "Whatever.", + }, + { + "ending with whitespace", + "Okay if like my spacebar quite a bit? ", + "Sure.", + }, + { + "other whitespace", + "\n\r \t\v\u00a0\u2002", + "Fine. Be that way!", + }, +} diff --git a/go/bracket-push/README.md b/go/bracket-push/README.md new file mode 100644 index 0000000..a6657e5 --- /dev/null +++ b/go/bracket-push/README.md @@ -0,0 +1,20 @@ +# Bracket Push + +Make sure the brackets and braces all match. + +Ensure that all the brackets and braces are matched correctly, +and nested correctly. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Ginna Baker [view source]() diff --git a/go/bracket-push/bracket-push.go b/go/bracket-push/bracket-push.go new file mode 100644 index 0000000..f990ac1 --- /dev/null +++ b/go/bracket-push/bracket-push.go @@ -0,0 +1,26 @@ +package bracket_push + +// Bracket makes sure that all brackets match +func Bracket(s string) (bool, error) { + // Set up a map of matches that we care about + matches := make(map[byte]byte) + matches['}'] = '{' + matches[')'] = '(' + matches[']'] = '[' + var pairs []byte + for i := range s { + if v, ok := matches[s[i]]; ok { + // Found a match, it's a closing bracket + if len(pairs) == 0 || pairs[len(pairs)-1] != v { + return false, nil + } + pairs = pairs[:len(pairs)-1] + } else { + pairs = append(pairs, s[i]) + } + } + if len(pairs) > 0 { + return false, nil + } + return true, nil +} \ No newline at end of file diff --git a/go/bracket-push/bracket-push_test.go b/go/bracket-push/bracket-push_test.go new file mode 100644 index 0000000..1b3146d --- /dev/null +++ b/go/bracket-push/bracket-push_test.go @@ -0,0 +1,72 @@ +package bracket_push + +import ( + "testing" +) + +var testCases = []struct { + input string + expected bool +}{ + { + input: "", + expected: true, + }, + { + input: "{}", + expected: true, + }, + { + input: "{{", + expected: false, + }, + { + input: "}{", + expected: false, + }, + { + input: "{}[]", + expected: true, + }, + { + input: "{[]}", + expected: true, + }, + { + input: "{[}]", + expected: false, + }, + { + input: "{[)][]}", + expected: false, + }, + { + input: "{[]([()])}", + expected: true, + }, +} + +func TestBracket(t *testing.T) { + for _, tt := range testCases { + actual, err := Bracket(tt.input) + // We don't expect errors for any of the test cases + if err != nil { + t.Fatalf("Bracket(%q) returned error %q. Error not expected.", tt.input, err) + } + if actual != tt.expected { + t.Fatalf("Bracket(%q) was expected to return %v but returned %v.", + tt.input, tt.expected, actual) + } + } +} + +func BenchmarkBracket(b *testing.B) { + b.StopTimer() + for _, tt := range testCases { + b.StartTimer() + for i := 0; i < b.N; i++ { + Bracket(tt.input) + } + b.StopTimer() + } +} diff --git a/go/bracket-push/bracket_push_test.go b/go/bracket-push/bracket_push_test.go new file mode 100644 index 0000000..a4a7eed --- /dev/null +++ b/go/bracket-push/bracket_push_test.go @@ -0,0 +1,77 @@ +package brackets + +import ( + "testing" +) + +const testVersion = 2 + +var testCases = []struct { + input string + expected bool +}{ + { + input: "", + expected: true, + }, + { + input: "{}", + expected: true, + }, + { + input: "{{", + expected: false, + }, + { + input: "}{", + expected: false, + }, + { + input: "{}[]", + expected: true, + }, + { + input: "{[]}", + expected: true, + }, + { + input: "{[}]", + expected: false, + }, + { + input: "{[)][]}", + expected: false, + }, + { + input: "{[]([()])}", + expected: true, + }, +} + +func TestBracket(t *testing.T) { + for _, tt := range testCases { + actual, err := Bracket(tt.input) + // We don't expect errors for any of the test cases + if err != nil { + t.Fatalf("Bracket(%q) returned error %q. Error not expected.", tt.input, err) + } + if actual != tt.expected { + t.Fatalf("Bracket(%q) was expected to return %v but returned %v.", + tt.input, tt.expected, actual) + } + } + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v.", TestVersion, testVersion) + } +} + +func BenchmarkBracket(b *testing.B) { + b.StopTimer() + for _, tt := range testCases { + b.StartTimer() + for i := 0; i < b.N; i++ { + Bracket(tt.input) + } + b.StopTimer() + } +} diff --git a/go/clock/README.md b/go/clock/README.md new file mode 100644 index 0000000..b81e69b --- /dev/null +++ b/go/clock/README.md @@ -0,0 +1,23 @@ +# Clock + +Implement a clock that handles times without dates. + +Create a clock that is independent of date. + +You should be able to add and subtract minutes to it. + +Two clocks that represent the same time should be equal to each other. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Pairing session with Erin Drummond [view source](https://twitter.com/ebdrummond) diff --git a/go/clock/cases_test.go b/go/clock/cases_test.go new file mode 100644 index 0000000..287e7fe --- /dev/null +++ b/go/clock/cases_test.go @@ -0,0 +1,78 @@ +package clock + +// Source: exercism/x-common +// Commit: 269f498 Merge pull request #48 from soniakeys/custom-set-json + +// Test creating a new clock with an initial time. +var timeTests = []struct { + h, m int + want string +}{ + {8, 0, "08:00"}, // on the hour + {9, 0, "09:00"}, // on the hour + {11, 9, "11:09"}, // past the hour + {11, 19, "11:19"}, // past the hour + {24, 0, "00:00"}, // midnight is zero hours + {25, 0, "01:00"}, // hour rolls over + {1, 60, "02:00"}, // sixty minutes is next hour + {0, 160, "02:40"}, // minutes roll over + {25, 160, "03:40"}, // hour and minutes roll over + {-1, 15, "23:15"}, // negative hour + {-25, 0, "23:00"}, // negative hour rolls over + {1, -40, "00:20"}, // negative minutes + {1, -160, "22:20"}, // negative minutes roll over + {-25, -160, "20:20"}, // negative hour and minutes both roll over +} + +// Test adding and subtracting minutes. +var addTests = []struct { + h, m, a int + want string +}{ + {10, 0, 3, "10:03"}, // add minutes + {0, 45, 40, "01:25"}, // add to next hour + {10, 0, 61, "11:01"}, // add more than one hour + {23, 59, 2, "00:01"}, // add across midnight + {5, 32, 1500, "06:32"}, // add more than one day (1500 min = 25 hrs) + {0, 45, 160, "03:25"}, // add more than two hours with carry + {10, 3, -3, "10:00"}, // subtract minutes + {10, 3, -30, "09:33"}, // subtract to previous hour + {10, 3, -70, "08:53"}, // subtract more than an hour + {0, 3, -4, "23:59"}, // subtract across midnight + {0, 0, -160, "21:20"}, // subtract more than two hours + {5, 32, -1500, "04:32"}, // subtract more than one day (1500 min = 25 hrs) + {6, 15, -160, "03:35"}, // subtract more than two hours with borrow +} + +// Construct two separate clocks, set times, test if they are equal. +type hm struct{ h, m int } + +var eqTests = []struct { + c1, c2 hm + want bool +}{ + // clocks with same time + { + hm{15, 37}, + hm{15, 37}, + true, + }, + // clocks a minute apart + { + hm{15, 36}, + hm{15, 37}, + false, + }, + // clocks an hour apart + { + hm{14, 37}, + hm{15, 37}, + false, + }, + // clocks set 24 hours apart + { + hm{10, 37}, + hm{34, 37}, + true, + }, +} diff --git a/go/clock/clock.go b/go/clock/clock.go new file mode 100644 index 0000000..43db94f --- /dev/null +++ b/go/clock/clock.go @@ -0,0 +1,34 @@ +package clock + +import "fmt" + +// TestVersion is for exercism +const TestVersion = 2 + +// Clock is an int representing the time of day +type Clock int + +// Time returns a Clock representing the given hour & minute +func Time(hour, minute int) Clock { + return TimeFromMinutes(hour*60 + minute) +} + +// String returns a string representation of Clock +func (c Clock) String() string { + return fmt.Sprintf("%02d:%02d", c/60, c%60) +} + +// Add adds minutes to the clock +func (c Clock) Add(minutes int) Clock { + return TimeFromMinutes(int(c) + minutes) +} + +// TimeFromMinutes takes a minutes integer value and returns a Clock +func TimeFromMinutes(minutes int) Clock { + for minutes < 0 { + // Keep adding 24 hours to the minutes value until it's positive + minutes = minutes + (24 * 60) + } + minutes = minutes % (24 * 60) + return Clock(minutes) +} diff --git a/go/clock/clock_test.go b/go/clock/clock_test.go new file mode 100644 index 0000000..27e92bd --- /dev/null +++ b/go/clock/clock_test.go @@ -0,0 +1,69 @@ +package clock + +import ( + "reflect" + "testing" +) + +// Clock type API: +// +// Time(hour, minute int) Clock // a "constructor" +// (Clock) String() string // a "stringer" +// (Clock) Add(minutes int) Clock +// +// Add should also handle subtraction by accepting negative values. +// To satisfy the readme requirement about clocks being equal, values of +// your Clock type need to work with the == operator. +// +// It might help to study the time.Time type in the standard library +// (https://golang.org/pkg/time/#Time) as a model. See how constructors there +// (Date and Now) return Time values rather than pointers. Note also how +// most time.Time methods have value receivers rather that pointer recievers. +// For more background on this read +// https://github.com/golang/go/wiki/CodeReviewComments#receiver-type. + +const testVersion = 2 + +// Retired testVersions +// (none) 79937f6d58e25ebafe12d1cb4a9f88f4de70cfd6 +// 1 8d0cb8b617be2e36b2ca5ad2034e5f80f2372924 + +func TestCreateClock(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + for _, n := range timeTests { + if got := Time(n.h, n.m); got.String() != n.want { + t.Fatalf("Time(%d, %d) = %q, want %q", n.h, n.m, got, n.want) + } + } + t.Log(len(timeTests), "test cases") +} + +func TestAddMinutes(t *testing.T) { + for _, a := range addTests { + if got := Time(a.h, a.m).Add(a.a); got.String() != a.want { + t.Fatalf("Time(%d, %d).Add(%d) = %q, want %q", + a.h, a.m, a.a, got, a.want) + } + } + t.Log(len(addTests), "test cases") +} + +func TestCompareClocks(t *testing.T) { + for _, e := range eqTests { + clock1 := Time(e.c1.h, e.c1.m) + clock2 := Time(e.c2.h, e.c2.m) + got := clock1 == clock2 + if got != e.want { + t.Log("Clock1:", clock1) + t.Log("Clock2:", clock2) + t.Logf("Clock1 == Clock2 is %t, want %t", got, e.want) + if reflect.DeepEqual(clock1, clock2) { + t.Log("(Hint: see comments in clock_test.go.)") + } + t.FailNow() + } + } + t.Log(len(eqTests), "test cases") +} diff --git a/go/crypto-square/README.md b/go/crypto-square/README.md new file mode 100644 index 0000000..952f602 --- /dev/null +++ b/go/crypto-square/README.md @@ -0,0 +1,87 @@ +# Crypto Square + +Implement the classic method for composing secret messages called a square code. + +The input is first normalized: The spaces and punctuation are removed +from the English text and the message is downcased. + +Then, the normalized characters are broken into rows. These rows can be +regarded as forming a rectangle when printed with intervening newlines. + +For example, the sentence + +> If man was meant to stay on the ground god would have given us roots + +is 54 characters long. + +Broken into 8-character columns, it yields 7 rows. + +Those 7 rows produce this rectangle when printed one per line: + +```plain +ifmanwas +meanttos +tayonthe +groundgo +dwouldha +vegivenu +sroots +``` + +The coded message is obtained by reading down the columns going left to +right. + +For example, the message above is coded as: + +```plain +imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau +``` + +Write a program that, given an English text, outputs the encoded version +of that text. + +The size of the square (number of columns) should be decided by the +length of the message. + +If the message is a length that creates a perfect square (e.g. 4, 9, 16, +25, 36, etc), use that number of columns. + +If the message doesn't fit neatly into a square, choose the number of +columns that corresponds to the smallest square that is larger than the +number of characters in the message. + +For example, a message 4 characters long should use a 2 x 2 square. A +message that is 81 characters long would use a square that is 9 columns +wide. + +A message between 5 and 8 characters long should use a rectangle 3 +characters wide. + +Output the encoded text grouped by column. + +For example: + +- "Have a nice day. Feed the dog & chill out!" + - Normalizes to: "haveanicedayfeedthedogchillout" + - Which has length: 30 + - And splits into 5 6-character rows: + - "havean" + - "iceday" + - "feedth" + - "edogch" + - "illout" + - Which yields a ciphertext beginning: "hifei acedl v…" + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +J Dalbey's Programming Practice problems [view source](http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html) diff --git a/go/crypto-square/crypto_square.go b/go/crypto-square/crypto_square.go new file mode 100644 index 0000000..3251061 --- /dev/null +++ b/go/crypto-square/crypto_square.go @@ -0,0 +1,45 @@ +package cryptosquare + +import ( + "math" + "regexp" + "strings" +) + +// TestVersion is an exercism thing +const TestVersion = 1 + +// Encode implements the classic method for composing +// secret messages called a square code +func Encode(txt string) string { + r := regexp.MustCompile("[^a-zA-Z0-9]+") + nrm := strings.ToLower(r.ReplaceAllString(txt, "")) + // The string should be normalized now (alphanumeric, lower case) + sqrt := int(math.Ceil(math.Sqrt(float64(len(nrm))))) + var square, ret []string + var tmp string + + // Build the initial square + for i := 0; i < len(nrm); i++ { + if i%sqrt == 0 && len(tmp) != 0 { + square = append(square, tmp) + tmp = "" + } + tmp += string(nrm[i]) + } + square = append(square, tmp) + tmp = "" + + // Now rebuild the string by columns + for i := 0; i < len(square[0]); i++ { + for j := 0; j < len(square); j++ { + if i < len(square[j]) { + tmp += string(square[j][i]) + } + } + ret = append(ret, tmp) + tmp = "" + } + + return strings.Join(ret, " ") +} diff --git a/go/crypto-square/crypto_square_test.go b/go/crypto-square/crypto_square_test.go new file mode 100644 index 0000000..c0dfe13 --- /dev/null +++ b/go/crypto-square/crypto_square_test.go @@ -0,0 +1,111 @@ +package cryptosquare + +import "testing" + +const testVersion = 1 + +// Retired testVersions +// (none) 71ad8ac57fe7d5b777cfa1afd116cd41e1af55ed + +var tests = []struct { + pt string // plain text + ct string // cipher text +}{ + { + "s#$%^&plunk", + "su pn lk", + }, + { + "1, 2, 3 GO!", + "1g 2o 3", + }, + { + "1234", + "13 24", + }, + { + "123456789", + "147 258 369", + }, + { + "123456789abc", + "159 26a 37b 48c", + }, + { + "Never vex thine heart with idle woes", + "neewl exhie vtetw ehaho ririe vntds", + }, + { + "ZOMG! ZOMBIES!!!", + "zzi ooe mms gb", + }, + { + "Time is an illusion. Lunchtime doubly so.", + "tasney inicds miohoo elntu illib suuml", + }, + { + "We all know interspecies romance is weird.", + "wneiaw eorene awssci liprer lneoid ktcms", + }, + { + "Madness, and then illumination.", + "msemo aanin dnin ndla etlt shui", + }, + { + "Vampires are people too!", + "vrel aepe mset paoo irpo", + }, + { + "", + "", + }, + { + "1", + "1", + }, + { + "12", + "1 2", + }, + { + "12 3", + "13 2", + }, + { + "12345678", + "147 258 36", + }, + { + "123456789a", + "159 26a 37 48", + }, + { + "If man was meant to stay on the ground god would have given us roots", + "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau", + }, + { + "Have a nice day. Feed the dog & chill out!", + "hifei acedl veeol eddgo aatcu nyhht", + }, +} + +func TestEncode(t *testing.T) { + if TestVersion != testVersion { + t.Errorf("Found TestVersion = %v, want %v.", TestVersion, testVersion) + } + for _, test := range tests { + if ct := Encode(test.pt); ct != test.ct { + t.Fatalf(`Encode(%q): +got %q +want %q`, test.pt, ct, test.ct) + } + } +} + +func BenchmarkEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range tests { + Encode(test.pt) + } + } +} diff --git a/go/current b/go/current new file mode 120000 index 0000000..8f1726f --- /dev/null +++ b/go/current @@ -0,0 +1 @@ +react \ No newline at end of file diff --git a/go/difference-of-squares/README.md b/go/difference-of-squares/README.md new file mode 100644 index 0000000..0e713da --- /dev/null +++ b/go/difference-of-squares/README.md @@ -0,0 +1,30 @@ +# Difference Of Squares + +Find the difference between the sum of the squares and the square of the sums of the first N natural numbers. + +The square of the sum of the first ten natural numbers is, + + (1 + 2 + ... + 10)**2 = 55**2 = 3025 + +The sum of the squares of the first ten natural numbers is, + + 1**2 + 2**2 + ... + 10**2 = 385 + +Hence the difference between the square of the sum of the first +ten natural numbers and the sum of the squares is 2640: + + 3025 - 385 = 2640 + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Problem 6 at Project Euler [view source](http://projecteuler.net/problem=6) diff --git a/go/difference-of-squares/difference_of_squares.go b/go/difference-of-squares/difference_of_squares.go new file mode 100644 index 0000000..87a00e6 --- /dev/null +++ b/go/difference-of-squares/difference_of_squares.go @@ -0,0 +1,32 @@ +package diffsquares + +import "math" + +// SquareOfSums calculates the Square of the sums +// of the first 'num' natural numbers +func SquareOfSums(num int) int { + ret := 0 + for num > 0 { + ret += num + num-- + } + return int(math.Pow(float64(ret), 2)) +} + +// SumOfSquares calculates the Sum of the Squares +// of the first 'num' natural numbers +func SumOfSquares(num int) int { + ret := 0 + for num > 0 { + ret += int(math.Pow(float64(num), 2)) + num-- + } + return ret +} + +// Difference calculates the difference between +// The SquareOfSums and the SumOfSquares for the +// first 'num' natural numbers +func Difference(num int) int { + return SquareOfSums(num) - SumOfSquares(num) +} diff --git a/go/difference-of-squares/difference_of_squares_test.go b/go/difference-of-squares/difference_of_squares_test.go new file mode 100644 index 0000000..d3fe30f --- /dev/null +++ b/go/difference-of-squares/difference_of_squares_test.go @@ -0,0 +1,54 @@ +package diffsquares + +import "testing" + +var tests = []struct{ n, sqOfSums, sumOfSq int }{ + {5, 225, 55}, + {10, 3025, 385}, + {100, 25502500, 338350}, +} + +func TestSquareOfSums(t *testing.T) { + for _, test := range tests { + if s := SquareOfSums(test.n); s != test.sqOfSums { + t.Fatalf("SquareOfSums(%d) = %d, want %d", test.n, s, test.sqOfSums) + } + } +} + +func TestSumOfSquares(t *testing.T) { + for _, test := range tests { + if s := SumOfSquares(test.n); s != test.sumOfSq { + t.Fatalf("SumOfSquares(%d) = %d, want %d", test.n, s, test.sumOfSq) + } + } +} + +func TestDifference(t *testing.T) { + for _, test := range tests { + want := test.sqOfSums - test.sumOfSq + if s := Difference(test.n); s != want { + t.Fatalf("Difference(%d) = %d, want %d", test.n, s, want) + } + } +} + +// Benchmark functions on just a single number (100, from the original PE problem) +// to avoid overhead of iterating over tests. +func BenchmarkSquareOfSums(b *testing.B) { + for i := 0; i < b.N; i++ { + SquareOfSums(100) + } +} + +func BenchmarkSumOfSquares(b *testing.B) { + for i := 0; i < b.N; i++ { + SumOfSquares(100) + } +} + +func BenchmarkDifference(b *testing.B) { + for i := 0; i < b.N; i++ { + Difference(100) + } +} diff --git a/go/etl/README.md b/go/etl/README.md new file mode 100644 index 0000000..cec3c49 --- /dev/null +++ b/go/etl/README.md @@ -0,0 +1,62 @@ +# Etl + +We are going to do the `Transform` step of an Extract-Transform-Load. + +### ETL +Extract-Transform-Load (ETL) is a fancy way of saying, "We have some crufty, legacy data over in this system, and now we need it in this shiny new system over here, so +we're going to migrate this." + +(Typically, this is followed by, "We're only going to need to run this +once." That's then typically followed by much forehead slapping and +moaning about how stupid we could possibly be.) + +### The goal +We're going to extract some scrabble scores from a legacy system. + +The old system stored a list of letters per score: + +- 1 point: "A", "E", "I", "O", "U", "L", "N", "R", "S", "T", +- 2 points: "D", "G", +- 3 points: "B", "C", "M", "P", +- 4 points: "F", "H", "V", "W", "Y", +- 5 points: "K", +- 8 points: "J", "X", +- 10 points: "Q", "Z", + +The shiny new scrabble system instead stores the score per letter, which +makes it much faster and easier to calculate the score for a word. It +also stores the letters in lower-case regardless of the case of the +input letters: + +- "a" is worth 1 point. +- "b" is worth 3 points. +- "c" is worth 3 points. +- "d" is worth 2 points. +- Etc. + +Your mission, should you choose to accept it, is to write a program that +transforms the legacy data format to the shiny new format. + +### Notes +Note that both the old and the new system use strings to represent +letters, even in languages that have a separate data type for +characters. + +A final note about scoring, Scrabble is played around the world in a +variety of languages, each with its own unique scoring table. For +example, an "A" is scored at 14 in the Basque-language version of the +game while being scored at 9 in the Latin-language version. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +The Jumpstart Lab team [view source](http://jumpstartlab.com) diff --git a/go/etl/etl.go b/go/etl/etl.go new file mode 100644 index 0000000..95f476a --- /dev/null +++ b/go/etl/etl.go @@ -0,0 +1,17 @@ +package etl + +import "strings" + +// Transform takes the legacy data structure +// and converts it into the new and improved +// data structure oh man this new system will +// make us so rich you guys. +func Transform(input map[int][]string) map[string]int { + ret := make(map[string]int) + for k, v := range input { + for _, let := range v { + ret[strings.ToLower(let)] = k + } + } + return ret +} diff --git a/go/etl/etl_test.go b/go/etl/etl_test.go new file mode 100644 index 0000000..70cb93e --- /dev/null +++ b/go/etl/etl_test.go @@ -0,0 +1,90 @@ +package etl + +import "testing" + +type given map[int][]string +type expectation map[string]int + +var transformTests = []struct { + input given + output expectation +}{ + { + given{1: {"A"}}, + expectation{"a": 1}, + }, + { + given{1: {"A", "E", "I", "O", "U"}}, + expectation{"a": 1, "e": 1, "i": 1, "o": 1, "u": 1}, + }, + { + given{ + 1: {"A", "E"}, + 2: {"D", "G"}, + }, + expectation{ + "a": 1, + "e": 1, + "d": 2, + "g": 2, + }, + }, + { + given{ + 1: {"A", "E", "I", "O", "U", "L", "N", "R", "S", "T"}, + 2: {"D", "G"}, + 3: {"B", "C", "M", "P"}, + 4: {"F", "H", "V", "W", "Y"}, + 5: {"K"}, + 8: {"J", "X"}, + 10: {"Q", "Z"}, + }, + expectation{ + "a": 1, "e": 1, "i": 1, "o": 1, "u": 1, "l": 1, "n": 1, "r": 1, "s": 1, "t": 1, + "d": 2, "g": 2, + "b": 3, "c": 3, "m": 3, "p": 3, + "f": 4, "h": 4, "v": 4, "w": 4, "y": 4, + "k": 5, + "j": 8, "x": 8, + "q": 10, "z": 10, + }, + }, +} + +func equal(actual map[string]int, expectation map[string]int) bool { + if len(actual) != len(expectation) { + return false + } + + for k, actualVal := range actual { + expectationVal, present := expectation[k] + + if !present || actualVal != expectationVal { + return false + } + } + + return true +} + +func TestTranform(t *testing.T) { + for _, tt := range transformTests { + actual := Transform(map[int][]string(tt.input)) + if !equal(actual, tt.output) { + t.Fatalf("Transform(%v). Expected [%v], Actual [%v]", tt.input, tt.output, actual) + } + } +} + +func BenchmarkTranform(b *testing.B) { + b.StopTimer() + for _, tt := range transformTests { + b.StartTimer() + + for i := 0; i < b.N; i++ { + Transform(map[int][]string(tt.input)) + } + + b.StopTimer() + } +} diff --git a/go/food-chain/README.md b/go/food-chain/README.md new file mode 100644 index 0000000..2594301 --- /dev/null +++ b/go/food-chain/README.md @@ -0,0 +1,80 @@ +# Food Chain + +Write a program that generates the lyrics of the song 'I Know an Old Lady Who Swallowed a Fly' + +Write a program that generates the lyrics to the song +"I know an old lady who swallowed a fly". While you could +copy/paste the lyrics, or read them from a file, this +problem is much more interesting if you approach it +algorithmically. + +This is a [cumulative song](http://en.wikipedia.org/wiki/Cumulative_song) of unknown origin. + +This is one of many common variants. + +```plain +I know an old lady who swallowed a fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a spider. +It wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a bird. +How absurd to swallow a bird! +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a cat. +Imagine that, to swallow a cat! +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a dog. +What a hog, to swallow a dog! +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a goat. +Just opened her throat and swallowed a goat! +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a cow. +I don't know how she swallowed a cow! +She swallowed the cow to catch the goat. +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a horse. +She's dead, of course! +``` + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Wikipedia [view source](http://en.wikipedia.org/wiki/There_Was_an_Old_Lady_Who_Swallowed_a_Fly) diff --git a/go/food-chain/food_chain.go b/go/food-chain/food_chain.go new file mode 100644 index 0000000..6f9fa6a --- /dev/null +++ b/go/food-chain/food_chain.go @@ -0,0 +1,100 @@ +package foodchain + +import ( + "fmt" + "strings" +) + +// TestVersion is an exercism thing +const TestVersion = 1 + +// An Inedible is something that you probably shouldn't eat. +// At the least, you shouldn't eat it whole/live. +type Inedible struct { + // What it is + Name string + // A quick jab about it + FollowUp string +} + +// DoNotEat is a non-exhaustive list of Inedibles. It's recommended +// that you don't eat them. Yet the old lady did. +var DoNotEat = []Inedible{ + Inedible{ + "fly", "I don't know why she swallowed the fly. Perhaps she'll die.", + }, + Inedible{ + "spider", "It wriggled and jiggled and tickled inside her.", + }, + Inedible{ + "bird", "How absurd to swallow a bird!", + }, + Inedible{ + "cat", "Imagine that, to swallow a cat!", + }, + Inedible{ + "dog", "What a hog, to swallow a dog!", + }, + Inedible{ + "goat", "Just opened her throat and swallowed a goat!", + }, + Inedible{ + "cow", "I don't know how she swallowed a cow!", + }, + Inedible{ + "horse", "She's dead, of course!", + }, +} + +// Verse generates the text for a specific verse +func Verse(verseNum int) string { + return strings.Trim(Swallow(verseNum-1, true), "\n") +} + +// Verses generates the text for all verses from verse1 to verse2 +func Verses(verse1, verse2 int) string { + var ret string + for verse1 <= verse2 { + ret += Verse(verse1) + "\n\n" + verse1++ + } + return strings.Trim(ret, "\n") +} + +// Song generates all verses +func Song() string { + var ret string + for verseNum := 1; verseNum <= len(DoNotEat); verseNum++ { + ret += Verse(verseNum) + "\n\n" + } + return strings.Trim(ret, "\n") +} + +// Swallow generates the text for swallowing something +func Swallow(dneIdx int, first bool) string { + var ret string + + if first || dneIdx == len(DoNotEat)-1 { + ret = fmt.Sprintf( + "I know an old lady who swallowed a %s.\n%s\n", + DoNotEat[dneIdx].Name, + DoNotEat[dneIdx].FollowUp, + ) + if dneIdx == 0 || dneIdx == len(DoNotEat)-1 { + return ret + } + } + ret += fmt.Sprintf("She swallowed the %s to catch the %s", + DoNotEat[dneIdx].Name, + DoNotEat[dneIdx-1].Name, + ) + if DoNotEat[dneIdx-1].Name == "spider" { + ret += " that wriggled and jiggled and tickled inside her.\n" + } else if DoNotEat[dneIdx-1].Name == "fly" { + ret += ".\nI don't know why she swallowed the fly. Perhaps she'll die.\n" + return ret + } else { + ret += ".\n" + } + return ret + Swallow(dneIdx-1, false) +} diff --git a/go/food-chain/food_chain_test.go b/go/food-chain/food_chain_test.go new file mode 100644 index 0000000..1c36b37 --- /dev/null +++ b/go/food-chain/food_chain_test.go @@ -0,0 +1,95 @@ +package foodchain + +import ( + "strings" + "testing" +) + +const testVersion = 1 + +func TestTestVersion(t *testing.T) { + if TestVersion != testVersion { + t.Errorf("Found TestVersion = %v, want %v.", TestVersion, testVersion) + } +} + +var ref = []string{``, + + `I know an old lady who swallowed a fly. +I don't know why she swallowed the fly. Perhaps she'll die.`, + + `I know an old lady who swallowed a spider. +It wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die.`, + + `I know an old lady who swallowed a bird. +How absurd to swallow a bird! +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die.`, + + `I know an old lady who swallowed a cat. +Imagine that, to swallow a cat! +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die.`, + + `I know an old lady who swallowed a dog. +What a hog, to swallow a dog! +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die.`, + + `I know an old lady who swallowed a goat. +Just opened her throat and swallowed a goat! +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die.`, + + `I know an old lady who swallowed a cow. +I don't know how she swallowed a cow! +She swallowed the cow to catch the goat. +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die.`, + + `I know an old lady who swallowed a horse. +She's dead, of course!`, +} + +func TestVerse(t *testing.T) { + for v := 1; v <= 8; v++ { + if ret := Verse(v); ret != ref[v] { + t.Fatalf("Verse(%d) =\n%s\n want:\n%s\n", v, ret, ref[v]) + } + } +} + +func TestVerses(t *testing.T) { + if ret, want := Verses(1, 2), ref[1]+"\n\n"+ref[2]; ret != want { + t.Fatalf("Verses(1, 2) =\n%s\n want:\n%s\n", ret, want) + } + +} + +func TestSong(t *testing.T) { + if ret, want := Song(), strings.Join(ref[1:], "\n\n"); ret != want { + t.Fatalf("Song() =\n%s\n want:\n%s\n", ret, want) + } +} + +func BenchmarkSong(b *testing.B) { + for i := 0; i < b.N; i++ { + Song() + } +} diff --git a/go/gigasecond/README.md b/go/gigasecond/README.md new file mode 100644 index 0000000..06b13e7 --- /dev/null +++ b/go/gigasecond/README.md @@ -0,0 +1,19 @@ +# Gigasecond + +Write a program that will calculate the date that someone turned or will celebrate their 1 Gs anniversary. + +A gigasecond is one billion (10**9) seconds. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Chapter 9 in Chris Pine's online Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=09) diff --git a/go/gigasecond/cases_test.go b/go/gigasecond/cases_test.go new file mode 100644 index 0000000..520101b --- /dev/null +++ b/go/gigasecond/cases_test.go @@ -0,0 +1,31 @@ +package gigasecond + +// Source: exercism/x-common +// Commit: 1e9e232 Merge pull request #45 from soniakeys/gigasecond-tests + +// Add one gigasecond to the input. +var addCases = []struct { + in string + want string +}{ + { + "2011-04-25", + "2043-01-01T01:46:40", + }, + { + "1977-06-13", + "2009-02-19T01:46:40", + }, + { + "1959-07-19", + "1991-03-27T01:46:40", + }, + { + "2015-01-24T22:00:00", + "2046-10-02T23:46:40", + }, + { + "2015-01-24T23:59:59", + "2046-10-03T01:46:39", + }, +} diff --git a/go/gigasecond/gigasecond.go b/go/gigasecond/gigasecond.go new file mode 100644 index 0000000..0b812b7 --- /dev/null +++ b/go/gigasecond/gigasecond.go @@ -0,0 +1,14 @@ +package gigasecond + +import "time" + +// TestVersion +const TestVersion = 2 // find the value in gigasecond_test.go + +// AddGigasecond Adds a gigasecond to the time t +func AddGigasecond(t time.Time) time.Time { + return t.Add(time.Second * 1000000000) +} + +// Birthday is my fake birthday +var Birthday = time.Date(1979, 4, 23, 10, 2, 0, 0, time.UTC) diff --git a/go/gigasecond/gigasecond_test.go b/go/gigasecond/gigasecond_test.go new file mode 100644 index 0000000..d8225fe --- /dev/null +++ b/go/gigasecond/gigasecond_test.go @@ -0,0 +1,73 @@ +package gigasecond + +// Write a function AddGigasecond that works with time.Time. +// Also define a variable Birthday set to your (or someone else's) birthday. +// Run go test -v to see your gigasecond anniversary. + +import ( + "os" + "testing" + "time" +) + +const testVersion = 2 + +// Retired testVersions +// (none) 98807b314216ff27492378a00df60410cc971d32 +// 1 ed0594b6fd6664928d17bbc70b543a56da05a5b8 + +// date formats used in test data +const ( + fmtD = "2006-01-02" + fmtDT = "2006-01-02T15:04:05" +) + +func TestAddGigasecond(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v.", TestVersion, testVersion) + } + for _, tc := range addCases { + in := parse(tc.in, t) + want := parse(tc.want, t) + got := AddGigasecond(in) + if !got.Equal(want) { + t.Fatalf(`AddGigasecond(%s) + = %s +want %s`, in, got, want) + } + } + t.Log("Tested", len(addCases), "cases.") +} + +func TestYourAnniversary(t *testing.T) { + t.Logf(` +Your birthday: %s +Your gigasecond anniversary: %s`, Birthday, AddGigasecond(Birthday)) +} + +func parse(s string, t *testing.T) time.Time { + tt, err := time.Parse(fmtDT, s) // try full date time format first + if err != nil { + tt, err = time.Parse(fmtD, s) // also allow just date + } + if err != nil { + // can't run tests if input won't parse. if this seems to be a + // development or ci environment, raise an error. if this condition + // makes it to the solver though, ask for a bug report. + _, statErr := os.Stat("example_gen.go") + if statErr == nil || os.Getenv("TRAVIS_GO_VERSION") > "" { + t.Fatal(err) + } else { + t.Log(err) + t.Skip("(Not your problem. " + + "please file issue at https://github.com/exercism/xgo.)") + } + } + return tt +} + +func BenchmarkAddGigasecond(b *testing.B) { + for i := 0; i < b.N; i++ { + AddGigasecond(time.Time{}) + } +} diff --git a/go/grains/README.md b/go/grains/README.md new file mode 100644 index 0000000..ddf87be --- /dev/null +++ b/go/grains/README.md @@ -0,0 +1,41 @@ +# Grains + +Write a program that calculates the number of grains of wheat on a chessboard given that the number on each square doubles. + +There once was a wise servant who saved the life of a prince. The king +promised to pay whatever the servant could dream up. Knowing that the +king loved chess, the servant told the king he would like to have grains +of wheat. One grain on the first square of a chess board. Two grains on +the next. Four on the third, and so on. + +There are 64 squares on a chessboard. + +Write a program that shows: +- how many grains were on each square, and +- the total number of grains + + +## For bonus points + +Did you get the tests passing and the code clean? If you want to, these +are some additional things you could try: + +- Optimize for speed. +- Optimize for readability. + +Then please share your thoughts in a comment on the submission. Did this +experiment make the code better? Worse? Did you learn anything from it? + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +JavaRanch Cattle Drive, exercise 6 [view source](http://www.javaranch.com/grains.jsp) diff --git a/go/grains/grains.go b/go/grains/grains.go new file mode 100644 index 0000000..5e962da --- /dev/null +++ b/go/grains/grains.go @@ -0,0 +1,30 @@ +package grains + +import "errors" + +// Square just takes 1 * 2^sq +func Square(sq int) (uint64, error) { + if sq > 0 && sq < 65 { + return (1 << uint(sq-1)), nil + } + return 0, errors.New("Invalid Square Requested") +} + +// TotalForSquare calculates the total number +// for all squares up to sq (cause why not) +func TotalForSquare(sq int) (uint64, error) { + if sq < 0 || sq > 64 { + return 0, errors.New("Invalid Square Requested") + } + var ret uint64 + for i := 0; i <= sq; i++ { + ret = (ret << 1) | 1 + } + return ret, nil +} + +// Total calculates the total for the entire board +func Total() uint64 { + ret, _ := TotalForSquare(64) + return ret +} diff --git a/go/grains/grains_test.go b/go/grains/grains_test.go new file mode 100644 index 0000000..e37cdab --- /dev/null +++ b/go/grains/grains_test.go @@ -0,0 +1,61 @@ +package grains + +import ( + "testing" +) + +var squareTests = []struct { + input int + expectedVal uint64 + expectError bool +}{ + {1, 1, false}, + {2, 2, false}, + {3, 4, false}, + {4, 8, false}, + {16, 32768, false}, + {32, 2147483648, false}, + {64, 9223372036854775808, false}, + {65, 0, true}, + {0, 0, true}, + {-1, 0, true}, +} + +func TestSquare(t *testing.T) { + for _, test := range squareTests { + actualVal, actualErr := Square(test.input) + if actualVal != test.expectedVal { + t.Errorf("Square(%d) expected %d, Actual %d", test.input, test.expectedVal, actualVal) + } + + // if we expect an error and there isn't one + if test.expectError && actualErr == nil { + t.Errorf("Square(%d) expected an error, but error is nil", test.input) + } + // if we don't expect an error and there is one + if !test.expectError && actualErr != nil { + t.Errorf("Square(%d) expected no error, but error is: %s", test.input, actualErr) + } + } +} + +func TestTotal(t *testing.T) { + var expected uint64 = 18446744073709551615 + if actual := Total(); actual != expected { + t.Errorf("Total() expected %d, Actual %d", expected, actual) + } +} + +func BenchmarkSquare(b *testing.B) { + b.StopTimer() + + for _, test := range squareTests { + b.StartTimer() + + for i := 0; i < b.N; i++ { + Square(test.input) + } + + b.StopTimer() + } +} diff --git a/go/hamming/README.md b/go/hamming/README.md new file mode 100644 index 0000000..b7cf731 --- /dev/null +++ b/go/hamming/README.md @@ -0,0 +1,50 @@ +# Hamming + +Write a program that can calculate the Hamming difference between two DNA strands. + +A mutation is simply a mistake that occurs during the creation or +copying of a nucleic acid, in particular DNA. Because nucleic acids are +vital to cellular functions, mutations tend to cause a ripple effect +throughout the cell. Although mutations are technically mistakes, a very +rare mutation may equip the cell with a beneficial attribute. In fact, +the macro effects of evolution are attributable by the accumulated +result of beneficial microscopic mutations over many generations. + +The simplest and most common type of nucleic acid mutation is a point +mutation, which replaces one base with another at a single nucleotide. + +By counting the number of differences between two homologous DNA strands +taken from different genomes with a common ancestor, we get a measure of +the minimum number of point mutations that could have occurred on the +evolutionary path between the two strands. + +This is called the 'Hamming distance'. + +It is found by comparing two DNA strands and counting how many of the +nucleotides are different from their equivalent in the other string. + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +The Hamming distance between these two DNA strands is 7. + +# Implementation notes + +The Hamming distance is only defined for sequences of equal length. This means +that based on the definition, each language could deal with getting sequences +of equal length differently. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +The Calculating Point Mutations problem at Rosalind [view source](http://rosalind.info/problems/hamm/) diff --git a/go/hamming/cases_test.go b/go/hamming/cases_test.go new file mode 100644 index 0000000..fc808b5 --- /dev/null +++ b/go/hamming/cases_test.go @@ -0,0 +1,81 @@ +package hamming + +// Source: exercism/x-common +// Commit: c84e435 Merge pull request #51 from soniakeys/master + +var testCases = []struct { + s1 string + s2 string + want int +}{ + { // identical strands + "A", + "A", + 0, + }, + { // long identical strands + "GGACTGA", + "GGACTGA", + 0, + }, + { // complete distance in single nucleotide strands + "A", + "G", + 1, + }, + { // complete distance in small strands + "AG", + "CT", + 2, + }, + { // small distance in small strands + "AT", + "CT", + 1, + }, + { // small distance + "GGACG", + "GGTCG", + 1, + }, + { // small distance in long strands + "ACCAGGG", + "ACTATGG", + 2, + }, + { // non-unique character in first strand + "AGA", + "AGG", + 1, + }, + { // non-unique character in second strand + "AGG", + "AGA", + 1, + }, + { // large distance + "GATACA", + "GCATAA", + 4, + }, + { // large distance in off-by-one strand + "GGACGGATTCTG", + "AGGACGGATTCT", + 9, + }, + { // empty strands + "", + "", + 0, + }, + { // disallow first strand longer + "AATG", + "AAA", + -1, + }, + { // disallow second strand longer + "ATA", + "AGTG", + -1, + }, +} diff --git a/go/hamming/hamming.go b/go/hamming/hamming.go new file mode 100644 index 0000000..a7c9107 --- /dev/null +++ b/go/hamming/hamming.go @@ -0,0 +1,21 @@ +package hamming + +import "errors" + +// TestVersion is an exercism thing +const TestVersion = 2 + +// Distance measures the hamming distance between two sequences +// and returns the number if different bytes and an error value +func Distance(seq1, seq2 string) (int, error) { + if len(seq1) != len(seq2) { + return -1, errors.New("Strands must be equal length") + } + var ret int + for i := 0; i < len(seq1); i++ { + if seq1[i] != seq2[i] { + ret++ + } + } + return ret, nil +} diff --git a/go/hamming/hamming_test.go b/go/hamming/hamming_test.go new file mode 100644 index 0000000..b69ae35 --- /dev/null +++ b/go/hamming/hamming_test.go @@ -0,0 +1,39 @@ +package hamming + +import "testing" + +const testVersion = 2 + +// Retired testVersions +// (none) df178dc24b57f7d4ccf54d47430192749d56898f +// 1 4f6fe21682f7f2a7845683cb26ff557208153ffe + +func TestHamming(t *testing.T) { + if TestVersion != testVersion { + t.Errorf("Found TestVersion = %v, want %v.", TestVersion, testVersion) + } + for _, tc := range testCases { + switch got, err := Distance(tc.s1, tc.s2); { + case err != nil: + if tc.want >= 0 { + t.Fatalf("Distance(%q, %q) returned error: %v", + tc.s1, tc.s2, err) + } + case tc.want < 0: + t.Fatalf("Distance(%q, %q) = %d. Expected error.", + tc.s1, tc.s2, got) + case got != tc.want: + t.Fatalf("Distance(%q, %q) = %d, want %d.", + tc.s1, tc.s2, got, tc.want) + } + } +} + +func BenchmarkHamming(b *testing.B) { + // bench combined time to run through all test cases + for i := 0; i < b.N; i++ { + for _, tc := range testCases { + Distance(tc.s1, tc.s2) + } + } +} diff --git a/go/house/README.md b/go/house/README.md new file mode 100644 index 0000000..fefd810 --- /dev/null +++ b/go/house/README.md @@ -0,0 +1,121 @@ +# House + +Write a program that outputs the nursery rhyme 'This is the House that Jack Built'. + +> [The] process of placing a phrase of clause within another phrase of +> clause is called embedding. It is through the processes of recursion +> and embedding that we are able to take a finite number of forms (words +> and phrases) and construct an infinite number of expressions. +> Furthermore, embedding also allows us to construct an infinitely long +> structure, in theory anyway. + +- [papyr.com](http://papyr.com/hypertextbooks/grammar/ph_noun.htm) + + +The nursery rhyme reads as follows: + +```plain +This is the house that Jack built. + +This is the malt +that lay in the house that Jack built. + +This is the rat +that ate the malt +that lay in the house that Jack built. + +This is the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the farmer sowing his corn +that kept the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the horse and the hound and the horn +that belonged to the farmer sowing his corn +that kept the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. +``` + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +British nursery rhyme [view source](http://en.wikipedia.org/wiki/This_Is_The_House_That_Jack_Built) diff --git a/go/house/house.go b/go/house/house.go new file mode 100644 index 0000000..2db8500 --- /dev/null +++ b/go/house/house.go @@ -0,0 +1,50 @@ +package house + +// ASong holds the data we need to generate a song +type ASong struct { + start string + clauses []string + end string +} + +// Embed takes two strings and returns a string with the embedded +func Embed(l, p string) string { + return l + " " + p +} + +// Verse takes three things and returns a verse +func Verse(start string, clause []string, end string) string { + ret := start + " " + for i := 0; i < len(clause); i++ { + ret += clause[i] + " " + } + ret += end + return ret +} + +// Song generates the whole song +func Song() string { + jackSong := ASong{ + start: "This is", + clauses: []string{ + "the horse and the hound and the horn\nthat belonged to", + "the farmer sowing his corn\nthat kept", + "the rooster that crowed in the morn\nthat woke", + "the priest all shaven and shorn\nthat married", + "the man all tattered and torn\nthat kissed", + "the maiden all forlorn\nthat milked", + "the cow with the crumpled horn\nthat tossed", + "the dog\nthat worried", + "the cat\nthat killed", + "the rat\nthat ate", + "the malt\nthat lay in", + }, + end: "the house that Jack built.", + } + var ret string + for i := len(jackSong.clauses); i >= 0; i-- { + ret += Verse(jackSong.start, jackSong.clauses[i:], jackSong.end) + "\n\n" + } + // Trim the trailing "\n\n" + return ret[:len(ret)-2] +} diff --git a/go/house/house_test.go b/go/house/house_test.go new file mode 100644 index 0000000..1b67195 --- /dev/null +++ b/go/house/house_test.go @@ -0,0 +1,171 @@ +// Embed embeds a noun phrase as the object of relative clause with a +// transitive verb. +// +// Argument relPhrase is a phrase with a relative clause, minus the object +// of the clause. That is, relPhrase consists of a subject, a relative +// pronoun, a transitive verb, possibly a preposition, but then no object. +// +// func Embed(relPhrase, nounPhrase string) string + +// Verse generates a verse of a song with relative clauses that have +// a recursive structure. +// +// func Verse(subject string, relPhrases []string, nounPhrase string) string +// +// There are different ways to do this of course, but try using Embed as a +// subroutine and using programmatic recursion that reflects the grammatical +// recursion. + +// Song generates the full text of "The House That Jack Built". Oh yes, you +// could just return a string literal, but humor us; use Verse as a subroutine. +// +// func Song() string + +package house + +import ( + "fmt" + "strings" + "testing" +) + +var ( + s = "This is" + r = []string{ + "the cat that broke", + "the vase that was on", + } + p = "the shelf." + last = len(r) - 1 + // song copied from readme + song = `This is the house that Jack built. + +This is the malt +that lay in the house that Jack built. + +This is the rat +that ate the malt +that lay in the house that Jack built. + +This is the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the farmer sowing his corn +that kept the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built. + +This is the horse and the hound and the horn +that belonged to the farmer sowing his corn +that kept the rooster that crowed in the morn +that woke the priest all shaven and shorn +that married the man all tattered and torn +that kissed the maiden all forlorn +that milked the cow with the crumpled horn +that tossed the dog +that worried the cat +that killed the rat +that ate the malt +that lay in the house that Jack built.` +) + +func TestEmbed(t *testing.T) { + l := r[last] + want := l + " " + p + if e := Embed(l, p); e != want { + t.Fatalf("Embed(%q, %q) = %q, want %q.", l, p, e, want) + } +} + +func TestVerse(t *testing.T) { + for i := len(r); i >= 0; i-- { + ri := r[i:] + want := s + " " + strings.Join(append(ri, p), " ") + if v := Verse(s, ri, p); v != want { + t.Fatalf("Verse(%q, %q, %q) = %q, want %q.", s, ri, p, v, want) + } + } +} + +func TestSong(t *testing.T) { + s := Song() + if s == song { + return + } + fmt.Print(s) + // a little help in locating an error + got := strings.Split(s, "\n") + want := strings.Split(song, "\n") + var g, w string + var i int + for i, w = range want { + if len(got) <= i { + g = "" + break + } + if g = got[i]; g != w { + break + } + } + t.Fatalf("Song() line %d = %q, want %q", i+1, g, w) +} diff --git a/go/largest-series-product/README.md b/go/largest-series-product/README.md new file mode 100644 index 0000000..8a6ad7b --- /dev/null +++ b/go/largest-series-product/README.md @@ -0,0 +1,24 @@ +# Largest Series Product + +Write a program that, when given a string of digits, can calculate the largest product for a series of consecutive digits of length n. + +For example, for the input `'0123456789'`, the largest product for a +series of 3 digits is 504 (7 * 8 * 9), and the largest product for a +series of 5 digits is 15120 (5 * 6 * 7 * 8 * 9). + +For the input `'73167176531330624919225119674426574742355349194934'`, +the largest product for a series of 6 digits is 23520. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +A variation on Problem 8 at Project Euler [view source](http://projecteuler.net/problem=8) diff --git a/go/largest-series-product/cases_test.go b/go/largest-series-product/cases_test.go new file mode 100644 index 0000000..ad71012 --- /dev/null +++ b/go/largest-series-product/cases_test.go @@ -0,0 +1,29 @@ +package lsproduct + +// Source: exercism/x-common +// Commit: 3764abd Merge pull request #167 from petertseng/largest-series-product-json + +var tests = []struct { + digits string + span int + product int64 + ok bool +}{ + {"0123456789", 2, 72, true}, + {"576802143", 2, 48, true}, + {"29", 2, 18, true}, + {"0123456789", 3, 504, true}, + {"1027839564", 3, 270, true}, + {"0123456789", 5, 15120, true}, + {"73167176531330624919225119674426574742355349194934", 6, 23520, true}, + {"52677741234314237566414902593461595376319419139427", 6, 28350, true}, + {"7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450", 13, 23514624000, true}, + {"0000", 2, 0, true}, + {"99099", 3, 0, true}, + {"123", 4, -1, false}, + {"", 0, 1, true}, + {"123", 0, 1, true}, + {"", 1, -1, false}, + {"1234a5", 2, -1, false}, + {"12345", -1, -1, false}, +} diff --git a/go/largest-series-product/largest_series_product.go b/go/largest-series-product/largest_series_product.go new file mode 100644 index 0000000..50f8ba7 --- /dev/null +++ b/go/largest-series-product/largest_series_product.go @@ -0,0 +1,45 @@ +package lsproduct + +import "fmt" + +// TestVersion defines version testing. +const TestVersion = 1 + +// LargestSeriesProduct Takes an input string of digits +// and a length for the series. It returns the largest +// series product from that string of that length. +func LargestSeriesProduct(input string, size int) (int, error) { + if size == 0 { + return 1, nil + } else if size > len(input) { + return 0, fmt.Errorf("Invalid Span Size") + } + var high int + for i := 0; i < (len(input) - size + 1); i++ { + try := GetProduct(input[i : i+size]) + if try < 0 { + return 0, fmt.Errorf("Invalid input") + } + if try > high { + high = try + } + } + return high, nil +} + +// GetProduct takes a string of numbers, splits it up +// and returns the product of them +func GetProduct(input string) int { + if len(input) > 0 { + total := 1 + for i := range input { + next := input[i] - 48 + if next < 0 || next > 9 { + return -1 + } + total = total * int(next) + } + return total + } + return 0 +} diff --git a/go/largest-series-product/largest_series_product_test.go b/go/largest-series-product/largest_series_product_test.go new file mode 100644 index 0000000..32c4c40 --- /dev/null +++ b/go/largest-series-product/largest_series_product_test.go @@ -0,0 +1,92 @@ +package lsproduct + +import "testing" + +const testVersion = 1 + +// Retired testVersions +// (none) ba7a22a355a32901caf46529c799fa53118ded0a + +var tests = []struct { + digits string + span int + product int64 + ok bool +}{ + {"0123456789", + 2, 72, true}, + {"12", + 2, 2, true}, + {"19", + 2, 9, true}, + {"576802143", + 2, 48, true}, + {"0123456789", + 3, 504, true}, + {"1027839564", + 3, 270, true}, + {"0123456789", + 5, 15120, true}, + {"73167176531330624919225119674426574742355349194934", + 6, 23520, true}, + {"52677741234314237566414902593461595376319419139427", + 6, 28350, true}, + {"", + 0, 1, true}, + {"123", + 4, 0, false}, + {pe1k, 5, 40824, true}, // original PE problem + {pe1k, 13, 23514624000, true}, // new PE problem +} + +const pe1k = "73167176531330624919225119674426574742355349194934" + + "96983520312774506326239578318016984801869478851843" + + "85861560789112949495459501737958331952853208805511" + + "12540698747158523863050715693290963295227443043557" + + "66896648950445244523161731856403098711121722383113" + + "62229893423380308135336276614282806444486645238749" + + "30358907296290491560440772390713810515859307960866" + + "70172427121883998797908792274921901699720888093776" + + "65727333001053367881220235421809751254540594752243" + + "52584907711670556013604839586446706324415722155397" + + "53697817977846174064955149290862569321978468622482" + + "83972241375657056057490261407972968652414535100474" + + "82166370484403199890008895243450658541227588666881" + + "16427171479924442928230863465674813919123162824586" + + "17866458359124566529476545682848912883142607690042" + + "24219022671055626321111109370544217506941658960408" + + "07198403850962455444362981230987879927244284909188" + + "84580156166097919133875499200524063689912560717606" + + "05886116467109405077541002256983155200055935729725" + + "71636269561882670428252483600823257530420752963450" + +func TestLargestSeriesProduct(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + for _, test := range tests { + p, err := LargestSeriesProduct(test.digits, test.span) + switch { + case err != nil: + if test.ok { + t.Fatalf("LargestSeriesProduct(%s, %d) returned error %q. "+ + "Error not expected.", + test.digits, test.span, err) + } + case !test.ok: + t.Fatalf("LargestSeriesProduct(%s, %d) = %d, %v. Expected error", + test.digits, test.span, p, err) + case int64(p) != test.product: + t.Fatalf("LargestSeriesProduct(%s, %d) = %d, want %d", + test.digits, test.span, p, test.product) + } + } +} + +func BenchmarkLargestSeriesProduct(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range tests { + LargestSeriesProduct(test.digits, test.span) + } + } +} diff --git a/go/leap/README.md b/go/leap/README.md new file mode 100644 index 0000000..fbb101f --- /dev/null +++ b/go/leap/README.md @@ -0,0 +1,38 @@ +# Leap + +Write a program that will take a year and report if it is a leap year. + +The tricky thing here is that a leap year occurs: + +```plain +on every year that is evenly divisible by 4 + except every year that is evenly divisible by 100 + unless the year is also evenly divisible by 400 +``` + +For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap +year, but 2000 is. + +If your language provides a method in the standard library that does +this look-up, pretend it doesn't exist and implement it yourself. + +## Notes + +For a delightful, four minute explanation of the whole leap year +phenomenon, go watch [this youtube video][video]. + +[video]: http://www.youtube.com/watch?v=xX96xng7sAE + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +JavaRanch Cattle Drive, exercise 3 [view source](http://www.javaranch.com/leap.jsp) diff --git a/go/leap/cases_test.go b/go/leap/cases_test.go new file mode 100644 index 0000000..d1af40f --- /dev/null +++ b/go/leap/cases_test.go @@ -0,0 +1,17 @@ +package leap + +// Source: exercism/x-common +// Commit: 945d08e Merge pull request #50 from soniakeys/master + +var testCases = []struct { + year int + expected bool + description string +}{ + {1996, true, "leap year"}, + {1997, false, "non-leap year"}, + {1998, false, "non-leap even year"}, + {1900, false, "century"}, + {2400, true, "fourth century"}, + {2000, true, "Y2K"}, +} diff --git a/go/leap/leap.go b/go/leap/leap.go new file mode 100644 index 0000000..d7e3a4e --- /dev/null +++ b/go/leap/leap.go @@ -0,0 +1,15 @@ +package leap + +// TestVersion is an exercism thing. +const TestVersion = 1 + +// IsLeapYear returns whether the given year is a leap year. +func IsLeapYear(year int) bool { + if year%4 != 0 { + return false + } + if year%400 == 0 { + return true + } + return year%100 != 0 +} diff --git a/go/leap/leap_test.go b/go/leap/leap_test.go new file mode 100644 index 0000000..6789d88 --- /dev/null +++ b/go/leap/leap_test.go @@ -0,0 +1,34 @@ +package leap + +import "testing" + +// Define a function IsLeapYear(int) bool. +// +// Also define an exported TestVersion with a value that matches +// the internal testVersion here. + +const testVersion = 1 + +// Retired testVersions +// (none) 4a9e144a3c5dc0d9773f4cf641ffe3efe48641d8 + +func TestLeapYears(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + for _, test := range testCases { + observed := IsLeapYear(test.year) + if observed != test.expected { + t.Fatalf("IsLeapYear(%d) = %t, want %t (%s)", + test.year, observed, test.expected, test.description) + } + } +} + +func BenchmarkLeapYears(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range testCases { + IsLeapYear(test.year) + } + } +} diff --git a/go/luhn/README.md b/go/luhn/README.md new file mode 100644 index 0000000..afbfe24 --- /dev/null +++ b/go/luhn/README.md @@ -0,0 +1,71 @@ +# Luhn + +Write a program that can take a number and determine whether or not it is valid per the Luhn formula. + +The Luhn formula is a simple checksum formula used to validate a variety +of identification numbers, such as credit card numbers and Canadian +Social Insurance Numbers. + +The formula verifies a number against its included check digit, which is +usually appended to a partial number to generate the full number. This +number must pass the following test: + +- Counting from rightmost digit (which is the check digit) and moving + left, double the value of every second digit. +- For any digits that thus become 10 or more, subtract 9 from the + result. + - 1111 becomes 2121. + - 8763 becomes 7733 (from 2×6=12 → 12-9=3 and 2×8=16 → 16-9=7). +- Add all these digits together. + - 1111 becomes 2121 sums as 2+1+2+1 to give a check digit of 6. + - 8763 becomes 7733, and 7+7+3+3 is 20. + +If the total ends in 0 (put another way, if the total modulus 10 is +congruent to 0), then the number is valid according to the Luhn formula; +else it is not valid. So, 1111 is not valid (as shown above, it comes +out to 6), while 8763 is valid (as shown above, it comes out to 20). + +Write a program that, given a number + +- Can check if it is valid per the Luhn formula. This should treat, for + example, "2323 2005 7766 3554" as valid. +- Can return the checksum, or the remainder from using the Luhn method. +- Can add a check digit to make the number valid per the Luhn formula and + return the original number plus that digit. This should give "2323 2005 7766 + 3554" in response to "2323 2005 7766 355". + +## About Checksums + +A checksum has to do with error-detection. There are a number of different +ways in which a checksum could be calculated. + +When transmitting data, you might also send along a checksum that says how +many bytes of data are being sent. That means that when the data arrives on +the other side, you can count the bytes and compare it to the checksum. If +these are different, then the data has been garbled in transmission. + +In the Luhn problem the final digit acts as a sanity check for all the prior +digits. Running those prior digits through a particular algorithm should give +you that final digit. + +It doesn't actually tell you if it's a real credit card number, only that it's +a plausible one. It's the same thing with the bytes that get transmitted -- +you could have the right number of bytes and still have a garbled message. So +checksums are a simple sanity-check, not a real in-depth verification of the +authenticity of some data. It's often a cheap first pass, and can be used to +quickly discard obviously invalid things. + + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +The Luhn Algorithm on Wikipedia [view source](http://en.wikipedia.org/wiki/Luhn_algorithm) diff --git a/go/luhn/luhn.go b/go/luhn/luhn.go new file mode 100644 index 0000000..bd140d8 --- /dev/null +++ b/go/luhn/luhn.go @@ -0,0 +1,58 @@ +package luhn + +import ( + "fmt" + "regexp" + "strconv" +) + +// Valid takes a numeric string and returns whether +// it's Luhn valid. +func Valid(toCheck string) bool { + return GetRemainder(toCheck) == 0 +} + +// GetRemainder returns the leftover from +// running a number through the Luhn checker +func GetRemainder(toCheck string) int { + // Remove any non-numeric characters + r := regexp.MustCompile("[^0-9]+") + toCheck = r.ReplaceAllString(toCheck, "") + + if len(toCheck) == 0 { + return -1 + } + var total int + var double bool + for i := range toCheck { + var add int + var err error + idx := (len(toCheck) - 1) - i + if add, err = strconv.Atoi(string(toCheck[idx])); err != nil { + return -1 + } + if double { + add = add * 2 + if add >= 10 { + add = add - 9 + } + } + double = !double + total += add + } + return total % 10 +} + +// AddCheck takes a number and returns the appropriate +// number with an added digit that makes it valid +func AddCheck(toCheck string) string { + if GetRemainder(toCheck) != 0 { + for i := 0; i <= 9; i++ { + tst := fmt.Sprintf("%s%d", toCheck, i) + if GetRemainder(tst) == 0 { + return tst + } + } + } + return toCheck +} diff --git a/go/luhn/luhn_test.go b/go/luhn/luhn_test.go new file mode 100644 index 0000000..db7fc4a --- /dev/null +++ b/go/luhn/luhn_test.go @@ -0,0 +1,54 @@ +package luhn + +import "testing" + +var validTests = []struct { + n string + ok bool +}{ + {"738", false}, + {"8739567", true}, + {"1111", false}, + {"8763", true}, + {" ", false}, + {"", false}, + {"2323 2005 7766 3554", true}, +} + +var addTests = []struct{ raw, luhn string }{ + {"123", "1230"}, + {"873956", "8739567"}, + {"837263756", "8372637564"}, + {"2323 2005 7766 355", "2323 2005 7766 3554"}, + // bonus Unicode cases + // {"2323·2005·7766·355", "2323·2005·7766·3554"}, + // {"123", "1230"}, +} + +func TestValid(t *testing.T) { + for _, test := range validTests { + if ok := Valid(test.n); ok != test.ok { + t.Fatalf("Valid(%s) = %t, want %t.", test.n, ok, test.ok) + } + } +} + +func TestAddCheck(t *testing.T) { + for _, test := range addTests { + if luhn := AddCheck(test.raw); luhn != test.luhn { + t.Fatalf("AddCheck(%s) = %s, want %s.", test.raw, luhn, test.luhn) + } + } +} + +func BenchmarkValid(b *testing.B) { + for i := 0; i < b.N; i++ { + Valid("2323 2005 7766 3554") + } +} + +func BenchmarkAddCheck(b *testing.B) { + for i := 0; i < b.N; i++ { + AddCheck("2323 2005 7766 355") + } +} diff --git a/go/palindrome-products/README.md b/go/palindrome-products/README.md new file mode 100644 index 0000000..78001fd --- /dev/null +++ b/go/palindrome-products/README.md @@ -0,0 +1,20 @@ +# Palindrome Products + +Write a program that can detect palindrome products in a given range. + +A palindromic number reads the same both ways. The largest palindrome +made from the product of two 2-digit numbers is 9009 = 91 x 99. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Problem 4 at Project Euler [view source](http://projecteuler.net/problem=4) diff --git a/go/palindrome-products/palindrome/palindrome_products.go b/go/palindrome-products/palindrome/palindrome_products.go new file mode 100644 index 0000000..ba69e76 --- /dev/null +++ b/go/palindrome-products/palindrome/palindrome_products.go @@ -0,0 +1,91 @@ +package palindrome + +import ( + "fmt" + "strconv" +) + +// Product is a palindromic product and all of its +// factorizations +type Product struct { + Product int + Factorizations [][2]int +} + +func createProduct(fac1, fac2 int) *Product { + p := Product{Product: (fac1 * fac2)} + p.addFactors(fac1, fac2) + return &p +} + +func (p *Product) hasFactors(fac1, fac2 int) bool { + for i := 0; i < len(p.Factorizations); i++ { + if p.Factorizations[i][0] == fac1 && p.Factorizations[i][1] == fac2 { + return true + } + if p.Factorizations[i][1] == fac1 && p.Factorizations[i][0] == fac2 { + return true + } + } + return false +} + +func (p *Product) addFactors(fac1, fac2 int) { + if (fac1 * fac2) == p.Product { + if !p.hasFactors(fac1, fac2) { + p.Factorizations = append(p.Factorizations, [2]int{fac1, fac2}) + } + } +} + +// Products takes a min and a max and finds +func Products(fmin, fmax int) (Product, Product, error) { + if fmin > fmax { + return Product{}, Product{}, fmt.Errorf("fmin > fmax") + } + var pMin, pMax Product + var err error + var allProducts []Product + + for i := fmin; i <= fmax; i++ { + for j := fmin; j <= fmax; j++ { + if isPalindrome(strconv.Itoa(i * j)) { + var found bool + for k := 0; k < len(allProducts); k++ { + if allProducts[k].Product == (i * j) { + allProducts[k].addFactors(i, j) + found = true + break + } + } + if !found { + allProducts = append(allProducts, *createProduct(i, j)) + } + } + } + } + for i := range allProducts { + if allProducts[i].Product > pMax.Product { + // is the old pMax the new pMin? + if len(pMin.Factorizations) == 0 { + pMin = pMax + } + pMax = allProducts[i] + } else { + if allProducts[i].Product < pMin.Product { + pMin = allProducts[i] + } + } + } + fmt.Println(allProducts) + return pMin, pMax, err +} + +func isPalindrome(s string) bool { + for i := 0; i < (len(s) / 2); i++ { + if s[i] != s[len(s)-1-i] { + return false + } + } + return true +} diff --git a/go/palindrome-products/palindrome_products.go b/go/palindrome-products/palindrome_products.go new file mode 100644 index 0000000..3021394 --- /dev/null +++ b/go/palindrome-products/palindrome_products.go @@ -0,0 +1,92 @@ +package palindrome + +import ( + "fmt" + "strconv" +) + +// Product is a palindromic product and all of its +// factorizations +type Product struct { + Product int + Factorizations [][2]int +} + +func createProduct(fac1, fac2 int) *Product { + p := Product{Product: (fac1 * fac2)} + p.addFactors(fac1, fac2) + return &p +} + +func (p *Product) hasFactors(fac1, fac2 int) bool { + for i := 0; i < len(p.Factorizations); i++ { + if p.Factorizations[i][0] == fac1 && p.Factorizations[i][1] == fac2 { + return true + } + if p.Factorizations[i][1] == fac1 && p.Factorizations[i][0] == fac2 { + return true + } + } + return false +} + +func (p *Product) addFactors(fac1, fac2 int) { + if (fac1 * fac2) == p.Product { + if !p.hasFactors(fac1, fac2) { + p.Factorizations = append(p.Factorizations, [2]int{fac1, fac2}) + } + } +} + +// Products takes a min and a max and finds +func Products(fmin, fmax int) (Product, Product, error) { + if fmin > fmax { + return Product{}, Product{}, fmt.Errorf("fmin > fmax") + } + var pMin, pMax Product + var allProducts []Product + + for i := fmin; i <= fmax; i++ { + for j := fmin; j <= fmax; j++ { + if isPalindrome(strconv.Itoa(i * j)) { + var found bool + for k := 0; k < len(allProducts); k++ { + if allProducts[k].Product == (i * j) { + allProducts[k].addFactors(i, j) + found = true + break + } + } + if !found { + allProducts = append(allProducts, *createProduct(i, j)) + } + } + } + } + for i := range allProducts { + if allProducts[i].Product > pMax.Product { + // is the old pMax the new pMin? + if len(pMin.Factorizations) == 0 { + pMin = pMax + } + pMax = allProducts[i] + } else { + if allProducts[i].Product < pMin.Product { + pMin = allProducts[i] + } + } + } + if len(allProducts) == 0 { + return pMin, pMax, fmt.Errorf("No palindromes") + } + return pMin, pMax, nil +} + +func isPalindrome(s string) bool { + for i := 0; i < (len(s) / 2); i++ { + if s[i] != s[len(s)-1-i] { + return false + } + } + return true +} diff --git a/go/palindrome-products/palindrome_products_test.go b/go/palindrome-products/palindrome_products_test.go new file mode 100644 index 0000000..49b70ca --- /dev/null +++ b/go/palindrome-products/palindrome_products_test.go @@ -0,0 +1,98 @@ +package palindrome + +import ( + "fmt" + "reflect" + "strings" + "testing" +) + +// API to impliment: +// type Product struct { +// Product int // palindromic, of course +// // list of all possible two-factor factorizations of Product, within +// // given limits, in order +// Factorizations [][2]int +// } +// func Products(fmin, fmax int) (pmin, pmax Product, error) + +var testData = []struct { + // input to Products(): range limits for factors of the palindrome + fmin, fmax int + // output from Products(): + pmin, pmax Product // min and max palandromic products + errPrefix string // start of text if there is an error, "" otherwise +}{ + {1, 9, + Product{}, // zero value means don't bother to test it + Product{9, [][2]int{{1, 9}, {3, 3}}}, + ""}, + {10, 99, + Product{121, [][2]int{{11, 11}}}, + Product{9009, [][2]int{{91, 99}}}, + ""}, + {100, 999, + Product{10201, [][2]int{{101, 101}}}, + Product{906609, [][2]int{{913, 993}}}, + ""}, + {4, 10, Product{}, Product{}, "No palindromes"}, + {10, 4, Product{}, Product{}, "fmin > fmax"}, + /* bonus curiosities. (can a negative number be a palindrome? + // most say no + {-99, -10, Product{}, Product{}, "Negative limits"}, + // but you can still get non-negative products from negative factors. + {-99, -10, + Product{121, [][2]int{{-11, -11}}}, + Product{9009, [][2]int{{-99, -91}}}, + ""}, + {-2, 2, + Product{0, [][2]int{{-2, 0}, {-1, 0}, {0, 0}, {0, 1}, {0, 2}}}, + Product{4, [][2]int{{-2, -2}, {2, 2}}}, + ""}, + // or you could reverse the *digits*, keeping the minus sign in place. + {-2, 2, + Product{-4, [][2]int{{-2, 2}}}, + Product{4, [][2]int{{-2, -2}, {2, 2}}}, + ""}, + { + {0, (^uint(0))>>1, Product{}, Product{}, "This one's gonna overflow"}, + */ +} + +func TestPalindromeProducts(t *testing.T) { + for _, test := range testData { + // common preamble for test failures + ret := fmt.Sprintf("Products(%d, %d) returned", + test.fmin, test.fmax) + // test + pmin, pmax, err := Products(test.fmin, test.fmax) + switch { + case err == nil: + if test.errPrefix > "" { + t.Fatalf(ret+" err = nil, want %q", test.errPrefix+"...") + } + case test.errPrefix == "": + t.Fatalf(ret+" err = %q, want nil", err) + case !strings.HasPrefix(err.Error(), test.errPrefix): + t.Fatalf(ret+" err = %q, want %q", err, test.errPrefix+"...") + default: + continue // correct error, no further tests for this test case + } + matchProd := func(ww string, rp, wp Product) { + if len(wp.Factorizations) > 0 && // option to skip test + !reflect.DeepEqual(rp, wp) { + t.Fatal(ret, ww, "=", rp, "want", wp) + } + } + matchProd("pmin", pmin, test.pmin) + matchProd("pmax", pmax, test.pmax) + } +} + +func BenchmarkPalindromeProducts(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range testData { + Products(test.fmin, test.fmax) + } + } +} diff --git a/go/parallel-letter-frequency/README.md b/go/parallel-letter-frequency/README.md new file mode 100644 index 0000000..2eff28f --- /dev/null +++ b/go/parallel-letter-frequency/README.md @@ -0,0 +1,22 @@ +# Parallel Letter Frequency + +Write a program that counts the frequency of letters in texts using parallel computation. + +Parallelism is about doing things in parallel that can also be done +sequentially. A common example is counting the frequency of letters. +Create a function that returns the total frequency of each letter in a +list of texts and that employs parallelism. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + + [view source]() diff --git a/go/parallel-letter-frequency/by_the_letter.go b/go/parallel-letter-frequency/by_the_letter.go new file mode 100644 index 0000000..f91ff1c --- /dev/null +++ b/go/parallel-letter-frequency/by_the_letter.go @@ -0,0 +1,27 @@ +package letter + +import "time" + +// ConcurrentFrequency concurrently calls Frequency +// and returns the final Frequency Map +func ConcurrentFrequency(input []string) FreqMap { + var procCnt = len(input) + var toMerge []FreqMap + for _, chunk := range input { + go func(chunk string) { + toMerge = append(toMerge, Frequency(chunk)) + procCnt-- + }(chunk) + } + for procCnt > 0 { + time.Sleep(time.Millisecond) + } + // We should have all FreqMaps now... merge them + ret := make(map[rune]int) + for _, aResult := range toMerge { + for k, v := range aResult { + ret[k] += v + } + } + return ret +} diff --git a/go/parallel-letter-frequency/frequency.go b/go/parallel-letter-frequency/frequency.go new file mode 100644 index 0000000..0ea7cb2 --- /dev/null +++ b/go/parallel-letter-frequency/frequency.go @@ -0,0 +1,11 @@ +package letter + +type FreqMap map[rune]int + +func Frequency(s string) FreqMap { + m := FreqMap{} + for _, r := range s { + m[r]++ + } + return m +} diff --git a/go/parallel-letter-frequency/letter.go b/go/parallel-letter-frequency/letter.go new file mode 100644 index 0000000..e804f25 --- /dev/null +++ b/go/parallel-letter-frequency/letter.go @@ -0,0 +1,30 @@ +package letter + +import ( + "sync" + "time" +) + +// MyConcurrentFrequency ... +func MyConcurrentFrequency(input []string) FreqMap { + var ProcMap = struct { + sync.RWMutex + m map[rune]int + }{m: make(map[rune]int)} + + var procCnt = len(input) + for _, chunk := range input { + go func(chunk string) { + for _, rn := range chunk { + ProcMap.Lock() + ProcMap.m[rn]++ + ProcMap.Unlock() + } + procCnt-- + }(chunk) + } + for procCnt > 0 { + time.Sleep(time.Millisecond) + } + return ProcMap.m +} diff --git a/go/parallel-letter-frequency/parallel_letter_frequency_test.go b/go/parallel-letter-frequency/parallel_letter_frequency_test.go new file mode 100644 index 0000000..4a1354c --- /dev/null +++ b/go/parallel-letter-frequency/parallel_letter_frequency_test.go @@ -0,0 +1,72 @@ +package letter + +import ( + "reflect" + "testing" +) + +// In the separate file frequency.go, you are given a function, Frequency(), +// to sequentially count letter frequencies in a single text. +// Perform this exercise on parallelism using Go concurrency features. +// Make concurrent calls to Frequency and combine results to obtain the answer. + +func TestConcurrentFrequency(t *testing.T) { + seq := Frequency(euro + dutch + us) + con := ConcurrentFrequency([]string{euro, dutch, us}) + if !reflect.DeepEqual(con, seq) { + t.Fatal("ConcurrentFrequency wrong result") + } +} + +var ( + euro = `Freude schöner Götterfunken +Tochter aus Elysium, +Wir betreten feuertrunken, +Himmlische, dein Heiligtum! +Deine Zauber binden wieder +Was die Mode streng geteilt; +Alle Menschen werden Brüder, +Wo dein sanfter Flügel weilt.` + dutch = `Wilhelmus van Nassouwe +ben ik, van Duitsen bloed, +den vaderland getrouwe +blijf ik tot in den dood. +Een Prinse van Oranje +ben ik, vrij, onverveerd, +den Koning van Hispanje +heb ik altijd geëerd.` + us = `O say can you see by the dawn's early light, +What so proudly we hailed at the twilight's last gleaming, +Whose broad stripes and bright stars through the perilous fight, +O'er the ramparts we watched, were so gallantly streaming? +And the rockets' red glare, the bombs bursting in air, +Gave proof through the night that our flag was still there; +O say does that star-spangled banner yet wave, +O'er the land of the free and the home of the brave?` +) + +func BenchmarkConcurrentFrequency(b *testing.B) { + b.StopTimer() + var bTest []string + for i := 0; i < 5; i++ { + bTest = append(bTest, euro) + bTest = append(bTest, dutch) + bTest = append(bTest, us) + } + b.StartTimer() + ConcurrentFrequency(bTest) + b.StopTimer() +} + +func BenchmarkMyConcurrentFrequency(b *testing.B) { + b.StopTimer() + var bTest []string + for i := 0; i < 5; i++ { + bTest = append(bTest, euro) + bTest = append(bTest, dutch) + bTest = append(bTest, us) + } + b.StartTimer() + MyConcurrentFrequency(bTest) + b.StopTimer() +} diff --git a/go/pascals-triangle/README.md b/go/pascals-triangle/README.md new file mode 100644 index 0000000..c598965 --- /dev/null +++ b/go/pascals-triangle/README.md @@ -0,0 +1,29 @@ +# Pascals Triangle + +Write a program that computes Pascal's triangle up to a given number of rows. + +In Pascal's Triangle each number is computed by adding the numbers to +the right and left of the current position in the previous row. + +```plain + 1 + 1 1 + 1 2 1 + 1 3 3 1 +1 4 6 4 1 +# ... etc +``` + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Pascal's Triangle at Wolfram Math World [view source](http://mathworld.wolfram.com/PascalsTriangle.html) diff --git a/go/pascals-triangle/pascal.go b/go/pascals-triangle/pascal.go new file mode 100644 index 0000000..eb9412c --- /dev/null +++ b/go/pascals-triangle/pascal.go @@ -0,0 +1,26 @@ +package pascal + +// Triangle returns pascals triangle up to depth +func Triangle(depth int) [][]int { + var ret [][]int + for currDepth := 0; currDepth < depth; currDepth++ { + var newRow, prevRow []int + // Each row is currDepth+1 long + rowLength := currDepth + 1 + // Rows start with a 1 + newRow = append(newRow, 1) + if currDepth > 0 { + prevRow = ret[currDepth-1] + } + for i := 1; i < rowLength; i++ { + if i == rowLength-1 { + // Rows end with a 1 also + newRow = append(newRow, 1) + break + } + newRow = append(newRow, prevRow[i-1]+prevRow[i]) + } + ret = append(ret, newRow) + } + return ret +} diff --git a/go/pascals-triangle/pascal_printer b/go/pascals-triangle/pascal_printer new file mode 100755 index 0000000..2f9a28e Binary files /dev/null and b/go/pascals-triangle/pascal_printer differ diff --git a/go/pascals-triangle/pascal_printer.go b/go/pascals-triangle/pascal_printer.go new file mode 100644 index 0000000..9d7596e --- /dev/null +++ b/go/pascals-triangle/pascal_printer.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "os" + "strconv" + + "gogs.bullercodeworks.com/brian/pascal" +) + +func main() { + if len(os.Args) == 2 { + if num, err := strconv.Atoi(os.Args[1]); err == nil { + ret := pascal.Triangle(num) + for i := range ret { + fmt.Println(ret[i]) + } + return + } + } + fmt.Println("Usage: ./pascal_printer ") +} \ No newline at end of file diff --git a/go/pascals-triangle/pascals_triangle_test.go b/go/pascals-triangle/pascals_triangle_test.go new file mode 100644 index 0000000..955c7af --- /dev/null +++ b/go/pascals-triangle/pascals_triangle_test.go @@ -0,0 +1,49 @@ +package pascal + +import ( + "fmt" + "reflect" + "testing" +) + +var t20 = [][]int{ + {1}, + {1, 1}, + {1, 2, 1}, + {1, 3, 3, 1}, + {1, 4, 6, 4, 1}, + {1, 5, 10, 10, 5, 1}, + {1, 6, 15, 20, 15, 6, 1}, + {1, 7, 21, 35, 35, 21, 7, 1}, + {1, 8, 28, 56, 70, 56, 28, 8, 1}, + {1, 9, 36, 84, 126, 126, 84, 36, 9, 1}, + {1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1}, + {1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1}, + {1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1}, + {1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1}, + {1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1}, + {1, 15, 105, 455, 1365, 3003, 5005, 6435, 6435, 5005, 3003, 1365, 455, 105, 15, 1}, + {1, 16, 120, 560, 1820, 4368, 8008, 11440, 12870, 11440, 8008, 4368, 1820, 560, 120, 16, 1}, + {1, 17, 136, 680, 2380, 6188, 12376, 19448, 24310, 24310, 19448, 12376, 6188, 2380, 680, 136, 17, 1}, + {1, 18, 153, 816, 3060, 8568, 18564, 31824, 43758, 48620, 43758, 31824, 18564, 8568, 3060, 816, 153, 18, 1}, + {1, 19, 171, 969, 3876, 11628, 27132, 50388, 75582, 92378, 92378, 75582, 50388, 27132, 11628, 3876, 969, 171, 19, 1}, +} + +func TestTriangle(t *testing.T) { + for n := 1; n <= 20; n++ { + res := Triangle(n) + want := t20[:n] + if !reflect.DeepEqual(res, want) { + t.Fatalf("Triangle(%d) = %s,\nwant:%s\n", + n, format(res), format(want)) + } + } + t.Log(format(Triangle(20))) +} + +func format(t [][]int) (s string) { + for _, r := range t { + s = fmt.Sprintf("%s\n%v", s, r) + } + return +} diff --git a/go/pythagorean-triplet/README.md b/go/pythagorean-triplet/README.md new file mode 100644 index 0000000..adf3b59 --- /dev/null +++ b/go/pythagorean-triplet/README.md @@ -0,0 +1,30 @@ +# Pythagorean Triplet + +There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product a * b * c. + +A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for +which, + +``` +a**2 + b**2 = c**2 +``` + +For example, + +``` +3**2 + 4**2 = 9 + 16 = 25 = 5**2. +``` + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Problem 9 at Project Euler [view source](http://projecteuler.net/problem=9) diff --git a/go/pythagorean-triplet/pythagorean.go b/go/pythagorean-triplet/pythagorean.go new file mode 100644 index 0000000..f754958 --- /dev/null +++ b/go/pythagorean-triplet/pythagorean.go @@ -0,0 +1,44 @@ +package pythagorean + +import "math" + +// Triplet just holds three ints +type Triplet struct { + a, b, c int +} + +// Range finds all pythagorean triplets +// from min to max +func Range(min, max int) []Triplet { + var ret []Triplet + for a := min; a <= max; a++ { + for b := a + 1; b <= max; b++ { + cSq := float64(a*a + b*b) + c := int(math.Sqrt(cSq)) + if c >= min && c <= max && isTriplet(a, b, c) { + ret = append(ret, Triplet{a, b, c}) + } + } + } + return ret +} + +// Sum finds all triplets that sum up to total +func Sum(total int) []Triplet { + var ret []Triplet + + // No side of a triangle can be over 1/2 of the total + for a := 1; a <= (total / 2); a++ { + for b := a; b <= (total / 2); b++ { + c := total - a - b + if isTriplet(a, b, c) { + ret = append(ret, Triplet{a, b, c}) + } + } + } + return ret +} + +func isTriplet(a, b, c int) bool { + return (a*a + b*b) == c*c +} diff --git a/go/pythagorean-triplet/pythagorean_triplet_test.go b/go/pythagorean-triplet/pythagorean_triplet_test.go new file mode 100644 index 0000000..0af626a --- /dev/null +++ b/go/pythagorean-triplet/pythagorean_triplet_test.go @@ -0,0 +1,73 @@ +package pythagorean + +// Use this type definition, +// +// type Triplet [3]int +// +// and implement two functions, +// +// Range(min, max int) []Triplet +// Sum(p int) []Triplet +// +// Range returns a list of all Pythagorean triplets with sides in the +// range min to max inclusive. +// +// Sum returns a list of all Pythagorean triplets where the sum a+b+c +// (the perimeter) is equal to p. +// +// The three elements of each returned triplet must be in order, +// t[0] <= t[1] <= t[2], and the list of triplets must be in lexicographic +// order. + +import ( + "reflect" + "testing" +) + +var rangeTests = []struct { + min, max int + ts []Triplet +}{ + {1, 10, []Triplet{{3, 4, 5}, {6, 8, 10}}}, + {11, 20, []Triplet{{12, 16, 20}}}, +} + +func TestRange(t *testing.T) { + for _, test := range rangeTests { + ts := Range(test.min, test.max) + if !reflect.DeepEqual(ts, test.ts) { + t.Fatalf("Range(%d, %d) = %v, want %v", + test.min, test.max, ts, test.ts) + } + } +} + +var sumTests = []struct { + sum int + ts []Triplet +}{ + {180, []Triplet{{18, 80, 82}, {30, 72, 78}, {45, 60, 75}}}, + {1000, []Triplet{{200, 375, 425}}}, +} + +func TestSum(t *testing.T) { + for _, test := range sumTests { + ts := Sum(test.sum) + if !reflect.DeepEqual(ts, test.ts) { + t.Fatalf("Sum(%d) = %v, want %v", + test.sum, ts, test.ts) + } + } +} + +func BenchmarkRange(b *testing.B) { + for i := 0; i < b.N; i++ { + Range(1, 100) + } +} + +func BenchmarkSum(b *testing.B) { + for i := 0; i < b.N; i++ { + Sum(1000) + } +} diff --git a/go/queen-attack/README.md b/go/queen-attack/README.md new file mode 100644 index 0000000..b3223ca --- /dev/null +++ b/go/queen-attack/README.md @@ -0,0 +1,40 @@ +# Queen Attack + +Write a program that positions two queens on a chess board and indicates whether or not they are positioned so that they can attack each other. + +In the game of chess, a queen can attack pieces which are on the same +row, column, or diagonal. + +A chessboard can be represented by an 8 by 8 array. + +So if you're told the white queen is at (2, 3) and the black queen at +(5, 6), then you'd know you've got a set-up like so: + +```plain +_ _ _ _ _ _ _ _ +_ _ _ _ _ _ _ _ +_ _ _ W _ _ _ _ +_ _ _ _ _ _ _ _ +_ _ _ _ _ _ _ _ +_ _ _ _ _ _ B _ +_ _ _ _ _ _ _ _ +_ _ _ _ _ _ _ _ +``` + +You'd also be able to answer whether the queens can attack each other. +In this case, that answer would be yes, they can, because both pieces +share a diagonal. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +J Dalbey's Programming Practice problems [view source](http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html) diff --git a/go/queen-attack/queen_attack.go b/go/queen-attack/queen_attack.go new file mode 100644 index 0000000..5828191 --- /dev/null +++ b/go/queen-attack/queen_attack.go @@ -0,0 +1,29 @@ +package queenattack + +import ( + "errors" + "math" +) + +// CanQueenAttack takes two positions one for a +// white queen (wq) and one for a black queen (bq) +// it returns a boolean value: if an attack can +// be made, and an error +func CanQueenAttack(wq, bq string) (bool, error) { + if len(wq) != 2 || len(bq) != 2 || + wq[0] < 'a' || wq[0] > 'z' || + wq[1] < '0' || wq[1] > '8' || + bq[0] < 'a' || bq[0] > 'z' || + bq[1] < '0' || bq[1] > '8' || + wq == bq { + return false, errors.New("Invalid pieces/placement") + } + wx, wy := float64(int8(wq[0])), float64(int8(wq[1])) + bx, by := float64(int8(bq[0])), float64(int8(bq[1])) + if wx == bx || wy == by || + math.Abs(wx-bx) == math.Abs(wy-by) { + return true, nil + } + + return false, nil +} diff --git a/go/queen-attack/queen_attack_test.go b/go/queen-attack/queen_attack_test.go new file mode 100644 index 0000000..586b060 --- /dev/null +++ b/go/queen-attack/queen_attack_test.go @@ -0,0 +1,53 @@ +package queenattack + +import "testing" + +// Arguments to CanQueenAttack are in algebraic notation. +// See http://en.wikipedia.org/wiki/Algebraic_notation_(chess) + +var tests = []struct { + w, b string + attack bool + ok bool +}{ + {"b4", "b4", false, false}, // same square + {"a8", "b9", false, false}, // off board + {"here", "there", false, false}, // invalid + {"", "", false, false}, + + {"b3", "d7", false, true}, // no attack + {"b4", "b7", true, true}, // same file + {"e4", "b4", true, true}, // same rank + {"a1", "f6", true, true}, // common diagonals + {"a6", "b7", true, true}, + {"d1", "f3", true, true}, + {"f1", "a6", true, true}, +} + +func TestCanQueenAttack(t *testing.T) { + for _, test := range tests { + switch attack, err := CanQueenAttack(test.w, test.b); { + case err != nil: + if test.ok { + t.Fatalf("CanQueenAttack(%s, %s) returned error %q. "+ + "Error not expected.", + test.w, test.b, err) + } + case !test.ok: + t.Fatalf("CanQueenAttack(%s, %s) = %t, %v. Expected error.", + test.w, test.b, attack, err) + case attack != test.attack: + t.Fatalf("CanQueenAttack(%s, %s) = %t, want %t.", + test.w, test.b, attack, test.attack) + } + } +} + +// Benchmark combined time for all test cases +func BenchmarkCanQueenAttack(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range tests { + CanQueenAttack(test.w, test.b) + } + } +} diff --git a/go/raindrops/README.md b/go/raindrops/README.md new file mode 100644 index 0000000..0e8086d --- /dev/null +++ b/go/raindrops/README.md @@ -0,0 +1,33 @@ +# Raindrops + +Write a program that converts a number to a string, the contents of which depends on the number's prime factors. + +- If the number contains 3 as a prime factor, output 'Pling'. +- If the number contains 5 as a prime factor, output 'Plang'. +- If the number contains 7 as a prime factor, output 'Plong'. +- If the number does not contain 3, 5, or 7 as a prime factor, + just pass the number's digits straight through. + +## Examples + +- 28's prime-factorization is 2, 2, 7. + - In raindrop-speak, this would be a simple "Plong". +- 1755 prime-factorization is 3, 3, 3, 5, 13. + - In raindrop-speak, this would be a "PlingPlang". +- The prime factors of 34 are 2 and 17. + - Raindrop-speak doesn't know what to make of that, + so it just goes with the straightforward "34". + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +A variation on a famous interview question intended to weed out potential candidates. [view source](http://jumpstartlab.com) diff --git a/go/raindrops/cases_test.go b/go/raindrops/cases_test.go new file mode 100644 index 0000000..e551032 --- /dev/null +++ b/go/raindrops/cases_test.go @@ -0,0 +1,25 @@ +package raindrops + +// Source: exercism/x-common +// Commit: 3b07e53 Merge pull request #117 from mikeyjcat/add-raindrops-json + +var tests = []struct { + input int + expected string +}{ + {1, "1"}, + {3, "Pling"}, + {5, "Plang"}, + {7, "Plong"}, + {6, "Pling"}, + {9, "Pling"}, + {10, "Plang"}, + {14, "Plong"}, + {15, "PlingPlang"}, + {21, "PlingPlong"}, + {25, "Plang"}, + {35, "PlangPlong"}, + {49, "Plong"}, + {52, "52"}, + {105, "PlingPlangPlong"}, +} diff --git a/go/raindrops/raindrops.go b/go/raindrops/raindrops.go new file mode 100644 index 0000000..91d8b19 --- /dev/null +++ b/go/raindrops/raindrops.go @@ -0,0 +1,26 @@ +package raindrops + +import "fmt" + +// TestVersion +const TestVersion = 1 + +// Convert takes a number and returns Raindrop-speak +func Convert(i int) string { + var ret string + if i%3 == 0 { + ret += "Pling" + } + if i%5 == 0 { + ret += "Plang" + } + if i%7 == 0 { + ret += "Plong" + } + if ret != "" { + return ret + } + return fmt.Sprintf("%d", i) +} + +// The test program has a benchmark too. How fast does your Convert convert? diff --git a/go/raindrops/raindrops_test.go b/go/raindrops/raindrops_test.go new file mode 100644 index 0000000..d4a6c72 --- /dev/null +++ b/go/raindrops/raindrops_test.go @@ -0,0 +1,28 @@ +package raindrops + +import "testing" + +const testVersion = 1 + +// Retired testVersions +// (none) 52fb31c169bc1b540109028f33f4f61b5f429753 + +func TestConvert(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + for _, test := range tests { + if actual := Convert(test.input); actual != test.expected { + t.Errorf("Convert(%d) = %q, expected %q.", + test.input, actual, test.expected) + } + } +} + +func BenchmarkConvert(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range tests { + Convert(test.input) + } + } +} diff --git a/go/react/README.md b/go/react/README.md new file mode 100644 index 0000000..e4f7d1a --- /dev/null +++ b/go/react/README.md @@ -0,0 +1,32 @@ +# React + +Implement a basic reactive system. + +Reactive programming is a programming paradigm that focuses on how values +are computed in terms of each other to allow a change to one value to +automatically propagate to other values, like in a spreadsheet. + +Implement a basic reactive system with cells with settable values ("input" +cells) and cells with values computed in terms of other cells ("compute" +cells). Implement updates so that when an input value is changed, values +propagate to reach a new stable system state. + +In addition, compute cells should allow for registering change notification +callbacks. Call a cell’s callbacks when the cell’s value in a new stable +state has changed from the previous stable state. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + + + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/react/interfaces.go b/go/react/interfaces.go new file mode 100644 index 0000000..05f3e42 --- /dev/null +++ b/go/react/interfaces.go @@ -0,0 +1,49 @@ +package react + +// A Reactor manages linked cells. +type Reactor interface { + // CreateInput creates an input cell linked into the reactor + // with the given initial value. + CreateInput(int) InputCell + + // CreateCompute1 creates a compute cell which computes its value + // based on one other cell. The compute function will only be called + // if the value of the passed cell changes. + CreateCompute1(Cell, func(int) int) ComputeCell + + // CreateCompute2 is like CreateCompute1, but depending on two cells. + // The compute function will only be called if the value of any of the + // passed cells changes. + CreateCompute2(Cell, Cell, func(int, int) int) ComputeCell +} + +// A Cell is conceptually a holder of a value. +type Cell interface { + // Value returns the current value of the cell. + Value() int +} + +// An InputCell has a changeable value, changing the value triggers updates to +// other cells. +type InputCell interface { + Cell + + // SetValue sets the value of the cell. + SetValue(int) +} + +// A ComputeCell always computes its value based on other cells and can +// call callbacks upon changes. +type ComputeCell interface { + Cell + + // AddCallback adds a callback which will be called when the value changes. + // It returns a callback handle which can be used to remove the callback. + AddCallback(func(int)) CallbackHandle + + // RemoveCallback removes a previously added callback, if it exists. + RemoveCallback(CallbackHandle) +} + +// A CallbackHandle is used to remove previously added callbacks, see ComputeCell. +type CallbackHandle interface{} diff --git a/go/react/react.go b/go/react/react.go new file mode 100644 index 0000000..2d3b512 --- /dev/null +++ b/go/react/react.go @@ -0,0 +1,94 @@ +package react + +import ( + "fmt" + "strconv" +) + +const testVersion = 4 + +// MyReactor implements Reactor +type MyReactor struct { + lastId int + cells []Cell +} + +// New creates a new Reactor +func New() *MyReactor { + r := &MyReactor{} + //r.callbacks = make(map[Cell][]func(int)) + return r +} + +// CreateInput builds an input cell and adds it to the reactor +func (r *MyReactor) CreateInput(i int) InputCell { + r.lastId++ + ic := MyCell{val: i, id: r.lastId} + return &ic +} + +// CreateCompute1 Takes a cell and a function and returns a compute cell +// which has a value based on running the function on the cells value. +func (r *MyReactor) CreateCompute1(c Cell, f func(int) int) ComputeCell { + r.lastId++ + cc := &MyCell{id: r.lastId, isComputed: true} + cc.compVal = func() int { return f(c.Value()) } + return cc +} + +// CreateCompute2 Takes two cells and a function and returns a compute cell +// which has a value based on running the function on the cells values. +func (r *MyReactor) CreateCompute2(c1, c2 Cell, f func(int, int) int) ComputeCell { + r.lastId++ + cc := &MyCell{id: r.lastId, isComputed: true} + cc.compVal = func() int { return f(c1.Value(), c2.Value()) } + return cc +} + +// MyCell implements the all Cell interfaces +type MyCell struct { + id int + isComputed bool + val int + compVal func() int + lastCallbackId int + callbacks map[int]func(int) +} + +// Value returns the value of the cell +func (c MyCell) Value() int { + if c.isComputed { + return c.compVal() + } + return c.val +} + +// SetValue sets the value on the cell +func (c *MyCell) SetValue(i int) { + if i == c.val || c.isComputed { + // No change or this is a computed cell, just return + return + } + c.val = i + // Hit all callbacks + for _, v := range c.callbacks { + fmt.Println("Hitting a callback: " + strconv.Itoa(i)) + v(i) + } +} + +func (c *MyCell) AddCallback(cb func(int)) CallbackHandle { + if c.lastCallbackId == 0 { + fmt.Println("Initializing Callback Map (Cell " + strconv.Itoa(c.id) + ")") + c.callbacks = make(map[int]func(int)) + } + fmt.Println("Adding a Callback to " + strconv.Itoa(c.id)) + c.lastCallbackId++ + c.callbacks[c.lastCallbackId] = cb + fmt.Println("Number of Callbacks: " + strconv.Itoa(c.lastCallbackId)) + return c.lastCallbackId +} + +func (c *MyCell) RemoveCallback(cbh CallbackHandle) { + delete(c.callbacks, cbh.(int)) +} diff --git a/go/react/react_test.go b/go/react/react_test.go new file mode 100644 index 0000000..0cc5f25 --- /dev/null +++ b/go/react/react_test.go @@ -0,0 +1,278 @@ +package react + +import ( + "runtime" + "testing" +) + +// Define a function New() Reactor and the stuff that follows from +// implementing Reactor. +// +// Also define a testVersion with a value that matches +// the targetTestVersion here. + +const targetTestVersion = 4 + +// This is a compile time check to see if you've properly implemented New(). +var _ Reactor = New() + +// If this test fails and you've proprly defined testVersion the requirements +// of the tests have changed since you wrote your submission. +func TestTestVersion(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } +} + +func assertCellValue(t *testing.T, c Cell, expected int, explanation string) { + observed := c.Value() + _, _, line, _ := runtime.Caller(1) + if observed != expected { + t.Fatalf("(from line %d) %s: expected %d, got %d", line, explanation, expected, observed) + } +} + +// Setting the value of an input cell changes the observable Value() +func TestSetInput(t *testing.T) { + r := New() + i := r.CreateInput(1) + assertCellValue(t, i, 1, "i.Value() doesn't match initial value") + i.SetValue(2) + assertCellValue(t, i, 2, "i.Value() doesn't match changed value") +} + +// The value of a compute 1 cell is determined by the value of the dependencies. +func TestBasicCompute1(t *testing.T) { + r := New() + i := r.CreateInput(1) + c := r.CreateCompute1(i, func(v int) int { return v + 1 }) + assertCellValue(t, c, 2, "c.Value() isn't properly computed based on initial input cell value") + i.SetValue(2) + assertCellValue(t, c, 3, "c.Value() isn't properly computed based on changed input cell value") +} + +// The value of a compute 2 cell is determined by the value of the dependencies. +func TestBasicCompute2(t *testing.T) { + r := New() + i1 := r.CreateInput(1) + i2 := r.CreateInput(2) + c := r.CreateCompute2(i1, i2, func(v1, v2 int) int { return v1 | v2 }) + assertCellValue(t, c, 3, "c.Value() isn't properly computed based on initial input cell values") + i1.SetValue(4) + assertCellValue(t, c, 6, "c.Value() isn't properly computed when first input cell value changes") + i2.SetValue(8) + assertCellValue(t, c, 12, "c.Value() isn't properly computed when second input cell value changes") +} + +// Compute 2 cells can depend on compute 1 cells. +func TestCompute2Diamond(t *testing.T) { + r := New() + i := r.CreateInput(1) + c1 := r.CreateCompute1(i, func(v int) int { return v + 1 }) + c2 := r.CreateCompute1(i, func(v int) int { return v - 1 }) + c3 := r.CreateCompute2(c1, c2, func(v1, v2 int) int { return v1 * v2 }) + assertCellValue(t, c3, 0, "c3.Value() isn't properly computed based on initial input cell value") + i.SetValue(3) + assertCellValue(t, c3, 8, "c3.Value() isn't properly computed based on changed input cell value") +} + +// Compute 1 cells can depend on other compute 1 cells. +func TestCompute1Chain(t *testing.T) { + r := New() + inp := r.CreateInput(1) + var c Cell = inp + for i := 2; i <= 8; i++ { + // must save current value of loop variable i for correct behavior. + // compute function has to use digitToAdd not i. + digitToAdd := i + c = r.CreateCompute1(c, func(v int) int { return v*10 + digitToAdd }) + } + assertCellValue(t, c, 12345678, "c.Value() isn't properly computed based on initial input cell value") + inp.SetValue(9) + assertCellValue(t, c, 92345678, "c.Value() isn't properly computed based on changed input cell value") +} + +// Compute 2 cells can depend on other compute 2 cells. +func TestCompute2Tree(t *testing.T) { + r := New() + ins := make([]InputCell, 3) + for i, v := range []int{1, 10, 100} { + ins[i] = r.CreateInput(v) + } + + add := func(v1, v2 int) int { return v1 + v2 } + + firstLevel := make([]ComputeCell, 2) + for i := 0; i < 2; i++ { + firstLevel[i] = r.CreateCompute2(ins[i], ins[i+1], add) + } + + output := r.CreateCompute2(firstLevel[0], firstLevel[1], add) + assertCellValue(t, output, 121, "output.Value() isn't properly computed based on initial input cell values") + + for i := 0; i < 3; i++ { + ins[i].SetValue(ins[i].Value() * 2) + } + + assertCellValue(t, output, 242, "output.Value() isn't properly computed based on changed input cell values") +} + +// Compute cells can have callbacks. +func TestBasicCallback(t *testing.T) { + r := New() + i := r.CreateInput(1) + c := r.CreateCompute1(i, func(v int) int { return v + 1 }) + var observed []int + c.AddCallback(func(v int) { + observed = append(observed, v) + }) + if len(observed) != 0 { + t.Fatalf("callback called before changes were made") + } + i.SetValue(2) + if len(observed) != 1 { + t.Fatalf("callback not called when changes were made") + } + if observed[0] != 3 { + t.Fatalf("callback not called with proper value") + } +} + +// Callbacks and only trigger on change. +func TestOnlyCallOnChanges(t *testing.T) { + r := New() + i := r.CreateInput(1) + c := r.CreateCompute1(i, func(v int) int { + if v > 3 { + return v + 1 + } + return 2 + }) + var observedCalled int + c.AddCallback(func(int) { + observedCalled++ + }) + i.SetValue(1) + if observedCalled != 0 { + t.Fatalf("observe function called even though input didn't change") + } + i.SetValue(2) + if observedCalled != 0 { + t.Fatalf("observe function called even though computed value didn't change") + } +} + +// Callbacks can be added and removed. +func TestCallbackAddRemove(t *testing.T) { + r := New() + i := r.CreateInput(1) + c := r.CreateCompute1(i, func(v int) int { return v + 1 }) + var observed1 []int + cb1 := c.AddCallback(func(v int) { + observed1 = append(observed1, v) + }) + var observed2 []int + c.AddCallback(func(v int) { + observed2 = append(observed2, v) + }) + i.SetValue(2) + if len(observed1) != 1 || observed1[0] != 3 { + t.Fatalf("observed1 not properly called") + } + if len(observed2) != 1 || observed2[0] != 3 { + t.Fatalf("observed2 not properly called") + } + c.RemoveCallback(cb1) + i.SetValue(3) + if len(observed1) != 1 { + t.Fatalf("observed1 called after removal") + } + if len(observed2) != 2 || observed2[1] != 4 { + t.Fatalf("observed2 not properly called after first callback removal") + } +} + +func TestMultipleCallbackRemoval(t *testing.T) { + r := New() + inp := r.CreateInput(1) + c := r.CreateCompute1(inp, func(v int) int { return v + 1 }) + + numCallbacks := 5 + + calls := make([]int, numCallbacks) + handles := make([]CallbackHandle, numCallbacks) + for i := 0; i < numCallbacks; i++ { + // Rebind i, otherwise all callbacks will use i = numCallbacks + i := i + handles[i] = c.AddCallback(func(v int) { calls[i]++ }) + } + + inp.SetValue(2) + for i := 0; i < numCallbacks; i++ { + if calls[i] != 1 { + t.Fatalf("callback %d/%d should be called 1 time, was called %d times", i+1, numCallbacks, calls[i]) + } + c.RemoveCallback(handles[i]) + } + + inp.SetValue(3) + for i := 0; i < numCallbacks; i++ { + if calls[i] != 1 { + t.Fatalf("callback %d/%d was called after it was removed", i+1, numCallbacks) + } + } +} + +func TestRemoveIdempotence(t *testing.T) { + r := New() + inp := r.CreateInput(1) + output := r.CreateCompute1(inp, func(v int) int { return v + 1 }) + timesCalled := 0 + cb1 := output.AddCallback(func(int) {}) + output.AddCallback(func(int) { timesCalled++ }) + for i := 0; i < 10; i++ { + output.RemoveCallback(cb1) + } + inp.SetValue(2) + if timesCalled != 1 { + t.Fatalf("remaining callback function was not called") + } +} + +// Callbacks should only be called once even though +// multiple dependencies have changed. +func TestOnlyCallOnceOnMultipleDepChanges(t *testing.T) { + r := New() + i := r.CreateInput(1) + c1 := r.CreateCompute1(i, func(v int) int { return v + 1 }) + c2 := r.CreateCompute1(i, func(v int) int { return v - 1 }) + c3 := r.CreateCompute1(c2, func(v int) int { return v - 1 }) + c4 := r.CreateCompute2(c1, c3, func(v1, v3 int) int { return v1 * v3 }) + changed4 := 0 + c4.AddCallback(func(int) { changed4++ }) + i.SetValue(3) + if changed4 < 1 { + t.Fatalf("callback function was not called") + } else if changed4 > 1 { + t.Fatalf("callback function was called too often") + } +} + +// Callbacks should not be called if dependencies change in such a way +// that the final value of the compute cell does not change. +func TestNoCallOnDepChangesResultingInNoChange(t *testing.T) { + r := New() + inp := r.CreateInput(0) + plus1 := r.CreateCompute1(inp, func(v int) int { return v + 1 }) + minus1 := r.CreateCompute1(inp, func(v int) int { return v - 1 }) + // The output's value is always 2, no matter what the input is. + output := r.CreateCompute2(plus1, minus1, func(v1, v2 int) int { return v1 - v2 }) + + timesCalled := 0 + output.AddCallback(func(int) { timesCalled++ }) + + inp.SetValue(5) + if timesCalled != 0 { + t.Fatalf("callback function called even though computed value didn't change") + } +} diff --git a/go/rna-transcription/README.md b/go/rna-transcription/README.md new file mode 100644 index 0000000..687dff5 --- /dev/null +++ b/go/rna-transcription/README.md @@ -0,0 +1,33 @@ +# Rna Transcription + +Write a program that, given a DNA strand, returns its RNA complement (per RNA transcription). + +Both DNA and RNA strands are a sequence of nucleotides. + +The four nucleotides found in DNA are adenine (**A**), cytosine (**C**), +guanine (**G**) and thymine (**T**). + +The four nucleotides found in RNA are adenine (**A**), cytosine (**C**), +guanine (**G**) and uracil (**U**). + +Given a DNA strand, its transcribed RNA strand is formed by replacing +each nucleotide with its complement: + +* `G` -> `C` +* `C` -> `G` +* `T` -> `A` +* `A` -> `U` + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +Rosalind [view source](http://rosalind.info/problems/rna) diff --git a/go/rna-transcription/cases_test.go b/go/rna-transcription/cases_test.go new file mode 100644 index 0000000..156f70d --- /dev/null +++ b/go/rna-transcription/cases_test.go @@ -0,0 +1,24 @@ +package strand + +// Source: exercism/x-common +// Commit: 6985644 Merge pull request #121 from mikeyjcat/add-roman-numerals-test-definition + +var rnaTests = []struct { + input string + expected string +}{ + // rna complement of cytosine is guanine + {"C", "G"}, + + // rna complement of guanine is cytosine + {"G", "C"}, + + // rna complement of thymine is adenine + {"T", "A"}, + + // rna complement of adenine is uracil + {"A", "U"}, + + // rna complement + {"ACGTGGTCTTAA", "UGCACCAGAAUU"}, +} diff --git a/go/rna-transcription/rna_transcription_test.go b/go/rna-transcription/rna_transcription_test.go new file mode 100644 index 0000000..69dba97 --- /dev/null +++ b/go/rna-transcription/rna_transcription_test.go @@ -0,0 +1,25 @@ +package strand + +import "testing" + +const testVersion = 2 + +func TestRNATranscription(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + for _, test := range rnaTests { + if actual := ToRNA(test.input); actual != test.expected { + t.Errorf("ToRNA(%s): %s, expected %s", + test.input, actual, test.expected) + } + } +} + +func BenchmarkRNATranscription(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range rnaTests { + ToRNA(test.input) + } + } +} diff --git a/go/roman-numerals/README.md b/go/roman-numerals/README.md new file mode 100644 index 0000000..7a1bbbe --- /dev/null +++ b/go/roman-numerals/README.md @@ -0,0 +1,57 @@ +# Roman Numerals + +Write a function to convert from normal numbers to Roman Numerals: e.g. + +The Romans were a clever bunch. They conquered most of Europe and ruled +it for hundreds of years. They invented concrete and straight roads and +even bikinis. One thing they never discovered though was the number +zero. This made writing and dating extensive histories of their exploits +slightly more challenging, but the system of numbers they came up with +is still in use today. For example the BBC uses Roman numerals to date +their programmes. + +The Romans wrote numbers using letters - I, V, X, L, C, D, M. (notice +these letters have lots of straight lines and are hence easy to hack +into stone tablets). + +``` + 1 => I +10 => X + 7 => VII +``` + +There is no need to be able to convert numbers larger than about 3000. +(The Romans themselves didn't tend to go any higher) + +Wikipedia says: Modern Roman numerals ... are written by expressing each +digit separately starting with the left most digit and skipping any +digit with a value of zero. + +To see this in practice, consider the example of 1990. + +In Roman numerals 1990 is MCMXC: + +1000=M +900=CM +90=XC + +2008 is written as MMVIII: + +2000=MM +8=VIII + +See also: http://www.novaroma.org/via_romana/numbers.html + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +The Roman Numeral Kata [view source](http://codingdojo.org/cgi-bin/wiki.pl?KataRomanNumerals) diff --git a/go/roman-numerals/cases_test.go b/go/roman-numerals/cases_test.go new file mode 100644 index 0000000..8e99b8e --- /dev/null +++ b/go/roman-numerals/cases_test.go @@ -0,0 +1,31 @@ +package romannumerals + +// Source: exercism/x-common +// Commit: 6985644 Merge pull request #121 from mikeyjcat/add-roman-numerals-test-definition + +type romanNumeralTest struct { + arabic int + roman string + hasError bool +} + +var romanNumeralTests = []romanNumeralTest{ + {1, "I", false}, + {2, "II", false}, + {3, "III", false}, + {4, "IV", false}, + {5, "V", false}, + {6, "VI", false}, + {9, "IX", false}, + {27, "XXVII", false}, + {48, "XLVIII", false}, + {59, "LIX", false}, + {93, "XCIII", false}, + {141, "CXLI", false}, + {163, "CLXIII", false}, + {402, "CDII", false}, + {575, "DLXXV", false}, + {911, "CMXI", false}, + {1024, "MXXIV", false}, + {3000, "MMM", false}, +} diff --git a/go/roman-numerals/cmd/cmd b/go/roman-numerals/cmd/cmd new file mode 100755 index 0000000..f42ecf2 Binary files /dev/null and b/go/roman-numerals/cmd/cmd differ diff --git a/go/roman-numerals/cmd/test.go b/go/roman-numerals/cmd/test.go new file mode 100644 index 0000000..c3030ff --- /dev/null +++ b/go/roman-numerals/cmd/test.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "strconv" + + "../../roman-numerals" +) + +func main() { + arabic := []int{0, -1, 4000, 3999, 1, 2, 3, 4, 5, 6, 9, 27, 48, 59, 93, 141, 163, 402, 575, 911, 1024, 3000} + for i := range arabic { + fmt.Println(strconv.Itoa(arabic[i]) + ": ") + if v, err := romannumerals.ToRomanNumeral(arabic[i]); err == nil { + fmt.Print("-->") + fmt.Println(v) + } else { + fmt.Print("-->") + fmt.Println(err.Error()) + } + } +} diff --git a/go/roman-numerals/roman_numerals_test.go b/go/roman-numerals/roman_numerals_test.go new file mode 100644 index 0000000..6a0d49b --- /dev/null +++ b/go/roman-numerals/roman_numerals_test.go @@ -0,0 +1,39 @@ +package romannumerals + +import "testing" + +const testVersion = 1 + +func TestRomanNumerals(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + tc := append(romanNumeralTests, []romanNumeralTest{ + {0, "", true}, + {-1, "", true}, + {4000, "", true}, + {3999, "MMMCMXCIX", false}, + }...) + for _, test := range tc { + actual, err := ToRomanNumeral(test.arabic) + if err == nil && test.hasError { + t.Errorf("ToRomanNumeral(%d) should return an error.", test.arabic) + continue + } + if err != nil && !test.hasError { + t.Errorf("ToRomanNumeral(%d) should not return an error.", test.arabic) + continue + } + if actual != test.roman { + t.Errorf("ToRomanNumeral(%d): %s, expected %s", test.arabic, actual, test.roman) + } + } +} + +func BenchmarkRomanNumerals(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range romanNumeralTests { + ToRomanNumeral(test.arabic) + } + } +} diff --git a/go/roman-numerals/romannumerals.go b/go/roman-numerals/romannumerals.go new file mode 100644 index 0000000..b070878 --- /dev/null +++ b/go/roman-numerals/romannumerals.go @@ -0,0 +1,72 @@ +package romannumerals + +import ( + "errors" + "strings" +) + +// TestVersion tells exercism which tests to use +const TestVersion = 1 + +// ToRomanNumeral takes an int and returns it's roman numberal string value +// Or an error if it can't be done. +func ToRomanNumeral(arabic int) (string, error) { + if arabic <= 0 || arabic > 3999 { + return "", errors.New("Invalid number given") + } + var ret string + var err error + var care int + place := 1 + for ; arabic > 0; arabic = (arabic - care) / 10 { + care = arabic % 10 + ret = getRomanChar(care, place) + ret + place *= 10 + } + if strings.Contains(ret, "?") { + err = errors.New("Invalid number given") + } + return ret, err +} + +func getRomanChar(dg, pl int) string { + switch { + case dg <= 0: + return "" + case dg < 4: + return strings.Repeat(getOnesPlaceChar(pl), dg) + case dg == 4: + return getOnesPlaceChar(pl) + getFivesPlaceChar(pl) + case dg < 9: + return getFivesPlaceChar(pl) + getRomanChar(dg-5, pl) + case dg == 9: + return getOnesPlaceChar(pl) + getOnesPlaceChar(pl*10) + } + return "?" +} + +func getOnesPlaceChar(pl int) string { + switch pl { + case 1: + return "I" + case 10: + return "X" + case 100: + return "C" + case 1000: + return "M" + } + return "?" +} + +func getFivesPlaceChar(pl int) string { + switch pl { + case 1: + return "V" + case 10: + return "L" + case 100: + return "D" + } + return "?" +} diff --git a/go/say/README.md b/go/say/README.md new file mode 100644 index 0000000..4b5f488 --- /dev/null +++ b/go/say/README.md @@ -0,0 +1,77 @@ +# Say + +Write a program that will take a number from 0 to 999,999,999,999 and spell out that number in English. + +## Step 1 + +Handle the basic case of 0 through 99. + +If the input to the program is `22`, then the output should be +`'twenty-two'`. + +Your program should complain loudly if given a number outside the +blessed range. + +Some good test cases for this program are: + +- 0 +- 14 +- 50 +- 98 +- -1 +- 100 + +### Extension + +If you're on a Mac, shell out to Mac OS X's `say` program to talk out +loud. + +## Step 2 + +Implement breaking a number up into chunks of thousands. + +So `1234567890` should yield a list like 1, 234, 567, and 890, while the +far simpler `1000` should yield just 1 and 0. + +The program must also report any values that are out of range. + +## Step 3 + +Now handle inserting the appropriate scale word between those chunks. + +So `1234567890` should yield `'1 billion 234 million 567 thousand 890'` + +The program must also report any values that are out of range. It's +fine to stop at "trillion". + +## Step 4 + +Put it all together to get nothing but plain English. + +`12345` should give `twelve thousand three hundred forty-five`. + +The program must also report any values that are out of range. + +### Extensions + +Use _and_ (correctly) when spelling out the number in English: + +- 14 becomes "fourteen". +- 100 becomes "one hundred". +- 120 becomes "one hundred and twenty". +- 1002 becomes "one thousand and two". +- 1323 becomes "one thousand three hundred and twenty-three". + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +A variation on JavaRanch CattleDrive, exercise 4a [http://www.javaranch.com/say.jsp](http://www.javaranch.com/say.jsp) diff --git a/go/say/cmd/cmd b/go/say/cmd/cmd new file mode 100755 index 0000000..2b18721 Binary files /dev/null and b/go/say/cmd/cmd differ diff --git a/go/say/cmd/main.go b/go/say/cmd/main.go new file mode 100644 index 0000000..0c0eca2 --- /dev/null +++ b/go/say/cmd/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + + "../../say" +) + +func main() { + tst := []int{0, 14, 50, 98, -1, 100} + for i := range tst { + fmt.Println(say.GetPlaceValue(tst[i], 10)) + //fmt.Println(say.Say(tst[i])) + } +} diff --git a/go/say/say.go b/go/say/say.go new file mode 100644 index 0000000..f02a079 --- /dev/null +++ b/go/say/say.go @@ -0,0 +1,39 @@ +package say + +import ( + "fmt" + "strconv" +) + +func Say(num int) string { + // Tens place gives us the y-nums (twent_y-num, thirt_y-num, etc) + //tens := num % 100 + /* + switch tens - (tens%10)/10 { + case tens > 10: + switch tens % 10 { + case 1: + return Say(num-tens) + " eleven" + case 2: + return Say(num-tens) + " twelve" + case 3: + return Say(num-tens) + " thirteen" + case 4: + return Say(num-tens) + " fourteen" + case 5: + return Say(num-tens) + " fifteen" + default: + return Say(num-tens) + " " + Say(tens%10) + "teen" + } + } + */ + return "" +} + +func GetPlaceValue(num, place int) int { + fmt.Println("Testing " + strconv.Itoa(place) + "s place of " + strconv.Itoa(num)) + if num > place { + return num - (num%place)/place + } + return 0 +} diff --git a/go/say/say_test.go b/go/say/say_test.go new file mode 100644 index 0000000..e4144a5 --- /dev/null +++ b/go/say/say_test.go @@ -0,0 +1,47 @@ +package say + +// The steps are interesting, but all that matters is the final exam. + +import ( + "math" + "testing" +) + +var tests = []struct { + uint64 + string +}{ + {1, "one"}, + {14, "fourteen"}, + {20, "twenty"}, + {22, "twenty-two"}, + {100, "one hundred"}, + {120, "one hundred twenty"}, + {123, "one hundred twenty-three"}, + {1000, "one thousand"}, + {1234, "one thousand two hundred thirty-four"}, + {1000000, "one million"}, + {1000002, "one million two"}, + {1002345, "one million two thousand three hundred forty-five"}, + {1e9, "one billion"}, + {987654321123, "nine hundred eighty-seven billion " + + "six hundred fifty-four million " + + "three hundred twenty-one thousand " + + "one hundred twenty-three"}, + {0, "zero"}, + {math.MaxUint64, "eighteen quintillion " + + "four hundred forty-six quadrillion " + + "seven hundred forty-four trillion " + + "seventy-three billion " + + "seven hundred nine million " + + "five hundred fifty-one thousand " + + "six hundred fifteen"}, +} + +func TestSay(t *testing.T) { + for _, test := range tests { + if s := Say(test.uint64); s != test.string { + t.Errorf("Say(%d) = %q. Want %q.", test.uint64, s, test.string) + } + } +} diff --git a/go/scrabble-score/README.md b/go/scrabble-score/README.md new file mode 100644 index 0000000..3525dc8 --- /dev/null +++ b/go/scrabble-score/README.md @@ -0,0 +1,52 @@ +# Scrabble Score + +Write a program that, given a word, computes the scrabble score for that word. + +## Letter Values + +You'll need these: + +```plain +Letter Value +A, E, I, O, U, L, N, R, S, T 1 +D, G 2 +B, C, M, P 3 +F, H, V, W, Y 4 +K 5 +J, X 8 +Q, Z 10 +``` + +## Examples +"cabbage" should be scored as worth 14 points: + +- 3 points for C +- 1 point for A, twice +- 3 points for B, twice +- 2 points for G +- 1 point for E + +And to total: + +- `3 + 2*1 + 2*3 + 2 + 1` +- = `3 + 2 + 6 + 3` +- = `5 + 9` +- = 14 + +## Extensions +- You can play a `:double` or a `:triple` letter. +- You can play a `:double` or a `:triple` word. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Inspired by the Extreme Startup game [view source](https://github.com/rchatley/extreme_startup) diff --git a/go/scrabble-score/scrabble_score.go b/go/scrabble-score/scrabble_score.go new file mode 100644 index 0000000..04b1cb5 --- /dev/null +++ b/go/scrabble-score/scrabble_score.go @@ -0,0 +1,24 @@ +package scrabble_score + +import "strings" + +// Score takes a word and returns the +// Scrabble score for that word +func Score(word string) int { + word = strings.ToUpper(word) + letterValues := map[rune]int{ + 'A': 1, 'E': 1, 'I': 1, 'O': 1, 'U': 1, + 'L': 1, 'N': 1, 'R': 1, 'S': 1, 'T': 1, + 'D': 2, 'G': 2, + 'B': 3, 'C': 3, 'M': 3, 'P': 3, + 'F': 4, 'H': 4, 'V': 4, 'W': 4, 'Y': 4, + 'K': 5, + 'J': 8, 'X': 8, + 'Q': 10, 'Z': 10, + } + var ret int + for _, ch := range word { + ret += letterValues[ch] + } + return ret +} diff --git a/go/scrabble-score/scrabble_score_test.go b/go/scrabble-score/scrabble_score_test.go new file mode 100644 index 0000000..838b527 --- /dev/null +++ b/go/scrabble-score/scrabble_score_test.go @@ -0,0 +1,33 @@ +package scrabble_score + +import "testing" + +var tests = []struct { + input string + expected int +}{ + {"", 0}, + {" \t\n", 0}, + {"a", 1}, + {"f", 4}, + {"street", 6}, + {"quirky", 22}, + {"oxyphenbutazone", 41}, + {"alacrity", 13}, +} + +func TestScore(t *testing.T) { + for _, test := range tests { + if actual := Score(test.input); actual != test.expected { + t.Errorf("Score(%q) expected %d, Actual %d", test.input, test.expected, actual) + } + } +} + +func BenchmarkScore(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range tests { + Score(test.input) + } + } +} diff --git a/go/secret-handshake/README.md b/go/secret-handshake/README.md new file mode 100644 index 0000000..0286cf0 --- /dev/null +++ b/go/secret-handshake/README.md @@ -0,0 +1,44 @@ +# Secret Handshake + +Write a program that will take a decimal number, and convert it to the appropriate sequence of events for a secret handshake. + +> There are 10 types of people in the world: Those who understand +> binary, and those who don't. + +You and your fellow cohort of those in the "know" when it comes to +binary decide to come up with a secret "handshake". + +``` +1 = wink +10 = double blink +100 = close your eyes +1000 = jump + + +10000 = Reverse the order of the operations in the secret handshake. +``` + +``` +handshake = SecretHandshake.new 9 +handshake.commands # => ["wink","jump"] + +handshake = SecretHandshake.new "11001" +handshake.commands # => ["jump","wink"] +``` + +The program should consider strings specifying an invalid binary as the +value 0. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Bert, in Mary Poppins [view source](http://www.imdb.com/character/ch0011238/quotes) diff --git a/go/secret-handshake/secret_handshake.go b/go/secret-handshake/secret_handshake.go new file mode 100644 index 0000000..877ba1a --- /dev/null +++ b/go/secret-handshake/secret_handshake.go @@ -0,0 +1,31 @@ +package secret + +// Handshake converts an integer into a string slice +// of the code +func Handshake(code int) []string { + if code < 0 { + return nil + } + var ret []string + if code&1 == 1 { + ret = append(ret, "wink") + } + if code&2 == 2 { + ret = append(ret, "double blink") + } + if code&4 == 4 { + ret = append(ret, "close your eyes") + } + if code&8 == 8 { + ret = append(ret, "jump") + } + if code&16 == 16 { + var revRet []string + for len(ret) > 0 { + revRet = append(revRet, ret[len(ret)-1]) + ret = ret[:len(ret)-1] + } + ret = revRet + } + return ret +} diff --git a/go/secret-handshake/secret_handshake_test.go b/go/secret-handshake/secret_handshake_test.go new file mode 100644 index 0000000..65fd058 --- /dev/null +++ b/go/secret-handshake/secret_handshake_test.go @@ -0,0 +1,43 @@ +package secret + +import ( + "reflect" + "testing" +) + +var tests = []struct { + code int + h []string +}{ + {1, []string{"wink"}}, + {2, []string{"double blink"}}, + {4, []string{"close your eyes"}}, + {8, []string{"jump"}}, + {3, []string{"wink", "double blink"}}, + {19, []string{"double blink", "wink"}}, + {31, []string{"jump", "close your eyes", "double blink", "wink"}}, + {0, nil}, + {-1, nil}, + {32, nil}, + {33, []string{"wink"}}, +} + +func TestHandshake(t *testing.T) { + for _, test := range tests { + h := Handshake(test.code) + // use len() to allow either nil or empty list, because + // they are not equal by DeepEqual + if len(h) == 0 && len(test.h) == 0 { + continue + } + if !reflect.DeepEqual(h, test.h) { + t.Fatalf("Handshake(%d) = %v, want %v.", test.code, h, test.h) + } + } +} + +func BenchmarkHandshake(b *testing.B) { + for i := 0; i < b.N; i++ { + Handshake(31) + } +} diff --git a/go/series/README.md b/go/series/README.md new file mode 100644 index 0000000..44d1fe8 --- /dev/null +++ b/go/series/README.md @@ -0,0 +1,31 @@ +# Series + +Write a program that will take a string of digits and give you all the possible consecutive number series of length `n` in that string. + +For example, the string "01234" has the following 3-digit series: + +- 012 +- 123 +- 234 + +And the following 4-digit series: + +- 0123 +- 1234 + +And if you ask for a 6-digit series from a 5-digit string, you deserve +whatever you get. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +A subset of the Problem 8 at Project Euler [view source](http://projecteuler.net/problem=8) diff --git a/go/series/asktoomuch_test.go b/go/series/asktoomuch_test.go new file mode 100644 index 0000000..7ef092b --- /dev/null +++ b/go/series/asktoomuch_test.go @@ -0,0 +1,29 @@ +// +build asktoomuch + +package slice + +import "testing" + +func TestAskTooMuch(t *testing.T) { + test := allTests[0] + defer func() { + if recover() != nil { + t.Fatalf("Yikes, Frist(%d, %s) panicked!", test.n, test.s) + } + }() + for _, test = range allTests { + switch res := Frist(test.n, test.s); { + case len(test.out) > 0: // well, this should work + if res != test.out[0] { + t.Fatalf("Yikes, Frist(%d, %s) = %q, want %q.", + test.n, test.s, res, test.out[0]) + } + case len(res) != test.n: + t.Fatalf("Yikes, Frist(%d, %s) = %q, but %q doesn't have %d characters.", + test.n, test.s, res, res, test.n) + default: + t.Fatalf("Yikes, Frist(%d, %s) = %q, but %q isn't in %q", + test.n, test.s, res, res, test.s) + } + } +} diff --git a/go/series/first_test.go b/go/series/first_test.go new file mode 100644 index 0000000..cbe524b --- /dev/null +++ b/go/series/first_test.go @@ -0,0 +1,23 @@ +// +build first + +package slice + +import "testing" + +func TestFirst(t *testing.T) { + for _, test := range allTests { + switch res, ok := First(test.n, test.s); { + case !ok: + if len(test.out) > 0 { + t.Fatalf("First(%d, %s) returned !ok, want ok.", + test.n, test.s) + } + case len(test.out) == 0: + t.Fatalf("First(%d, %s) = %s, %t. Expected ok == false", + test.n, test.s, res, ok) + case res != test.out[0]: + t.Fatalf("First(%d, %s) = %s. Want %s.", + test.n, test.s, res, test.out[0]) + } + } +} diff --git a/go/series/main/main b/go/series/main/main new file mode 100755 index 0000000..0ad9ea7 Binary files /dev/null and b/go/series/main/main differ diff --git a/go/series/main/main.go b/go/series/main/main.go new file mode 100644 index 0000000..5e82fe6 --- /dev/null +++ b/go/series/main/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" +) + +// All ... +func All(l int, str string) []string { + var ret []string + for len(str) >= l { + ret = append(ret, str[:l]) + str = str[1:] + } + return ret +} + +func main() { + var allTests = []struct { + n int + s string + out []string + }{ + {1, "01234", + []string{"0", "1", "2", "3", "4"}}, + {1, "92834", + []string{"9", "2", "8", "3", "4"}}, + {2, "01234", + []string{"01", "12", "23", "34"}}, + {2, "98273463", + []string{"98", "82", "27", "73", "34", "46", "63"}}, + {2, "37103", + []string{"37", "71", "10", "03"}}, + {3, "01234", + []string{"012", "123", "234"}}, + {3, "31001", + []string{"310", "100", "001"}}, + {3, "982347", + []string{"982", "823", "234", "347"}}, + {4, "01234", + []string{"0123", "1234"}}, + {4, "91274", + []string{"9127", "1274"}}, + {5, "01234", + []string{"01234"}}, + {5, "81228", + []string{"81228"}}, + {6, "01234", nil}, + } + for _, test := range allTests { + fmt.Println(All(test.n, test.s)) + } +} diff --git a/go/series/series_test.go b/go/series/series_test.go new file mode 100644 index 0000000..03216fb --- /dev/null +++ b/go/series/series_test.go @@ -0,0 +1,86 @@ +// Define two functions: (Two? Yes, sometimes we ask more out of Go.) +// +// // All returns a list of all substrings of s with length n. +// All(n int, s string) []string +// +// // Frist returns the first substring of s with length n. +// Frist(n int, s string) string +// +// Wait, is that a typo? It'll make sense if you do the bonus! +// +// Bonus exercise: +// +// Maybe we typed too fast. Once you get `go test` passing, try +// `go test -tags asktoomuch`. (Hint, you can't make it happy.) +// +// Now slow down and do things right(tm). Define +// +// First(int, string) (first string, ok bool) +// +// spelling first correctly this time, and test with `go test -tags first`. + +package slice + +import ( + "reflect" + "testing" +) + +var allTests = []struct { + n int + s string + out []string +}{ + {1, "01234", + []string{"0", "1", "2", "3", "4"}}, + {1, "92834", + []string{"9", "2", "8", "3", "4"}}, + {2, "01234", + []string{"01", "12", "23", "34"}}, + {2, "98273463", + []string{"98", "82", "27", "73", "34", "46", "63"}}, + {2, "37103", + []string{"37", "71", "10", "03"}}, + {3, "01234", + []string{"012", "123", "234"}}, + {3, "31001", + []string{"310", "100", "001"}}, + {3, "982347", + []string{"982", "823", "234", "347"}}, + {4, "01234", + []string{"0123", "1234"}}, + {4, "91274", + []string{"9127", "1274"}}, + {5, "01234", + []string{"01234"}}, + {5, "81228", + []string{"81228"}}, + {6, "01234", nil}, + {len(cx) + 1, cx, nil}, +} + +var cx = "01032987583" + +func TestAll(t *testing.T) { + for _, test := range allTests { + switch res := All(test.n, test.s); { + case len(res) == 0 && len(test.out) == 0: + case reflect.DeepEqual(res, test.out): + default: + t.Fatalf("All(%d, %s) = %v, want %v.", + test.n, test.s, res, test.out) + } + } +} + +func TestFrist(t *testing.T) { + for _, test := range allTests { + if len(test.out) == 0 { + continue + } + if res := Frist(test.n, test.s); res != test.out[0] { + t.Fatalf("Frist(%d, %s) = %s, want %s.", + test.n, test.s, res, test.out[0]) + } + } +} diff --git a/go/series/slice.go b/go/series/slice.go new file mode 100644 index 0000000..8173bf5 --- /dev/null +++ b/go/series/slice.go @@ -0,0 +1,21 @@ +package slice + +// All takes a string 'str' and a length 'l' and returns +// all substrings of length l +func All(l int, str string) []string { + var ret []string + for len(str) >= l { + ret = append(ret, str[:l]) + str = str[1:] + } + return ret +} + +// Frist (Frist?!) takes a string 'str' and a length 'l' and returns +// the first substring of length l +func Frist(l int, str string) string { + if len(str) >= l { + return str[:l] + } + return "" +} diff --git a/go/sieve/README.md b/go/sieve/README.md new file mode 100644 index 0000000..12a5fc4 --- /dev/null +++ b/go/sieve/README.md @@ -0,0 +1,41 @@ +# Sieve + +Write a program that uses the Sieve of Eratosthenes to find all the primes from 2 up to a given number. + +The Sieve of Eratosthenes is a simple, ancient algorithm for finding all +prime numbers up to any given limit. It does so by iteratively marking as +composite (i.e. not prime) the multiples of each prime, +starting with the multiples of 2. + +Create your range, starting at two and continuing up to and including the given limit. (i.e. [2, limit]) + +The algorithm consists of repeating the following over and over: + +- take the next available unmarked number in your list (it is prime) +- mark all the multiples of that number (they are not prime) + +Repeat until you have processed each number in your range. + +When the algorithm terminates, all the numbers in the list that have not +been marked are prime. + +The wikipedia article has a useful graphic that explains the algorithm: +https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes + +Notice that this is a very specific algorithm, and the tests don't check +that you've implemented the algorithm, only that you've come up with the +correct list of primes. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +Sieve of Eratosthenes at Wikipedia [view source](http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) diff --git a/go/sieve/sieve.go b/go/sieve/sieve.go new file mode 100644 index 0000000..1f6f250 --- /dev/null +++ b/go/sieve/sieve.go @@ -0,0 +1,25 @@ +package sieve + +import "fmt" + +// Sieve applies the Sieve of Eratosthenes up to depth +// Returning a slice of all of the results +func Sieve(depth int) []int { + var primes []int + test := 2 + for test <= depth { + testIsPrime := true + for idx := range primes { + if test%primes[idx] == 0 { + testIsPrime = false + break + } + } + if testIsPrime { + primes = append(primes, test) + } + test++ + fmt.Println("") + } + return primes +} diff --git a/go/sieve/sieve_test.go b/go/sieve/sieve_test.go new file mode 100644 index 0000000..1eec072 --- /dev/null +++ b/go/sieve/sieve_test.go @@ -0,0 +1,36 @@ +package sieve + +import ( + "reflect" + "testing" +) + +var p10 = []int{2, 3, 5, 7} +var p1000 = []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, + 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, + 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, + 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, + 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, + 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, + 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, + 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, + 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997} + +func TestSieve(t *testing.T) { + p := Sieve(10) + if !reflect.DeepEqual(p, p10) { + t.Fatalf("Sieve(10) = %v, want %v", p, p10) + } + p = Sieve(1000) + if !reflect.DeepEqual(p, p1000) { + t.Fatalf("Sieve(1000) = %v, want %v", p, p1000) + } +} + +func BenchmarkSieve(b *testing.B) { + for i := 0; i < b.N; i++ { + Sieve(1000) + } +} diff --git a/go/sum-of-multiples/README.md b/go/sum-of-multiples/README.md new file mode 100644 index 0000000..a724902 --- /dev/null +++ b/go/sum-of-multiples/README.md @@ -0,0 +1,25 @@ +# Sum Of Multiples + +Write a program that, given a number, can 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 15 that are +multiples of either 3 or 5, we get 3, 5, 6 and 9, 10, and 12. + +The sum of these multiples is 45. + +Write a program that can find the sum of the multiples of a given set of +numbers. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +A variation on Problem 1 at Project Euler [view source](http://projecteuler.net/problem=1) diff --git a/go/sum-of-multiples/sum_of_multiples_test.go b/go/sum-of-multiples/sum_of_multiples_test.go new file mode 100644 index 0000000..c21560d --- /dev/null +++ b/go/sum-of-multiples/sum_of_multiples_test.go @@ -0,0 +1,65 @@ +package summultiples + +import "testing" + +var test35 = []struct { + limit int + sum int +}{ + {1, 0}, + {4, 3}, + {10, 23}, + {1000, 233168}, +} + +var varTests = []struct { + divisors []int + limit int + sum int +}{ + {[]int{7, 13, 17}, 20, 51}, + {[]int{43, 47}, 10000, 2203160}, + {[]int{5, 10, 12}, 10000, 13331672}, + {[]int{1, 1}, 10000, 49995000}, + {[]int{}, 10000, 0}, +} + +func Test35(t *testing.T) { + sum35 := MultipleSummer(3, 5) + for _, test := range test35 { + s := sum35(test.limit) + if s != test.sum { + t.Fatalf("Sum to %d returned %d, want %d.", test.limit, s, test.sum) + } + } +} + +func TestVar(t *testing.T) { + for _, test := range varTests { + sv := MultipleSummer(test.divisors...) + s := sv(test.limit) + if s != test.sum { + t.Fatalf("Sum of multiples of %v to %d returned %d, want %d.", + test.divisors, test.limit, s, test.sum) + } + } +} + +func Benchmark35(b *testing.B) { + sum35 := MultipleSummer(3, 5) + b.ResetTimer() // bench just the sum function + for i := 0; i < b.N; i++ { + for _, test := range test35 { + sum35(test.limit) + } + } +} + +func BenchmarkVar(b *testing.B) { + // bench combined time to bind sum function and call it. + for i := 0; i < b.N; i++ { + for _, test := range varTests { + MultipleSummer(test.divisors...)(test.limit) + } + } +} diff --git a/go/sum-of-multiples/summultiples.go b/go/sum-of-multiples/summultiples.go new file mode 100644 index 0000000..ce479f4 --- /dev/null +++ b/go/sum-of-multiples/summultiples.go @@ -0,0 +1,27 @@ +package summultiples + +// MultipleSummer takes a variable number of ints +// and returns a function that, when given a limit +// returns the sum of the multiples up to that limit +func MultipleSummer(mults ...int) func(int) int { + return func(limit int) int { + var ret int + for i := range mults { + sumMult := mults[i] + for sumMult < limit { + var skip bool + for j := 0; j < i && !skip; j++ { + // Make sure that we haven't already added sumMult + if sumMult%mults[j] == 0 { + skip = true + } + } + if !skip { + ret += sumMult + } + sumMult += mults[i] + } + } + return ret + } +} diff --git a/go/triangle/README.md b/go/triangle/README.md new file mode 100644 index 0000000..1667e45 --- /dev/null +++ b/go/triangle/README.md @@ -0,0 +1,27 @@ +# Triangle + +Write a program that can tell you if a triangle is equilateral, isosceles, or scalene. + +The program should raise an error if the triangle cannot exist. + +Tests are provided, delete one `skip` at a time. + +## Hint + +The sum of the lengths of any two sides of a triangle always exceeds the +length of the third side, a principle known as the _triangle +inequality_. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://help.exercism.io/getting-started-with-go.html). + +## Source + +The Ruby Koans triangle project, parts 1 & 2 [view source](http://rubykoans.com) diff --git a/go/triangle/triangle.go b/go/triangle/triangle.go new file mode 100644 index 0000000..c07013f --- /dev/null +++ b/go/triangle/triangle.go @@ -0,0 +1,30 @@ +package triangle + +// KindFromSides returns what type of triangle has the sides +// of length a, b, and c +func KindFromSides(a, b, c float64) Kind { + if a+b > c && b+c > a && a+c > b { + if a == b && b == c { + return Equ + } + if a == b || b == c || a == c { + return Iso + } + return Sca + } + return NaT +} + +// Kind describes the different types of triangles +type Kind int + +const ( + // Equ - equilateral + Equ = iota + // Iso - isosceles + Iso + // Sca - scalene + Sca + // NaT - not a triangle + NaT +) diff --git a/go/triangle/triangle_test.go b/go/triangle/triangle_test.go new file mode 100644 index 0000000..873f88a --- /dev/null +++ b/go/triangle/triangle_test.go @@ -0,0 +1,66 @@ +package triangle + +import ( + "math" + "testing" +) + +type testCase struct { + want Kind + a, b, c float64 +} + +// basic test cases +var testData = []testCase{ + {Equ, 2, 2, 2}, // same length + {Equ, 10, 10, 10}, // a little bigger + {Iso, 3, 4, 4}, // last two sides equal + {Iso, 4, 3, 4}, // first and last sides equal + {Iso, 4, 4, 3}, // first two sides equal + {Iso, 10, 10, 2}, // again + {Sca, 3, 4, 5}, // no sides equal + {Sca, 10, 11, 12}, // again + {Sca, 5, 4, 2}, // descending order + {Sca, .4, .6, .3}, // small sides + {NaT, 0, 0, 0}, // zero length + {NaT, 3, 4, -5}, // negative length + {NaT, 1, 1, 3}, // fails triangle inequality + {NaT, 2, 4, 2}, // another + {NaT, 7, 3, 2}, // another +} + +// generate cases with NaN and Infs, append to basic cases +func init() { + nan := math.NaN() + pinf := math.Inf(1) + ninf := math.Inf(-1) + nf := make([]testCase, 4*4*4) + i := 0 + for _, a := range []float64{3, nan, pinf, ninf} { + for _, b := range []float64{4, nan, pinf, ninf} { + for _, c := range []float64{5, nan, pinf, ninf} { + nf[i] = testCase{NaT, a, b, c} + i++ + } + } + } + testData = append(testData, nf[1:]...) +} + +func TestKind(t *testing.T) { + for _, test := range testData { + got := KindFromSides(test.a, test.b, test.c) + if got != test.want { + t.Fatalf("Triangle with sides, %g, %g, %g = %v, want %v", + test.a, test.b, test.c, got, test.want) + } + } +} + +func BenchmarkKind(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range testData { + KindFromSides(test.a, test.b, test.c) + } + } +} diff --git a/go/word-count/README.md b/go/word-count/README.md new file mode 100644 index 0000000..9f8fcf6 --- /dev/null +++ b/go/word-count/README.md @@ -0,0 +1,27 @@ +# Word Count + +Write a program that given a phrase can count the occurrences of each word in that phrase. + +For example for the input `"olly olly in come free"` + +```plain +olly: 2 +in: 1 +come: 1 +free: 1 +``` + + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour. [view source]() diff --git a/go/word-count/cases_test.go b/go/word-count/cases_test.go new file mode 100644 index 0000000..204e122 --- /dev/null +++ b/go/word-count/cases_test.go @@ -0,0 +1,41 @@ +package wordcount + +// Source: exercism/x-common +// Commit: 3b07e53 Merge pull request #117 from mikeyjcat/add-raindrops-json + +var testCases = []struct { + description string + input string + output Frequency +}{ + { + "count one word", + "word", + Frequency{"word": 1}, + }, + { + "count one of each word", + "one of each", + Frequency{"each": 1, "of": 1, "one": 1}, + }, + { + "multiple occurrences of a word", + "one fish two fish red fish blue fish", + Frequency{"blue": 1, "fish": 4, "one": 1, "red": 1, "two": 1}, + }, + { + "ignore punctuation", + "car : carpet as java : javascript!!&@$%^&", + Frequency{"as": 1, "car": 1, "carpet": 1, "java": 1, "javascript": 1}, + }, + { + "include numbers", + "testing, 1, 2 testing", + Frequency{"1": 1, "2": 1, "testing": 2}, + }, + { + "normalize case", + "go Go GO", + Frequency{"go": 3}, + }, +} diff --git a/go/word-count/word_count.go b/go/word-count/word_count.go new file mode 100644 index 0000000..081df17 --- /dev/null +++ b/go/word-count/word_count.go @@ -0,0 +1,28 @@ +package wordcount + +import ( + "regexp" + "strings" +) + +// TestVersion is an exercism thing +const TestVersion = 1 + +// Frequency is the return type +type Frequency map[string]int + +// WordCount returns how many of each word in 'phrase' +func WordCount(phrase string) Frequency { + ret := make(Frequency) + words := strings.Split(phrase, " ") + cleanUp, _ := regexp.Compile("[^A-Za-z0-9]") + for _, v := range words { + // The test cases assume that we're stripping non-alphanumeric runes + // and making it lower case + v = strings.ToLower(cleanUp.ReplaceAllString(v, "")) + if v != "" { + ret[v]++ + } + } + return ret +} diff --git a/go/word-count/word_count_test.go b/go/word-count/word_count_test.go new file mode 100644 index 0000000..0f964f7 --- /dev/null +++ b/go/word-count/word_count_test.go @@ -0,0 +1,34 @@ +package wordcount + +import ( + "reflect" + "testing" +) + +const testVersion = 1 + +// Retired testVersions +// (none) 133d626683b18a22f9aa59ad0990c7d0f565291c + +func TestWordCount(t *testing.T) { + if TestVersion != testVersion { + t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion) + } + for _, tt := range testCases { + expected := tt.output + actual := WordCount(tt.input) + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("%s\n\tExpected: %v\n\tGot: %v", tt.description, expected, actual) + } else { + t.Logf("PASS: %s - WordCount(%s)", tt.description, tt.input) + } + } +} + +func BenchmarkWordCount(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, tt := range testCases { + WordCount(tt.input) + } + } +} diff --git a/haskell/current b/haskell/current new file mode 120000 index 0000000..b905e3b --- /dev/null +++ b/haskell/current @@ -0,0 +1 @@ +leap \ No newline at end of file diff --git a/haskell/leap/README.md b/haskell/leap/README.md new file mode 100644 index 0000000..362c564 --- /dev/null +++ b/haskell/leap/README.md @@ -0,0 +1,39 @@ +# Leap + +Write a program that will take a year and report if it is a leap year. + +The tricky thing here is that a leap year occurs: + +```plain +on every year that is evenly divisible by 4 + except every year that is evenly divisible by 100 + unless the year is also evenly divisible by 400 +``` + +For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap +year, but 2000 is. + +If your language provides a method in the standard library that does +this look-up, pretend it doesn't exist and implement it yourself. + +## Notes + +For a delightful, four minute explanation of the whole leap year +phenomenon, go watch [this youtube video][video]. + +[video]: http://www.youtube.com/watch?v=xX96xng7sAE + +Check out [Exercism +Help](http://help.exercism.io/getting-started-with-haskell.html) for +instructions to get started writing Haskell. + +## Running Tests + +Use `runhaskell` (included in the Haskell Platform) to compile and run your +Haskell code. + + $ runhaskell -Wall bob_test.hs + +## Source + +JavaRanch Cattle Drive, exercise 3 [view source](http://www.javaranch.com/leap.jsp) diff --git a/haskell/leap/leap_test.hs b/haskell/leap/leap_test.hs new file mode 100644 index 0000000..0298586 --- /dev/null +++ b/haskell/leap/leap_test.hs @@ -0,0 +1,27 @@ +import Test.HUnit (Assertion, (@=?), runTestTT, Test(..), Counts(..)) +import System.Exit (ExitCode(..), exitWith) +import LeapYear (isLeapYear) + +exitProperly :: IO Counts -> IO () +exitProperly m = do + counts <- m + exitWith $ if failures counts /= 0 || errors counts /= 0 then ExitFailure 1 else ExitSuccess + +testCase :: String -> Assertion -> Test +testCase label assertion = TestLabel label (TestCase assertion) + +main :: IO () +main = exitProperly $ runTestTT $ TestList + [ TestList isLeapYearTests ] + +isLeapYearTests :: [Test] +isLeapYearTests = + [ testCase "vanilla leap year" $ + True @=? isLeapYear 1996 + , testCase "any old year" $ + False @=? isLeapYear 1997 + , testCase "century" $ + False @=? isLeapYear 1900 + , testCase "exceptional century" $ + True @=? isLeapYear 2400 + ] diff --git a/java/anagram/.gradle/2.10/taskArtifacts/cache.properties b/java/anagram/.gradle/2.10/taskArtifacts/cache.properties new file mode 100644 index 0000000..af04242 --- /dev/null +++ b/java/anagram/.gradle/2.10/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Thu Jan 28 06:47:22 CST 2016 diff --git a/java/anagram/.gradle/2.10/taskArtifacts/cache.properties.lock b/java/anagram/.gradle/2.10/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..4305ba1 Binary files /dev/null and b/java/anagram/.gradle/2.10/taskArtifacts/cache.properties.lock differ diff --git a/java/anagram/.gradle/2.10/taskArtifacts/fileHashes.bin b/java/anagram/.gradle/2.10/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..6c3da46 Binary files /dev/null and b/java/anagram/.gradle/2.10/taskArtifacts/fileHashes.bin differ diff --git a/java/anagram/.gradle/2.10/taskArtifacts/fileSnapshots.bin b/java/anagram/.gradle/2.10/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..5cf5f48 Binary files /dev/null and b/java/anagram/.gradle/2.10/taskArtifacts/fileSnapshots.bin differ diff --git a/java/anagram/.gradle/2.10/taskArtifacts/outputFileStates.bin b/java/anagram/.gradle/2.10/taskArtifacts/outputFileStates.bin new file mode 100644 index 0000000..3c3a6b5 Binary files /dev/null and b/java/anagram/.gradle/2.10/taskArtifacts/outputFileStates.bin differ diff --git a/java/anagram/.gradle/2.10/taskArtifacts/taskArtifacts.bin b/java/anagram/.gradle/2.10/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..650f1d1 Binary files /dev/null and b/java/anagram/.gradle/2.10/taskArtifacts/taskArtifacts.bin differ diff --git a/java/anagram/.gradle/2.9/taskArtifacts/cache.properties b/java/anagram/.gradle/2.9/taskArtifacts/cache.properties new file mode 100644 index 0000000..55d2079 --- /dev/null +++ b/java/anagram/.gradle/2.9/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Fri Nov 20 13:11:51 CST 2015 diff --git a/java/anagram/.gradle/2.9/taskArtifacts/cache.properties.lock b/java/anagram/.gradle/2.9/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..6670b4e Binary files /dev/null and b/java/anagram/.gradle/2.9/taskArtifacts/cache.properties.lock differ diff --git a/java/anagram/.gradle/2.9/taskArtifacts/fileHashes.bin b/java/anagram/.gradle/2.9/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..2ad9089 Binary files /dev/null and b/java/anagram/.gradle/2.9/taskArtifacts/fileHashes.bin differ diff --git a/java/anagram/.gradle/2.9/taskArtifacts/fileSnapshots.bin b/java/anagram/.gradle/2.9/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..7b8a0fe Binary files /dev/null and b/java/anagram/.gradle/2.9/taskArtifacts/fileSnapshots.bin differ diff --git a/java/anagram/.gradle/2.9/taskArtifacts/outputFileStates.bin b/java/anagram/.gradle/2.9/taskArtifacts/outputFileStates.bin new file mode 100644 index 0000000..ed9b314 Binary files /dev/null and b/java/anagram/.gradle/2.9/taskArtifacts/outputFileStates.bin differ diff --git a/java/anagram/.gradle/2.9/taskArtifacts/taskArtifacts.bin b/java/anagram/.gradle/2.9/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..74d81e4 Binary files /dev/null and b/java/anagram/.gradle/2.9/taskArtifacts/taskArtifacts.bin differ diff --git a/java/anagram/README.md b/java/anagram/README.md new file mode 100644 index 0000000..306d038 --- /dev/null +++ b/java/anagram/README.md @@ -0,0 +1,11 @@ +# Anagram +Write a program that, given a word and a list of possible anagrams, selects the correct sublist. + +Given `"listen"` and a list of candidates like `"enlists" "google" +"inlets" "banana"` the program should return a list containing +`"inlets"`. + + +## Source + +Inspired by the Extreme Startup game [view source](https://github.com/rchatley/extreme_startup) diff --git a/java/anagram/build.gradle b/java/anagram/build.gradle new file mode 100644 index 0000000..9af8b0b --- /dev/null +++ b/java/anagram/build.gradle @@ -0,0 +1,11 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.10" +} diff --git a/java/anagram/build/classes/main/Anagram.class b/java/anagram/build/classes/main/Anagram.class new file mode 100644 index 0000000..e481342 Binary files /dev/null and b/java/anagram/build/classes/main/Anagram.class differ diff --git a/java/anagram/build/classes/test/AnagramTest.class b/java/anagram/build/classes/test/AnagramTest.class new file mode 100644 index 0000000..14e6261 Binary files /dev/null and b/java/anagram/build/classes/test/AnagramTest.class differ diff --git a/java/anagram/build/libs/anagram.jar b/java/anagram/build/libs/anagram.jar new file mode 100644 index 0000000..5589eca Binary files /dev/null and b/java/anagram/build/libs/anagram.jar differ diff --git a/java/anagram/build/reports/tests/classes/AnagramTest.html b/java/anagram/build/reports/tests/classes/AnagramTest.html new file mode 100644 index 0000000..291f81a --- /dev/null +++ b/java/anagram/build/reports/tests/classes/AnagramTest.html @@ -0,0 +1,141 @@ + + + + + +Test results - Class AnagramTest + + + + + +
+

Class AnagramTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
10
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.006s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
testAnagramsAreCaseInsensitive0.001spassed
testDetectAnagrams0spassed
testDetectMultipleAnagrams0spassed
testDoesNotConfuseDifferentDuplicates0.001spassed
testEliminateAnagramSubsets0spassed
testEliminateAnagramsWithSameChecksum0spassed
testIdenticalWordIsNotAnagram0spassed
testMultipleAnagrams0spassed
testNoMatches0spassed
testSimpleAnagram0.004spassed
+
+
+ +
+ + diff --git a/java/anagram/build/reports/tests/css/base-style.css b/java/anagram/build/reports/tests/css/base-style.css new file mode 100644 index 0000000..4afa73e --- /dev/null +++ b/java/anagram/build/reports/tests/css/base-style.css @@ -0,0 +1,179 @@ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; + font-size: 12pt; +} + +body, a, a:visited { + color: #303030; +} + +#content { + padding-left: 50px; + padding-right: 50px; + padding-top: 30px; + padding-bottom: 30px; +} + +#content h1 { + font-size: 160%; + margin-bottom: 10px; +} + +#footer { + margin-top: 100px; + font-size: 80%; + white-space: nowrap; +} + +#footer, #footer a { + color: #a0a0a0; +} + +#line-wrapping-toggle { + vertical-align: middle; +} + +#label-for-line-wrapping-toggle { + vertical-align: middle; +} + +ul { + margin-left: 0; +} + +h1, h2, h3 { + white-space: nowrap; +} + +h2 { + font-size: 120%; +} + +ul.tabLinks { + padding-left: 0; + padding-top: 10px; + padding-bottom: 10px; + overflow: auto; + min-width: 800px; + width: auto !important; + width: 800px; +} + +ul.tabLinks li { + float: left; + height: 100%; + list-style: none; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + -moz-border-radius: 7px; + border-radius: 7px; + margin-right: 25px; + border: solid 1px #d4d4d4; + background-color: #f0f0f0; +} + +ul.tabLinks li:hover { + background-color: #fafafa; +} + +ul.tabLinks li.selected { + background-color: #c5f0f5; + border-color: #c5f0f5; +} + +ul.tabLinks a { + font-size: 120%; + display: block; + outline: none; + text-decoration: none; + margin: 0; + padding: 0; +} + +ul.tabLinks li h2 { + margin: 0; + padding: 0; +} + +div.tab { +} + +div.selected { + display: block; +} + +div.deselected { + display: none; +} + +div.tab table { + min-width: 350px; + width: auto !important; + width: 350px; + border-collapse: collapse; +} + +div.tab th, div.tab table { + border-bottom: solid #d0d0d0 1px; +} + +div.tab th { + text-align: left; + white-space: nowrap; + padding-left: 6em; +} + +div.tab th:first-child { + padding-left: 0; +} + +div.tab td { + white-space: nowrap; + padding-left: 6em; + padding-top: 5px; + padding-bottom: 5px; +} + +div.tab td:first-child { + padding-left: 0; +} + +div.tab td.numeric, div.tab th.numeric { + text-align: right; +} + +span.code { + display: inline-block; + margin-top: 0em; + margin-bottom: 1em; +} + +span.code pre { + font-size: 11pt; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin: 0; + background-color: #f7f7f7; + border: solid 1px #d0d0d0; + min-width: 700px; + width: auto !important; + width: 700px; +} + +span.wrapped pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +label.hidden { + display: none; +} \ No newline at end of file diff --git a/java/anagram/build/reports/tests/css/style.css b/java/anagram/build/reports/tests/css/style.css new file mode 100644 index 0000000..3dc4913 --- /dev/null +++ b/java/anagram/build/reports/tests/css/style.css @@ -0,0 +1,84 @@ + +#summary { + margin-top: 30px; + margin-bottom: 40px; +} + +#summary table { + border-collapse: collapse; +} + +#summary td { + vertical-align: top; +} + +.breadcrumbs, .breadcrumbs a { + color: #606060; +} + +.infoBox { + width: 110px; + padding-top: 15px; + padding-bottom: 15px; + text-align: center; +} + +.infoBox p { + margin: 0; +} + +.counter, .percent { + font-size: 120%; + font-weight: bold; + margin-bottom: 8px; +} + +#duration { + width: 125px; +} + +#successRate, .summaryGroup { + border: solid 2px #d0d0d0; + -moz-border-radius: 10px; + border-radius: 10px; +} + +#successRate { + width: 140px; + margin-left: 35px; +} + +#successRate .percent { + font-size: 180%; +} + +.success, .success a { + color: #008000; +} + +div.success, #successRate.success { + background-color: #bbd9bb; + border-color: #008000; +} + +.failures, .failures a { + color: #b60808; +} + +.skipped, .skipped a { + color: #c09853; +} + +div.failures, #successRate.failures { + background-color: #ecdada; + border-color: #b60808; +} + +ul.linkList { + padding-left: 0; +} + +ul.linkList li { + list-style: none; + margin-bottom: 5px; +} diff --git a/java/anagram/build/reports/tests/index.html b/java/anagram/build/reports/tests/index.html new file mode 100644 index 0000000..560d1bf --- /dev/null +++ b/java/anagram/build/reports/tests/index.html @@ -0,0 +1,132 @@ + + + + + +Test results - Test Summary + + + + + +
+

Test Summary

+
+ + + + + +
+
+ + + + + + + +
+
+
10
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.006s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Packages

+ + + + + + + + + + + + + + + + + + + + + +
PackageTestsFailuresIgnoredDurationSuccess rate
+default-package +10000.006s100%
+
+
+

Classes

+ + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+AnagramTest +10000.006s100%
+
+
+ +
+ + diff --git a/java/anagram/build/reports/tests/js/report.js b/java/anagram/build/reports/tests/js/report.js new file mode 100644 index 0000000..83bab4a --- /dev/null +++ b/java/anagram/build/reports/tests/js/report.js @@ -0,0 +1,194 @@ +(function (window, document) { + "use strict"; + + var tabs = {}; + + function changeElementClass(element, classValue) { + if (element.getAttribute("className")) { + element.setAttribute("className", classValue); + } else { + element.setAttribute("class", classValue); + } + } + + function getClassAttribute(element) { + if (element.getAttribute("className")) { + return element.getAttribute("className"); + } else { + return element.getAttribute("class"); + } + } + + function addClass(element, classValue) { + changeElementClass(element, getClassAttribute(element) + " " + classValue); + } + + function removeClass(element, classValue) { + changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + } + + function initTabs() { + var container = document.getElementById("tabs"); + + tabs.tabs = findTabs(container); + tabs.titles = findTitles(tabs.tabs); + tabs.headers = findHeaders(container); + tabs.select = select; + tabs.deselectAll = deselectAll; + tabs.select(0); + + return true; + } + + function getCheckBox() { + return document.getElementById("line-wrapping-toggle"); + } + + function getLabelForCheckBox() { + return document.getElementById("label-for-line-wrapping-toggle"); + } + + function findCodeBlocks() { + var spans = document.getElementById("tabs").getElementsByTagName("span"); + var codeBlocks = []; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].className.indexOf("code") >= 0) { + codeBlocks.push(spans[i]); + } + } + return codeBlocks; + } + + function forAllCodeBlocks(operation) { + var codeBlocks = findCodeBlocks(); + + for (var i = 0; i < codeBlocks.length; ++i) { + operation(codeBlocks[i], "wrapped"); + } + } + + function toggleLineWrapping() { + var checkBox = getCheckBox(); + + if (checkBox.checked) { + forAllCodeBlocks(addClass); + } else { + forAllCodeBlocks(removeClass); + } + } + + function initControls() { + if (findCodeBlocks().length > 0) { + var checkBox = getCheckBox(); + var label = getLabelForCheckBox(); + + checkBox.onclick = toggleLineWrapping; + checkBox.checked = false; + + removeClass(label, "hidden"); + } + } + + function switchTab() { + var id = this.id.substr(1); + + for (var i = 0; i < tabs.tabs.length; i++) { + if (tabs.tabs[i].id === id) { + tabs.select(i); + break; + } + } + + return false; + } + + function select(i) { + this.deselectAll(); + + changeElementClass(this.tabs[i], "tab selected"); + changeElementClass(this.headers[i], "selected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var h2 = document.createElement("H2"); + + h2.appendChild(document.createTextNode(this.titles[i])); + this.headers[i].appendChild(h2); + } + + function deselectAll() { + for (var i = 0; i < this.tabs.length; i++) { + changeElementClass(this.tabs[i], "tab deselected"); + changeElementClass(this.headers[i], "deselected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var a = document.createElement("A"); + + a.setAttribute("id", "ltab" + i); + a.setAttribute("href", "#tab" + i); + a.onclick = switchTab; + a.appendChild(document.createTextNode(this.titles[i])); + + this.headers[i].appendChild(a); + } + } + + function findTabs(container) { + return findChildElements(container, "DIV", "tab"); + } + + function findHeaders(container) { + var owner = findChildElements(container, "UL", "tabLinks"); + return findChildElements(owner[0], "LI", null); + } + + function findTitles(tabs) { + var titles = []; + + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + var header = findChildElements(tab, "H2", null)[0]; + + header.parentNode.removeChild(header); + + if (header.innerText) { + titles.push(header.innerText); + } else { + titles.push(header.textContent); + } + } + + return titles; + } + + function findChildElements(container, name, targetClass) { + var elements = []; + var children = container.childNodes; + + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + + if (child.nodeType === 1 && child.nodeName === name) { + if (targetClass && child.className.indexOf(targetClass) < 0) { + continue; + } + + elements.push(child); + } + } + + return elements; + } + + // Entry point. + + window.onload = function() { + initTabs(); + initControls(); + }; +} (window, window.document)); \ No newline at end of file diff --git a/java/anagram/build/reports/tests/packages/default-package.html b/java/anagram/build/reports/tests/packages/default-package.html new file mode 100644 index 0000000..d5fa760 --- /dev/null +++ b/java/anagram/build/reports/tests/packages/default-package.html @@ -0,0 +1,103 @@ + + + + + +Test results - Default package + + + + + +
+

Default package

+ +
+ + + + + +
+
+ + + + + + + +
+
+
10
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.006s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+AnagramTest +10000.006s100%
+
+
+ +
+ + diff --git a/java/anagram/build/test-results/TEST-AnagramTest.xml b/java/anagram/build/test-results/TEST-AnagramTest.xml new file mode 100644 index 0000000..11406ee --- /dev/null +++ b/java/anagram/build/test-results/TEST-AnagramTest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/java/anagram/build/test-results/binary/test/output.bin b/java/anagram/build/test-results/binary/test/output.bin new file mode 100644 index 0000000..e69de29 diff --git a/java/anagram/build/test-results/binary/test/output.bin.idx b/java/anagram/build/test-results/binary/test/output.bin.idx new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/java/anagram/build/test-results/binary/test/output.bin.idx differ diff --git a/java/anagram/build/test-results/binary/test/results.bin b/java/anagram/build/test-results/binary/test/results.bin new file mode 100644 index 0000000..feb0e2c Binary files /dev/null and b/java/anagram/build/test-results/binary/test/results.bin differ diff --git a/java/anagram/build/tmp/jar/MANIFEST.MF b/java/anagram/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/java/anagram/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/java/anagram/src/main/java/.keep b/java/anagram/src/main/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/anagram/src/main/java/Anagram.java b/java/anagram/src/main/java/Anagram.java new file mode 100644 index 0000000..21fd44c --- /dev/null +++ b/java/anagram/src/main/java/Anagram.java @@ -0,0 +1,71 @@ +import java.util.*; + +/** + * Anagram will give you anagram info about a word + */ +public class Anagram { + String word; + Map map; + + public Anagram(String w) { + this.word = w; + this.map = generateCharMap(this.word); + } + + public List match(List matchWords) { + List ret = new ArrayList(); + Map myWordMap = this.generateCharMap(this.word); + for(int i = 0; i < matchWords.size(); i++) { + // Must have the same number of characters + String tstWord = matchWords.get(i); + if(tstWord.length() != this.word.length()) { + continue; + } + + if(this.isAnagram(tstWord)) { + ret.add(matchWords.get(i)); + } + } + return ret; + } + + private boolean isAnagram(String tst) { + Map tstMap = new HashMap(this.map); + boolean ret = true; + tst = tst.toLowerCase(); + if(tst.equals(this.word.toLowerCase())) { + return false; + } + for(int i = 0; i < tst.toCharArray().length; i++) { + if(tstMap.containsKey(tst.toCharArray()[i])) { + int left = tstMap.get(tst.toCharArray()[i]); + if(left <= 0) { + ret = false; + } else { + left--; + tstMap.put(tst.toCharArray()[i], left); + } + } else { + ret = false; + } + if(!ret) { + // If ret ever hits false, we're done. + break; + } + } + return ret; + } + + private Map generateCharMap(String wrd) { + Map wordMap = new HashMap(); + for(int i = 0; i < this.word.toCharArray().length; i++) { + Character tst = this.word.toCharArray()[i]; + tst = Character.toLowerCase(tst); + if(!wordMap.containsKey(tst)) { + wordMap.put(tst, 0); + } + wordMap.put(tst, wordMap.get(tst)+1); + } + return wordMap; + } +} diff --git a/java/anagram/src/test/java/AnagramTest.java b/java/anagram/src/test/java/AnagramTest.java new file mode 100644 index 0000000..c619154 --- /dev/null +++ b/java/anagram/src/test/java/AnagramTest.java @@ -0,0 +1,77 @@ +import static org.hamcrest.CoreMatchers.*; +import static org.junit.matchers.JUnitMatchers.*; +import static org.junit.Assert.*; + +import java.util.*; +import org.junit.*; + +public class AnagramTest { + + @Test + public void testNoMatches() { + Anagram detector = new Anagram("diaper"); + assertTrue(detector.match(Arrays.asList("hello", "world", "zombies", "pants")).isEmpty()); + } + + @Test + public void testSimpleAnagram() { + Anagram detector = new Anagram("ant"); + List anagram = detector.match(Arrays.asList("tan", "stand", "at")); + assertThat(anagram, hasItems("tan")); + } + + @Test + public void testDetectMultipleAnagrams() { + Anagram detector = new Anagram("master"); + List anagrams = detector.match(Arrays.asList("stream", "pigeon", "maters")); + assertThat(anagrams, hasItems("maters", "stream")); + } + + @Test + public void testDoesNotConfuseDifferentDuplicates() { + Anagram detector = new Anagram("galea"); + List anagrams = detector.match(Arrays.asList("eagle")); + assertTrue(anagrams.isEmpty()); + } + + @Test + public void testIdenticalWordIsNotAnagram() { + Anagram detector = new Anagram("corn"); + List anagrams = detector.match(Arrays.asList("corn", "dark", "Corn", "rank", "CORN", "cron", "park")); + assertEquals(anagrams, Arrays.asList("cron")); + } + + @Test + public void testEliminateAnagramsWithSameChecksum() { + Anagram detector = new Anagram("mass"); + assertTrue(detector.match(Arrays.asList("last")).isEmpty()); + } + + @Test + public void testEliminateAnagramSubsets() { + Anagram detector = new Anagram("good"); + assertTrue(detector.match(Arrays.asList("dog", "goody")).isEmpty()); + } + + @Test + public void testDetectAnagrams() { + Anagram detector = new Anagram("listen"); + List anagrams = detector.match(Arrays.asList("enlists", "google", "inlets", "banana")); + assertThat(anagrams, hasItems("inlets")); + } + + @Test + public void testMultipleAnagrams() { + Anagram detector = new Anagram("allergy"); + List anagrams = detector.match(Arrays.asList("gallery", "ballerina", "regally", "clergy", "largely", "leading")); + assertThat(anagrams, hasItems("gallery", "largely", "regally")); + } + + @Test + public void testAnagramsAreCaseInsensitive() { + Anagram detector = new Anagram("Orchestra"); + List anagrams = detector.match(Arrays.asList("cashregister", "Carthorse", "radishes")); + assertThat(anagrams, hasItems("Carthorse")); + } + +} diff --git a/java/current b/java/current new file mode 120000 index 0000000..547c5c3 --- /dev/null +++ b/java/current @@ -0,0 +1 @@ +hamming \ No newline at end of file diff --git a/java/etl/.gradle/2.9/taskArtifacts/cache.properties b/java/etl/.gradle/2.9/taskArtifacts/cache.properties new file mode 100644 index 0000000..e771cc8 --- /dev/null +++ b/java/etl/.gradle/2.9/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Thu Nov 19 21:34:57 CST 2015 diff --git a/java/etl/.gradle/2.9/taskArtifacts/cache.properties.lock b/java/etl/.gradle/2.9/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..258ec48 Binary files /dev/null and b/java/etl/.gradle/2.9/taskArtifacts/cache.properties.lock differ diff --git a/java/etl/.gradle/2.9/taskArtifacts/fileHashes.bin b/java/etl/.gradle/2.9/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..82be836 Binary files /dev/null and b/java/etl/.gradle/2.9/taskArtifacts/fileHashes.bin differ diff --git a/java/etl/.gradle/2.9/taskArtifacts/fileSnapshots.bin b/java/etl/.gradle/2.9/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..74c6a01 Binary files /dev/null and b/java/etl/.gradle/2.9/taskArtifacts/fileSnapshots.bin differ diff --git a/java/etl/.gradle/2.9/taskArtifacts/outputFileStates.bin b/java/etl/.gradle/2.9/taskArtifacts/outputFileStates.bin new file mode 100644 index 0000000..1c23b93 Binary files /dev/null and b/java/etl/.gradle/2.9/taskArtifacts/outputFileStates.bin differ diff --git a/java/etl/.gradle/2.9/taskArtifacts/taskArtifacts.bin b/java/etl/.gradle/2.9/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..88aa4be Binary files /dev/null and b/java/etl/.gradle/2.9/taskArtifacts/taskArtifacts.bin differ diff --git a/java/etl/README.md b/java/etl/README.md new file mode 100644 index 0000000..77c0b7e --- /dev/null +++ b/java/etl/README.md @@ -0,0 +1,53 @@ +# Etl + +We are going to do the `Transform` step of an Extract-Transform-Load. + +### ETL +Extract-Transform-Load (ETL) is a fancy way of saying, "We have some crufty, legacy data over in this system, and now we need it in this shiny new system over here, so +we're going to migrate this." + +(Typically, this is followed by, "We're only going to need to run this +once." That's then typically followed by much forehead slapping and +moaning about how stupid we could possibly be.) + +### The goal +We're going to extract some scrabble scores from a legacy system. + +The old system stored a list of letters per score: + +- 1 point: "A", "E", "I", "O", "U", "L", "N", "R", "S", "T", +- 2 points: "D", "G", +- 3 points: "B", "C", "M", "P", +- 4 points: "F", "H", "V", "W", "Y", +- 5 points: "K", +- 8 points: "J", "X", +- 10 points: "Q", "Z", + +The shiny new scrabble system instead stores the score per letter, which +makes it much faster and easier to calculate the score for a word. It +also stores the letters in lower-case regardless of the case of the +input letters: + +- "a" is worth 1 point. +- "b" is worth 3 points. +- "c" is worth 3 points. +- "d" is worth 2 points. +- Etc. + +Your mission, should you choose to accept it, is to write a program that +transforms the legacy data format to the shiny new format. + +### Notes +Note that both the old and the new system use strings to represent +letters, even in languages that have a separate data type for +characters. + +A final note about scoring, Scrabble is played around the world in a +variety of languages, each with its own unique scoring table. For +example, an "A" is scored at 14 in the Basque-language version of the +game while being scored at 9 in the Latin-language version. + + +## Source + +The Jumpstart Lab team [view source](http://jumpstartlab.com) diff --git a/java/etl/build.gradle b/java/etl/build.gradle new file mode 100644 index 0000000..547aa48 --- /dev/null +++ b/java/etl/build.gradle @@ -0,0 +1,13 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.10" + testCompile "org.easytesting:fest-assert-core:2.0M10" + testCompile "com.google.guava:guava:16+" +} diff --git a/java/etl/build/classes/main/Etl.class b/java/etl/build/classes/main/Etl.class new file mode 100644 index 0000000..85ba134 Binary files /dev/null and b/java/etl/build/classes/main/Etl.class differ diff --git a/java/etl/build/classes/test/EtlTest.class b/java/etl/build/classes/test/EtlTest.class new file mode 100644 index 0000000..ab03c76 Binary files /dev/null and b/java/etl/build/classes/test/EtlTest.class differ diff --git a/java/etl/build/libs/etl.jar b/java/etl/build/libs/etl.jar new file mode 100644 index 0000000..6950470 Binary files /dev/null and b/java/etl/build/libs/etl.jar differ diff --git a/java/etl/build/reports/tests/classes/EtlTest.html b/java/etl/build/reports/tests/classes/EtlTest.html new file mode 100644 index 0000000..18b8784 --- /dev/null +++ b/java/etl/build/reports/tests/classes/EtlTest.html @@ -0,0 +1,111 @@ + + + + + +Test results - Class EtlTest + + + + + +
+

Class EtlTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
4
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.038s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
testFullDataset0.008spassed
testMoreKeys0.001spassed
testTransformMoreValues0spassed
testTransformOneValue0.029spassed
+
+
+ +
+ + diff --git a/java/etl/build/reports/tests/css/base-style.css b/java/etl/build/reports/tests/css/base-style.css new file mode 100644 index 0000000..4afa73e --- /dev/null +++ b/java/etl/build/reports/tests/css/base-style.css @@ -0,0 +1,179 @@ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; + font-size: 12pt; +} + +body, a, a:visited { + color: #303030; +} + +#content { + padding-left: 50px; + padding-right: 50px; + padding-top: 30px; + padding-bottom: 30px; +} + +#content h1 { + font-size: 160%; + margin-bottom: 10px; +} + +#footer { + margin-top: 100px; + font-size: 80%; + white-space: nowrap; +} + +#footer, #footer a { + color: #a0a0a0; +} + +#line-wrapping-toggle { + vertical-align: middle; +} + +#label-for-line-wrapping-toggle { + vertical-align: middle; +} + +ul { + margin-left: 0; +} + +h1, h2, h3 { + white-space: nowrap; +} + +h2 { + font-size: 120%; +} + +ul.tabLinks { + padding-left: 0; + padding-top: 10px; + padding-bottom: 10px; + overflow: auto; + min-width: 800px; + width: auto !important; + width: 800px; +} + +ul.tabLinks li { + float: left; + height: 100%; + list-style: none; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + -moz-border-radius: 7px; + border-radius: 7px; + margin-right: 25px; + border: solid 1px #d4d4d4; + background-color: #f0f0f0; +} + +ul.tabLinks li:hover { + background-color: #fafafa; +} + +ul.tabLinks li.selected { + background-color: #c5f0f5; + border-color: #c5f0f5; +} + +ul.tabLinks a { + font-size: 120%; + display: block; + outline: none; + text-decoration: none; + margin: 0; + padding: 0; +} + +ul.tabLinks li h2 { + margin: 0; + padding: 0; +} + +div.tab { +} + +div.selected { + display: block; +} + +div.deselected { + display: none; +} + +div.tab table { + min-width: 350px; + width: auto !important; + width: 350px; + border-collapse: collapse; +} + +div.tab th, div.tab table { + border-bottom: solid #d0d0d0 1px; +} + +div.tab th { + text-align: left; + white-space: nowrap; + padding-left: 6em; +} + +div.tab th:first-child { + padding-left: 0; +} + +div.tab td { + white-space: nowrap; + padding-left: 6em; + padding-top: 5px; + padding-bottom: 5px; +} + +div.tab td:first-child { + padding-left: 0; +} + +div.tab td.numeric, div.tab th.numeric { + text-align: right; +} + +span.code { + display: inline-block; + margin-top: 0em; + margin-bottom: 1em; +} + +span.code pre { + font-size: 11pt; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin: 0; + background-color: #f7f7f7; + border: solid 1px #d0d0d0; + min-width: 700px; + width: auto !important; + width: 700px; +} + +span.wrapped pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +label.hidden { + display: none; +} \ No newline at end of file diff --git a/java/etl/build/reports/tests/css/style.css b/java/etl/build/reports/tests/css/style.css new file mode 100644 index 0000000..3dc4913 --- /dev/null +++ b/java/etl/build/reports/tests/css/style.css @@ -0,0 +1,84 @@ + +#summary { + margin-top: 30px; + margin-bottom: 40px; +} + +#summary table { + border-collapse: collapse; +} + +#summary td { + vertical-align: top; +} + +.breadcrumbs, .breadcrumbs a { + color: #606060; +} + +.infoBox { + width: 110px; + padding-top: 15px; + padding-bottom: 15px; + text-align: center; +} + +.infoBox p { + margin: 0; +} + +.counter, .percent { + font-size: 120%; + font-weight: bold; + margin-bottom: 8px; +} + +#duration { + width: 125px; +} + +#successRate, .summaryGroup { + border: solid 2px #d0d0d0; + -moz-border-radius: 10px; + border-radius: 10px; +} + +#successRate { + width: 140px; + margin-left: 35px; +} + +#successRate .percent { + font-size: 180%; +} + +.success, .success a { + color: #008000; +} + +div.success, #successRate.success { + background-color: #bbd9bb; + border-color: #008000; +} + +.failures, .failures a { + color: #b60808; +} + +.skipped, .skipped a { + color: #c09853; +} + +div.failures, #successRate.failures { + background-color: #ecdada; + border-color: #b60808; +} + +ul.linkList { + padding-left: 0; +} + +ul.linkList li { + list-style: none; + margin-bottom: 5px; +} diff --git a/java/etl/build/reports/tests/index.html b/java/etl/build/reports/tests/index.html new file mode 100644 index 0000000..7d64685 --- /dev/null +++ b/java/etl/build/reports/tests/index.html @@ -0,0 +1,132 @@ + + + + + +Test results - Test Summary + + + + + +
+

Test Summary

+
+ + + + + +
+
+ + + + + + + +
+
+
4
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.038s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Packages

+ + + + + + + + + + + + + + + + + + + + + +
PackageTestsFailuresIgnoredDurationSuccess rate
+default-package +4000.038s100%
+
+
+

Classes

+ + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+EtlTest +4000.038s100%
+
+
+ +
+ + diff --git a/java/etl/build/reports/tests/js/report.js b/java/etl/build/reports/tests/js/report.js new file mode 100644 index 0000000..83bab4a --- /dev/null +++ b/java/etl/build/reports/tests/js/report.js @@ -0,0 +1,194 @@ +(function (window, document) { + "use strict"; + + var tabs = {}; + + function changeElementClass(element, classValue) { + if (element.getAttribute("className")) { + element.setAttribute("className", classValue); + } else { + element.setAttribute("class", classValue); + } + } + + function getClassAttribute(element) { + if (element.getAttribute("className")) { + return element.getAttribute("className"); + } else { + return element.getAttribute("class"); + } + } + + function addClass(element, classValue) { + changeElementClass(element, getClassAttribute(element) + " " + classValue); + } + + function removeClass(element, classValue) { + changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + } + + function initTabs() { + var container = document.getElementById("tabs"); + + tabs.tabs = findTabs(container); + tabs.titles = findTitles(tabs.tabs); + tabs.headers = findHeaders(container); + tabs.select = select; + tabs.deselectAll = deselectAll; + tabs.select(0); + + return true; + } + + function getCheckBox() { + return document.getElementById("line-wrapping-toggle"); + } + + function getLabelForCheckBox() { + return document.getElementById("label-for-line-wrapping-toggle"); + } + + function findCodeBlocks() { + var spans = document.getElementById("tabs").getElementsByTagName("span"); + var codeBlocks = []; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].className.indexOf("code") >= 0) { + codeBlocks.push(spans[i]); + } + } + return codeBlocks; + } + + function forAllCodeBlocks(operation) { + var codeBlocks = findCodeBlocks(); + + for (var i = 0; i < codeBlocks.length; ++i) { + operation(codeBlocks[i], "wrapped"); + } + } + + function toggleLineWrapping() { + var checkBox = getCheckBox(); + + if (checkBox.checked) { + forAllCodeBlocks(addClass); + } else { + forAllCodeBlocks(removeClass); + } + } + + function initControls() { + if (findCodeBlocks().length > 0) { + var checkBox = getCheckBox(); + var label = getLabelForCheckBox(); + + checkBox.onclick = toggleLineWrapping; + checkBox.checked = false; + + removeClass(label, "hidden"); + } + } + + function switchTab() { + var id = this.id.substr(1); + + for (var i = 0; i < tabs.tabs.length; i++) { + if (tabs.tabs[i].id === id) { + tabs.select(i); + break; + } + } + + return false; + } + + function select(i) { + this.deselectAll(); + + changeElementClass(this.tabs[i], "tab selected"); + changeElementClass(this.headers[i], "selected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var h2 = document.createElement("H2"); + + h2.appendChild(document.createTextNode(this.titles[i])); + this.headers[i].appendChild(h2); + } + + function deselectAll() { + for (var i = 0; i < this.tabs.length; i++) { + changeElementClass(this.tabs[i], "tab deselected"); + changeElementClass(this.headers[i], "deselected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var a = document.createElement("A"); + + a.setAttribute("id", "ltab" + i); + a.setAttribute("href", "#tab" + i); + a.onclick = switchTab; + a.appendChild(document.createTextNode(this.titles[i])); + + this.headers[i].appendChild(a); + } + } + + function findTabs(container) { + return findChildElements(container, "DIV", "tab"); + } + + function findHeaders(container) { + var owner = findChildElements(container, "UL", "tabLinks"); + return findChildElements(owner[0], "LI", null); + } + + function findTitles(tabs) { + var titles = []; + + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + var header = findChildElements(tab, "H2", null)[0]; + + header.parentNode.removeChild(header); + + if (header.innerText) { + titles.push(header.innerText); + } else { + titles.push(header.textContent); + } + } + + return titles; + } + + function findChildElements(container, name, targetClass) { + var elements = []; + var children = container.childNodes; + + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + + if (child.nodeType === 1 && child.nodeName === name) { + if (targetClass && child.className.indexOf(targetClass) < 0) { + continue; + } + + elements.push(child); + } + } + + return elements; + } + + // Entry point. + + window.onload = function() { + initTabs(); + initControls(); + }; +} (window, window.document)); \ No newline at end of file diff --git a/java/etl/build/reports/tests/packages/default-package.html b/java/etl/build/reports/tests/packages/default-package.html new file mode 100644 index 0000000..0fa1cea --- /dev/null +++ b/java/etl/build/reports/tests/packages/default-package.html @@ -0,0 +1,103 @@ + + + + + +Test results - Default package + + + + + +
+

Default package

+ +
+ + + + + +
+
+ + + + + + + +
+
+
4
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.038s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+EtlTest +4000.038s100%
+
+
+ +
+ + diff --git a/java/etl/build/test-results/TEST-EtlTest.xml b/java/etl/build/test-results/TEST-EtlTest.xml new file mode 100644 index 0000000..e229009 --- /dev/null +++ b/java/etl/build/test-results/TEST-EtlTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/java/etl/build/test-results/binary/test/output.bin b/java/etl/build/test-results/binary/test/output.bin new file mode 100644 index 0000000..e69de29 diff --git a/java/etl/build/test-results/binary/test/output.bin.idx b/java/etl/build/test-results/binary/test/output.bin.idx new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/java/etl/build/test-results/binary/test/output.bin.idx differ diff --git a/java/etl/build/test-results/binary/test/results.bin b/java/etl/build/test-results/binary/test/results.bin new file mode 100644 index 0000000..62751a7 Binary files /dev/null and b/java/etl/build/test-results/binary/test/results.bin differ diff --git a/java/etl/build/tmp/jar/MANIFEST.MF b/java/etl/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/java/etl/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/java/etl/src/main/java/.keep b/java/etl/src/main/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/etl/src/main/java/Etl.java b/java/etl/src/main/java/Etl.java new file mode 100644 index 0000000..1f58858 --- /dev/null +++ b/java/etl/src/main/java/Etl.java @@ -0,0 +1,15 @@ +import java.util.*; + +// Etl transforms a scrabble score set from the old data structure +// To the new. +public class Etl { + public Map transform(Map> old) { + Map ret = new HashMap(); + for (Map.Entry> entry : old.entrySet()) { + for (int i = 0; i < entry.getValue().size(); i++) { + ret.put(entry.getValue().get(i).toLowerCase(), entry.getKey()); + } + } + return ret; + } +} diff --git a/java/etl/src/test/java/.keep b/java/etl/src/test/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/etl/src/test/java/EtlTest.java b/java/etl/src/test/java/EtlTest.java new file mode 100644 index 0000000..eac85ec --- /dev/null +++ b/java/etl/src/test/java/EtlTest.java @@ -0,0 +1,74 @@ +import com.google.common.collect.ImmutableMap; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.fest.assertions.api.Assertions.assertThat; + +public class EtlTest { + private final Etl etl = new Etl(); + + @Test + public void testTransformOneValue() { + Map> old = ImmutableMap.of(1, Arrays.asList("A")); + Map expected = ImmutableMap.of("a", 1); + + assertThat(etl.transform(old)).isEqualTo(expected); + } + + @Test + public void testTransformMoreValues() { + Map> old = ImmutableMap.of( + 1, Arrays.asList("A", "E", "I", "O", "U") + ); + Map expected = ImmutableMap.of( + "a", 1, + "e", 1, + "i", 1, + "o", 1, + "u", 1 + ); + + assertThat(etl.transform(old)).isEqualTo(expected); + } + + @Test + public void testMoreKeys() { + Map> old = ImmutableMap.of( + 1, Arrays.asList("A", "E"), + 2, Arrays.asList("D", "G") + ); + Map expected = ImmutableMap.of( + "a", 1, + "e", 1, + "d", 2, + "g", 2 + ); + + assertThat(etl.transform(old)).isEqualTo(expected); + } + + @Test + public void testFullDataset() { + Map> old = ImmutableMap.>builder(). + put(1, Arrays.asList("A", "E", "I", "O", "U", "L", "N", "R", "S", "T")). + put(2, Arrays.asList("D", "G")). + put(3, Arrays.asList("B", "C", "M", "P")). + put(4, Arrays.asList("F", "H", "V", "W", "Y")). + put(5, Arrays.asList("K")). + put(8, Arrays.asList("J", "X")). + put(10, Arrays.asList("Q", "Z")). + build(); + Map expected = ImmutableMap.builder(). + put("a", 1).put("b", 3).put("c", 3).put("d", 2).put("e", 1). + put("f", 4).put("g", 2).put("h", 4).put("i", 1).put("j", 8). + put("k", 5).put("l", 1).put("m", 3).put("n", 1).put("o", 1). + put("p", 3).put("q", 10).put("r", 1).put("s", 1).put("t", 1). + put("u", 1).put("v", 4).put("w", 4).put("x", 8).put("y", 4). + put("z", 10).build(); + + assertThat(etl.transform(old)).isEqualTo(expected); + } +} diff --git a/java/hamming/README.md b/java/hamming/README.md new file mode 100644 index 0000000..8cee585 --- /dev/null +++ b/java/hamming/README.md @@ -0,0 +1,41 @@ +# Hamming + +Write a program that can calculate the Hamming difference between two DNA strands. + +A mutation is simply a mistake that occurs during the creation or +copying of a nucleic acid, in particular DNA. Because nucleic acids are +vital to cellular functions, mutations tend to cause a ripple effect +throughout the cell. Although mutations are technically mistakes, a very +rare mutation may equip the cell with a beneficial attribute. In fact, +the macro effects of evolution are attributable by the accumulated +result of beneficial microscopic mutations over many generations. + +The simplest and most common type of nucleic acid mutation is a point +mutation, which replaces one base with another at a single nucleotide. + +By counting the number of differences between two homologous DNA strands +taken from different genomes with a common ancestor, we get a measure of +the minimum number of point mutations that could have occurred on the +evolutionary path between the two strands. + +This is called the 'Hamming distance'. + +It is found by comparing two DNA strands and counting how many of the +nucleotides are different from their equivalent in the other string. + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +The Hamming distance between these two DNA strands is 7. + +# Implementation notes + +The Hamming distance is only defined for sequences of equal length. This means +that based on the definition, each language could deal with getting sequences +of equal length differently. + + +## Source + +The Calculating Point Mutations problem at Rosalind [view source](http://rosalind.info/problems/hamm/) diff --git a/java/hamming/build.gradle b/java/hamming/build.gradle new file mode 100644 index 0000000..9af8b0b --- /dev/null +++ b/java/hamming/build.gradle @@ -0,0 +1,11 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.10" +} diff --git a/java/hamming/src/main/java/.keep b/java/hamming/src/main/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/hamming/src/main/java/Hamming.java b/java/hamming/src/main/java/Hamming.java new file mode 100644 index 0000000..7bae401 --- /dev/null +++ b/java/hamming/src/main/java/Hamming.java @@ -0,0 +1,2 @@ +public class Hamming { +} diff --git a/java/hamming/src/test/java/HammingTest.java b/java/hamming/src/test/java/HammingTest.java new file mode 100644 index 0000000..04b6438 --- /dev/null +++ b/java/hamming/src/test/java/HammingTest.java @@ -0,0 +1,53 @@ +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.Test; + +public class HammingTest { + + @Test + public void testNoDifferenceBetweenIdenticalStrands() { + assertThat(Hamming.compute("A", "A"), is(0)); + } + + @Test + public void testCompleteHammingDistanceOfForSingleNucleotideStrand() { + assertThat(Hamming.compute("A", "G"), is(1)); + } + + @Test + public void testCompleteHammingDistanceForSmallStrand() { + assertThat(Hamming.compute("AG", "CT"), is(2)); + } + + @Test + public void testSmallHammingDistance() { + assertThat(Hamming.compute("AT", "CT"), is(1)); + } + + @Test + public void testSmallHammingDistanceInLongerStrand() { + assertThat(Hamming.compute("GGACG", "GGTCG"), is(1)); + } + + @Test(expected = IllegalArgumentException.class) + public void testValidatesFirstStrandNotLonger() { + Hamming.compute("AAAG", "AAA"); + } + + @Test(expected = IllegalArgumentException.class) + public void testValidatesOtherStrandNotLonger() { + Hamming.compute("AAA", "AAAG"); + } + + @Test + public void testLargeHammingDistance() { + assertThat(Hamming.compute("GATACA", "GCATAA"), is(4)); + } + + @Test + public void testHammingDistanceInVeryLongStrand() { + assertThat(Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT"), is(9)); + } + +} diff --git a/java/nucleotide-count/.gradle/2.9/taskArtifacts/cache.properties b/java/nucleotide-count/.gradle/2.9/taskArtifacts/cache.properties new file mode 100644 index 0000000..89b2705 --- /dev/null +++ b/java/nucleotide-count/.gradle/2.9/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Fri Nov 20 07:44:37 CST 2015 diff --git a/java/nucleotide-count/.gradle/2.9/taskArtifacts/cache.properties.lock b/java/nucleotide-count/.gradle/2.9/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..3194f3c Binary files /dev/null and b/java/nucleotide-count/.gradle/2.9/taskArtifacts/cache.properties.lock differ diff --git a/java/nucleotide-count/.gradle/2.9/taskArtifacts/fileHashes.bin b/java/nucleotide-count/.gradle/2.9/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..b422f49 Binary files /dev/null and b/java/nucleotide-count/.gradle/2.9/taskArtifacts/fileHashes.bin differ diff --git a/java/nucleotide-count/.gradle/2.9/taskArtifacts/fileSnapshots.bin b/java/nucleotide-count/.gradle/2.9/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..524f7d5 Binary files /dev/null and b/java/nucleotide-count/.gradle/2.9/taskArtifacts/fileSnapshots.bin differ diff --git a/java/nucleotide-count/.gradle/2.9/taskArtifacts/outputFileStates.bin b/java/nucleotide-count/.gradle/2.9/taskArtifacts/outputFileStates.bin new file mode 100644 index 0000000..c5cb4c2 Binary files /dev/null and b/java/nucleotide-count/.gradle/2.9/taskArtifacts/outputFileStates.bin differ diff --git a/java/nucleotide-count/.gradle/2.9/taskArtifacts/taskArtifacts.bin b/java/nucleotide-count/.gradle/2.9/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..ac89306 Binary files /dev/null and b/java/nucleotide-count/.gradle/2.9/taskArtifacts/taskArtifacts.bin differ diff --git a/java/nucleotide-count/README.md b/java/nucleotide-count/README.md new file mode 100644 index 0000000..0e3788b --- /dev/null +++ b/java/nucleotide-count/README.md @@ -0,0 +1,32 @@ +# Nucleotide Count + +Given a DNA string, compute how many times each nucleotide occurs in the string. + +DNA is represented by an alphabet of the following symbols: 'A', 'C', +'G', and 'T'. + +Each symbol represents a nucleotide, which is a fancy name for the +particular molecules that happen to make up a large part of DNA. + +Shortest intro to biochemistry EVAR: + +- twigs are to birds nests as +- nucleotides are to DNA and RNA as +- amino acids are to proteins as +- sugar is to starch as +- oh crap lipids + +I'm not going to talk about lipids because they're crazy complex. + +So back to nucleotides. + +DNA contains four types of them: adenine (`A`), cytosine (`C`), guanine +(`G`), and thymine (`T`). + +RNA contains a slightly different set of nucleotides, but we don't care +about that for now. + + +## Source + +The Calculating DNA Nucleotides_problem at Rosalind [view source](http://rosalind.info/problems/dna/) diff --git a/java/nucleotide-count/build.gradle b/java/nucleotide-count/build.gradle new file mode 100644 index 0000000..cdc2b43 --- /dev/null +++ b/java/nucleotide-count/build.gradle @@ -0,0 +1,12 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.10" + testCompile "org.easytesting:fest-assert-core:2.0M10" +} diff --git a/java/nucleotide-count/build/classes/main/DNA.class b/java/nucleotide-count/build/classes/main/DNA.class new file mode 100644 index 0000000..1210a83 Binary files /dev/null and b/java/nucleotide-count/build/classes/main/DNA.class differ diff --git a/java/nucleotide-count/build/classes/test/NucleotideTest.class b/java/nucleotide-count/build/classes/test/NucleotideTest.class new file mode 100644 index 0000000..7a618ca Binary files /dev/null and b/java/nucleotide-count/build/classes/test/NucleotideTest.class differ diff --git a/java/nucleotide-count/build/libs/nucleotide-count.jar b/java/nucleotide-count/build/libs/nucleotide-count.jar new file mode 100644 index 0000000..d94e136 Binary files /dev/null and b/java/nucleotide-count/build/libs/nucleotide-count.jar differ diff --git a/java/nucleotide-count/build/reports/tests/classes/NucleotideTest.html b/java/nucleotide-count/build/reports/tests/classes/NucleotideTest.html new file mode 100644 index 0000000..9a68b1f --- /dev/null +++ b/java/nucleotide-count/build/reports/tests/classes/NucleotideTest.html @@ -0,0 +1,136 @@ + + + + + +Test results - Class NucleotideTest + + + + + +
+

Class NucleotideTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
9
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.012s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
testCountsANucleotideOnlyOnce0.007spassed
testCountsAllNucleotides0.003spassed
testCountsOnlyThymidine0spassed
testDnaCountsDoNotChangeAfterCountingAdenosine0spassed
testEmptyDnaStringHasNoAdenosine0spassed
testEmptyDnaStringHasNoNucleotides0spassed
testRepetitiveCytidineGetsCounted0.001spassed
testRepetitiveSequenceWithOnlyGuanosine0spassed
testValidatesNucleotides0.001spassed
+
+
+ +
+ + diff --git a/java/nucleotide-count/build/reports/tests/css/base-style.css b/java/nucleotide-count/build/reports/tests/css/base-style.css new file mode 100644 index 0000000..4afa73e --- /dev/null +++ b/java/nucleotide-count/build/reports/tests/css/base-style.css @@ -0,0 +1,179 @@ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; + font-size: 12pt; +} + +body, a, a:visited { + color: #303030; +} + +#content { + padding-left: 50px; + padding-right: 50px; + padding-top: 30px; + padding-bottom: 30px; +} + +#content h1 { + font-size: 160%; + margin-bottom: 10px; +} + +#footer { + margin-top: 100px; + font-size: 80%; + white-space: nowrap; +} + +#footer, #footer a { + color: #a0a0a0; +} + +#line-wrapping-toggle { + vertical-align: middle; +} + +#label-for-line-wrapping-toggle { + vertical-align: middle; +} + +ul { + margin-left: 0; +} + +h1, h2, h3 { + white-space: nowrap; +} + +h2 { + font-size: 120%; +} + +ul.tabLinks { + padding-left: 0; + padding-top: 10px; + padding-bottom: 10px; + overflow: auto; + min-width: 800px; + width: auto !important; + width: 800px; +} + +ul.tabLinks li { + float: left; + height: 100%; + list-style: none; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + -moz-border-radius: 7px; + border-radius: 7px; + margin-right: 25px; + border: solid 1px #d4d4d4; + background-color: #f0f0f0; +} + +ul.tabLinks li:hover { + background-color: #fafafa; +} + +ul.tabLinks li.selected { + background-color: #c5f0f5; + border-color: #c5f0f5; +} + +ul.tabLinks a { + font-size: 120%; + display: block; + outline: none; + text-decoration: none; + margin: 0; + padding: 0; +} + +ul.tabLinks li h2 { + margin: 0; + padding: 0; +} + +div.tab { +} + +div.selected { + display: block; +} + +div.deselected { + display: none; +} + +div.tab table { + min-width: 350px; + width: auto !important; + width: 350px; + border-collapse: collapse; +} + +div.tab th, div.tab table { + border-bottom: solid #d0d0d0 1px; +} + +div.tab th { + text-align: left; + white-space: nowrap; + padding-left: 6em; +} + +div.tab th:first-child { + padding-left: 0; +} + +div.tab td { + white-space: nowrap; + padding-left: 6em; + padding-top: 5px; + padding-bottom: 5px; +} + +div.tab td:first-child { + padding-left: 0; +} + +div.tab td.numeric, div.tab th.numeric { + text-align: right; +} + +span.code { + display: inline-block; + margin-top: 0em; + margin-bottom: 1em; +} + +span.code pre { + font-size: 11pt; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin: 0; + background-color: #f7f7f7; + border: solid 1px #d0d0d0; + min-width: 700px; + width: auto !important; + width: 700px; +} + +span.wrapped pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +label.hidden { + display: none; +} \ No newline at end of file diff --git a/java/nucleotide-count/build/reports/tests/css/style.css b/java/nucleotide-count/build/reports/tests/css/style.css new file mode 100644 index 0000000..3dc4913 --- /dev/null +++ b/java/nucleotide-count/build/reports/tests/css/style.css @@ -0,0 +1,84 @@ + +#summary { + margin-top: 30px; + margin-bottom: 40px; +} + +#summary table { + border-collapse: collapse; +} + +#summary td { + vertical-align: top; +} + +.breadcrumbs, .breadcrumbs a { + color: #606060; +} + +.infoBox { + width: 110px; + padding-top: 15px; + padding-bottom: 15px; + text-align: center; +} + +.infoBox p { + margin: 0; +} + +.counter, .percent { + font-size: 120%; + font-weight: bold; + margin-bottom: 8px; +} + +#duration { + width: 125px; +} + +#successRate, .summaryGroup { + border: solid 2px #d0d0d0; + -moz-border-radius: 10px; + border-radius: 10px; +} + +#successRate { + width: 140px; + margin-left: 35px; +} + +#successRate .percent { + font-size: 180%; +} + +.success, .success a { + color: #008000; +} + +div.success, #successRate.success { + background-color: #bbd9bb; + border-color: #008000; +} + +.failures, .failures a { + color: #b60808; +} + +.skipped, .skipped a { + color: #c09853; +} + +div.failures, #successRate.failures { + background-color: #ecdada; + border-color: #b60808; +} + +ul.linkList { + padding-left: 0; +} + +ul.linkList li { + list-style: none; + margin-bottom: 5px; +} diff --git a/java/nucleotide-count/build/reports/tests/index.html b/java/nucleotide-count/build/reports/tests/index.html new file mode 100644 index 0000000..07d9abc --- /dev/null +++ b/java/nucleotide-count/build/reports/tests/index.html @@ -0,0 +1,132 @@ + + + + + +Test results - Test Summary + + + + + +
+

Test Summary

+
+ + + + + +
+
+ + + + + + + +
+
+
9
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.012s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Packages

+ + + + + + + + + + + + + + + + + + + + + +
PackageTestsFailuresIgnoredDurationSuccess rate
+default-package +9000.012s100%
+
+
+

Classes

+ + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+NucleotideTest +9000.012s100%
+
+
+ +
+ + diff --git a/java/nucleotide-count/build/reports/tests/js/report.js b/java/nucleotide-count/build/reports/tests/js/report.js new file mode 100644 index 0000000..83bab4a --- /dev/null +++ b/java/nucleotide-count/build/reports/tests/js/report.js @@ -0,0 +1,194 @@ +(function (window, document) { + "use strict"; + + var tabs = {}; + + function changeElementClass(element, classValue) { + if (element.getAttribute("className")) { + element.setAttribute("className", classValue); + } else { + element.setAttribute("class", classValue); + } + } + + function getClassAttribute(element) { + if (element.getAttribute("className")) { + return element.getAttribute("className"); + } else { + return element.getAttribute("class"); + } + } + + function addClass(element, classValue) { + changeElementClass(element, getClassAttribute(element) + " " + classValue); + } + + function removeClass(element, classValue) { + changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + } + + function initTabs() { + var container = document.getElementById("tabs"); + + tabs.tabs = findTabs(container); + tabs.titles = findTitles(tabs.tabs); + tabs.headers = findHeaders(container); + tabs.select = select; + tabs.deselectAll = deselectAll; + tabs.select(0); + + return true; + } + + function getCheckBox() { + return document.getElementById("line-wrapping-toggle"); + } + + function getLabelForCheckBox() { + return document.getElementById("label-for-line-wrapping-toggle"); + } + + function findCodeBlocks() { + var spans = document.getElementById("tabs").getElementsByTagName("span"); + var codeBlocks = []; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].className.indexOf("code") >= 0) { + codeBlocks.push(spans[i]); + } + } + return codeBlocks; + } + + function forAllCodeBlocks(operation) { + var codeBlocks = findCodeBlocks(); + + for (var i = 0; i < codeBlocks.length; ++i) { + operation(codeBlocks[i], "wrapped"); + } + } + + function toggleLineWrapping() { + var checkBox = getCheckBox(); + + if (checkBox.checked) { + forAllCodeBlocks(addClass); + } else { + forAllCodeBlocks(removeClass); + } + } + + function initControls() { + if (findCodeBlocks().length > 0) { + var checkBox = getCheckBox(); + var label = getLabelForCheckBox(); + + checkBox.onclick = toggleLineWrapping; + checkBox.checked = false; + + removeClass(label, "hidden"); + } + } + + function switchTab() { + var id = this.id.substr(1); + + for (var i = 0; i < tabs.tabs.length; i++) { + if (tabs.tabs[i].id === id) { + tabs.select(i); + break; + } + } + + return false; + } + + function select(i) { + this.deselectAll(); + + changeElementClass(this.tabs[i], "tab selected"); + changeElementClass(this.headers[i], "selected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var h2 = document.createElement("H2"); + + h2.appendChild(document.createTextNode(this.titles[i])); + this.headers[i].appendChild(h2); + } + + function deselectAll() { + for (var i = 0; i < this.tabs.length; i++) { + changeElementClass(this.tabs[i], "tab deselected"); + changeElementClass(this.headers[i], "deselected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var a = document.createElement("A"); + + a.setAttribute("id", "ltab" + i); + a.setAttribute("href", "#tab" + i); + a.onclick = switchTab; + a.appendChild(document.createTextNode(this.titles[i])); + + this.headers[i].appendChild(a); + } + } + + function findTabs(container) { + return findChildElements(container, "DIV", "tab"); + } + + function findHeaders(container) { + var owner = findChildElements(container, "UL", "tabLinks"); + return findChildElements(owner[0], "LI", null); + } + + function findTitles(tabs) { + var titles = []; + + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + var header = findChildElements(tab, "H2", null)[0]; + + header.parentNode.removeChild(header); + + if (header.innerText) { + titles.push(header.innerText); + } else { + titles.push(header.textContent); + } + } + + return titles; + } + + function findChildElements(container, name, targetClass) { + var elements = []; + var children = container.childNodes; + + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + + if (child.nodeType === 1 && child.nodeName === name) { + if (targetClass && child.className.indexOf(targetClass) < 0) { + continue; + } + + elements.push(child); + } + } + + return elements; + } + + // Entry point. + + window.onload = function() { + initTabs(); + initControls(); + }; +} (window, window.document)); \ No newline at end of file diff --git a/java/nucleotide-count/build/reports/tests/packages/default-package.html b/java/nucleotide-count/build/reports/tests/packages/default-package.html new file mode 100644 index 0000000..e8f045e --- /dev/null +++ b/java/nucleotide-count/build/reports/tests/packages/default-package.html @@ -0,0 +1,103 @@ + + + + + +Test results - Default package + + + + + +
+

Default package

+ +
+ + + + + +
+
+ + + + + + + +
+
+
9
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.012s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+NucleotideTest +9000.012s100%
+
+
+ +
+ + diff --git a/java/nucleotide-count/build/test-results/TEST-NucleotideTest.xml b/java/nucleotide-count/build/test-results/TEST-NucleotideTest.xml new file mode 100644 index 0000000..00af030 --- /dev/null +++ b/java/nucleotide-count/build/test-results/TEST-NucleotideTest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/java/nucleotide-count/build/test-results/binary/test/output.bin b/java/nucleotide-count/build/test-results/binary/test/output.bin new file mode 100644 index 0000000..e69de29 diff --git a/java/nucleotide-count/build/test-results/binary/test/output.bin.idx b/java/nucleotide-count/build/test-results/binary/test/output.bin.idx new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/java/nucleotide-count/build/test-results/binary/test/output.bin.idx differ diff --git a/java/nucleotide-count/build/test-results/binary/test/results.bin b/java/nucleotide-count/build/test-results/binary/test/results.bin new file mode 100644 index 0000000..225217e Binary files /dev/null and b/java/nucleotide-count/build/test-results/binary/test/results.bin differ diff --git a/java/nucleotide-count/build/tmp/jar/MANIFEST.MF b/java/nucleotide-count/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/java/nucleotide-count/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/java/nucleotide-count/src/main/java/.keep b/java/nucleotide-count/src/main/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/nucleotide-count/src/main/java/DNA.java b/java/nucleotide-count/src/main/java/DNA.java new file mode 100644 index 0000000..a7ee035 --- /dev/null +++ b/java/nucleotide-count/src/main/java/DNA.java @@ -0,0 +1,50 @@ +import java.util.*; +import java.lang.String; + + +/** + * DNA holds a string of nucleotides and allows + * @param nucleos The nucleotide string + * anything that isn't ACG or T is ignored + * by all functions in the class. + */ +public class DNA { + private String nucleotides = ""; + public DNA(String nucleos) { + this.nucleotides = nucleos; + } + + /** + * nucleotideCounts returns a Map of how many there are of each + * nucleotide in the string. + * @return The Map from nucleotide -> count + */ + public Map nucleotideCounts() { + Map ret = new HashMap(); + ret.put('A', this.count('A')); + ret.put('C', this.count('C')); + ret.put('G', this.count('G')); + ret.put('T', this.count('T')); + return ret; + } + + /** + * Counts how many instances of a specific nucleotide exist + * in the string. + * @param which The nucleotide that we're counting + * @return How many of that nucleotide there were. + */ + public int count(char which) { + if(which != 'A' && which != 'C' && which != 'G' && which != 'T') { + throw new IllegalArgumentException(); + } + char[] nucChar = this.nucleotides.toCharArray(); + int ret = 0; + for(int i = 0; i < nucChar.length; i++) { + if(nucChar[i] == which) { + ret++; + } + } + return ret; + } +} diff --git a/java/nucleotide-count/src/test/java/.keep b/java/nucleotide-count/src/test/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/nucleotide-count/src/test/java/NucleotideTest.java b/java/nucleotide-count/src/test/java/NucleotideTest.java new file mode 100644 index 0000000..fc848b0 --- /dev/null +++ b/java/nucleotide-count/src/test/java/NucleotideTest.java @@ -0,0 +1,83 @@ +import static org.fest.assertions.api.Assertions.assertThat; +import static org.fest.assertions.api.Assertions.entry; + +import org.junit.Test; + +public class NucleotideTest { + @Test + public void testEmptyDnaStringHasNoAdenosine() { + DNA dna = new DNA(""); + assertThat(dna.count('A')).isEqualTo(0); + } + + @Test + public void testEmptyDnaStringHasNoNucleotides() { + DNA dna = new DNA(""); + assertThat(dna.nucleotideCounts()).hasSize(4).contains( + entry('A', 0), + entry('C', 0), + entry('G', 0), + entry('T', 0) + ); + } + + @Test + public void testRepetitiveCytidineGetsCounted() { + DNA dna = new DNA("CCCCC"); + assertThat(dna.count('C')).isEqualTo(5); + } + + @Test + public void testRepetitiveSequenceWithOnlyGuanosine() { + DNA dna = new DNA("GGGGGGGG"); + assertThat(dna.nucleotideCounts()).hasSize(4).contains( + entry('A', 0), + entry('C', 0), + entry('G', 8), + entry('T', 0) + ); + } + + @Test + public void testCountsOnlyThymidine() { + DNA dna = new DNA("GGGGGTAACCCGG"); + assertThat(dna.count('T')).isEqualTo(1); + } + + @Test + public void testCountsANucleotideOnlyOnce() { + DNA dna = new DNA("CGATTGGG"); + dna.count('T'); + assertThat(dna.count('T')).isEqualTo(2); + } + + @Test + public void testDnaCountsDoNotChangeAfterCountingAdenosine() { + DNA dna = new DNA("GATTACA"); + dna.count('A'); + assertThat(dna.nucleotideCounts()).hasSize(4).contains( + entry('A', 3), + entry('C', 1), + entry('G', 1), + entry('T', 2) + ); + } + + @Test(expected = IllegalArgumentException.class) + public void testValidatesNucleotides() { + DNA dna = new DNA("GACT"); + dna.count('X'); + } + + @Test + public void testCountsAllNucleotides() { + String s = "AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"; + DNA dna = new DNA(s); + assertThat(dna.nucleotideCounts()).hasSize(4).contains( + entry('A', 20), + entry('C', 12), + entry('G', 17), + entry('T', 21) + ); + } +} diff --git a/java/pangram/.gradle/2.10/taskArtifacts/cache.properties b/java/pangram/.gradle/2.10/taskArtifacts/cache.properties new file mode 100644 index 0000000..9ea0fd0 --- /dev/null +++ b/java/pangram/.gradle/2.10/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Thu Jan 28 07:47:05 CST 2016 diff --git a/java/pangram/.gradle/2.10/taskArtifacts/cache.properties.lock b/java/pangram/.gradle/2.10/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..491ebe8 Binary files /dev/null and b/java/pangram/.gradle/2.10/taskArtifacts/cache.properties.lock differ diff --git a/java/pangram/.gradle/2.10/taskArtifacts/fileHashes.bin b/java/pangram/.gradle/2.10/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..54dd598 Binary files /dev/null and b/java/pangram/.gradle/2.10/taskArtifacts/fileHashes.bin differ diff --git a/java/pangram/.gradle/2.10/taskArtifacts/fileSnapshots.bin b/java/pangram/.gradle/2.10/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..0552efc Binary files /dev/null and b/java/pangram/.gradle/2.10/taskArtifacts/fileSnapshots.bin differ diff --git a/java/pangram/.gradle/2.10/taskArtifacts/outputFileStates.bin b/java/pangram/.gradle/2.10/taskArtifacts/outputFileStates.bin new file mode 100644 index 0000000..601ab56 Binary files /dev/null and b/java/pangram/.gradle/2.10/taskArtifacts/outputFileStates.bin differ diff --git a/java/pangram/.gradle/2.10/taskArtifacts/taskArtifacts.bin b/java/pangram/.gradle/2.10/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..5919ab8 Binary files /dev/null and b/java/pangram/.gradle/2.10/taskArtifacts/taskArtifacts.bin differ diff --git a/java/pangram/README.md b/java/pangram/README.md new file mode 100644 index 0000000..ce5d977 --- /dev/null +++ b/java/pangram/README.md @@ -0,0 +1,12 @@ +# Pangram + +Determine if a sentence is a pangram. + +Determine if a sentence is a pangram. A pangram (Greek: παν γράμμα, pan gramma, +"every letter") is a sentence using every letter of the alphabet at least once. +The best known English pangram is "The quick brown fox jumps over the lazy dog." + + +## Source + +Wikipedia [view source](https://en.wikipedia.org/wiki/Pangram) diff --git a/java/pangram/build.gradle b/java/pangram/build.gradle new file mode 100644 index 0000000..9af8b0b --- /dev/null +++ b/java/pangram/build.gradle @@ -0,0 +1,11 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.10" +} diff --git a/java/pangram/build/classes/main/Pangrams.class b/java/pangram/build/classes/main/Pangrams.class new file mode 100644 index 0000000..1d5df22 Binary files /dev/null and b/java/pangram/build/classes/main/Pangrams.class differ diff --git a/java/pangram/build/classes/test/PangramTest.class b/java/pangram/build/classes/test/PangramTest.class new file mode 100644 index 0000000..47fe83a Binary files /dev/null and b/java/pangram/build/classes/test/PangramTest.class differ diff --git a/java/pangram/build/libs/pangram.jar b/java/pangram/build/libs/pangram.jar new file mode 100644 index 0000000..84a1dc8 Binary files /dev/null and b/java/pangram/build/libs/pangram.jar differ diff --git a/java/pangram/build/reports/tests/classes/PangramTest.html b/java/pangram/build/reports/tests/classes/PangramTest.html new file mode 100644 index 0000000..5c6adbe --- /dev/null +++ b/java/pangram/build/reports/tests/classes/PangramTest.html @@ -0,0 +1,116 @@ + + + + + +Test results - Class PangramTest + + + + + +
+

Class PangramTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.001s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
emptySentence0spassed
missingCharacterX0spassed
mixedCaseAndPunctuation0spassed
nonAsciiCharacters0spassed
testLowercasePangram0.001spassed
+
+
+ +
+ + diff --git a/java/pangram/build/reports/tests/css/base-style.css b/java/pangram/build/reports/tests/css/base-style.css new file mode 100644 index 0000000..4afa73e --- /dev/null +++ b/java/pangram/build/reports/tests/css/base-style.css @@ -0,0 +1,179 @@ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; + font-size: 12pt; +} + +body, a, a:visited { + color: #303030; +} + +#content { + padding-left: 50px; + padding-right: 50px; + padding-top: 30px; + padding-bottom: 30px; +} + +#content h1 { + font-size: 160%; + margin-bottom: 10px; +} + +#footer { + margin-top: 100px; + font-size: 80%; + white-space: nowrap; +} + +#footer, #footer a { + color: #a0a0a0; +} + +#line-wrapping-toggle { + vertical-align: middle; +} + +#label-for-line-wrapping-toggle { + vertical-align: middle; +} + +ul { + margin-left: 0; +} + +h1, h2, h3 { + white-space: nowrap; +} + +h2 { + font-size: 120%; +} + +ul.tabLinks { + padding-left: 0; + padding-top: 10px; + padding-bottom: 10px; + overflow: auto; + min-width: 800px; + width: auto !important; + width: 800px; +} + +ul.tabLinks li { + float: left; + height: 100%; + list-style: none; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + -moz-border-radius: 7px; + border-radius: 7px; + margin-right: 25px; + border: solid 1px #d4d4d4; + background-color: #f0f0f0; +} + +ul.tabLinks li:hover { + background-color: #fafafa; +} + +ul.tabLinks li.selected { + background-color: #c5f0f5; + border-color: #c5f0f5; +} + +ul.tabLinks a { + font-size: 120%; + display: block; + outline: none; + text-decoration: none; + margin: 0; + padding: 0; +} + +ul.tabLinks li h2 { + margin: 0; + padding: 0; +} + +div.tab { +} + +div.selected { + display: block; +} + +div.deselected { + display: none; +} + +div.tab table { + min-width: 350px; + width: auto !important; + width: 350px; + border-collapse: collapse; +} + +div.tab th, div.tab table { + border-bottom: solid #d0d0d0 1px; +} + +div.tab th { + text-align: left; + white-space: nowrap; + padding-left: 6em; +} + +div.tab th:first-child { + padding-left: 0; +} + +div.tab td { + white-space: nowrap; + padding-left: 6em; + padding-top: 5px; + padding-bottom: 5px; +} + +div.tab td:first-child { + padding-left: 0; +} + +div.tab td.numeric, div.tab th.numeric { + text-align: right; +} + +span.code { + display: inline-block; + margin-top: 0em; + margin-bottom: 1em; +} + +span.code pre { + font-size: 11pt; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin: 0; + background-color: #f7f7f7; + border: solid 1px #d0d0d0; + min-width: 700px; + width: auto !important; + width: 700px; +} + +span.wrapped pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +label.hidden { + display: none; +} \ No newline at end of file diff --git a/java/pangram/build/reports/tests/css/style.css b/java/pangram/build/reports/tests/css/style.css new file mode 100644 index 0000000..3dc4913 --- /dev/null +++ b/java/pangram/build/reports/tests/css/style.css @@ -0,0 +1,84 @@ + +#summary { + margin-top: 30px; + margin-bottom: 40px; +} + +#summary table { + border-collapse: collapse; +} + +#summary td { + vertical-align: top; +} + +.breadcrumbs, .breadcrumbs a { + color: #606060; +} + +.infoBox { + width: 110px; + padding-top: 15px; + padding-bottom: 15px; + text-align: center; +} + +.infoBox p { + margin: 0; +} + +.counter, .percent { + font-size: 120%; + font-weight: bold; + margin-bottom: 8px; +} + +#duration { + width: 125px; +} + +#successRate, .summaryGroup { + border: solid 2px #d0d0d0; + -moz-border-radius: 10px; + border-radius: 10px; +} + +#successRate { + width: 140px; + margin-left: 35px; +} + +#successRate .percent { + font-size: 180%; +} + +.success, .success a { + color: #008000; +} + +div.success, #successRate.success { + background-color: #bbd9bb; + border-color: #008000; +} + +.failures, .failures a { + color: #b60808; +} + +.skipped, .skipped a { + color: #c09853; +} + +div.failures, #successRate.failures { + background-color: #ecdada; + border-color: #b60808; +} + +ul.linkList { + padding-left: 0; +} + +ul.linkList li { + list-style: none; + margin-bottom: 5px; +} diff --git a/java/pangram/build/reports/tests/index.html b/java/pangram/build/reports/tests/index.html new file mode 100644 index 0000000..48cc49a --- /dev/null +++ b/java/pangram/build/reports/tests/index.html @@ -0,0 +1,132 @@ + + + + + +Test results - Test Summary + + + + + +
+

Test Summary

+
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.001s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Packages

+ + + + + + + + + + + + + + + + + + + + + +
PackageTestsFailuresIgnoredDurationSuccess rate
+default-package +5000.001s100%
+
+
+

Classes

+ + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+PangramTest +5000.001s100%
+
+
+ +
+ + diff --git a/java/pangram/build/reports/tests/js/report.js b/java/pangram/build/reports/tests/js/report.js new file mode 100644 index 0000000..83bab4a --- /dev/null +++ b/java/pangram/build/reports/tests/js/report.js @@ -0,0 +1,194 @@ +(function (window, document) { + "use strict"; + + var tabs = {}; + + function changeElementClass(element, classValue) { + if (element.getAttribute("className")) { + element.setAttribute("className", classValue); + } else { + element.setAttribute("class", classValue); + } + } + + function getClassAttribute(element) { + if (element.getAttribute("className")) { + return element.getAttribute("className"); + } else { + return element.getAttribute("class"); + } + } + + function addClass(element, classValue) { + changeElementClass(element, getClassAttribute(element) + " " + classValue); + } + + function removeClass(element, classValue) { + changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + } + + function initTabs() { + var container = document.getElementById("tabs"); + + tabs.tabs = findTabs(container); + tabs.titles = findTitles(tabs.tabs); + tabs.headers = findHeaders(container); + tabs.select = select; + tabs.deselectAll = deselectAll; + tabs.select(0); + + return true; + } + + function getCheckBox() { + return document.getElementById("line-wrapping-toggle"); + } + + function getLabelForCheckBox() { + return document.getElementById("label-for-line-wrapping-toggle"); + } + + function findCodeBlocks() { + var spans = document.getElementById("tabs").getElementsByTagName("span"); + var codeBlocks = []; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].className.indexOf("code") >= 0) { + codeBlocks.push(spans[i]); + } + } + return codeBlocks; + } + + function forAllCodeBlocks(operation) { + var codeBlocks = findCodeBlocks(); + + for (var i = 0; i < codeBlocks.length; ++i) { + operation(codeBlocks[i], "wrapped"); + } + } + + function toggleLineWrapping() { + var checkBox = getCheckBox(); + + if (checkBox.checked) { + forAllCodeBlocks(addClass); + } else { + forAllCodeBlocks(removeClass); + } + } + + function initControls() { + if (findCodeBlocks().length > 0) { + var checkBox = getCheckBox(); + var label = getLabelForCheckBox(); + + checkBox.onclick = toggleLineWrapping; + checkBox.checked = false; + + removeClass(label, "hidden"); + } + } + + function switchTab() { + var id = this.id.substr(1); + + for (var i = 0; i < tabs.tabs.length; i++) { + if (tabs.tabs[i].id === id) { + tabs.select(i); + break; + } + } + + return false; + } + + function select(i) { + this.deselectAll(); + + changeElementClass(this.tabs[i], "tab selected"); + changeElementClass(this.headers[i], "selected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var h2 = document.createElement("H2"); + + h2.appendChild(document.createTextNode(this.titles[i])); + this.headers[i].appendChild(h2); + } + + function deselectAll() { + for (var i = 0; i < this.tabs.length; i++) { + changeElementClass(this.tabs[i], "tab deselected"); + changeElementClass(this.headers[i], "deselected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var a = document.createElement("A"); + + a.setAttribute("id", "ltab" + i); + a.setAttribute("href", "#tab" + i); + a.onclick = switchTab; + a.appendChild(document.createTextNode(this.titles[i])); + + this.headers[i].appendChild(a); + } + } + + function findTabs(container) { + return findChildElements(container, "DIV", "tab"); + } + + function findHeaders(container) { + var owner = findChildElements(container, "UL", "tabLinks"); + return findChildElements(owner[0], "LI", null); + } + + function findTitles(tabs) { + var titles = []; + + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + var header = findChildElements(tab, "H2", null)[0]; + + header.parentNode.removeChild(header); + + if (header.innerText) { + titles.push(header.innerText); + } else { + titles.push(header.textContent); + } + } + + return titles; + } + + function findChildElements(container, name, targetClass) { + var elements = []; + var children = container.childNodes; + + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + + if (child.nodeType === 1 && child.nodeName === name) { + if (targetClass && child.className.indexOf(targetClass) < 0) { + continue; + } + + elements.push(child); + } + } + + return elements; + } + + // Entry point. + + window.onload = function() { + initTabs(); + initControls(); + }; +} (window, window.document)); \ No newline at end of file diff --git a/java/pangram/build/reports/tests/packages/default-package.html b/java/pangram/build/reports/tests/packages/default-package.html new file mode 100644 index 0000000..12d5e82 --- /dev/null +++ b/java/pangram/build/reports/tests/packages/default-package.html @@ -0,0 +1,103 @@ + + + + + +Test results - Default package + + + + + +
+

Default package

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.001s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+PangramTest +5000.001s100%
+
+
+ +
+ + diff --git a/java/pangram/build/test-results/TEST-PangramTest.xml b/java/pangram/build/test-results/TEST-PangramTest.xml new file mode 100644 index 0000000..d78b682 --- /dev/null +++ b/java/pangram/build/test-results/TEST-PangramTest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/java/pangram/build/test-results/binary/test/output.bin b/java/pangram/build/test-results/binary/test/output.bin new file mode 100644 index 0000000..e69de29 diff --git a/java/pangram/build/test-results/binary/test/output.bin.idx b/java/pangram/build/test-results/binary/test/output.bin.idx new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/java/pangram/build/test-results/binary/test/output.bin.idx differ diff --git a/java/pangram/build/test-results/binary/test/results.bin b/java/pangram/build/test-results/binary/test/results.bin new file mode 100644 index 0000000..39fd013 Binary files /dev/null and b/java/pangram/build/test-results/binary/test/results.bin differ diff --git a/java/pangram/build/tmp/jar/MANIFEST.MF b/java/pangram/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/java/pangram/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/java/pangram/src/main/java/.keep b/java/pangram/src/main/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/pangram/src/main/java/Pangrams.java b/java/pangram/src/main/java/Pangrams.java new file mode 100644 index 0000000..6a529be --- /dev/null +++ b/java/pangram/src/main/java/Pangrams.java @@ -0,0 +1,27 @@ +import java.util.*; + +/** + * Pangram lets you know if a string is a Pangram + * (contains all letters in the alphabet) + */ +public class Pangrams { + public static boolean isPangram(String test) { + char ch = 'a'; + char[] strBytes = test.toLowerCase().toCharArray(); + for(int i = 0; i < 26; i++) { + boolean foundChar = false; + for(int j = 0; j < strBytes.length; j++) { + if(strBytes[j] == ch) { + foundChar = true; + break; + } + } + ch++; + if(foundChar) { + continue; + } + return false; + } + return true; + } +} diff --git a/java/pangram/src/test/java/.keep b/java/pangram/src/test/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/pangram/src/test/java/PangramTest.java b/java/pangram/src/test/java/PangramTest.java new file mode 100644 index 0000000..cc20288 --- /dev/null +++ b/java/pangram/src/test/java/PangramTest.java @@ -0,0 +1,33 @@ +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +public class PangramTest { + + @Test + public void emptySentence() { + assertFalse(Pangrams.isPangram("")); + } + + @Test + public void testLowercasePangram() { + assertTrue(Pangrams.isPangram("the quick brown fox jumps over the lazy dog")); + } + + @Test + public void missingCharacterX() { + assertFalse(Pangrams.isPangram("a quick movement of the enemy will jeopardize five gunboats")); + } + + @Test + public void mixedCaseAndPunctuation() { + assertTrue(Pangrams.isPangram("\"Five quacking Zephyrs jolt my wax bed.\"")); + } + + @Test + public void nonAsciiCharacters() { + assertTrue(Pangrams.isPangram("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.")); + } + +} diff --git a/java/testing/.gradle/2.10/taskArtifacts/cache.properties b/java/testing/.gradle/2.10/taskArtifacts/cache.properties new file mode 100644 index 0000000..4051bdc --- /dev/null +++ b/java/testing/.gradle/2.10/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Thu Jan 28 06:57:37 CST 2016 diff --git a/java/testing/.gradle/2.10/taskArtifacts/cache.properties.lock b/java/testing/.gradle/2.10/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..60dba0d Binary files /dev/null and b/java/testing/.gradle/2.10/taskArtifacts/cache.properties.lock differ diff --git a/java/testing/.gradle/2.10/taskArtifacts/fileHashes.bin b/java/testing/.gradle/2.10/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..6a2e0b6 Binary files /dev/null and b/java/testing/.gradle/2.10/taskArtifacts/fileHashes.bin differ diff --git a/java/testing/.gradle/2.10/taskArtifacts/fileSnapshots.bin b/java/testing/.gradle/2.10/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..9acf996 Binary files /dev/null and b/java/testing/.gradle/2.10/taskArtifacts/fileSnapshots.bin differ diff --git a/java/testing/.gradle/2.10/taskArtifacts/outputFileStates.bin b/java/testing/.gradle/2.10/taskArtifacts/outputFileStates.bin new file mode 100644 index 0000000..66f5f4e Binary files /dev/null and b/java/testing/.gradle/2.10/taskArtifacts/outputFileStates.bin differ diff --git a/java/testing/.gradle/2.10/taskArtifacts/taskArtifacts.bin b/java/testing/.gradle/2.10/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..a4a0554 Binary files /dev/null and b/java/testing/.gradle/2.10/taskArtifacts/taskArtifacts.bin differ diff --git a/java/testing/build.gradle b/java/testing/build.gradle new file mode 100644 index 0000000..0432984 --- /dev/null +++ b/java/testing/build.gradle @@ -0,0 +1,27 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +version = '1.0' +sourceCompatibility = 1.7 +targetCompatibility = 1.7 + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.10" +} + +//create a single Jar with all dependencies +task fatJar(type: Jar) { + manifest { + attributes 'Implementation-Title': 'Gradle Jar File Example', + 'Implementation-Version': version, + 'Main-Class': 'Testing' + } + baseName = project.name + '-all' + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + with jar +} diff --git a/java/testing/build/classes/main/Testing.class b/java/testing/build/classes/main/Testing.class new file mode 100644 index 0000000..814cdd7 Binary files /dev/null and b/java/testing/build/classes/main/Testing.class differ diff --git a/java/testing/build/libs/testing-all-1.0.jar b/java/testing/build/libs/testing-all-1.0.jar new file mode 100644 index 0000000..f336f77 Binary files /dev/null and b/java/testing/build/libs/testing-all-1.0.jar differ diff --git a/java/testing/build/tmp/fatJar/MANIFEST.MF b/java/testing/build/tmp/fatJar/MANIFEST.MF new file mode 100644 index 0000000..32fbb13 --- /dev/null +++ b/java/testing/build/tmp/fatJar/MANIFEST.MF @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Implementation-Title: Gradle Jar File Example +Implementation-Version: 1.0 +Main-Class: Testing + diff --git a/java/testing/build/tmp/jar/MANIFEST.MF b/java/testing/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/java/testing/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/java/testing/src/main/java/Testing.java b/java/testing/src/main/java/Testing.java new file mode 100644 index 0000000..fe6d7e8 --- /dev/null +++ b/java/testing/src/main/java/Testing.java @@ -0,0 +1,35 @@ +import java.util.*; + +public class Testing { + public static void main(String[] args) { + + if("pangram".equals(args[0])) { + if(testPangram(args[1])) { + System.out.println("true"); + } else { + System.out.println("false"); + } + } + } + + private static boolean testPangram(String test) { + System.out.println("Pangram Testing ("+test+")"); + char ch = 'a'; + char[] strBytes = test.toLowerCase().toCharArray(); + for(int i = 0; i < 26; i++) { + boolean foundChar = false; + for(int j = 0; j < strBytes.length; j++) { + if(strBytes[j] == ch) { + foundChar = true; + break; + } + } + ch++; + if(foundChar) { + continue; + } + return false; + } + return true; + } +} \ No newline at end of file diff --git a/java/word-count/.gradle/2.9/taskArtifacts/cache.properties b/java/word-count/.gradle/2.9/taskArtifacts/cache.properties new file mode 100644 index 0000000..4a49d9f --- /dev/null +++ b/java/word-count/.gradle/2.9/taskArtifacts/cache.properties @@ -0,0 +1 @@ +#Fri Nov 20 08:32:56 CST 2015 diff --git a/java/word-count/.gradle/2.9/taskArtifacts/cache.properties.lock b/java/word-count/.gradle/2.9/taskArtifacts/cache.properties.lock new file mode 100644 index 0000000..0a112d3 Binary files /dev/null and b/java/word-count/.gradle/2.9/taskArtifacts/cache.properties.lock differ diff --git a/java/word-count/.gradle/2.9/taskArtifacts/fileHashes.bin b/java/word-count/.gradle/2.9/taskArtifacts/fileHashes.bin new file mode 100644 index 0000000..373f92d Binary files /dev/null and b/java/word-count/.gradle/2.9/taskArtifacts/fileHashes.bin differ diff --git a/java/word-count/.gradle/2.9/taskArtifacts/fileSnapshots.bin b/java/word-count/.gradle/2.9/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..cbdb6ab Binary files /dev/null and b/java/word-count/.gradle/2.9/taskArtifacts/fileSnapshots.bin differ diff --git a/java/word-count/.gradle/2.9/taskArtifacts/outputFileStates.bin b/java/word-count/.gradle/2.9/taskArtifacts/outputFileStates.bin new file mode 100644 index 0000000..b06a963 Binary files /dev/null and b/java/word-count/.gradle/2.9/taskArtifacts/outputFileStates.bin differ diff --git a/java/word-count/.gradle/2.9/taskArtifacts/taskArtifacts.bin b/java/word-count/.gradle/2.9/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..69566e7 Binary files /dev/null and b/java/word-count/.gradle/2.9/taskArtifacts/taskArtifacts.bin differ diff --git a/java/word-count/README.md b/java/word-count/README.md new file mode 100644 index 0000000..7dc0618 --- /dev/null +++ b/java/word-count/README.md @@ -0,0 +1,18 @@ +# Word Count + +Write a program that given a phrase can count the occurrences of each word in that phrase. + +For example for the input `"olly olly in come free"` + +```plain +olly: 2 +in: 1 +come: 1 +free: 1 +``` + + + +## Source + +The golang tour [view source](http://tour.golang.org) diff --git a/java/word-count/build.gradle b/java/word-count/build.gradle new file mode 100644 index 0000000..9af8b0b --- /dev/null +++ b/java/word-count/build.gradle @@ -0,0 +1,11 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.10" +} diff --git a/java/word-count/build/classes/main/WordCount.class b/java/word-count/build/classes/main/WordCount.class new file mode 100644 index 0000000..fce9f75 Binary files /dev/null and b/java/word-count/build/classes/main/WordCount.class differ diff --git a/java/word-count/build/classes/test/WordCountTest.class b/java/word-count/build/classes/test/WordCountTest.class new file mode 100644 index 0000000..0222eeb Binary files /dev/null and b/java/word-count/build/classes/test/WordCountTest.class differ diff --git a/java/word-count/build/libs/word-count.jar b/java/word-count/build/libs/word-count.jar new file mode 100644 index 0000000..0ac2f8f Binary files /dev/null and b/java/word-count/build/libs/word-count.jar differ diff --git a/java/word-count/build/reports/tests/classes/WordCountTest.html b/java/word-count/build/reports/tests/classes/WordCountTest.html new file mode 100644 index 0000000..92a45bc --- /dev/null +++ b/java/word-count/build/reports/tests/classes/WordCountTest.html @@ -0,0 +1,121 @@ + + + + + +Test results - Class WordCountTest + + + + + +
+

Class WordCountTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
6
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.002s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
countMultipleOccurences0spassed
countOneOfEach0.001spassed
countOneWord0spassed
ignorePunctuation0spassed
includeNumbers0spassed
normalizeCase0.001spassed
+
+
+ +
+ + diff --git a/java/word-count/build/reports/tests/css/base-style.css b/java/word-count/build/reports/tests/css/base-style.css new file mode 100644 index 0000000..4afa73e --- /dev/null +++ b/java/word-count/build/reports/tests/css/base-style.css @@ -0,0 +1,179 @@ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; + font-size: 12pt; +} + +body, a, a:visited { + color: #303030; +} + +#content { + padding-left: 50px; + padding-right: 50px; + padding-top: 30px; + padding-bottom: 30px; +} + +#content h1 { + font-size: 160%; + margin-bottom: 10px; +} + +#footer { + margin-top: 100px; + font-size: 80%; + white-space: nowrap; +} + +#footer, #footer a { + color: #a0a0a0; +} + +#line-wrapping-toggle { + vertical-align: middle; +} + +#label-for-line-wrapping-toggle { + vertical-align: middle; +} + +ul { + margin-left: 0; +} + +h1, h2, h3 { + white-space: nowrap; +} + +h2 { + font-size: 120%; +} + +ul.tabLinks { + padding-left: 0; + padding-top: 10px; + padding-bottom: 10px; + overflow: auto; + min-width: 800px; + width: auto !important; + width: 800px; +} + +ul.tabLinks li { + float: left; + height: 100%; + list-style: none; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + -moz-border-radius: 7px; + border-radius: 7px; + margin-right: 25px; + border: solid 1px #d4d4d4; + background-color: #f0f0f0; +} + +ul.tabLinks li:hover { + background-color: #fafafa; +} + +ul.tabLinks li.selected { + background-color: #c5f0f5; + border-color: #c5f0f5; +} + +ul.tabLinks a { + font-size: 120%; + display: block; + outline: none; + text-decoration: none; + margin: 0; + padding: 0; +} + +ul.tabLinks li h2 { + margin: 0; + padding: 0; +} + +div.tab { +} + +div.selected { + display: block; +} + +div.deselected { + display: none; +} + +div.tab table { + min-width: 350px; + width: auto !important; + width: 350px; + border-collapse: collapse; +} + +div.tab th, div.tab table { + border-bottom: solid #d0d0d0 1px; +} + +div.tab th { + text-align: left; + white-space: nowrap; + padding-left: 6em; +} + +div.tab th:first-child { + padding-left: 0; +} + +div.tab td { + white-space: nowrap; + padding-left: 6em; + padding-top: 5px; + padding-bottom: 5px; +} + +div.tab td:first-child { + padding-left: 0; +} + +div.tab td.numeric, div.tab th.numeric { + text-align: right; +} + +span.code { + display: inline-block; + margin-top: 0em; + margin-bottom: 1em; +} + +span.code pre { + font-size: 11pt; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin: 0; + background-color: #f7f7f7; + border: solid 1px #d0d0d0; + min-width: 700px; + width: auto !important; + width: 700px; +} + +span.wrapped pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +label.hidden { + display: none; +} \ No newline at end of file diff --git a/java/word-count/build/reports/tests/css/style.css b/java/word-count/build/reports/tests/css/style.css new file mode 100644 index 0000000..3dc4913 --- /dev/null +++ b/java/word-count/build/reports/tests/css/style.css @@ -0,0 +1,84 @@ + +#summary { + margin-top: 30px; + margin-bottom: 40px; +} + +#summary table { + border-collapse: collapse; +} + +#summary td { + vertical-align: top; +} + +.breadcrumbs, .breadcrumbs a { + color: #606060; +} + +.infoBox { + width: 110px; + padding-top: 15px; + padding-bottom: 15px; + text-align: center; +} + +.infoBox p { + margin: 0; +} + +.counter, .percent { + font-size: 120%; + font-weight: bold; + margin-bottom: 8px; +} + +#duration { + width: 125px; +} + +#successRate, .summaryGroup { + border: solid 2px #d0d0d0; + -moz-border-radius: 10px; + border-radius: 10px; +} + +#successRate { + width: 140px; + margin-left: 35px; +} + +#successRate .percent { + font-size: 180%; +} + +.success, .success a { + color: #008000; +} + +div.success, #successRate.success { + background-color: #bbd9bb; + border-color: #008000; +} + +.failures, .failures a { + color: #b60808; +} + +.skipped, .skipped a { + color: #c09853; +} + +div.failures, #successRate.failures { + background-color: #ecdada; + border-color: #b60808; +} + +ul.linkList { + padding-left: 0; +} + +ul.linkList li { + list-style: none; + margin-bottom: 5px; +} diff --git a/java/word-count/build/reports/tests/index.html b/java/word-count/build/reports/tests/index.html new file mode 100644 index 0000000..3a85c74 --- /dev/null +++ b/java/word-count/build/reports/tests/index.html @@ -0,0 +1,132 @@ + + + + + +Test results - Test Summary + + + + + +
+

Test Summary

+
+ + + + + +
+
+ + + + + + + +
+
+
6
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.002s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Packages

+ + + + + + + + + + + + + + + + + + + + + +
PackageTestsFailuresIgnoredDurationSuccess rate
+default-package +6000.002s100%
+
+
+

Classes

+ + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+WordCountTest +6000.002s100%
+
+
+ +
+ + diff --git a/java/word-count/build/reports/tests/js/report.js b/java/word-count/build/reports/tests/js/report.js new file mode 100644 index 0000000..83bab4a --- /dev/null +++ b/java/word-count/build/reports/tests/js/report.js @@ -0,0 +1,194 @@ +(function (window, document) { + "use strict"; + + var tabs = {}; + + function changeElementClass(element, classValue) { + if (element.getAttribute("className")) { + element.setAttribute("className", classValue); + } else { + element.setAttribute("class", classValue); + } + } + + function getClassAttribute(element) { + if (element.getAttribute("className")) { + return element.getAttribute("className"); + } else { + return element.getAttribute("class"); + } + } + + function addClass(element, classValue) { + changeElementClass(element, getClassAttribute(element) + " " + classValue); + } + + function removeClass(element, classValue) { + changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + } + + function initTabs() { + var container = document.getElementById("tabs"); + + tabs.tabs = findTabs(container); + tabs.titles = findTitles(tabs.tabs); + tabs.headers = findHeaders(container); + tabs.select = select; + tabs.deselectAll = deselectAll; + tabs.select(0); + + return true; + } + + function getCheckBox() { + return document.getElementById("line-wrapping-toggle"); + } + + function getLabelForCheckBox() { + return document.getElementById("label-for-line-wrapping-toggle"); + } + + function findCodeBlocks() { + var spans = document.getElementById("tabs").getElementsByTagName("span"); + var codeBlocks = []; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].className.indexOf("code") >= 0) { + codeBlocks.push(spans[i]); + } + } + return codeBlocks; + } + + function forAllCodeBlocks(operation) { + var codeBlocks = findCodeBlocks(); + + for (var i = 0; i < codeBlocks.length; ++i) { + operation(codeBlocks[i], "wrapped"); + } + } + + function toggleLineWrapping() { + var checkBox = getCheckBox(); + + if (checkBox.checked) { + forAllCodeBlocks(addClass); + } else { + forAllCodeBlocks(removeClass); + } + } + + function initControls() { + if (findCodeBlocks().length > 0) { + var checkBox = getCheckBox(); + var label = getLabelForCheckBox(); + + checkBox.onclick = toggleLineWrapping; + checkBox.checked = false; + + removeClass(label, "hidden"); + } + } + + function switchTab() { + var id = this.id.substr(1); + + for (var i = 0; i < tabs.tabs.length; i++) { + if (tabs.tabs[i].id === id) { + tabs.select(i); + break; + } + } + + return false; + } + + function select(i) { + this.deselectAll(); + + changeElementClass(this.tabs[i], "tab selected"); + changeElementClass(this.headers[i], "selected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var h2 = document.createElement("H2"); + + h2.appendChild(document.createTextNode(this.titles[i])); + this.headers[i].appendChild(h2); + } + + function deselectAll() { + for (var i = 0; i < this.tabs.length; i++) { + changeElementClass(this.tabs[i], "tab deselected"); + changeElementClass(this.headers[i], "deselected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var a = document.createElement("A"); + + a.setAttribute("id", "ltab" + i); + a.setAttribute("href", "#tab" + i); + a.onclick = switchTab; + a.appendChild(document.createTextNode(this.titles[i])); + + this.headers[i].appendChild(a); + } + } + + function findTabs(container) { + return findChildElements(container, "DIV", "tab"); + } + + function findHeaders(container) { + var owner = findChildElements(container, "UL", "tabLinks"); + return findChildElements(owner[0], "LI", null); + } + + function findTitles(tabs) { + var titles = []; + + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + var header = findChildElements(tab, "H2", null)[0]; + + header.parentNode.removeChild(header); + + if (header.innerText) { + titles.push(header.innerText); + } else { + titles.push(header.textContent); + } + } + + return titles; + } + + function findChildElements(container, name, targetClass) { + var elements = []; + var children = container.childNodes; + + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + + if (child.nodeType === 1 && child.nodeName === name) { + if (targetClass && child.className.indexOf(targetClass) < 0) { + continue; + } + + elements.push(child); + } + } + + return elements; + } + + // Entry point. + + window.onload = function() { + initTabs(); + initControls(); + }; +} (window, window.document)); \ No newline at end of file diff --git a/java/word-count/build/reports/tests/packages/default-package.html b/java/word-count/build/reports/tests/packages/default-package.html new file mode 100644 index 0000000..de9b12c --- /dev/null +++ b/java/word-count/build/reports/tests/packages/default-package.html @@ -0,0 +1,103 @@ + + + + + +Test results - Default package + + + + + +
+

Default package

+ +
+ + + + + +
+
+ + + + + + + +
+
+
6
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.002s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+WordCountTest +6000.002s100%
+
+
+ +
+ + diff --git a/java/word-count/build/test-results/TEST-WordCountTest.xml b/java/word-count/build/test-results/TEST-WordCountTest.xml new file mode 100644 index 0000000..b52f243 --- /dev/null +++ b/java/word-count/build/test-results/TEST-WordCountTest.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/java/word-count/build/test-results/binary/test/output.bin b/java/word-count/build/test-results/binary/test/output.bin new file mode 100644 index 0000000..e69de29 diff --git a/java/word-count/build/test-results/binary/test/output.bin.idx b/java/word-count/build/test-results/binary/test/output.bin.idx new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/java/word-count/build/test-results/binary/test/output.bin.idx differ diff --git a/java/word-count/build/test-results/binary/test/results.bin b/java/word-count/build/test-results/binary/test/results.bin new file mode 100644 index 0000000..c96b7a4 Binary files /dev/null and b/java/word-count/build/test-results/binary/test/results.bin differ diff --git a/java/word-count/build/tmp/jar/MANIFEST.MF b/java/word-count/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..58630c0 --- /dev/null +++ b/java/word-count/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/java/word-count/src/main/java/.keep b/java/word-count/src/main/java/.keep new file mode 100644 index 0000000..e69de29 diff --git a/java/word-count/src/main/java/WordCount.java b/java/word-count/src/main/java/WordCount.java new file mode 100644 index 0000000..27ac8fc --- /dev/null +++ b/java/word-count/src/main/java/WordCount.java @@ -0,0 +1,26 @@ +import java.util.*; +import java.lang.String; + +public class WordCount { + /** + * Phrase takes a string and returns a map that counts + * how many of each word are in the phrase + * @param thePhrase The phrase to work with + * @return The map with word counts + */ + public Map Phrase(String thePhrase) { + Map ret = new HashMap(); + thePhrase = thePhrase.replaceAll("[^a-zA-Z0-9 ]", "").replaceAll(" +"," ").toLowerCase(); + String[] words = thePhrase.split(" "); + for(int i = 0; i < words.length; i++) { + int wordCount = 0; + if(ret.containsKey(words[i])) { + wordCount = ret.get(words[i]); + } + if(words[i].trim() != "") { + ret.put(words[i], wordCount+1); + } + } + return ret; + } +} diff --git a/java/word-count/src/test/java/WordCountTest.java b/java/word-count/src/test/java/WordCountTest.java new file mode 100644 index 0000000..7c2bbc4 --- /dev/null +++ b/java/word-count/src/test/java/WordCountTest.java @@ -0,0 +1,99 @@ +import org.junit.Test; + +import java.lang.Integer; +import java.lang.String; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class WordCountTest { + + private final WordCount wordCount = new WordCount(); + + @Test + public void countOneWord() { + Map actualWordCount = new HashMap(); + final Map expectedWordCount = new HashMap(); + expectedWordCount.put("word", 1); + + actualWordCount = wordCount.Phrase("word"); + assertEquals( + expectedWordCount, actualWordCount + ); + } + + @Test + public void countOneOfEach() { + Map actualWordCount = new HashMap(); + final Map expectedWordCount = new HashMap(); + expectedWordCount.put("one", 1); + expectedWordCount.put("of", 1); + expectedWordCount.put("each", 1); + + actualWordCount = wordCount.Phrase("one of each"); + assertEquals( + expectedWordCount, actualWordCount + ); + } + + @Test + public void countMultipleOccurences() { + Map actualWordCount = new HashMap(); + final Map expectedWordCount = new HashMap(); + expectedWordCount.put("one", 1); + expectedWordCount.put("fish", 4); + expectedWordCount.put("two", 1); + expectedWordCount.put("red", 1); + expectedWordCount.put("blue", 1); + + actualWordCount = wordCount.Phrase("one fish two fish red fish blue fish"); + assertEquals( + expectedWordCount, actualWordCount + ); + } + + @Test + public void ignorePunctuation() { + Map actualWordCount = new HashMap(); + final Map expectedWordCount = new HashMap(); + expectedWordCount.put("car", 1); + expectedWordCount.put("carpet", 1); + expectedWordCount.put("as", 1); + expectedWordCount.put("java", 1); + expectedWordCount.put("javascript", 1); + + actualWordCount = wordCount.Phrase("car : carpet as java : javascript!!&@$%^&"); + assertEquals( + expectedWordCount, actualWordCount + ); + + } + + @Test + public void includeNumbers() { + Map actualWordCount = new HashMap(); + final Map expectedWordCount = new HashMap(); + expectedWordCount.put("testing", 2); + expectedWordCount.put("1", 1); + expectedWordCount.put("2", 1); + + actualWordCount = wordCount.Phrase("testing, 1, 2 testing"); + assertEquals( + expectedWordCount, actualWordCount + ); + } + + @Test + public void normalizeCase() { + Map actualWordCount = new HashMap(); + final Map expectedWordCount = new HashMap(); + expectedWordCount.put("go", 3); + + actualWordCount = wordCount.Phrase("go Go GO"); + assertEquals( + expectedWordCount, actualWordCount + ); + } + +} diff --git a/javascript/current b/javascript/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/javascript/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/javascript/hello-world/README.md b/javascript/hello-world/README.md new file mode 100644 index 0000000..03dfcc8 --- /dev/null +++ b/javascript/hello-world/README.md @@ -0,0 +1,64 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +## Setup + +Go through the setup instructions for JavaScript to +install the necessary dependencies: + +http://help.exercism.io/getting-started-with-javascript.html + +## Making the Test Suite Pass + +Execute the tests with: + +```bash +$ jasmine-node . +``` + +In many test suites all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +changing `xit` to `it`. + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/javascript/hello-world/hello-world.js b/javascript/hello-world/hello-world.js new file mode 100644 index 0000000..dfb2ad9 --- /dev/null +++ b/javascript/hello-world/hello-world.js @@ -0,0 +1,15 @@ +// +// This is only a SKELETON file for the 'Hello World' exercise. It's been provided as a +// convenience to get you started writing code faster. +// Make sure to look at test.script.js--that should give you some hints about what is +// expected here. + +var HelloWorld = function() {}; + +HelloWorld.prototype.hello = function(input) { +// +// YOUR CODE GOES HERE +// +}; + +module.exports = HelloWorld; diff --git a/javascript/hello-world/hello-world.spec.js b/javascript/hello-world/hello-world.spec.js new file mode 100644 index 0000000..60d0769 --- /dev/null +++ b/javascript/hello-world/hello-world.spec.js @@ -0,0 +1,17 @@ +var HelloWorld = require('./hello-world'); + +describe('Hello World', function() { + var helloWorld = new HelloWorld(); + + it('says hello world with no name', function() { + expect(helloWorld.hello('')).toEqual('Hello, World!'); + }); + + xit('says hello to bob', function() { + expect(helloWorld.hello('Bob')).toEqual('Hello, Bob!'); + }); + + xit('says hello to sally', function() { + expect(helloWorld.hello('Sally')).toEqual('Hello, Sally!'); + }); +}); diff --git a/lfe/current b/lfe/current new file mode 120000 index 0000000..b905e3b --- /dev/null +++ b/lfe/current @@ -0,0 +1 @@ +leap \ No newline at end of file diff --git a/lfe/leap/Makefile b/lfe/leap/Makefile new file mode 100644 index 0000000..6ef2e00 --- /dev/null +++ b/lfe/leap/Makefile @@ -0,0 +1,19 @@ +ERL = $(shell which erl) +LFETOOL = $(shell which lfetool) +REBAR = $(shell which rebar) + +ifeq ($(ERL),) + $(error Can't find Erlang executable 'erl') +else ifeq ($(LFETOOL),) + $(error Can't find lfetool) +else ifeq ($(REBAR),) + $(error Can't find rebar) +endif + +get-deps: ; $(REBAR) get-deps compile + +clean: ; rebar clean + +compile: ; $(REBAR) compile + +test: compile; $(LFETOOL) tests unit diff --git a/lfe/leap/README.md b/lfe/leap/README.md new file mode 100644 index 0000000..786c455 --- /dev/null +++ b/lfe/leap/README.md @@ -0,0 +1,41 @@ +# Leap + +Write a program that will take a year and report if it is a leap year. + +The tricky thing here is that a leap year occurs: + +```plain +on every year that is evenly divisible by 4 + except every year that is evenly divisible by 100 + unless the year is also evenly divisible by 400 +``` + +For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap +year, but 2000 is. + +If your language provides a method in the standard library that does +this look-up, pretend it doesn't exist and implement it yourself. + +## Notes + +For a delightful, four minute explanation of the whole leap year +phenomenon, go watch [this youtube video][video]. + +[video]: http://www.youtube.com/watch?v=xX96xng7sAE + +* * * * + +For installation and learning resources, refer to the +[exercism help page](http://help.exercism.io/getting-started-with-lfe.html). + +For running the tests provided, you will need `make`. Open a terminal +window and run the following from the exercise directory: + + make test + +And you should now be able to see the results of the test suite for +the exercise. + +## Source + +JavaRanch Cattle Drive, exercise 3 [view source](http://www.javaranch.com/leap.jsp) diff --git a/lfe/leap/rebar.config b/lfe/leap/rebar.config new file mode 100644 index 0000000..0d304be --- /dev/null +++ b/lfe/leap/rebar.config @@ -0,0 +1,8 @@ +{erl_opts, [debug_info, {src_dirs, ["test"]}]}. +{lfe_first_files, []}. +{deps_dir, ["deps"]}. +{eunit_compile_opts, + [{src_dirs, ["test"]}]}. +{deps, + [{lfe, ".*", {git, "git://github.com/rvirding/lfe.git", {tag, "v0.9.2"}}}, + {ltest, ".*", {git, "git://github.com/lfex/ltest.git", {tag, "0.6.1"}}}]}. diff --git a/lfe/leap/src/leap.app.src b/lfe/leap/src/leap.app.src new file mode 100644 index 0000000..2da137e --- /dev/null +++ b/lfe/leap/src/leap.app.src @@ -0,0 +1,11 @@ +%% -*- erlang -*- +{application, 'leap', + [{description, ""}, + {vsn, "0.0.1"}, + {modules, + ['leap']}, + {registered, []}, + {applications, + [kernel, stdlib]}, + {included_applications, []}, + {env, []}]}. diff --git a/lfe/leap/test/leap-tests.lfe b/lfe/leap/test/leap-tests.lfe new file mode 100644 index 0000000..42dd92e --- /dev/null +++ b/lfe/leap/test/leap-tests.lfe @@ -0,0 +1,18 @@ +(defmodule leap-tests + (behaviour ltest-unit) + (export all)) + +(include-lib "eunit/include/eunit.hrl") +(include-lib "ltest/include/ltest-macros.lfe") + +(deftest leap-year + (is (leap:leap-year 1996))) + +(deftest non-leap-year + (is-not (leap:leap-year 1997))) + +(deftest century + (is-not (leap:leap-year 1900))) + +(deftest fourth-century + (is (leap:leap-year 2400))) diff --git a/lisp/current b/lisp/current new file mode 120000 index 0000000..27c76fb --- /dev/null +++ b/lisp/current @@ -0,0 +1 @@ +point-mutations \ No newline at end of file diff --git a/lisp/point-mutations/README.md b/lisp/point-mutations/README.md new file mode 100644 index 0000000..dd31169 --- /dev/null +++ b/lisp/point-mutations/README.md @@ -0,0 +1,43 @@ +# Point Mutations + +Write a program that can calculate the Hamming difference between two DNA strands. + +A mutation is simply a mistake that occurs during the creation or +copying of a nucleic acid, in particular DNA. Because nucleic acids are +vital to cellular functions, mutations tend to cause a ripple effect +throughout the cell. Although mutations are technically mistakes, a very +rare mutation may equip the cell with a beneficial attribute. In fact, +the macro effects of evolution are attributable by the accumulated +result of beneficial microscopic mutations over many generations. + +The simplest and most common type of nucleic acid mutation is a point +mutation, which replaces one base with another at a single nucleotide. + +By counting the number of differences between two homologous DNA strands +taken from different genomes with a common ancestor, we get a measure of +the minimum number of point mutations that could have occurred on the +evolutionary path between the two strands. + +This is called the 'Hamming distance' + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +The Hamming distance between these two DNA strands is 7. + +# Implementation notes + +The Hamming distance is only defined for sequences of equal length. Hence you +may assume that only sequences of equal length will be passed to your hamming +distance function. + +Check out +[Exercism Help](http://help.exercism.io/getting-started-with-lisp.html) +for instructions to get started writing Common Lisp. That page will +explain how to install and setup a Lisp implementation and how to run +the tests. + +## Source + +The Calculating Point Mutations problem at Rosalind [view source](http://rosalind.info/problems/hamm/) diff --git a/lisp/point-mutations/dna.lisp b/lisp/point-mutations/dna.lisp new file mode 100644 index 0000000..63c0525 --- /dev/null +++ b/lisp/point-mutations/dna.lisp @@ -0,0 +1,8 @@ +(defpackage #:dna + (:use #:cl) + (:export #:hamming-distance)) +(in-package #:dna) + +(defun hamming-distance (dna1 dna2) + "Determine number of mutations between DNA strands by computing the Hamming Distance." + ) diff --git a/lisp/point-mutations/point-mutations-test.lisp b/lisp/point-mutations/point-mutations-test.lisp new file mode 100644 index 0000000..4d27839 --- /dev/null +++ b/lisp/point-mutations/point-mutations-test.lisp @@ -0,0 +1,33 @@ +(ql:quickload "lisp-unit") + +(defpackage #:point-mutations-test + (:use #:common-lisp #:lisp-unit)) + +#-xlisp-test (load "dna") + +(in-package #:point-mutations-test) + +(define-test no-difference-between-empty-strands + (assert-equal 0 (dna:hamming-distance "" ""))) + +(define-test no-difference-between-identical-strands + (assert-equal 0 (dna:hamming-distance "GGACTGA" "GGACTGA"))) + +(define-test complete-hamming-distance-in-small-strand + (assert-equal 3 (dna:hamming-distance "ACT" "GGA"))) + +(define-test small-hamming-distance-in-middle-somewhere + (assert-equal 1 (dna:hamming-distance "GGACG" "GGTCG"))) + +(define-test larger-distance + (assert-equal 2 (dna:hamming-distance "ACCAGGG" "ACTATGG"))) + +(define-test invalid-to-get-distance-for-different-length-strings + (assert-equal nil (dna:hamming-distance "AGACAACAGCCAGCCGCCGGATT" "AGGCAA")) + (assert-equal nil (dna:hamming-distance "AGACAACAGCCAGCCGCCGGATT" "AGACATCTTTCAGCCGCCGGATTAGGCAA")) + (assert-equal nil (dna:hamming-distance "AGG" "AGACAACAGCCAGCCGCCGGATT"))) + +#-xlisp-test +(let ((*print-errors* t) + (*print-failures* t)) + (run-tests :all :point-mutations-test)) diff --git a/lua/accumulate/README.md b/lua/accumulate/README.md new file mode 100644 index 0000000..18d55ab --- /dev/null +++ b/lua/accumulate/README.md @@ -0,0 +1,57 @@ +# Accumulate + +Implement the `accumulate` operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection. + +For example, given the collection of numbers: + +- 1, 2, 3, 4, 5 + +And the operation: + +- square a number + +Your code should be able to produce the collection of squares: + +- 1, 4, 9, 16, 25 + +Check out the test suite to see the expected function signature. + +## Restrictions + +Keep your hands off that collect/map/fmap/whatchamacallit functionality +provided by your standard library! +Solve this one yourself using other basic tools instead. + +Elixir specific: it's perfectly fine to use `Enum.reduce` or +`Enumerable.reduce`. + +Lisp specific: it's perfectly fine to use `MAPCAR` or the equivalent, +as this is idiomatic Lisp, not a library function. + +### Getting started +First install lua and [luarocks][2] using [homebrew][1] + + $ brew install lua + +Then install [busted][3] testing framework for lua + + $ luarocks install busted + +Then run your test + + $ busted bob_test.lua + +Other resources + + 1. [Lua Style Guide][4] + 2. [Learn Lua in 15 minutes][5] + +[1]: http://brew.sh/ +[2]: http://luarocks.org/ +[3]: http://olivinelabs.com/busted/ +[4]: https://github.com/Olivine-Labs/lua-style-guide +[5]: http://tylerneylon.com/a/learn-lua/ + +## Source + +Conversation with James Edward Gray II [view source](https://twitter.com/jeg2) diff --git a/lua/accumulate/accumulate_spec.lua b/lua/accumulate/accumulate_spec.lua new file mode 100644 index 0000000..253a897 --- /dev/null +++ b/lua/accumulate/accumulate_spec.lua @@ -0,0 +1,23 @@ +local accumulate = require('accumulate') + +describe('accumulate', function() + + local function square(x) return x * x end + + it('should accumulate over an empty array', function() + assert.are.same({}, accumulate({}, square)) + end) + + it('should accumulate over an array with a single element', function() + assert.are.same({ 4 }, accumulate({ 2 }, square)) + end) + + it('should accumulate over an array with several elements', function() + assert.are.same({ 1, 4, 9 }, accumulate({ 1, 2, 3 }, square)) + end) + + it('should accumulate over an array with a different function', function() + assert.are.same({ 'HELLO', 'WORLD' }, accumulate({ 'hello', 'world' }, string.upper)) + end) + +end) diff --git a/lua/current b/lua/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/lua/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/lua/hello-world/README.md b/lua/hello-world/README.md new file mode 100644 index 0000000..8ff97b2 --- /dev/null +++ b/lua/hello-world/README.md @@ -0,0 +1,67 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +### Getting started +First install lua and [luarocks][2] using [homebrew][1] + + $ brew install lua + +Then install [busted][3] testing framework for lua + + $ luarocks install busted + +Then run your test + + $ busted bob_test.lua + +Other resources + + 1. [Lua Style Guide][4] + 2. [Learn Lua in 15 minutes][5] + +[1]: http://brew.sh/ +[2]: http://luarocks.org/ +[3]: http://olivinelabs.com/busted/ +[4]: https://github.com/Olivine-Labs/lua-style-guide +[5]: http://tylerneylon.com/a/learn-lua/ + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/lua/hello-world/hello-world_spec.lua b/lua/hello-world/hello-world_spec.lua new file mode 100644 index 0000000..e657b5e --- /dev/null +++ b/lua/hello-world/hello-world_spec.lua @@ -0,0 +1,19 @@ +local HelloWorld = require('hello_world') + +describe('Hello World', function() + + it('says hello world with no name', function() + local result = HelloWorld.hello() + assert.are.equals('Hello, world!', result) + end) + + it('says hello to Bob', function() + local result = HelloWorld.hello('Bob') + assert.are.equals('Hello, Bob!', result) + end) + + it('says hello to Sally', function() + local result = HelloWorld.hello('Sally') + assert.are.equals('Hello, Sally!', result) + end) +end) diff --git a/lua/hello-world/hello-world_test.lua b/lua/hello-world/hello-world_test.lua new file mode 100644 index 0000000..e657b5e --- /dev/null +++ b/lua/hello-world/hello-world_test.lua @@ -0,0 +1,19 @@ +local HelloWorld = require('hello_world') + +describe('Hello World', function() + + it('says hello world with no name', function() + local result = HelloWorld.hello() + assert.are.equals('Hello, world!', result) + end) + + it('says hello to Bob', function() + local result = HelloWorld.hello('Bob') + assert.are.equals('Hello, Bob!', result) + end) + + it('says hello to Sally', function() + local result = HelloWorld.hello('Sally') + assert.are.equals('Hello, Sally!', result) + end) +end) diff --git a/objective-c/current b/objective-c/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/objective-c/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/objective-c/hello-world/HelloWorldTest.m b/objective-c/hello-world/HelloWorldTest.m new file mode 100644 index 0000000..5c627d7 --- /dev/null +++ b/objective-c/hello-world/HelloWorldTest.m @@ -0,0 +1,35 @@ +#import +#import "HelloWorld.h" + +@interface test_suite : XCTestCase + +@end + +@implementation test_suite + +- (HelloWorld *)helloWorld { + return [[HelloWorld alloc] init]; +} + +- (void)testNoName { + NSString *input = nil; + NSString *expected = @"Hello, World!"; + NSString *result = [[self helloWorld] hello:input]; + XCTAssertEqualObjects(expected, result); +} + +- (void)testSampleName { + NSString *input = @"Alice"; + NSString *expected = @"Hello, Alice!"; + NSString *result = [[self helloWorld] hello:input]; + XCTAssertEqualObjects(expected, result); +} + +- (void)testOtherSampleName { + NSString *input = @"Bob"; + NSString *expected = @"Hello, Bob!"; + NSString *result = [[self helloWorld] hello:input]; + XCTAssertEqualObjects(expected, result); +} + +@end diff --git a/objective-c/hello-world/README.md b/objective-c/hello-world/README.md new file mode 100644 index 0000000..0591c1e --- /dev/null +++ b/objective-c/hello-world/README.md @@ -0,0 +1,59 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +## Setup + +There are two different methods of getting set up to run the tests with Objective-C: + +- Create an Xcode project with a test target which will run the tests. +- Use the ruby gem `objc` as a test runner utility. + +Both are described in more detail here: http://help.exercism.io/getting-started-with-objective-c.html + + +### Submitting Exercises + +When submitting an exercise, make sure your solution file is in the same directory as the test code. + +For example, if you're submitting `Bob.m` for the Bob exercise, the submit command would be something like `exercism submit /objective-c/bob/Bob.m`. + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/ocaml/bob/Makefile b/ocaml/bob/Makefile new file mode 100644 index 0000000..11b4c73 --- /dev/null +++ b/ocaml/bob/Makefile @@ -0,0 +1,10 @@ +test: test.native + @./test.native + +test.native: *.ml *.mli + @corebuild -quiet -pkg oUnit test.native + +clean: + rm -rf _build + +.PHONY: clean diff --git a/ocaml/bob/README.md b/ocaml/bob/README.md new file mode 100644 index 0000000..72890be --- /dev/null +++ b/ocaml/bob/README.md @@ -0,0 +1,54 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question. + +He answers 'Whoa, chill out!' if you yell at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +## Instructions + +Run the test file, and fix each of the errors in turn. When you get the +first test to pass, go to the first pending or skipped test, and make +that pass as well. When all of the tests are passing, feel free to +submit. + +Remember that passing code is just the first step. The goal is to work +towards a solution that is as readable and expressive as you can make +it. + +Please make your solution as general as possible. Good code doesn't just +pass the test suite, it works with any input that fits the +specification. + +Have fun! + + +## Running Tests + +Because OCaml is a compiled language you need to compile your submission and the test code before you can run the tests. Compile with + +```bash +$ corebuild -quiet test.native +``` + +and when successful run the tests by running the `test.native` executable: + +```bash +./test.native +``` + +Alternatively just type + +```bash +make +``` + +## Source + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=06) diff --git a/ocaml/bob/bob.mli b/ocaml/bob/bob.mli new file mode 100644 index 0000000..8e1772b --- /dev/null +++ b/ocaml/bob/bob.mli @@ -0,0 +1,18 @@ +(* +Answers to `hey` like a teenager. + +## Examples + + # response_for "" + "Fine. Be that way!" + + # response_for "Do you like math?" + "Sure." + + # response_for "HELLO!" + "Woah, chill out!" + + # response_for "Coding is cool." + "Whatever." +*) +val response_for : string -> string diff --git a/ocaml/bob/test.ml b/ocaml/bob/test.ml new file mode 100644 index 0000000..fda3318 --- /dev/null +++ b/ocaml/bob/test.ml @@ -0,0 +1,48 @@ +open Core.Std +open OUnit2 +open Bob + +let ae exp got _test_ctxt = assert_equal ~printer:String.to_string exp got + +let tests = + ["something">:: + ae "Whatever." (response_for "Tom-ay-to, tom-aaaah-to."); + "shouts">:: + ae "Whoa, chill out!" (response_for "WATCH OUT!"); + "questions">:: + ae "Sure." (response_for "Does this cryogenic chamber make me look fat?"); + "forceful talking">:: + ae "Whatever." (response_for "Let's go make out behind the gym!"); + "acronyms">:: + ae "Whatever." (response_for "It's ok if you don't want to go to the DMV."); + "forceful questions">:: + ae "Whoa, chill out!" (response_for "WHAT THE HELL WERE YOU THINKING?"); + "shouting with special characters">:: + ae "Whoa, chill out!" + (response_for "ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!"); + "shouting numbers">:: + ae "Whoa, chill out!" (response_for "1, 2, 3, GO!"); + "statement containing question mark">:: + ae "Whatever." (response_for "Ending with ? means a question."); + "silence">:: + ae "Fine. Be that way!" (response_for ""); + "prolonged silence">:: + ae "Fine. Be that way!" (response_for " "); + "non-letters with question">:: + ae "Sure." (response_for ":) ?"); + "multiple line questons">:: + ae "Whatever." + (response_for "\nDoes this cryogenic chamber make me look fat? \nno"); + "other whitespace">:: + (* No unicode whitespace as OCaml Core doesn't seem to handle Unicode. + * Not it seems does it see ASCII 11 (\v) as whitespace. + *) + ae "Fine. Be that way!" (response_for "\n\r \t"); + "only numbers">:: + ae "Whatever." (response_for "1, 2, 3"); + "question with only numbers">:: + ae "Sure." (response_for "4?"); + ] + +let () = + run_test_tt_main ("bob tests" >::: tests) diff --git a/ocaml/current b/ocaml/current new file mode 120000 index 0000000..2529de8 --- /dev/null +++ b/ocaml/current @@ -0,0 +1 @@ +bob \ No newline at end of file diff --git a/perl5/bob/README.md b/perl5/bob/README.md new file mode 100644 index 0000000..286c6dd --- /dev/null +++ b/perl5/bob/README.md @@ -0,0 +1,35 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question. + +He answers 'Whoa, chill out!' if you yell at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +## Instructions + +Run the test file, and fix each of the errors in turn. When you get the +first test to pass, go to the first pending or skipped test, and make +that pass as well. When all of the tests are passing, feel free to +submit. + +Remember that passing code is just the first step. The goal is to work +towards a solution that is as readable and expressive as you can make +it. + +Please make your solution as general as possible. Good code doesn't just +pass the test suite, it works with any input that fits the +specification. + +Have fun! + + + +## Source + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=06) diff --git a/perl5/bob/bob.pm b/perl5/bob/bob.pm new file mode 100644 index 0000000..47e0e0f --- /dev/null +++ b/perl5/bob/bob.pm @@ -0,0 +1,24 @@ +# +# This is a SKELETON file and has been provided to enable you to get working on the +# first exercise more quickly. +# + +use 5.006; +use strict; +use warnings; + +package Bob; + +our $VERSION = '1.000'; + +use Exporter 5.57 qw(import); + +our @EXPORT_OK = qw(hey); + +sub hey { +# +# YOUR CODE GOES HERE +# +} + +1; diff --git a/perl5/bob/bob.t b/perl5/bob/bob.t new file mode 100644 index 0000000..72357bf --- /dev/null +++ b/perl5/bob/bob.t @@ -0,0 +1,61 @@ +use strict; +use warnings; +use open ':std', ':encoding(utf8)'; +use utf8; + +my $module = $ENV{EXERCISM} ? 'Example' : 'Bob'; + +use Test::More; + +my @cases = map { + { + input => $_->[0], + expect => $_->[1], + desc => $_->[2], + } +} ( + # input expected output title + ['Tom-ay-to, tom-aaaah-to.', 'Whatever.', 'stating something'], + ['WATCH OUT!', 'Whoa, chill out!', 'shouting'], + ['Does this cryogenic chamber make me look fat?', 'Sure.', 'question'], + ['You are, what, like 15?', 'Sure.', 'numeric question'], + ["Let's go make out behind the gym!", 'Whatever.', 'talking forcefully'], + ["It's OK if you don't want to go to the DMV.", 'Whatever.', 'using acronyms in regular speech'], + ['WHAT THE HELL WERE YOU THINKING?', 'Whoa, chill out!', 'forceful questions'], + ['1, 2, 3 GO!', 'Whoa, chill out!', 'shouting numbers'], + ['1, 2, 3', 'Whatever.', 'only numbers'], + ['4?', 'Sure.', 'question with only numbers'], + ['ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!', 'Whoa, chill out!', 'shouting with special characters'], + ["ÜMLÄÜTS!", 'Whoa, chill out!', 'shouting with umlauts'], + ["\xdcML\xc4\xdcTS!", 'Whoa, chill out!', 'shouting with umlauts'], + ['_A', 'Whoa, chill out!', 'underscore shout - before'], + ['A_', 'Whoa, chill out!', 'underscore shout - after'], + ['$A', 'Whoa, chill out!', 'Dollar sign shout - before'], + ['A$', 'Whoa, chill out!', 'Dollar sign shout - after'], + ["ÜMLäÜTS!", 'Whatever.', 'speaking calmly with umlauts'], + ['I HATE YOU', 'Whoa, chill out!', 'shouting with no exclamation mark'], + ['Ending with ? means a question.', 'Whatever.', 'statement containing question mark'], + ["Wait! Hang on. Are you going to be OK?", 'Sure.', 'prattling on'], + ['', 'Fine. Be that way!', 'silence'], + [' ', 'Fine. Be that way!', 'prolonged silence'], + [" \nI just remembered...", 'Whatever.', 'Silence, then more'], +); + +ok -e "$module.pm", "missing $module.pm" + or BAIL_OUT("You need to create a module called $module.pm with a function called hey() that gets one parameter: The text Bob hears."); + +use_ok($module) + or BAIL_OUT("Does $module.pm compile? Does it end with 1; ?"); + +can_ok($module, 'hey') + or BAIL_OUT("Missing package $module; or missing sub hey()"); + +my $sub = $module->can('hey'); + +foreach my $c (@cases) { + #diag uc $c->{input}; + my $title = $c->{desc} ? "$c->{desc}: $c->{input}" : $c->{input}; + is $sub->( $c->{input} ), $c->{expect}, $title; +} + +done_testing(); diff --git a/perl5/current b/perl5/current new file mode 120000 index 0000000..2529de8 --- /dev/null +++ b/perl5/current @@ -0,0 +1 @@ +bob \ No newline at end of file diff --git a/php/current b/php/current new file mode 120000 index 0000000..547c5c3 --- /dev/null +++ b/php/current @@ -0,0 +1 @@ +hamming \ No newline at end of file diff --git a/php/hamming/README.md b/php/hamming/README.md new file mode 100644 index 0000000..9611294 --- /dev/null +++ b/php/hamming/README.md @@ -0,0 +1,54 @@ +# Hamming + +Write a program that can calculate the Hamming difference between two DNA strands. + +A mutation is simply a mistake that occurs during the creation or +copying of a nucleic acid, in particular DNA. Because nucleic acids are +vital to cellular functions, mutations tend to cause a ripple effect +throughout the cell. Although mutations are technically mistakes, a very +rare mutation may equip the cell with a beneficial attribute. In fact, +the macro effects of evolution are attributable by the accumulated +result of beneficial microscopic mutations over many generations. + +The simplest and most common type of nucleic acid mutation is a point +mutation, which replaces one base with another at a single nucleotide. + +By counting the number of differences between two homologous DNA strands +taken from different genomes with a common ancestor, we get a measure of +the minimum number of point mutations that could have occurred on the +evolutionary path between the two strands. + +This is called the 'Hamming distance'. + +It is found by comparing two DNA strands and counting how many of the +nucleotides are different from their equivalent in the other string. + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +The Hamming distance between these two DNA strands is 7. + +# Implementation notes + +The Hamming distance is only defined for sequences of equal length. This means +that based on the definition, each language could deal with getting sequences +of equal length differently. + +## Making the Test Suite Pass + +1. Get [PHPUnit]. + + % wget --no-check-certificate https://phar.phpunit.de/phpunit.phar + % chmod +x phpunit.phar + +2. Execute the tests for an assignment. + + % phpunit.phar wordy/wordy_test.php + +[PHPUnit]: http://phpunit.de + + +## Source + +The Calculating Point Mutations problem at Rosalind [view source](http://rosalind.info/problems/hamm/) diff --git a/php/hamming/hamming.php b/php/hamming/hamming.php new file mode 100644 index 0000000..b457e65 --- /dev/null +++ b/php/hamming/hamming.php @@ -0,0 +1,13 @@ +assertEquals(0, distance('A', 'A')); + } + + public function testCompleteHammingDistanceOfForSingleNucleotideStrand() + { + $this->markTestSkipped(); + $this->assertEquals(1, distance('A', 'G')); + } + + public function testCompleteHammingDistanceForSmallStrand() + { + $this->markTestSkipped(); + $this->assertEquals(2, distance('AG', 'CT')); + } + + public function testSmallHammingDistance() + { + $this->markTestSkipped(); + $this->assertEquals(1, distance('AT', 'CT')); + } + + public function testSmallHammingDistanceInLongerStrand() + { + $this->markTestSkipped(); + $this->assertEquals(1, distance('GGACG', 'GGTCG')); + } + + public function testLargeHammingDistance() + { + $this->markTestSkipped(); + $this->assertEquals(4, distance('GATACA', 'GCATAA')); + } + + public function testHammingDistanceInVeryLongStrand() + { + $this->markTestSkipped(); + $this->assertEquals(9, distance('GGACGGATTCTG', 'AGGACGGATTCT')); + } + + public function testExceptionThrownWhenStrandsAreDifferentLength() + { + $this->markTestSkipped(); + $this->setExpectedException('InvalidArgumentException', 'DNA strands must be of equal length.'); + distance('GGACG', 'AGGACGTGG'); + } +} diff --git a/plsql/current b/plsql/current new file mode 120000 index 0000000..547c5c3 --- /dev/null +++ b/plsql/current @@ -0,0 +1 @@ +hamming \ No newline at end of file diff --git a/plsql/hamming/GETTING_STARTED.md b/plsql/hamming/GETTING_STARTED.md new file mode 100644 index 0000000..10c0231 --- /dev/null +++ b/plsql/hamming/GETTING_STARTED.md @@ -0,0 +1,77 @@ +# Getting Started + +These exercises lean on Test-Driven Development (TDD), but they're not an +exact match. + +## Setup + +You'll need access to a mounted Oracle DB. If you don't have one already +installed, here are a few options: +* download VirtualBox from Oracle and run one of the freely +available images; at the time of writing, the easiest to get started with +at the time of writing might be _Database App Development VM_. The +image is quite large... +* download and install the a version of the Oracle DB itself. Developer licenses +are free. +* get a free workspace at https://apex.oracle.com + +**Note**: if you're using the online version of APEX, compilation errors will +not be indicated very clearly when working in _SQL Commands_ - you will simply +get "Error at line XX: PL/SQL: Statement ignored"... More insight can be +found using the _Object Browser_ and navigating to the object you created +(select either _Packages_ or _Procedures_ in the dropdown menu showing _Tables_, +depending on what you created for the exercise). Also, when you run statements, +"run" each individual `create` statement individually by selecting its text. +APEX does not seem to like doing too much work at once... + +To work on individual problems, a nice and free way is to use SQL Developer. If +you don't want to use yet another IDE, you can simply copy and paste your code +into a terminal / command prompt connected to the database. The files are +prepared in a way that will simply overwrite the previously compiled version. + +#Exercise + +## Step 1 + +Compile the test suite. You can easily do that by copy / pasting (let's call +that _installing_ for simplicity) into your terminal connected to a mounted +Oracle database. + +This will fail, complaining that there is no package called `HAMMING#`. + +To fix the error create the package by installing the prepared solution stub. +Note that you will have to re-install the package body of `UT_HAMMING#`. + +A few words about naming: the `#` at the end of the name signifies that this +is a package. `UT` means _unit test_. _PL/SQL_ has a maximum identifier length +of 30 characters, which is why you will find that many words are abbreviated. + +If you've worked with PL/SQL before, you might wonder why the template is a +package and not simply a standalone function. That would of course also be a +possibility, but in practice standalone procedures or functions are rarely used. + +## Step 2 + +Try to run the test. You will notice that you are missing the function's +implementation. Create it (see the test package for examples). + +Note that functions have to return a value, so for now just `return null;`. + +## Step 3 + +Run the test again. It should now execute, but the test will fail. +That's where you get to actually implement the function! + +## Wash, Rinse, Repeat + +Only the first test is enabled at first, the others are commented out. To enable +them, simply delete the `--` in front of the procedure call and they'll run +when you next install the test package! + +## Submit + +When everything is passing, you can submit your code with the following +command: + + $ exercism submit hamming#.plsql + diff --git a/plsql/hamming/README.md b/plsql/hamming/README.md new file mode 100644 index 0000000..5eb2dfe --- /dev/null +++ b/plsql/hamming/README.md @@ -0,0 +1,59 @@ +# Hamming + +Write a program that can calculate the Hamming difference between two DNA strands. + +A mutation is simply a mistake that occurs during the creation or +copying of a nucleic acid, in particular DNA. Because nucleic acids are +vital to cellular functions, mutations tend to cause a ripple effect +throughout the cell. Although mutations are technically mistakes, a very +rare mutation may equip the cell with a beneficial attribute. In fact, +the macro effects of evolution are attributable by the accumulated +result of beneficial microscopic mutations over many generations. + +The simplest and most common type of nucleic acid mutation is a point +mutation, which replaces one base with another at a single nucleotide. + +By counting the number of differences between two homologous DNA strands +taken from different genomes with a common ancestor, we get a measure of +the minimum number of point mutations that could have occurred on the +evolutionary path between the two strands. + +This is called the 'Hamming distance'. + +It is found by comparing two DNA strands and counting how many of the +nucleotides are different from their equivalent in the other string. + + GAGCCTACTAACGGGAT + CATCGTAATGACGGCCT + ^ ^ ^ ^ ^ ^^ + +The Hamming distance between these two DNA strands is 7. + +# Implementation notes + +The Hamming distance is only defined for sequences of equal length. This means +that based on the definition, each language could deal with getting sequences +of equal length differently. + +## Setup + +Go through the setup instructions for PL/SQL to get ready to code: + +http://help.exercism.io/getting-started-with-plsql.html + +## Running the Tests + +Execute the tests by calling the `run` method in the respective `ut_#` package. +The necessary code should be contained at the end of the test package. +As an example, the test for the _hamming_ exercise would be run using + +``` +begin + ut_hamming#.run; +end; +/ +``` + +## Source + +The Calculating Point Mutations problem at Rosalind [view source](http://rosalind.info/problems/hamm/) diff --git a/plsql/hamming/hamming#.plsql b/plsql/hamming/hamming#.plsql new file mode 100644 index 0000000..fed6de4 --- /dev/null +++ b/plsql/hamming/hamming#.plsql @@ -0,0 +1,23 @@ +create or replace package hamming# +is + --+--------------------------------------------------------------------------+ + -- Computes the Hamming distance between two starnds. + -- + -- @param i_first sequence to compare + -- @param i_second sequence to compare + -- + -- @return Hamming distance between i_first and i_second + --+--------------------------------------------------------------------------+ + function distance ( + i_first varchar2 + ,i_second varchar2 + ) return pls_integer; + +end hamming#; +/ + +create or replace package body hamming# +is + +end hamming#; +/ diff --git a/plsql/hamming/ut_hamming#.plsql b/plsql/hamming/ut_hamming#.plsql new file mode 100644 index 0000000..d1b6674 --- /dev/null +++ b/plsql/hamming/ut_hamming#.plsql @@ -0,0 +1,53 @@ +create or replace package ut_hamming# +is + procedure run; +end ut_hamming#; +/ + +create or replace package body ut_hamming# +is + + procedure test ( + i_descn varchar2 + ,i_exp pls_integer + ,i_act pls_integer + ) + is + begin + if i_exp = i_act then + dbms_output.put_line('SUCCESS: ' || i_descn); + else + dbms_output.put_line( + 'FAILURE: ' || i_descn + || ': expected ' || nvl('' || i_exp, 'null') + || ', but got ' || nvl('' || i_act, 'null') + || '!' + ); + end if; + end test; + + procedure run + is + begin + test('test_no_difference_between_identical_strands' , 0, hamming#.distance(i_first => 'A' , i_second => 'A' )); + --test('test_complete_hamming_distance_of_for_single_nucleotide_strand', 1, hamming#.distance(i_first => 'A' , i_second => 'G' )); + --test('test_complete_hamming_distance_of_for_small_strand' , 2, hamming#.distance(i_first => 'AG' , i_second => 'CT' )); + --test('test_small_hamming_distance' , 1, hamming#.distance(i_first => 'AG' , i_second => 'AT' )); + --test('test_small_hamming_distance_in_longer_strand' , 1, hamming#.distance(i_first => 'GGACG' , i_second => 'GGTCG' )); + --test('test_nonunique_characters_within_first_strand' , 1, hamming#.distance(i_first => 'AGA' , i_second => 'AGG' )); + --test('test_nonunique_characters_within_second_strand' , 1, hamming#.distance(i_first => 'AGG' , i_second => 'AGA' )); + --test('test_large_hamming_distance' , 4, hamming#.distance(i_first => 'GATACA' , i_second => 'GCATAA' )); + --test('test_hamming_distance_in_very_long_strand' , 9, hamming#.distance(i_first => 'GGACGGATTCTG', i_second => 'AGGACGGATTCT')); + exception + when others then + dbms_output.put_line('Test execution failed.'); + dbms_output.put_line(sqlerrm); + end run; + +end ut_hamming#; +/ + +begin + ut_hamming#.run; +end; +/ diff --git a/python/current b/python/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/python/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/python/hello-world/README.md b/python/hello-world/README.md new file mode 100644 index 0000000..1972356 --- /dev/null +++ b/python/hello-world/README.md @@ -0,0 +1,49 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +### Submitting Exercises + +Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/` directory. + +For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit /python/bob/bob.py`. + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/python/hello-world/hello_world.py b/python/hello-world/hello_world.py new file mode 100644 index 0000000..bfcb36f --- /dev/null +++ b/python/hello-world/hello_world.py @@ -0,0 +1,7 @@ +# +# Skeleton file for the Python "Hello World" exercise. +# + + +def hello(name=''): + return diff --git a/python/hello-world/hello_world_test.py b/python/hello-world/hello_world_test.py new file mode 100644 index 0000000..c6b5be9 --- /dev/null +++ b/python/hello-world/hello_world_test.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals +import unittest + +import hello_world + + +class BobTests(unittest.TestCase): + + def test_hello_without_name(self): + self.assertEqual( + 'Hello, World!', + hello_world.hello() + ) + + def test_hello_with_name(self): + self.assertEqual( + 'Hello, Jane!', + hello_world.hello('Jane') + ) + + def test_hello_with_umlaut_name(self): + self.assertEqual( + 'Hello, Jürgen!', + hello_world.hello('Jürgen') + ) + +if __name__ == '__main__': + unittest.main() diff --git a/racket/current b/racket/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/racket/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/racket/hello-world/README.md b/racket/hello-world/README.md new file mode 100644 index 0000000..19f7a0f --- /dev/null +++ b/racket/hello-world/README.md @@ -0,0 +1,67 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +* * * * + +For installation and learning resources, refer to the +[exercism help page](http://help.exercism.io/getting-started-with-racket.html). + +You can run the provided tests through DrRacket, or via the command line. + +To run the test through DrRacket, simply open the test file and click the 'Run' button in the upper right. + +To run the test from the command line, simply run the test from the exercise directory. For example, if the test suite is called `hello-world-test.rkt`, you can run the following command: + +``` +raco test hello-world-test.rkt +``` + +which will display the following: + +``` +raco test: (submod "hello-world-test.rkt" test) +2 success(es) 0 failure(s) 0 error(s) 2 test(s) run +0 +2 tests passed +``` + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/racket/hello-world/hello-world-test.rkt b/racket/hello-world/hello-world-test.rkt new file mode 100644 index 0000000..968e3cf --- /dev/null +++ b/racket/hello-world/hello-world-test.rkt @@ -0,0 +1,15 @@ +#lang racket + +(require "hello-world.rkt") + +(module+ test + (require rackunit rackunit/text-ui) + + (define suite + (test-suite + "hello world tests" + + (test-equal? "no arg returns Hello, World!" (hello) "Hello, World!") + (test-equal? "with arg returns Hello, arg!" (hello "exercism") "Hello, exercism!"))) + + (run-tests suite)) diff --git a/racket/hello-world/hello-world.rkt b/racket/hello-world/hello-world.rkt new file mode 100644 index 0000000..e015e98 --- /dev/null +++ b/racket/hello-world/hello-world.rkt @@ -0,0 +1,3 @@ +#lang racket + +(provide hello) diff --git a/ruby/current b/ruby/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/ruby/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/ruby/hello-world/.version b/ruby/hello-world/.version new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/ruby/hello-world/.version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/ruby/hello-world/GETTING_STARTED.md b/ruby/hello-world/GETTING_STARTED.md new file mode 100644 index 0000000..97d6dc6 --- /dev/null +++ b/ruby/hello-world/GETTING_STARTED.md @@ -0,0 +1,147 @@ +# Getting Started + +These exercises lean on Test-Driven Development (TDD), but they're not an +exact match. If you want a gentle introduction to TDD using minitest in +Ruby, see the "Intro to TDD" over at JumpstartLab: +http://tutorials.jumpstartlab.com/topics/testing/intro-to-tdd.html + +The following steps assume that you are in the same directory as the test +suite. + +You must have the `minitest` gem installed: + + $ gem install minitest + +## Step 1 + +Run the test suite. It's written using the Minitest framework, and can be +run with ruby: + + $ ruby hello_world_test.rb + +This will fail, complaining that there is no file called `hello_world`. + +To fix the error create an empty file called `hello_world.rb` in the same +directory as the `hello_world_test.rb` file. + +## Step 2 + +Run the test again. It will give you a new error, since now the file exists, +but is empty and does not contain the expected code. + +Depending on what platform you are on, the error will look different, but +the way to fix it will be the same. + +On Windows, it will complain about: + + syntax error, unexpected end-of-input, expecting '(' + +On OS X and Linux, the error will be something like: + + # Running: + + ESSS + + Finished in 0.001539s, 2599.0903 runs/s, 0.0000 assertions/s. + + 1) Error: + HelloWorldTest#test_no_name: + NameError: uninitialized constant HelloWorldTest::HelloWorld + hello-world/hello_world_test.rb:5:in `test_no_name' + +Within the first test, we are referencing a constant named `HelloWorld` when +we say `HelloWorld.hello`. When Ruby sees a capitalized name like +`HelloWorld`, it looks it up in a big huge list of all the constants it knows about, +to see what it points to. It could point to anything, and often in Ruby we have +constants that point to definitions of classes or modules. + +When it looks `HelloWorld` up in its list, it doesn't find anything, so we need +to make one. + +### Fixing the Error + +To fix it, open up the hello_world.rb file and add the following code: + + class HelloWorld + end + +### Understanding Test Failures + +Whether you are on Windows, Mac OS X or Linux, you will eventually be faced with +errors and failures that look a lot like the Mac OS X / Linux error above. + +The letters `ESSS` show that there are four tests altogether, +that one of them has an error (`E`), and that three of them are skipped (`S`). + +The goal is to have four passing tests, which will show as four dots: `....`. + +The tests are run in randomized order, which will cause the letters to display +in random order as well. + +## Step 3 + +Run the test again. + + 1) Error: + HelloWorldTest#test_no_name: + NoMethodError: undefined method `hello' for HelloWorld:Class + hello_world_test.rb:5:in `test_no_name' + +This time we have a `HelloWorld`, but we're trying tell it to `hello`, and +`HelloWorld` doesn't understand that message. + +Open up hello_world.rb and add a method definition inside the class: + + class HelloWorld + def self.hello + end + end + +## Step 4 + +Run the test again. + + 1) Failure: + HelloWorldTest#test_no_name [hello_world_test.rb:11]: + When given no name, we should greet the world!. + Expected: "Hello, world!" + Actual: nil + +Up until now we've been getting errors, this time we get a failure. + +An error means that Ruby cannot even run properly because of things like missing +files or syntax errors, or referring to things that don't exist. + +A failure is different. A failure is when Ruby is running just fine +and the test is expecting one outcome, but getting another. + +The test is expecting the `hello` method to return the string `"Hello, world!"`. The easiest way +to make it pass, is to simply stick the string `"Hello, world!"` inside the method definition. + +## Step 6 + +Run the test again. + +If it fails you're going to need to read the error message carefully to figure +out what went wrong, and then try again. + +If it passes, then you're ready to move to the next step. + +Open the hello_world_test.rb file, and find the word "skip". All but the first test +start with "skip", which tells Minitest to ignore the test. This is so that +you don't have to deal with all the failures at once. + +To activate the next test, delete the "skip", and run the test suite again. + +## Wash, Rinse, Repeat + +Delete one "skip" at a time, and make each test pass before you move to the +next one. + +## Submit + +When everything is passing, you can submit your code with the following +command: + + $ exercism submit hello_world.rb + diff --git a/ruby/hello-world/README.md b/ruby/hello-world/README.md new file mode 100644 index 0000000..200f0e7 --- /dev/null +++ b/ruby/hello-world/README.md @@ -0,0 +1,73 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +* * * * + +For installation and learning resources, refer to the +[exercism help page](http://help.exercism.io/getting-started-with-ruby.html). + +For running the tests provided, you will need the Minitest gem. Open a +terminal window and run the following command to install minitest: + + gem install minitest + +If you would like color output, you can `require 'minitest/pride'` in +the test file, or note the alternative instruction, below, for running +the test file. + +In order to run the test, you can run the test file from the exercise +directory. For example, if the test suite is called +`hello_world_test.rb`, you can run the following command: + + ruby hello_world_test.rb + +To include color from the command line: + + ruby -rminitest/pride hello_world_test.rb + +The test files may have the execution bit set so you may also be able to +run it like this: + + ./hello_world_test.rb + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/ruby/hello-world/hello_world_test.rb b/ruby/hello-world/hello_world_test.rb new file mode 100644 index 0000000..7de177b --- /dev/null +++ b/ruby/hello-world/hello_world_test.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby +begin + gem 'minitest', '>= 5.0.0' + require 'minitest/autorun' + require_relative 'hello_world' +rescue Gem::LoadError => e + puts "\nMissing Dependency:\n#{e.backtrace.first} #{e.message}" + puts 'Minitest 5.0 gem must be installed for the xRuby track.' +rescue LoadError => e + puts "\nError:\n#{e.backtrace.first} #{e.message}" + puts DATA.read + exit 1 +end + +# Test data version: +# 7668b09 Added hello world test definition + +class HelloWorldTest < Minitest::Test + def test_no_name + assert_equal 'Hello, World!', HelloWorld.hello + end + + def test_sample_name + skip + assert_equal 'Hello, Alice!', HelloWorld.hello('Alice') + end + + def test_other_sample_name + skip + assert_equal 'Hello, Bob!', HelloWorld.hello('Bob') + end +end + +__END__ + +***************************************************** +You got an error, which is exactly as it should be. +This is the first step in the Test-Driven Development +(TDD) process. + +The most important part of the error is + + cannot load such file + +It's looking for a file named hello_world.rb that doesn't +exist yet. + +To fix the error, create an empty file named hello_world.rb +in the same directory as the hello_world_test.rb file. + +Then run the test again. + +For more guidance as you work on this exercise, see +GETTING_STARTED.md. +***************************************************** diff --git a/rust/current b/rust/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/rust/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/rust/hello-world/Cargo.lock b/rust/hello-world/Cargo.lock new file mode 100644 index 0000000..ca4e4e2 --- /dev/null +++ b/rust/hello-world/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "hello-world" +version = "0.0.0" + diff --git a/rust/hello-world/Cargo.toml b/rust/hello-world/Cargo.toml new file mode 100644 index 0000000..375da45 --- /dev/null +++ b/rust/hello-world/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "hello-world" +version = "0.0.0" diff --git a/rust/hello-world/GETTING_STARTED.md b/rust/hello-world/GETTING_STARTED.md new file mode 100644 index 0000000..725b2d8 --- /dev/null +++ b/rust/hello-world/GETTING_STARTED.md @@ -0,0 +1,160 @@ +# Getting Started + +These exercises lean on Test-Driven Development (TDD), but they're not +an exact match. + +The following steps assume that you are in the same directory as the exercise. + +You must have rust installed. +Follow the [Installing Rust chapter in the Rust book](http://doc.rust-lang.org/stable/book/installing-rust.html). +The [getting started with rust](http://help.exercism.io/getting-started-with-rust.html) +section from exercism is also useful. + +## Step 1 + +Run the test suite. It can be run with `cargo`, which is installed with rust. + +``` +$ cargo test +``` + +This will fail, complaining that `hello-world` could not compile. + +To fix this, create a new directory called `src`. +Create a new file called, `lib.rs`, inside the `src` directory. + +## Step 2 + +Run the test again. It will give you a new error, another compile error. +Our `lib.rs` does not contain any code, specifically the `hello()` +function that our test is looking for. + +### Fixing the Error + +To fix it, open up the `src/lib.rs` file and add the following code: + +```rust +pub fn hello(name: Option<&str>) -> String { + "".to_string() +} +``` + +Our test is looking for the `hello()` function from the `hello_world` +crate. `lib.rs`, by default, is our crate root and our test +is looking for the `hello()` function there. + +The code we are adding to `lib.rs` defines a public function (`pub fn`) that is called "hello". +The function accepts a `name` as an optional argument (`Option`). +The function returns a `String`. +We start by returning an empty string (`"".to_string()`). + +## Step 3 + +Run the test again. + +This time, code compilation will pass and we receive actual test failures. + +``` +running 3 tests +test test_other_same_name ... ignored +test test_sample_name ... ignored +test test_no_name ... FAILED + +failures: + +---- test_no_name stdout ---- +thread 'test_no_name' panicked at 'assertion failed: `(left == right)` +(left: `"Hello, World!"`, right: `""`)', tests/hello-world.rs:5 + + +failures: + test_no_name + +test result: FAILED. 0 passed; 1 failed; 2 ignored; 0 measured +``` + +### Understanding Test Failures + +Only one of the tests runs (`test_no_name`) and it fails. The other +tests are ignored (more on that later). + +The `test_no_name` failure states that it is expecting the value, +`"Hello, World!"`, to be returned from `hello("")`. +The left side of the assertion (at line 5) should be equal to the right side. + +``` +---- test_no_name stdout ---- +thread 'test_no_name' panicked at 'assertion failed: `(left == right)` +(left: `"Hello, World!"`, right: `""`)', tests/hello-world.rs:5 +``` + +To fix it, let's return `"Hello, World!"`, instead of an empty string +(`""`) inside our `hello` function. + +```rust +pub fn hello(name: Option<&str>) -> String { + "Hello, World!".to_string() +} +``` + +## Step 4 + +Run the test again. This time, it will pass. + +``` +running 3 tests +test test_other_same_name ... ignored +test test_sample_name ... ignored +test test_no_name ... ok + +test result: ok. 1 passed; 0 failed; 2 ignored; 0 measured + + Doc-tests hello-world + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +You may have noticed compiler warnings earlier: + +``` +Compiling hello-world v0.0.0 +(file:////exercism/exercises/rust/hello-world) +src/lib.rs:1:14: 1:18 warning: unused variable: `name`, #[warn(unused_variables)] on by default +src/lib.rs:1 pub fn hello(name: Option<&str>) -> String { + ^~~~ +``` + +Our `hello` function does not use the `name` argument so the +compiler is letting us know that we could potentially remove the +argument from our function (it likes "clean code"). + +As we make the rest of the tests pass, we will find that we need the `name` +argument, so don't delete it. + +Activate the next test. Open the `tests/hello-world.rs` file. +Delete the `#[ignore]` line for the `test_sample_name` test. + +## Step 5 + +Run the test suite again. Read the test failure and make the test pass. + +As a reminder, the [rust book](http://doc.rust-lang.org/stable/book/README.html) +is a good reference for understanding rust. +The cargo output may also have hints to help you, depending on the errors you get. +For example, `rustc --explain E0425` will explain unresolved name errors. + +## Wash, Rinse, Repeat + +Delete one `#[ignore]` at a time, and make each test pass before you move to +the next one. + +## Submit + +When everything is passing, you can submit your code with the following +command: + +``` +$ exercism submit src/lib.rs +``` diff --git a/rust/hello-world/README.md b/rust/hello-world/README.md new file mode 100644 index 0000000..99f2bfc --- /dev/null +++ b/rust/hello-world/README.md @@ -0,0 +1,68 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, remove the ignore flag (`#[ignore]`) from the next test and get the tests +to pass again. The test file is located in the `tests` directory. You can +also remove the ignore flag from all the tests to get them to run all at once +if you wish. + +Make sure to read the [Crates and Modules](crates-and-modules) chapter if you +haven't already, it will help you with organizing your files. + +[help-page]: http://help.exercism.io/getting-started-with-rust.html +[crates-and-modules]: http://doc.rust-lang.org/stable/book/crates-and-modules.html + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/rust/hello-world/tests/hello-world.rs b/rust/hello-world/tests/hello-world.rs new file mode 100644 index 0000000..b8be861 --- /dev/null +++ b/rust/hello-world/tests/hello-world.rs @@ -0,0 +1,18 @@ +extern crate hello_world; + +#[test] +fn test_no_name() { + assert_eq!("Hello, World!", hello_world::hello(None)); +} + +#[test] +#[ignore] +fn test_sample_name() { + assert_eq!("Hello, Alice!", hello_world::hello(Some("Alice"))); +} + +#[test] +#[ignore] +fn test_other_same_name() { + assert_eq!("Hello, Bob!", hello_world::hello(Some("Bob"))); +} diff --git a/rust/leap/Cargo.lock b/rust/leap/Cargo.lock new file mode 100644 index 0000000..015af98 --- /dev/null +++ b/rust/leap/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "leap" +version = "0.0.0" + diff --git a/rust/leap/Cargo.toml b/rust/leap/Cargo.toml new file mode 100644 index 0000000..e9ad1e3 --- /dev/null +++ b/rust/leap/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "leap" +version = "0.0.0" diff --git a/rust/leap/README.md b/rust/leap/README.md new file mode 100644 index 0000000..8cb44d7 --- /dev/null +++ b/rust/leap/README.md @@ -0,0 +1,53 @@ +# Leap + +Write a program that will take a year and report if it is a leap year. + +The tricky thing here is that a leap year occurs: + +```plain +on every year that is evenly divisible by 4 + except every year that is evenly divisible by 100 + unless the year is also evenly divisible by 400 +``` + +For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap +year, but 2000 is. + +If your language provides a method in the standard library that does +this look-up, pretend it doesn't exist and implement it yourself. + +## Notes + +For a delightful, four minute explanation of the whole leap year +phenomenon, go watch [this youtube video][video]. + +[video]: http://www.youtube.com/watch?v=xX96xng7sAE + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Writing the Code + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, remove the ignore flag (`#[ignore]`) from the next test and get the tests +to pass again. The test file is located in the `tests` directory. You can +also remove the ignore flag from all the tests to get them to run all at once +if you wish. + +Make sure to read the [Crates and Modules](crates-and-modules) chapter if you +haven't already, it will help you with organizing your files. + +[help-page]: http://help.exercism.io/getting-started-with-rust.html +[crates-and-modules]: http://doc.rust-lang.org/stable/book/crates-and-modules.html + +## Source + +JavaRanch Cattle Drive, exercise 3 [view source](http://www.javaranch.com/leap.jsp) diff --git a/rust/leap/tests/leap.rs b/rust/leap/tests/leap.rs new file mode 100644 index 0000000..cd899d9 --- /dev/null +++ b/rust/leap/tests/leap.rs @@ -0,0 +1,24 @@ +extern crate leap; + +#[test] +fn test_vanilla_leap_year() { + assert_eq!(leap::is_leap_year(1996), true); +} + +#[test] +#[ignore] +fn test_any_old_year() { + assert_eq!(leap::is_leap_year(1997), false); +} + +#[test] +#[ignore] +fn test_century() { + assert_eq!(leap::is_leap_year(1900), false); +} + +#[test] +#[ignore] +fn test_exceptional_century() { + assert_eq!(leap::is_leap_year(2000), true); +} diff --git a/scala/current b/scala/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/scala/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/scala/hello-world/README.md b/scala/hello-world/README.md new file mode 100644 index 0000000..6258db7 --- /dev/null +++ b/scala/hello-world/README.md @@ -0,0 +1,53 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +The Scala exercises assume an SBT project scheme. The exercise solution source +should be placed within the exercise directory/src/main/scala. The exercise +unit tests can be found within the exercise directory/src/test/scala. + +To run the tests simply run the command `sbt test` in the exercise directory. + +For more detailed info about the Scala track see the [help +page](http://help.exercism.io/getting-started-with-scala.html). + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/scala/hello-world/build.sbt b/scala/hello-world/build.sbt new file mode 100644 index 0000000..5a39260 --- /dev/null +++ b/scala/hello-world/build.sbt @@ -0,0 +1,3 @@ +scalaVersion := "2.11.7" + +libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.5" % "test" diff --git a/scala/hello-world/src/main/scala/.keep b/scala/hello-world/src/main/scala/.keep new file mode 100644 index 0000000..e69de29 diff --git a/scala/hello-world/src/test/scala/HelloWorldTest.scala b/scala/hello-world/src/test/scala/HelloWorldTest.scala new file mode 100644 index 0000000..8e45e38 --- /dev/null +++ b/scala/hello-world/src/test/scala/HelloWorldTest.scala @@ -0,0 +1,15 @@ +import org.scalatest.{Matchers, FunSuite} + +class HelloWorldTest extends FunSuite with Matchers { + test("Without name") { + HelloWorld.hello() should be ("Hello, World!") + } + + test("with name") { + HelloWorld.hello("Jane") should be ("Hello, Jane!") + } + + test("with umlaut name") { + HelloWorld.hello("Jürgen") should be ("Hello, Jürgen!") + } +} diff --git a/scheme/current b/scheme/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/scheme/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/scheme/hello-world/README.md b/scheme/hello-world/README.md new file mode 100644 index 0000000..d9a535b --- /dev/null +++ b/scheme/hello-world/README.md @@ -0,0 +1,44 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/scheme/hello-world/hello-world-test.scm b/scheme/hello-world/hello-world-test.scm new file mode 100644 index 0000000..e3ac595 --- /dev/null +++ b/scheme/hello-world/hello-world-test.scm @@ -0,0 +1,21 @@ +;; Load SRFI-64 lightweight testing specification +(use-modules (srfi srfi-64)) + +;; Suppress log file output. To write logs, comment out the following line: +(module-define! (resolve-module '(srfi srfi-64)) 'test-log-to-file #f) + +;; Require module +(add-to-load-path (dirname (current-filename))) +(use-modules (hello-world)) + +(test-begin "hello-world") + +(test-assert "Called with no args returns hello world" + (equal? (hello) + "Hello, World!")) + +(test-assert "Called with an arg returns hello arg" + (equal? (hello "exercism") + "Hello, exercism!")) + +(test-end "hello-world") diff --git a/scheme/hello-world/hello-world.scm b/scheme/hello-world/hello-world.scm new file mode 100644 index 0000000..11f598d --- /dev/null +++ b/scheme/hello-world/hello-world.scm @@ -0,0 +1,2 @@ +(define-module (hello-world) + #:export (hello)) diff --git a/swift/current b/swift/current new file mode 120000 index 0000000..bdd51cc --- /dev/null +++ b/swift/current @@ -0,0 +1 @@ +hello-world \ No newline at end of file diff --git a/swift/hello-world/README.md b/swift/hello-world/README.md new file mode 100644 index 0000000..bf390d2 --- /dev/null +++ b/swift/hello-world/README.md @@ -0,0 +1,50 @@ +# Hello World + +Write a program that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +The `Hello World!` program will greet me, the caller. + +If I tell the program my name is Alice, it will greet me by saying "Hello, Alice!". + +If I neglect to give it my name, it will greet me by saying "Hello, World!" + +## 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](http://help.exercism.io/submitting-exercises.html). + +## 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. However, solutions to the hello-world exercise will be not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +## Setup + +Go through the project setup instructions for Xcode using Swift: + +http://help.exercism.io/getting-started-with-swift.html + + +## Source + +This is a program to introduce users to using Exercism [view source](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) diff --git a/swift/hello-world/helloWorld.swift b/swift/hello-world/helloWorld.swift new file mode 100644 index 0000000..15910c1 --- /dev/null +++ b/swift/hello-world/helloWorld.swift @@ -0,0 +1,3 @@ +// Apple Swift version 2.0 + +// Enter Solution Here \ No newline at end of file diff --git a/swift/hello-world/helloWorld.xcodeproj/project.pbxproj b/swift/hello-world/helloWorld.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a8aa09d --- /dev/null +++ b/swift/hello-world/helloWorld.xcodeproj/project.pbxproj @@ -0,0 +1,256 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 9DCE80801BA747050024C69D /* helloWorldTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DCE807F1BA747050024C69D /* helloWorldTest.swift */; }; + 9DCE80881BA748820024C69D /* helloWorld.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DCE80871BA748820024C69D /* helloWorld.swift */; settings = {ASSET_TAGS = (); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 9DCE807D1BA747050024C69D /* helloWorldTest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = helloWorldTest.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 9DCE807F1BA747050024C69D /* helloWorldTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = helloWorldTest.swift; sourceTree = ""; }; + 9DCE80811BA747050024C69D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9DCE80871BA748820024C69D /* helloWorld.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = helloWorld.swift; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9DCE807A1BA747050024C69D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9DCE80661BA746730024C69D = { + isa = PBXGroup; + children = ( + 9DCE807E1BA747050024C69D /* helloWorldTest */, + 9DCE80701BA746730024C69D /* Products */, + ); + sourceTree = ""; + }; + 9DCE80701BA746730024C69D /* Products */ = { + isa = PBXGroup; + children = ( + 9DCE807D1BA747050024C69D /* helloWorldTest.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 9DCE807E1BA747050024C69D /* helloWorldTest */ = { + isa = PBXGroup; + children = ( + 9DCE80871BA748820024C69D /* helloWorld.swift */, + 9DCE807F1BA747050024C69D /* helloWorldTest.swift */, + 9DCE80811BA747050024C69D /* Info.plist */, + ); + path = helloWorldTest; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 9DCE807C1BA747050024C69D /* helloWorldTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9DCE80841BA747050024C69D /* Build configuration list for PBXNativeTarget "helloWorldTest" */; + buildPhases = ( + 9DCE80791BA747050024C69D /* Sources */, + 9DCE807A1BA747050024C69D /* Frameworks */, + 9DCE807B1BA747050024C69D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = helloWorldTest; + productName = helloWorldTest; + productReference = 9DCE807D1BA747050024C69D /* helloWorldTest.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 9DCE80671BA746730024C69D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = exercism.io; + TargetAttributes = { + 9DCE807C1BA747050024C69D = { + CreatedOnToolsVersion = 7.0; + }; + }; + }; + buildConfigurationList = 9DCE806A1BA746730024C69D /* Build configuration list for PBXProject "helloWorld" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 9DCE80661BA746730024C69D; + productRefGroup = 9DCE80701BA746730024C69D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 9DCE807C1BA747050024C69D /* helloWorldTest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 9DCE807B1BA747050024C69D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 9DCE80791BA747050024C69D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9DCE80801BA747050024C69D /* helloWorldTest.swift in Sources */, + 9DCE80881BA748820024C69D /* helloWorld.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 9DCE80741BA746740024C69D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 9DCE80751BA746740024C69D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 9DCE80821BA747050024C69D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = helloWorldTest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.exercism.io.helloWorldTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 9DCE80831BA747050024C69D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = helloWorldTest/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.exercism.io.helloWorldTest; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 9DCE806A1BA746730024C69D /* Build configuration list for PBXProject "helloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9DCE80741BA746740024C69D /* Debug */, + 9DCE80751BA746740024C69D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9DCE80841BA747050024C69D /* Build configuration list for PBXNativeTarget "helloWorldTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9DCE80821BA747050024C69D /* Debug */, + 9DCE80831BA747050024C69D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 9DCE80671BA746730024C69D /* Project object */; +} diff --git a/swift/hello-world/helloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/swift/hello-world/helloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..db1c625 --- /dev/null +++ b/swift/hello-world/helloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/swift/hello-world/helloWorld.xcodeproj/xcshareddata/xcschemes/helloWorldTest.xcscheme b/swift/hello-world/helloWorld.xcodeproj/xcshareddata/xcschemes/helloWorldTest.xcscheme new file mode 100644 index 0000000..2aed485 --- /dev/null +++ b/swift/hello-world/helloWorld.xcodeproj/xcshareddata/xcschemes/helloWorldTest.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift/hello-world/helloWorldTest/Info.plist b/swift/hello-world/helloWorldTest/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/swift/hello-world/helloWorldTest/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/swift/hello-world/helloWorldTest/helloWorldTest.swift b/swift/hello-world/helloWorldTest/helloWorldTest.swift new file mode 100644 index 0000000..34a58d8 --- /dev/null +++ b/swift/hello-world/helloWorldTest/helloWorldTest.swift @@ -0,0 +1,27 @@ +import XCTest + +// Apple Swift version 2.0 + +class HelloWorldTest: 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") + } + +} \ No newline at end of file