This commit is contained in:
Ben Harris 2018-03-09 15:13:37 -05:00
parent 14005e4a12
commit 3a6f481571
13 changed files with 558 additions and 19 deletions

View File

@ -0,0 +1,69 @@
# All Your Base
Convert a number, represented as a sequence of digits in one base, to any other base.
Implement general base conversion. Given a number in base **a**,
represented as a sequence of digits, convert it to base **b**.
## Note
- Try to implement the conversion yourself.
Do not use something else to perform the conversion for you.
## About [Positional Notation](https://en.wikipedia.org/wiki/Positional_notation)
In positional notation, a number in base **b** can be understood as a linear
combination of powers of **b**.
The number 42, *in base 10*, means:
(4 * 10^1) + (2 * 10^0)
The number 101010, *in base 2*, means:
(1 * 2^5) + (0 * 2^4) + (1 * 2^3) + (0 * 2^2) + (1 * 2^1) + (0 * 2^0)
The number 1120, *in base 3*, means:
(1 * 3^3) + (1 * 3^2) + (2 * 3^1) + (0 * 3^0)
I think you got the idea!
*Yes. Those three numbers above are exactly the same. Congratulations!*
## Running tests
Execute the tests with:
```bash
$ elixir all_your_base_test.exs
```
### Pending tests
In the test suites, all but the first test have been skipped.
Once you get a test passing, you can unskip the next one by
commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
Or, you can enable all the tests by commenting out the
`ExUnit.configure` line in the test suite.
```elixir
# ExUnit.configure exclude: :pending, trace: true
```
For more detailed information about the Elixir track, please
see the [help page](http://exercism.io/languages/elixir).
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

View File

@ -0,0 +1,114 @@
if !System.get_env("EXERCISM_TEST_EXAMPLES") do
Code.load_file("all-your-base.exs", __DIR__)
end
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)
defmodule AllYourBaseTest do
use ExUnit.Case
test "convert single bit one to decimal" do
assert AllYourBase.convert([1], 2, 10) == [1]
end
@tag :pending
test "convert binary to single decimal" do
assert AllYourBase.convert([1, 0, 1], 2, 10) == [5]
end
@tag :pending
test "convert single decimal to binary" do
assert AllYourBase.convert([5], 10, 2) == [1, 0, 1]
end
@tag :pending
test "convert binary to multiple decimal" do
assert AllYourBase.convert([1, 0, 1, 0, 1, 0], 2, 10) == [4, 2]
end
@tag :pending
test "convert decimal to binary" do
assert AllYourBase.convert([4, 2], 10, 2) == [1, 0, 1, 0, 1, 0]
end
@tag :pending
test "convert trinary to hexadecimal" do
assert AllYourBase.convert([1, 1, 2, 0], 3, 16) == [2, 10]
end
@tag :pending
test "convert hexadecimal to trinary" do
assert AllYourBase.convert([2, 10], 16, 3) == [1, 1, 2, 0]
end
@tag :pending
test "convert 15-bit integer" do
assert AllYourBase.convert([3, 46, 60], 97, 73) == [6, 10, 45]
end
@tag :pending
test "convert empty list" do
assert AllYourBase.convert([], 2, 10) == nil
end
@tag :pending
test "convert single zero" do
assert AllYourBase.convert([0], 10, 2) == [0]
end
@tag :pending
test "convert multiple zeros" do
assert AllYourBase.convert([0, 0, 0], 10, 2) == [0]
end
@tag :pending
test "convert leading zeros" do
assert AllYourBase.convert([0, 6, 0], 7, 10) == [4, 2]
end
@tag :pending
test "convert negative digit" do
assert AllYourBase.convert([1, -1, 1, 0, 1, 0], 2, 10) == nil
end
@tag :pending
test "convert invalid positive digit" do
assert AllYourBase.convert([1, 2, 1, 0, 1, 0], 2, 10) == nil
end
@tag :pending
test "convert first base is one" do
assert AllYourBase.convert([0], 1, 10) == nil
end
@tag :pending
test "convert second base is one" do
assert AllYourBase.convert([1, 0, 1, 0, 1, 0], 2, 1) == nil
end
@tag :pending
test "convert first base is zero" do
assert AllYourBase.convert([], 0, 10) == nil
end
@tag :pending
test "convert second base is zero" do
assert AllYourBase.convert([7], 10, 0) == nil
end
@tag :pending
test "convert first base is negative" do
assert AllYourBase.convert([1], -2, 10) == nil
end
@tag :pending
test "convert second base is negative" do
assert AllYourBase.convert([1], 2, -7) == nil
end
@tag :pending
test "convert both bases are negative" do
assert AllYourBase.convert([1], -2, -7) == nil
end
end

View File

@ -0,0 +1,17 @@
defmodule AllYourBase do
@doc """
Given a number in base a, represented as a sequence of digits, converts it to base b,
or returns nil if either of the bases are less than 2
"""
@spec convert(list, integer, integer) :: list
def convert(digits, base_a, base_b) do
cond do
base_a < 2 || base_b < 2 ->
nil
true ->
""
end
end
end

View File

@ -0,0 +1,50 @@
# Nth Prime
Given a number n, determine what the nth prime is.
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that
the 6th prime is 13.
If your language provides methods in the standard library to deal with prime
numbers, pretend they don't exist and implement them yourself.
## Running tests
Execute the tests with:
```bash
$ elixir nth_prime_test.exs
```
### Pending tests
In the test suites, all but the first test have been skipped.
Once you get a test passing, you can unskip the next one by
commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
Or, you can enable all the tests by commenting out the
`ExUnit.configure` line in the test suite.
```elixir
# ExUnit.configure exclude: :pending, trace: true
```
For more detailed information about the Elixir track, please
see the [help page](http://exercism.io/languages/elixir).
## Source
A variation on Problem 7 at Project Euler [http://projecteuler.net/problem=7](http://projecteuler.net/problem=7)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

View File

@ -0,0 +1,26 @@
defmodule Prime do
@doc """
Generates the nth prime.
"""
@spec nth(non_neg_integer) :: non_neg_integer
def nth(count) when count > 0 do
Stream.iterate(1, &(&1 + 1))
|> Stream.filter(&prime?/1)
|> Enum.at(count - 1)
end
defp prime?(n) do
case n do
_n when n <= 1 ->
false
2 ->
true
_ ->
2..round(:math.sqrt(n))
|> Enum.filter(&(rem(n, &1) == 0))
|> Enum.empty?()
end
end
end

View File

@ -0,0 +1,35 @@
if !System.get_env("EXERCISM_TEST_EXAMPLES") do
Code.load_file("nth_prime.exs", __DIR__)
end
ExUnit.start()
ExUnit.configure(trace: true)
defmodule NthPrimeTest do
use ExUnit.Case
# @tag :pending
test "first prime" do
assert Prime.nth(1) == 2
end
@tag :pending
test "second prime" do
assert Prime.nth(2) == 3
end
@tag :pending
test "sixth prime" do
assert Prime.nth(6) == 13
end
@tag :pending
test "100th prime" do
assert Prime.nth(100) == 541
end
@tag :pending
test "weird case" do
catch_error(Prime.nth(0))
end
end

View File

@ -24,6 +24,17 @@ defmodule Phone do
"""
@spec number(String.t()) :: String.t()
def number(raw) do
n =
Regex.scan(~r/\d/, raw)
|> Enum.join()
|> String.replace_prefix("1", "")
if String.length(n) == 10 && not Regex.match?(~r/[01]/, String.at(n, 3)) &&
not Regex.match?(~r/[01]/, String.at(n, 0)) && not Regex.match?(~r/[a-z]/i, raw) do
n
else
"0000000000"
end
end
@doc """
@ -48,6 +59,7 @@ defmodule Phone do
"""
@spec area_code(String.t()) :: String.t()
def area_code(raw) do
String.slice(number(raw), 0..2)
end
@doc """
@ -72,5 +84,7 @@ defmodule Phone do
"""
@spec pretty(String.t()) :: String.t()
def pretty(raw) do
n = number(raw)
"(#{String.slice(n, 0..2)}) #{String.slice(n, 3..5)}-#{String.slice(n, 6..9)}"
end
end

View File

@ -3,7 +3,7 @@ if !System.get_env("EXERCISM_TEST_EXAMPLES") do
end
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)
ExUnit.configure(trace: true)
defmodule PhoneTest do
use ExUnit.Case

View File

@ -0,0 +1,84 @@
# Roman Numerals
Write a function to convert from normal numbers to Roman Numerals.
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).
```text
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
## Running tests
Execute the tests with:
```bash
$ elixir roman_numerals_test.exs
```
### Pending tests
In the test suites, all but the first test have been skipped.
Once you get a test passing, you can unskip the next one by
commenting out the relevant `@tag :pending` with a `#` symbol.
For example:
```elixir
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
```
Or, you can enable all the tests by commenting out the
`ExUnit.configure` line in the test suite.
```elixir
# ExUnit.configure exclude: :pending, trace: true
```
For more detailed information about the Elixir track, please
see the [help page](http://exercism.io/languages/elixir).
## Source
The Roman Numeral Kata [http://codingdojo.org/cgi-bin/index.pl?KataRomanNumerals](http://codingdojo.org/cgi-bin/index.pl?KataRomanNumerals)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

View File

@ -0,0 +1,35 @@
defmodule Roman do
@romans [
{"M", 1000},
{"CM", 900},
{"D", 500},
{"CD", 400},
{"C", 100},
{"XC", 90},
{"L", 50},
{"XL", 40},
{"X", 10},
{"IX", 9},
{"V", 5},
{"IV", 4},
{"I", 1}
]
@doc """
Convert the number to a roman number.
"""
@spec numerals(pos_integer) :: String.t()
def numerals(number) do
numerals(@romans, number, "")
end
defp numerals(_romans, 0, res), do: res
defp numerals([{_letter, number} | t], c, res) when c < number do
numerals(t, c, res)
end
defp numerals([{letter, number} | _t] = list, c, res) do
numerals(list, c - number, res <> letter)
end
end

View File

@ -0,0 +1,100 @@
if !System.get_env("EXERCISM_TEST_EXAMPLES") do
Code.load_file("roman.exs", __DIR__)
end
ExUnit.start()
ExUnit.configure(trace: true)
defmodule RomanTest do
use ExUnit.Case
# @tag :pending
test "1" do
assert Roman.numerals(1) == "I"
end
@tag :pending
test "2" do
assert Roman.numerals(2) == "II"
end
@tag :pending
test "3" do
assert Roman.numerals(3) == "III"
end
@tag :pending
test "4" do
assert Roman.numerals(4) == "IV"
end
@tag :pending
test "5" do
assert Roman.numerals(5) == "V"
end
@tag :pending
test "6" do
assert Roman.numerals(6) == "VI"
end
@tag :pending
test "9" do
assert Roman.numerals(9) == "IX"
end
@tag :pending
test "27" do
assert Roman.numerals(27) == "XXVII"
end
@tag :pending
test "48" do
assert Roman.numerals(48) == "XLVIII"
end
@tag :pending
test "59" do
assert Roman.numerals(59) == "LIX"
end
@tag :pending
test "93" do
assert Roman.numerals(93) == "XCIII"
end
@tag :pending
test "141" do
assert Roman.numerals(141) == "CXLI"
end
@tag :pending
test "163" do
assert Roman.numerals(163) == "CLXIII"
end
@tag :pending
test "402" do
assert Roman.numerals(402) == "CDII"
end
@tag :pending
test "575" do
assert Roman.numerals(575) == "DLXXV"
end
@tag :pending
test "911" do
assert Roman.numerals(911) == "CMXI"
end
@tag :pending
test "1024" do
assert Roman.numerals(1024) == "MXXIV"
end
@tag :pending
test "3000" do
assert Roman.numerals(3000) == "MMM"
end
end

View File

@ -3,16 +3,13 @@ class Prime
def self.nth(n)
raise ArgumentError.new('N must be positive') if n < 1
primes ||= [2, 3]
curr = primes.last
while n > primes.length
curr += 2
unless primes.any? { |p| curr % p == 0 }
# very naive and slow :(
primes.push(curr)
end
end
primes[n - 1]
sieve(50 * n)[n - 1]
end
def self.sieve(n)
(2..Math.sqrt(n)).each_with_object([nil, nil, *2..n]) do |p, res|
(p*p).step(n, p) { |m| res[m] = nil }
end.compact
end
end

View File

@ -1,20 +1,18 @@
class Sieve
@num
def initialize(base)
@num = base
end
def primes
primes = (0..@num).to_a
primes[0] = primes[1] = nil
primes.select{|p| p && p*p < @num}.each do |p|
(p*p).step(@num, p) {|m| primes[m] = nil}
end
primes.compact
(2..Math.sqrt(@num)).each_with_object([nil, nil, *2..@num]) do |p, res|
(p*p).step(@num, p) { |m| res[m] = nil }
end.compact
end
end
module BookKeeping
VERSION = 1
end