initial commit

This commit is contained in:
2021-08-08 21:11:22 +02:00
commit fe7136d801
130 changed files with 6858 additions and 0 deletions

54
bash/acronym/README.md Normal file
View File

@@ -0,0 +1,54 @@
# Acronym
Convert a phrase to its acronym.
Techies love their TLA (Three Letter Acronyms)!
Help generate some jargon by writing a program that converts a long name
like Portable Network Graphics to its acronym (PNG).
Run the tests with:
```bash
bats acronym_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats acronym_test.sh
```
## Source
Julien Vanier [https://github.com/monkbroc](https://github.com/monkbroc)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

58
bash/acronym/acronym.sh Executable file
View File

@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# V1: original version
# V2: final printf changeto avoid subshell
# external tools: none
# v1: initial version
# set to mask to enable logs
debug=0
shopt -s extglob
usage() {
echo "acronym.sh word1 [...]" >&2
exit 1
}
# $1: log level, then strings to display.
log () {
(( debug & $1 )) && shift && echo "${@}"
}
# check for basic errors. We will accept multiple args:
# acronym.sh i love suchi = acronym "i love suchi"
(( $# < 1 )) && usage
# valid word separators
VALID_SEPARATORS="-_*"
# replace valid chars with space, merge args in 1 string
words="${*//[$VALID_SEPARATORS]/ }"
log 1 valid separators ${#words[@]} "$words"
# remove remaining non alpha chars (keep blanks)
words="${words//[^[:alpha:][:blank:]]/}"
log 1 keep alpha "${words[@]}"
# capitalize, make an array
words=(${words^^})
log 1 "words ${#words[@]} ${words[@]}"
# print 1st chars
printf -v result "%c" ${words[@]}
log 1 result "$result"
echo "$result"
exit 0
# Indent style for emacs
# Local Variables:
# sh-basic-offset: 4
# sh-indentation: 4
# indent-tabs-mode: nil
# comment-column: 60
# End:

54
bash/anagram/README.md Normal file
View File

@@ -0,0 +1,54 @@
# Anagram
An anagram is a rearrangement of letters to form a new word.
Given a word and a list of candidates, select the sublist of anagrams of the given word.
Given `"listen"` and a list of candidates like `"enlists" "google"
"inlets" "banana"` the program should return a list containing
`"inlets"`.
Run the tests with:
```bash
bats anagram_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats anagram_test.sh
```
## Source
Inspired by the Extreme Startup game [https://github.com/rchatley/extreme_startup](https://github.com/rchatley/extreme_startup)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

60
bash/anagram/anagram.sh Executable file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env bash
#
# External tools: none.
# Subshells: none.
#
# V1: initial version
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
#local -i i
#if (( debug & $1 )) ; then
# for ((i=1; i<$1; ++i)); do
# echo -n " "
# done
# shift
# echo "${BASH_LINENO[0]}: ${@}" >&2
#fi
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: anagram.sh word anagrams-list"
}
# check for basic args
(($# < 2)) && usage
word="$1"
shift
# we will accept more than 1 anagram list:
# anagram.sh "BANANA" "banana BANANA" = anagram "BANANA" "banana" "BANANA"
# we start to split words
declare -a words
while (($# > 0)); do
words=("${words[@]}" $1)
typeset -p words
shift
done
debug 1 words=${#words[@]}:${words[@]}
typeset -p words
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 40
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,58 @@
# Armstrong Numbers
An [Armstrong number](https://en.wikipedia.org/wiki/Narcissistic_number) is a number that is the sum of its own digits each raised to the power of the number of digits.
For example:
- 9 is an Armstrong number, because `9 = 9^1 = 9`
- 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 1`
- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153`
- 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190`
Write some code to determine whether a number is an Armstrong number.
Run the tests with:
```bash
bats armstrong_numbers_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats armstrong_numbers_test.sh
```
## Source
Wikipedia [https://en.wikipedia.org/wiki/Narcissistic_number](https://en.wikipedia.org/wiki/Narcissistic_number)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,44 @@
#!/usr/bin/env bash
# set to mask to enable logs. 0: none, 255: all
(( DEBUG=2#00000000 ))
# $1: log level (mask), then strings to display.
debug () {
(( DEBUG & $1 )) && shift && echo "${@}" >&2
}
usage () {
echo "usage: ./armstrong_numbers.sh <number>" >&2
exit 1
}
# basic args checks: 1 arg, digits (at least 1) only
(( $# != 1)) || [[ ! "$1" =~ ^[[:digit:]]+$ ]] && usage
number="$1"
digits=${#number}
armstrong=0
result="false"
debug 1 d=$digits n=$number
# armstrong number calculation
for (( i=0; i<digits; ++i )); do
((armstrong += ${number:$i:1} ** digits ))
done
debug 2 "armstrong=$armstrong"
((number == armstrong)) && result="true"
echo "$result"
exit 0
# Indent style for emacs
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 60
# End:

View File

@@ -0,0 +1,75 @@
# Atbash Cipher
Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.
The Atbash cipher is a simple substitution cipher that relies on
transposing all the letters in the alphabet such that the resulting
alphabet is backwards. The first letter is replaced with the last
letter, the second with the second-last, and so on.
An Atbash cipher for the Latin alphabet would be as follows:
```text
Plain: abcdefghijklmnopqrstuvwxyz
Cipher: zyxwvutsrqponmlkjihgfedcba
```
It is a very weak cipher because it only has one possible key, and it is
a simple monoalphabetic substitution cipher. However, this may not have
been an issue in the cipher's time.
Ciphertext is written out in groups of fixed length, the traditional group size
being 5 letters, and punctuation is excluded. This is to make it harder to guess
things based on word boundaries.
## Examples
- Encoding `test` gives `gvhg`
- Decoding `gvhg` gives `test`
- Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `thequickbrownfoxjumpsoverthelazydog`
Run the tests with:
```bash
bats atbash_cipher_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats atbash_cipher_test.sh
```
## Source
Wikipedia [http://en.wikipedia.org/wiki/Atbash](http://en.wikipedia.org/wiki/Atbash)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,108 @@
#!/usr/bin/env bash
#
# External tools: none.
# Subshell: no.
#
# Tested on: bash 5.0, 3.2
#
# V1: initial version
# V2: changed +() to @() in args check. Fixed typo on lines 48-52 formulas.
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
#(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: atbash_cypher.sh encode|decode text [...]"
}
# we will accept the syntax:
# atbash_cypher.sh encode|decode text [...]
# in case text is separated as multiple arguments, we will consider a space is
# in between.
# example:
# atbash_cypher.sh encode "I am happy"
# will also be accepted as:
# atbash_cypher.sh encode I am happy
# basic args check & set all chars to lowercase
(($# < 2)) || [[ "$1" != @(encode|decode) ]] && usage
action="$1"
shift
string="${*,,}"
len="${#string}"
debug 1 "string=$string" "len=$len"
# algorithm we will use:
# to get rev element c' of c in a consecutive integer n-m list :
# c = n+i i is distance from n to c
# c' = m-i and also reverse distance from m to c'
# ------------
# c+c' = n+m sum the 2
# c' = n+m-c after simplification
# for printf, a '<char> arg is the ascii value of <char>
# and yes, we should use a constant, any programmer knows ascii value of 'a'
# and # of letters in alphabet, we could simply set tval to 219
printf -v aval "%d" "'a" # 'a' ascii value
printf -v zval "%d" "'z" # 'z' ascii value
printf -v tval "%d" $((aval+zval)) # their sum
# tval=219 # correct code for this exercise, for me
debug 1 "aval:$aval zval:$zval tval:$tval"
# many options here:
# - for encode, add <spaces> in loop, or at the end
# - use a table with all alphabet ({a..z}), to avoid multiple printf
# - fill acceptable chars only (my choice), insert spaces at end.
# I preferred that one to avoid multiple encode/decode tests in loop.
# - likely many others
result="" # resulting string, with no spaces
for ((i=0; i<len; ++i)); do
c=${string:$i:1} # current char
printf -v cval "%d" "'$c" # $c's ascii value
debug 2 "c='$c' cval=$cval"
case "$c" in
[[:alpha:]]) # rev $c's in alphabet (with hex value)
printf -v rval "%x" $((tval - cval))
printf -v c "\\x$rval" # shellcheck unhappy here
debug 4 "rev c=$c"
;;
[![:digit:]]) # we avoid 1 case (digits)
continue
;;
esac
result+="$c"
done
# for encoding, we split in 5 chars groups.
if [[ $action == encode ]]; then
[[ $result =~ ${result//?/(.)} ]]
# we use REMATCH here, to avoid loop, but we could end with a space.
printf -v result "%c%c%c%c%c " "${BASH_REMATCH[@]:1}"
fi
debug 1 "result: =${result%% }="
echo "${result%% }" # fix possible REMATCH extra final space
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 40
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

62
bash/bob/README.md Normal file
View File

@@ -0,0 +1,62 @@
# Bob
Bob is a lackadaisical teenager. In conversation, his responses are very limited.
Bob answers 'Sure.' if you ask him a question, such as "How are you?".
He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals).
He answers 'Calm down, I know what I'm doing!' if you yell a question at him.
He says 'Fine. Be that way!' if you address him without actually saying
anything.
He answers 'Whatever.' to anything else.
Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English.
Run the tests with:
```bash
bats bob_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats bob_test.sh
```
## Source
Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

56
bash/bob/bob.sh Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# V1: initial version
# V2: cosmetic changes
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
#(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo "${@}" >&2
}
arg="$1"
# trim all blank characters safely
arg="${arg//[[:space:]]/}"
debug 1 trim "$arg"
# and check if last char is question mark
[[ ${arg: -1} == "?" ]] && question=+
# the tricky part in test is that non alpha characters are considered
# differently in tests, depending on the rest of the string (having
# letters or not). So we remove them in that case.
[[ "$arg" == *[[:alpha:]]* ]] && arg="${arg//[![:alpha:]]/}"
debug 1 special "$arg" $question
# and now proceed with rules
case "$arg$question" in
"")
echo "Fine. Be that way!"
;;
+([[:upper:]])+)
echo "Calm down, I know what I'm doing!"
;;
*+)
echo "Sure."
;;
+([[:upper:]]))
echo "Whoa, chill out!"
;;
*)
echo "Whatever."
;;
esac
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 50
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

107
bash/bowling/README.md Normal file
View File

@@ -0,0 +1,107 @@
# Bowling
Score a bowling game.
Bowling is a game where players roll a heavy ball to knock down pins
arranged in a triangle. Write code to keep track of the score
of a game of bowling.
## Scoring Bowling
The game consists of 10 frames. A frame is composed of one or two ball
throws with 10 pins standing at frame initialization. There are three
cases for the tabulation of a frame.
* An open frame is where a score of less than 10 is recorded for the
frame. In this case the score for the frame is the number of pins
knocked down.
* A spare is where all ten pins are knocked down by the second
throw. The total value of a spare is 10 plus the number of pins
knocked down in their next throw.
* A strike is where all ten pins are knocked down by the first
throw. The total value of a strike is 10 plus the number of pins
knocked down in the next two throws. If a strike is immediately
followed by a second strike, then the value of the first strike
cannot be determined until the ball is thrown one more time.
Here is a three frame example:
| Frame 1 | Frame 2 | Frame 3 |
| :-------------: |:-------------:| :---------------------:|
| X (strike) | 5/ (spare) | 9 0 (open frame) |
Frame 1 is (10 + 5 + 5) = 20
Frame 2 is (5 + 5 + 9) = 19
Frame 3 is (9 + 0) = 9
This means the current running total is 48.
The tenth frame in the game is a special case. If someone throws a
strike or a spare then they get a fill ball. Fill balls exist to
calculate the total of the 10th frame. Scoring a strike or spare on
the fill ball does not give the player more fill balls. The total
value of the 10th frame is the total number of pins knocked down.
For a tenth frame of X1/ (strike and a spare), the total value is 20.
For a tenth frame of XXX (three strikes), the total value is 30.
## Requirements
Write code to keep track of the score of a game of bowling. It should
support two operations:
* `roll(pins : int)` is called each time the player rolls a ball. The
argument is the number of pins knocked down.
* `score() : int` is called only at the very end of the game. It
returns the total score for that game.
Run the tests with:
```bash
bats bowling_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats bowling_test.sh
```
## Source
The Bowling Game Kata at but UncleBob [http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata](http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

86
bash/bowling/bowling.sh Executable file
View File

@@ -0,0 +1,86 @@
#!/usr/bin/env bash
#
# V1: initial version
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: bowling.sh r1-20 [r21 [r22]]"
}
# pincount > 10. $1: frame
highroll() {
die Frame "Frame $1: Pin count exceeds pins on the lane."
}
# pincount > 10. $1: frame
negativeroll() {
die Frame "Frame $1: Negative roll is invalid."
}
# args test: 10 rolls mandatory
#(($# < 20)) && usage
rolls=($@)
debug 1 rolls=${rolls[@]}
((score = 0)) # total score
((tempscore = 0)) # tmp score (for spare/strike)
declare -a frames # frames scores
declare -a opened # spare:2, strike:1
((frame=-1)) # current frame
((curroll=1)) # roll in frame: 1:1st, 2:2nd
((i=0))
for ((roll=0; roll<$#; ++roll)); do
debug 2 loop roll="$roll"
(( ! roll % 2 && frame++ ))
exit 0
(( score=${rolls[$i]} ))
#(( score < 0 )) && || score > 10)) && echo 1
#if ((!roll % 2)); then # first roll in frame
((framescore=0)) # current frame score
for j in 0 1; do
(( roll = ${rolls[$i]} ))
((roll < 0)) && die Frame $((curframe+1)): Negative roll is invalid.
(( framescore += roll ))
((framescore == 10)) && ((opened[$curframe] = j+1))
(( i++ ))
done
debug 2 curframe=$curframe score=$framescore
#if ((roll))
((framescore > 10)) && wrongroll $curframe $curroll $framescore
frame[$curframe]=$framescore
((curroll = -curroll))
done
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 50
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

64
bash/darts/README.md Normal file
View File

@@ -0,0 +1,64 @@
# Darts
Write a function that returns the earned points in a single toss of a Darts game.
[Darts](https://en.wikipedia.org/wiki/Darts) is a game where players
throw darts to a [target](https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg).
In our particular instance of the game, the target rewards with 4 different amounts of points, depending on where the dart lands:
* If the dart lands outside the target, player earns no points (0 points).
* If the dart lands in the outer circle of the target, player earns 1 point.
* If the dart lands in the middle circle of the target, player earns 5 points.
* If the dart lands in the inner circle of the target, player earns 10 points.
The outer circle has a radius of 10 units (This is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1. Of course, they are all centered to the same point (That is, the circles are [concentric](http://mathworld.wolfram.com/ConcentricCircles.html)) defined by the coordinates (0, 0).
Write a function that given a point in the target (defined by its `real` cartesian coordinates `x` and `y`), returns the correct amount earned by a dart landing in that point.
This particular exercise, since it deals with floating point arithmetic, is natural to rely on external tools (see below). As an extra challenging challenge, find a way to implement this with plain bash.
Run the tests with:
```bash
bats darts_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats darts_test.sh
```
## Source
Inspired by an exercise created by a professor Della Paolera in Argentina
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

82
bash/darts/darts.sh Executable file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/env bash
#
# external tools: none (only integer operations).
#
# V1 : Initial version.
# V2 : Using reference instead of subshell, as of
# https://stackoverflow.com/questions/540298
# moved valid numbers in parseval function.
# V3/4 : added some quotes following suggestions
# set to mask to enable logs. 0: none, 255: all
#((DEBUG=2#00001111))
((DEBUG=2#00000000))
# $1: log level (mask), then strings to display.
debug () {
(( DEBUG & $1 )) && shift && echo "${@}" >&2
}
usage () {
echo "usage: darts x y" >&2
exit 1
}
shopt -s extglob
# To be able to use bash only, all numbers will be miltiplied by 1,000.
# Could be higher if we want more precision.
#
# So: 0.1 will be 100, 1 will be 1,000, 10 will br 10000, etc...
# circles. as we will use Pythagoras' theorem, so square value calc here
outer=$(( (10 * 1000 ) ** 2 ))
middle=$(( ( 5 * 1000 ) ** 2 ))
inner=$(( ( 1 * 1000 ) ** 2 ))
debug 1 outer=$outer middle=$middle inner=$inner
# basic args check: 2 args, and decimal numbers, which are:
# optional +- sign, optional digits, optional . and optional digits
(( ${#} != 2 )) && usage
parseval() {
# integer and decimal parts, final value by ref
local int dec
local -n calc=$1
# check for valid decimal number
[[ ${2} != ?([-+])+([0-9])?(.*([0-9])) ]] && usage
IFS=. read int dec <<< "$2"
debug 2 ${int} ${dec}
# we accept up to 3 decimals: add 3 zeroes to dec, then keep 3 first digits
# So a decimal part of "1" will become 100, 01 will become 10, etc...
# we also take care of leadings 0 (octal notation), and remove leading "-".
dec="$dec"000
dec="10#"${dec:0:3}
int="10#"${int#-}
debug 2 mult ${int} ${dec}
calc=$(( (int*1000 + dec) ** 2 ))
}
parseval x "$1"
parseval y "$2"
total=$(( x+y ))
debug 1 x=$x y=$y x+y=$total
(( total <= inner )) && echo 10 && exit 0
(( total <= middle )) && echo 5 && exit 0
(( total <= outer )) && echo 1 && exit 0
echo 0 && exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 60
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,63 @@
# Difference Of Squares
Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.
The square of the sum of the first ten natural numbers is
(1 + 2 + ... + 10)² = 55² = 3025.
The sum of the squares of the first ten natural numbers is
1² + 2² + ... + 10² = 385.
Hence the difference between the square of the sum of the first
ten natural numbers and the sum of the squares of the first ten
natural numbers is 3025 - 385 = 2640.
You are not expected to discover an efficient solution to this yourself from
first principles; research is allowed, indeed, encouraged. Finding the best
algorithm for the problem is a key skill in software engineering.
Run the tests with:
```bash
bats difference_of_squares_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats difference_of_squares_test.sh
```
## Source
Problem 6 at Project Euler [http://projecteuler.net/problem=6](http://projecteuler.net/problem=6)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,84 @@
#!/usr/bin/env bash
#
# External tools: none.
# subshell: none.
#
# V1: initial version
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
#(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: difference_of_squares.sh command color"
}
debug 1 "#=$#" "arg=$1"
(($# != 2)) || [[ $1 != @(square_of_sum|sum_of_squares|difference) ]] || \
[[ "$2" != +([[:digit:]]) ]] && usage
# the 2 next functions will set $1 to the calculated value for $2
sum_of_squares () { # set $1 to sum of squares ($2)
local -n res=$1
local val=$2
# the sum of 1st n integers squares is:
# S = 1² + 2² + 3² ..... + (n-1)² + n²
# = [ n * (n+1) * (2n+1) ] / 6
# demonstration on:
# http://www.takayaiwamoto.com/Sums_and_Series/sumsqr_1.html
(( res = val * (val+1) * (2*val + 1) / 6 ))
debug 2 "sum_of_squares($val) = $res"
}
square_of_sum () { # set $1 to square of sum ($2)
local -n res=$1
local val=$2
# The sum of n 1st integers is:
# S = 1 + 2 + 3 ... + (n-1) + n
# = [ n * (n+1) ] / 2
# demonstration is trivial for this one.
(( res = (val * (val+1) / 2 ) ** 2 ))
debug 2 "square_of_sum($val) = $res"
}
action="$1"
(( num = $2 ))
case "$action" in
square_of_sum)
square_of_sum result "$num"
debug 3 "result after calling square_of_sum: $result"
;;
sum_of_squares)
sum_of_squares result "$num"
debug 3 "result after calling sum_of_squares: $result"
;;
difference)
square_of_sum SqSum "$num"
sum_of_squares SumSq "$num"
((result = SqSum - SumSq))
debug 3 "result after calling difference: $result"
esac
echo $result
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 40
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,79 @@
# D&D Character
For a game of [Dungeons & Dragons][DND], each player starts by generating a
character they can play with. This character has, among other things, six
abilities; strength, dexterity, constitution, intelligence, wisdom and
charisma. These six abilities have scores that are determined randomly. You
do this by rolling four 6-sided dice and record the sum of the largest three
dice. You do this six times, once for each ability.
Your character's initial hitpoints are 10 + your character's constitution
modifier. You find your character's constitution modifier by subtracting 10
from your character's constitution, divide by 2 and round down.
Write a random character generator that follows the rules above.
For example, the six throws of four dice may look like:
* 5, 3, 1, 6: You discard the 1 and sum 5 + 3 + 6 = 14, which you assign to strength.
* 3, 2, 5, 3: You discard the 2 and sum 3 + 5 + 3 = 11, which you assign to dexterity.
* 1, 1, 1, 1: You discard the 1 and sum 1 + 1 + 1 = 3, which you assign to constitution.
* 2, 1, 6, 6: You discard the 1 and sum 2 + 6 + 6 = 14, which you assign to intelligence.
* 3, 5, 3, 4: You discard the 3 and sum 5 + 3 + 4 = 12, which you assign to wisdom.
* 6, 6, 6, 6: You discard the 6 and sum 6 + 6 + 6 = 18, which you assign to charisma.
Because constitution is 3, the constitution modifier is -4 and the hitpoints are 6.
## Notes
Most programming languages feature (pseudo-)random generators, but few
programming languages are designed to roll dice. One such language is [Troll].
[DND]: https://en.wikipedia.org/wiki/Dungeons_%26_Dragons
[Troll]: http://hjemmesider.diku.dk/~torbenm/Troll/
Run the tests with:
```bash
bats dnd_character_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats dnd_character_test.sh
```
## Source
Simon Shine, Erik Schierboom [https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945](https://github.com/exercism/problem-specifications/issues/616#issuecomment-437358945)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,115 @@
#!/usr/bin/env bash
#
# v1: initial version
# v2: cleanup, replaced while loops with for loops when possible
# external tools: none
# set to 0 to disable log function output, 1 otherwise
debug=0
declare -a abilities=( strength dexterity intelligence wisdom charisma constitution )
usage() {
echo "dnd_characters.sh generate|modifier <n>" >&2
exit 1
}
# log function takes 1 argument which is echoed if $debug is > 0
# todo: Add another argument (mask ?) to selectively log portions of code
log () {
(( $debug )) && echo "$*"
}
# simple bubble sort for numeric array (descending)
# args: 1: the array
# todo: add a parameter for asc/desc order.
sort_n() {
local -a array=( "$@" )
local -i max=$(( ${#array[@]} - 1 ))
for (( max= $(( ${#array[@]} - 1 )); max > 0; max-- )); do
local -i i
for (( i=0; i<max; i++ )); do
local -i val1=${array[$i]}
local -i val2=${array[$((i + 1))]}
# switch if necessary
if (( $val1 < $val2 )); then
local tmp=$val1
array[$i]=$val2
array[$(($i + 1))]=$tmp
fi
done
done
echo "${array[@]}"
}
# roll $2 times a $1 faces dice
roll() {
local -a rolls
local -i i
for (( i=1; i<=$2; i++ )); do
rolls[$i]=$((RANDOM % $1 + 1))
done
echo ${rolls[@]}
}
modifier() {
local -i res
local -i in=$1
local -i out=$(( $in - 10 ))
log modifier in "$1"
res=$(( $out / 2 )) # will alwaid round down
log modifier div "$res"
# adjust for negative numbers
(( $out < 0 )) && (( $out % 2 )) && (( res-- ))
log modifier adjust negative "$res"
echo $res
}
generate() {
local -i s
local -a dices
for ability in ${abilities[@]}; do
dices=( $(roll 6 4) )
s=( $(sort_n ${dices[@]}) )
sum=$(( ${s[1]} + ${s[2]} + ${s[3]} ))
echo $ability $sum
if [[ $ability == "constitution" ]]; then
echo "hitpoints $(( 10 - $(modifier $sum) ))"
fi
done
}
command="$1"
case "$command" in
"modifier")
(( $# != 2 )) && usage
modifier "$2"
;;
"generate")
(( $# != 1 )) && usage
generate
;;
*)
usage
;;
esac
exit 0
# Indent style for emacs
# Local Variables:
# sh-basic-offset: 4
# sh-indentation: 4
# indent-tabs-mode: nil
# comment-column: 60
# End:

View File

@@ -0,0 +1,53 @@
# Error Handling
Implement various kinds of error handling and resource management.
An important point of programming is how to handle errors and close
resources even if errors occur.
This exercise requires you to handle various errors. Because error handling
is rather programming language specific you'll have to refer to the tests
for your track to see what's exactly required.
Run the tests with:
```bash
bats error_handling_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats error_handling_test.sh
```
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,12 @@
#!/usr/bin/env bash
#
# Note: I don't like the test on empty arg or whitespaces only arg:
# 'error_handling.sh ""' and 'error_handling.sh " "'
# should be faulty, instead of displaying a strange message ("Hello, ")
usage() {
echo "Usage: ./error_handling <greetee>"
exit 1
}
(( $# != 1 )) && usage
echo "Hello, $1"

73
bash/grains/README.md Normal file
View File

@@ -0,0 +1,73 @@
# Grains
Calculate 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, with the number
of grains doubling on each successive square.
There are 64 squares on a chessboard (where square 1 has one grain, square 2 has two grains, and so on).
Write code that shows:
- how many grains were on a given square, and
- the total number of grains on the chessboard
## 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?
Run the tests with:
```bash
bats grains_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats grains_test.sh
```
## Source
JavaRanch Cattle Drive, exercise 6 [http://www.javaranch.com/grains.jsp](http://www.javaranch.com/grains.jsp)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

65
bash/grains/grains.sh Executable file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bash
#
# V1: initial version
#
# Note: untested on 32 bits and big-endian architectures
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
#(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "Error: invalid input"
}
# we want 1 arg only, "total" or digits only.
(($# !=1 )) || \
[[ "$1" != +([[:digit:]]) ]] && \
[[ "$1" != "total" ]] && usage
arg="${1##+(0)}" # we strip leading zeroes if any
debug 1 arg="$arg"
case "$arg" in
total)
# formula to calculate a geometric series of common ratio r and first
# term f, that is: S=f + fr² + fr³ ... + frⁿ
# is: S = f * [ (1 - rⁿ⁺¹) / (1 - r) ]
#
# for r=2 and f=1, it becomes:
# S = 1 * (1 - 2ⁿ⁺¹) / -1 = 2ⁿ⁺¹ - 1
# So here, as total does not accept an argument, such as "last square",
# the value is 2⁶⁴-1.
# Notes: (2**64) is 0 on 64 bits, but better not to use this property.
# We could also directly output the value, as it is a constant.
printf -v result "%llu" $(( 2**64 - 1 ))
;;
*) # always digits here
debug 2 "digits=args"
(( arg < 1 || arg > 64 )) && usage
printf -v result "%llu" $(( 2**(arg-1) ))
;;
esac
echo "$result"
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 40
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

111
bash/grep/README.md Normal file
View File

@@ -0,0 +1,111 @@
# Grep
Search a file for lines matching a regular expression pattern. Return the line
number and contents of each matching line.
The Unix [`grep`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html) command can be used to search for lines in one or more files
that match a user-provided search query (known as the *pattern*).
The `grep` command takes three arguments:
1. The pattern used to match lines in a file.
2. Zero or more flags to customize the matching behavior.
3. One or more files in which to search for matching lines.
Your task is to implement the `grep` function, which should read the contents
of the specified files, find the lines that match the specified pattern
and then output those lines as a single string. Note that the lines should
be output in the order in which they were found, with the first matching line
in the first file being output first.
As an example, suppose there is a file named "input.txt" with the following contents:
```text
hello
world
hello again
```
If we were to call `grep "hello" input.txt`, the returned string should be:
```text
hello
hello again
```
### Flags
As said earlier, the `grep` command should also support the following flags:
- `-n` Print the line numbers of each matching line.
- `-l` Print only the names of files that contain at least one matching line.
- `-i` Match line using a case-insensitive comparison.
- `-v` Invert the program -- collect all lines that fail to match the pattern.
- `-x` Only match entire lines, instead of lines that contain a match.
If we run `grep -n "hello" input.txt`, the `-n` flag will require the matching
lines to be prefixed with its line number:
```text
1:hello
3:hello again
```
And if we run `grep -i "HELLO" input.txt`, we'll do a case-insensitive match,
and the output will be:
```text
hello
hello again
```
The `grep` command should support multiple flags at once.
For example, running `grep -l -v "hello" file1.txt file2.txt` should
print the names of files that do not contain the string "hello".
Run the tests with:
```bash
bats grep_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats grep_test.sh
```
## Source
Conversation with Nate Foster. [http://www.cs.cornell.edu/Courses/cs3110/2014sp/hw/0/ps0.pdf](http://www.cs.cornell.edu/Courses/cs3110/2014sp/hw/0/ps0.pdf)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

88
bash/grep/grep.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/usr/bin/env bash
usage () {
echo "usage: grep.sh [-nlivx] [-e] pattern file [...]"
exit 1
}
# no arguments
LN= # be sure variables are reset
FN=
RV=
FL=
MULTI=
# parse args:
while getopts ":nlivxe" arg; do
case $arg in
n) LN=t ;; # will print line number
l) FN=t ;; # only file names
i) shopt -s nocasematch ;; # case insensitive
v) RV=t ;; # reverse search
x) FL=t ;; # full line search
e) break ;; # not in exercise: end args
*) usage ;;
esac
done
shift $((OPTIND-1))
# need at least pattern and 1 file.
# TODO: consider stdin if no file
[[ $# < 2 ]] && usage
[[ $# > 2 ]] && MULTI=t
# full line match
if [[ $FL = t ]]; then
pattern="^$1\$"
else
pattern=".*$1.*"
fi
shift
# will prevent leading/trailing whitespaces to be trimmed
IFS=""
while [[ $# > 0 ]]; do
file="$1"
if [[ ! -r "$file" ]]; then
echo "$file: no such file, or not readable."
exit 1
fi
lnum=0 # line number
match=n
while read -r line ; do # will consider '\' as normal char
(( lnum ++ ))
if [[ $line =~ $pattern ]] ; then # line match
match=y
# print only filename, go to next file
[[ $FN = t ]] && echo "$file" && break
# not reverse matching only
if [[ $RV != t ]]; then
# multiple files: print filename
[[ $MULTI == t ]] && echo -n "$file:"
[[ $LN = t ]] && echo -n "$lnum:"
echo "$line"
fi
else
# reverse match
if [[ $RV == t ]]; then
# print only filename, go to next file
[[ $FN = t ]] && echo "$file" && break
# multiple files: print filename
[[ $MULTI == t ]] && echo -n "$file:"
[[ $LN = t ]] && echo -n "$lnum:"
echo "$line"
fi
fi
done < "$1"
shift # next file
done
exit 0

70
bash/hamming/README.md Normal file
View File

@@ -0,0 +1,70 @@
# Hamming
Calculate the Hamming Distance between two DNA strands.
Your body is made up of cells that contain DNA. Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime!
When cells divide, their DNA replicates too. Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. If we compare two strands of DNA and count the differences between them we can see how many mistakes occurred. This is known as the "Hamming Distance".
We read DNA using the letters C,A,G and T. Two strands might look like this:
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^ ^ ^ ^^
They have 7 differences, and therefore the Hamming Distance is 7.
The Hamming Distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with :)
# Implementation notes
The Hamming distance is only defined for sequences of equal length, so
an attempt to calculate it between sequences of different lengths should
not work. The general handling of this situation (e.g., raising an
exception vs returning a special value) may differ between languages.
Run the tests with:
```bash
bats hamming_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats hamming_test.sh
```
## Source
The Calculating Point Mutations problem at Rosalind [http://rosalind.info/problems/hamm/](http://rosalind.info/problems/hamm/)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

42
bash/hamming/hamming.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
# set to 0 to disable log function output, 1 otherwise
debug=0
# echoes $1, then exit 1
die () {
echo "$1"
exit 1
}
# log function takes 1 argument which is echoed if $debug is > 0
# todo: Ad another argument (mask?) to selectively log portions of code
log () {
(( $debug )) && echo "$1"
}
# check basic errors
(( $# != 2 )) && die "Usage: hamming.sh <string1> <string2>"
(( ${#1} != ${#2} )) && die "left and right strands must be of equal length"
# compare strings
declare -i cur hamming=0
for (( cur=0; cur < ${#1}; cur++ )); do
log "$cur ${1:$cur:1} ${2:$cur:1}"
c1="${1:$cur:1}"
c2="${2:$cur:1}"
[[ "$c1" != "$c2" ]] && ((hamming++))
log "hamming in loop=$hamming"
done
echo "$hamming"
exit 0
# Indent style for emacs
# Local Variables:
# sh-basic-offset: 4
# sh-indentation: 4
# indent-tabs-mode: nil
# comment-column: 60
# End:

101
bash/hello-world/README.md Normal file
View File

@@ -0,0 +1,101 @@
# Hello World
The classical introductory exercise. Just say "Hello, World!".
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
the traditional first program for beginning programming in a new language
or environment.
The objectives are simple:
- Write a function that returns the string "Hello, World!".
- Run the test suite and make sure that it succeeds.
- Submit your solution and check it at the website.
If everything goes well, you will be ready to fetch your first real exercise.
# Welcome to Bash!
Unlike many other languages here, bash is a bit of a special snowflake.
If you are on a Mac or other unix-y platform, you almost definitely
already have bash. In fact, anything you type into the terminal is
likely going through bash.
The downside to this is that there isn't much of a development
ecosystem around bash like there is for other languages, and there are
multiple versions of bash that can be frustratingly incompatible. Luckily
we shouldn't hit those differences for these basic examples, and if you
can get the tests to pass on your machine, we are doing great.
## Installation
As mentioned above, if you are on a unix-like OS (Mac OS X, Linux, Solaris,
etc), you probably already have bash.
## Testing
As there isn't much of a bash ecosystem, there also isn't really a de
facto leader in the bash testing area. For these examples we are using
[bats](https://github.com/sstephenson/bats). You should be able to
install it from your favorite package manager, on OS X with homebrew
this would look something like this:
```
$ brew install bats
==> Downloading
https://github.com/sstephenson/bats/archive/v0.4.0.tar.gz
==> Downloading from
https://codeload.github.com/sstephenson/bats/tar.gz/v0.4.0
########################################################################
100.0%
==> ./install.sh /opt/boxen/homebrew/Cellar/bats/0.4.0
🍺 /opt/boxen/homebrew/Cellar/bats/0.4.0: 10 files, 60K, built in 2
seconds
```
Run the tests with:
```bash
bats hello_world_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats hello_world_test.sh
```
## Source
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,5 @@
#!/usr/bin/env bash
#
# exercism: hello world
echo "Hello, World!"

70
bash/leap/README.md Normal file
View File

@@ -0,0 +1,70 @@
# Leap
Given a year, report if it is a leap year.
The tricky thing here is that a leap year in the Gregorian calendar occurs:
```text
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.
## Notes
Though our exercise adopts some very simple rules, there is more to
learn!
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
Run the tests with:
```bash
bats leap_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats leap_test.sh
```
## Source
JavaRanch Cattle Drive, exercise 3 [http://www.javaranch.com/leap.jsp](http://www.javaranch.com/leap.jsp)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

13
bash/leap/leap.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
[[ $# != 1 || ! $1 =~ ^[0-9]+$ ]] && echo "Usage: $0 <year>" && exit 1
year=$1
leap=false
if ! (($year % 4)) && (($year % 100)) || ! (($year % 400))
then
leap=true
fi
echo $leap
exit 0

111
bash/luhn/README.md Normal file
View File

@@ -0,0 +1,111 @@
# Luhn
Given a number determine whether or not it is valid per the Luhn formula.
The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is
a simple checksum formula used to validate a variety of identification
numbers, such as credit card numbers and Canadian Social Insurance
Numbers.
The task is to check if a given string is valid.
Validating a Number
------
Strings of length 1 or less are not valid. Spaces are allowed in the input,
but they should be stripped before checking. All other non-digit characters
are disallowed.
## Example 1: valid credit card number
```text
4539 1488 0343 6467
```
The first step of the Luhn algorithm is to double every second digit,
starting from the right. We will be doubling
```text
4_3_ 1_8_ 0_4_ 6_6_
```
If doubling the number results in a number greater than 9 then subtract 9
from the product. The results of our doubling:
```text
8569 2478 0383 3437
```
Then sum all of the digits:
```text
8+5+6+9+2+4+7+8+0+3+8+3+3+4+3+7 = 80
```
If the sum is evenly divisible by 10, then the number is valid. This number is valid!
## Example 2: invalid credit card number
```text
8273 1232 7352 0569
```
Double the second digits, starting from the right
```text
7253 2262 5312 0539
```
Sum the digits
```text
7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57
```
57 is not evenly divisible by 10, so this number is not valid.
Run the tests with:
```bash
bats luhn_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats luhn_test.sh
```
## Source
The Luhn Algorithm on Wikipedia [http://en.wikipedia.org/wiki/Luhn_algorithm](http://en.wikipedia.org/wiki/Luhn_algorithm)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

57
bash/luhn/luhn.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env bash
#
# External tools: none.
#
# V1: initial version
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
#(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
shopt -s extglob
# basic args usage. We will accept the args to be splitted (out of scope
# for exercise): "luhn.sh '0 0'" is considered equivalent to "luhn.sh 0 0"
IFS="" number="${*// /}" # merge args, remove all <spaces>
debug 1 number="${number}"
((${#number} < 2)) || # args check: only [0-9], at least 2
[[ "$number" != +([0-9]) ]] &&
echo false && exit 0
((len=${#number}))
((sum=0)) # final sum
for ((i=1; i<=len; ++i)); do # we loop on each digit, from end
digit=${number:((-i)):1}
case $((i % 2)) in
0) # even position (relative to end)
((digit *= 2))
((digit >= 10)) && ((digit-=9))
debug 3 even ${digit}
;;
1) # odd position (relative to end)
debug 3 odd ${digit}
;;
esac
((sum+=digit))
debug 2 sum=${sum}
done
((sum % 10)) && echo false || echo true
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 40
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,51 @@
# Matching Brackets
Given a string containing brackets `[]`, braces `{}`, parentheses `()`,
or any combination thereof, verify that any and all pairs are matched
and nested correctly.
Run the tests with:
```bash
bats matching_brackets_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats matching_brackets_test.sh
```
## Source
Ginna Baker
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,23 @@
#!/usr/bin/env bash -x
shopt -s extglob
str=$1
# Brute force algorithm:
# 1 - remove all unwanted chars: keep only {}[]()
str=${str//[^\{\}\(\)\[\]]}
res=true
# 2- remove all pairs of [], {}, (). loop until string is empty (match ok) or unchanged
# (nok)
loop=1
while [[ ${#str} > 0 ]]
do
str2=${str//+(\[\]|\(\)|\{\})}
if [[ ${#str2} == ${#str} ]]; then
res=false
break
fi
str="$str2"
done
echo $res
exit 0

55
bash/pangram/README.md Normal file
View File

@@ -0,0 +1,55 @@
# 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.
The alphabet used consists of ASCII letters `a` to `z`, inclusive, and is case
insensitive. Input will not contain non-ASCII symbols.
Run the tests with:
```bash
bats pangram_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats pangram_test.sh
```
## Source
Wikipedia [https://en.wikipedia.org/wiki/Pangram](https://en.wikipedia.org/wiki/Pangram)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

49
bash/pangram/pangram.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# set to mask to enable logs. 0: none, 255: all
# (( debug=2#00001111 ))
(( debug=2#00000000 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & "$1" )) && shift && echo "${@}" >&2
}
usage () {
echo "usage: ./pangram.sh <string> [...]" >&2
exit 1
}
# basic args checks: at least 1 arg
(( $# )) || usage
# We will accept mutiple args here: "a" "b" is equivalent to "ab".
# get args in one string, change it to lower case.
IFS="" # not really needed
string="${*,,}"
debug 1 "string=$string"
# empty string
if (( ! ${#string} )); then
debug 2 "empty string"
result=false
else
result=true
# loop on all characters, from a to z. We need to check each one.
for c in {a..z} ; do
[[ ! ${string} =~ "$c" ]] && result=false && break
done
fi
echo "$result"
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 60
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

63
bash/proverb/README.md Normal file
View File

@@ -0,0 +1,63 @@
# Proverb
For want of a horseshoe nail, a kingdom was lost, or so the saying goes.
Given a list of inputs, generate the relevant proverb. For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme:
```text
For want of a nail the shoe was lost.
For want of a shoe the horse was lost.
For want of a horse the rider was lost.
For want of a rider the message was lost.
For want of a message the battle was lost.
For want of a battle the kingdom was lost.
And all for the want of a nail.
```
Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content. No line of the output text should be a static, unchanging string; all should vary according to the input given.
Run the tests with:
```bash
bats proverb_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats proverb_test.sh
```
## Source
Wikipedia [http://en.wikipedia.org/wiki/For_Want_of_a_Nail](http://en.wikipedia.org/wiki/For_Want_of_a_Nail)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

15
bash/proverb/proverb.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
[[ $# == 0 ]] && echo "" && exit 0
first="$1"
prev="$first"
shift
while [[ $# > 0 ]]; do
cur="$1"
echo "For want of a $prev the $cur was lost."
prev=$cur
shift
done
echo "And all for the want of a $first."
exit 0

64
bash/raindrops/README.md Normal file
View File

@@ -0,0 +1,64 @@
# Raindrops
Convert a number to a string, the contents of which depend on the number's factors.
- If the number has 3 as a factor, output 'Pling'.
- If the number has 5 as a factor, output 'Plang'.
- If the number has 7 as a factor, output 'Plong'.
- If the number does not have 3, 5, or 7 as a factor,
just pass the number's digits straight through.
## Examples
- 28's factors are 1, 2, 4, **7**, 14, 28.
- In raindrop-speak, this would be a simple "Plong".
- 30's factors are 1, 2, **3**, **5**, 6, 10, 15, 30.
- In raindrop-speak, this would be a "PlingPlang".
- 34 has four factors: 1, 2, 17, and 34.
- In raindrop-speak, this would be "34".
Run the tests with:
```bash
bats raindrops_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats raindrops_test.sh
```
## Source
A variation on a famous interview question intended to weed out potential candidates. [http://jumpstartlab.com](http://jumpstartlab.com)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

20
bash/raindrops/raindrops.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
function usage() {
echo "Usage: ./raindrop.sh number"
exit 1
}
shopt -s extglob
(( $# == 1 )) || usage
number="$1"
[[ "$number" == +([0-9]) ]] || usage
output=""
(( $number % 3 )) || output+="Pling"
(( $number % 5 )) || output+="Plang"
(( $number % 7 )) || output+="Plong"
echo ${output:-$number}
exit 0

View File

@@ -0,0 +1,68 @@
# Resistor Color Duo
If you want to build something using a Raspberry Pi, you'll probably use _resistors_. For this exercise, you need to know two things about them:
* Each resistor has a resistance value.
* Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read.
To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. Each band acts as a digit of a number. For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15.
In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands. The program will take two colors as input, and output the correct number.
The band colors are encoded as follows:
- Black: 0
- Brown: 1
- Red: 2
- Orange: 3
- Yellow: 4
- Green: 5
- Blue: 6
- Violet: 7
- Grey: 8
- White: 9
Run the tests with:
```bash
bats resistor_color_duo_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats resistor_color_duo_test.sh
```
## Source
Maud de Vries, Erik Schierboom [https://github.com/exercism/problem-specifications/issues/1464](https://github.com/exercism/problem-specifications/issues/1464)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,39 @@
#!/usr/bin/env bash
usage () {
if [[ $# == 1 ]]; then
echo "$1: invalid color."
else
echo "usage: resistor_color.sh color1 color2"
fi
exit 1
}
declare -A colors
colors=(
[black]=0
[brown]=1
[red]=2
[orange]=3
[yellow]=4
[green]=5
[blue]=6
[violet]=7
[grey]=8
[white]=9
)
result=""
# not sure here if 1 color only should be accepted (case is not in test). I assume yes:
# "resistor_color.sh Black" will return 0
# also (not in test cases), no args will return an error.
[[ $# == 0 ]] && usage
# we will accept capitalized colors: converting to lower case
for i in ${1,,} ${2,,}
do
[[ ${colors[$i]} == "" ]] && usage "$i"
result+=${colors[$i]}
done
echo $result
exit 0

View File

@@ -0,0 +1,91 @@
# Resistor Color Trio
If you want to build something using a Raspberry Pi, you'll probably use _resistors_. For this exercise, you need to know only three things about them:
- Each resistor has a resistance value.
- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read.
To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values.
- Each band acts as a digit of a number. For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15.
In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands. The program will take 3 colors as input, and outputs the correct value, in ohms.
The color bands are encoded as follows:
* Black: 0
* Brown: 1
* Red: 2
* Orange: 3
* Yellow: 4
* Green: 5
* Blue: 6
* Violet: 7
* Grey: 8
* White: 9
In `resistor-color duo` you decoded the first two colors. For instance: orange-orange got the main value `33`.
The third color stands for how many zeros need to be added to the main value. The main value plus the zeros gives us a value in ohms.
For the exercise it doesn't matter what ohms really are.
For example:
- orange-orange-black would be 33 and no zeros, which becomes 33 ohms.
- orange-orange-red would be 33 and 2 zeros, which becomes 3300 ohms.
- orange-orange-orange would be 33 and 3 zeros, which becomes 33000 ohms.
(If Math is your thing, you may want to think of the zeros as exponents of 10. If Math is not your thing, go with the zeros. It really is the same thing, just in plain English instead of Math lingo.)
This exercise is about translating the colors into a label:
> "... ohms"
So an input of `"orange", "orange", "black"` should return:
> "33 ohms"
When we get more than a thousand ohms, we say "kiloohms". That's similar to saying "kilometer" for 1000 meters, and "kilograms" for 1000 grams.
So an input of `"orange", "orange", "orange"` should return:
> "33 kiloohms"
Run the tests with:
```bash
bats resistor_color_trio_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats resistor_color_trio_test.sh
```
## Source
Maud de Vries, Erik Schierboom [https://github.com/exercism/problem-specifications/issues/1549](https://github.com/exercism/problem-specifications/issues/1549)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,93 @@
#!/usr/bin/env bash
#
# V1: initial version
# V2: merged power tables, add index one, improved unit str calculation
# set to mask to enable logs. 0: none, 255: all
((debug=2#00000000))
#((debug=2#00011111))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: resistor_color_trio.sh color1 [color2 [color3]]"
}
# not sure here if 1 or 2 colors only should be accepted (not in test cases).
# I will assume yes, it looks more coherent, even if out of scope:
# "resistor_color_trio.sh Black" will return 0
# "resistor_color_trio.sh yellow violet" will return 47
# also: (not in test cases), no args will return an error.
# (in test case), extra colors are ignored, I don't like it, personally
(( $# == 0 )) && usage
# value/power of different colors
declare -A colors=([black]=0 [brown]=1 [red]=2 [orange]=3 [yellow]=4
[green]=5 [blue]=6 [violet]=7 [grey]=8 [white]=9)
# available multiplicators (powers of 10).
declare -a powers=([9]=giga [6]=mega [3]=kilo)
idx=("${!powers[@]}") # keys copy for reverse loop
params=( ${@,,} ) # converting to lower case
(( result=0 )) # final number to display
# I would have preferred to throw an error if $# > 3, instead of ignoring
# extra args...
for ((i=0; i<3 && i<${#params[@]}; ++i)); do
color="${params[$i]}" # color name
val="${colors[$color]}" # color value
[[ -z "$val" ]] && die "$color: invalid color."
case $i in
0) (( result=val ))
debug 2 "new color 1 $color/$val. result=$result"
;;
# probably case 0 and 1 could be merged. Easier to read for me
# by separating them.
1) (( result*=10 ))
(( result+=val ))
debug 2 "new color 2 $color/$val. result=$result"
;;
2) (( result *= 10 ** val ))
debug 2 "new color 3 $color/$val. result=$result"
;;
esac
done
# we have final number, scaling to corresponding strings.
scalestr="" # "giga", etc...
if (( result )); then
for (( i = ${#idx[@]} - 1; i >= 0; i-- )); do # reverse loop by value
j=${idx[$i]} # also actual power (9, 6, 3)
(( power = 10 ** $j )) # actual value
debug 8 $i $j ${powers[$j]} $power $result
if ! (( result % power )); then # found power
scalestr=${powers[$j]}
(( result /= power ))
break
fi
done
fi
echo "$result ${scalestr}ohms"
exit 0
# emacs/vim settings below.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 50
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env bash
# set to mask to enable logs. 0: none, 255: all
# ((debug=2#00011111))
((debug=2#00000000))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: resistor_color_trio.sh color1 [color2 [color3]]"
}
# value/power of different colors
declare -A colors=([black]=0 [brown]=1 [red]=2 [orange]=3 [yellow]=4
[green]=5 [blue]=6 [violet]=7 [grey]=8 [white]=9)
# available multiplicators (powers of 10)
declare -a powers=(9 6 3)
# corresponding strings
declare -a powernames=(giga mega kilo)
# not sure here if 1 or 2 colors only should be accepted (not in test cases).
# I will assume yes, it looks more coherent, even if out of scope:
# "resistor_color_trio.sh Black" will return 0
# "resistor_color_trio.sh yellow violet" will return 47
# also: (not in test cases), no args will return an error.
# (in test case), extra colors are ignored, I don't like it, personally
(( $# == 0 )) && usage
scalestr="" # "giga", etc...
(( result=0 )) # number to display
debug 64 "params=${#params[@]} ${params[@]}"
# converting to lower case
params=( ${@,,} )
debug 2 "#params=${#params[@]} ${params[@]}"
# I would have preferred to throw an error if $# > 3, instead of ignoring
# extra args...
for ((i=0; i<3 && i<${#params[@]}; ++i)); do
color="${params[$i]}" # color name
val="${colors[$color]}" # color value
debug 8 "i=$i - color=$color - val=$val"
debug 4 val="$val" color="${color[$i]}"
[[ -z "$val" ]] && die "$color: invalid color."
case $i in
0) (( result=val ))
debug 2 "new color 1 $color/$val. result=$result"
;;
# probably case 0 and 1 could be merged. Easier to read for me
# separating them.
1) (( result*=10 ))
(( result+=val ))
debug 2 "new color 2 $color/$val. result=$result"
;;
2) (( result *= 10 ** val ))
debug 2 "new color 3 $color/$val. result=$result"
# we have final number, scaling to multiple strings.
for (( j=0; result && j<${#powers[@]}; ++j )); do
(( pow = 10 ** ${powers[j]} ))
debug 8 "val=$val result=$result j=$j pow=$pow"
if ! (( result && result % pow )); then
((result /= pow))
scalestr=${powernames[$j]}
break
fi
done
;;
esac
done
debug 4 res="$result" scalestr="$scalestr"
echo "$result ${scalestr}ohms"
exit 0
# emacs/vim settings below.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 60
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env bash
#
# V1: initial version
# V2: merged the
# set to mask to enable logs. 0: none, 255: all
# ((debug=2#00011111))
((debug=2#00000000))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: resistor_color_trio.sh color1 [color2 [color3]]"
}
# value/power of different colors
declare -A colors=([black]=0 [brown]=1 [red]=2 [orange]=3 [yellow]=4
[green]=5 [blue]=6 [violet]=7 [grey]=8 [white]=9)
# available multiplicators (powers of 10)
declare -a powers=(9 6 3)
scalestr="" # "giga", etc...
(( result=0 )) # number to display
# corresponding strings
declare -a powernames=(giga mega kilo)
# not sure here if 1 or 2 colors only should be accepted (not in test cases).
# I will assume yes, it looks more coherent, even if out of scope:
# "resistor_color_trio.sh Black" will return 0
# "resistor_color_trio.sh yellow violet" will return 47
# also: (not in test cases), no args will return an error.
# (in test case), extra colors are ignored, I don't like it, personally
(( $# == 0 )) && usage
debug 64 "params=${#params[@]} ${params[@]}"
# converting to lower case, adding default values if args missing
params=( ${@,,} black black black )
debug 2 "#params=${#params[@]} ${params[@]}"
# I would have preferred to throw an error if $# > 3, instead of ignoring
# extra args...
for ((i=0; i<3 && i<${#params[@]}; ++i)); do
color="${params[$i]}" # color name
val="${colors[$color]}" # color value
debug 4 val="$val" color="${color[$i]}"
[[ -z "$val" ]] && die "$color: invalid color."
case $i in
0) (( result=val ))
debug 2 "new color 1 $color/$val. result=$result"
;;
# probably case 0 and 1 could be merged. Easier to read for me
# by separating them.
1) (( result*=10 ))
(( result+=val ))
debug 2 "new color 2 $color/$val. result=$result"
;;
2) (( result *= 10 ** val ))
debug 2 "new color 3 $color/$val. result=$result"
;;
esac
done
# we have final number, scaling to corresponding strings.
for (( j=0; result && j<${#powers[@]}; ++j )); do
(( pow = 10 ** ${powers[j]} ))
debug 8 "val=$val result=$result j=$j pow=$pow"
if ! (( result && result % pow )); then
((result /= pow))
scalestr=${powernames[$j]}
break
fi
done
debug 4 res="$result" scalestr="$scalestr"
echo "$result ${scalestr}ohms"
exit 0
# emacs/vim settings below.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 50
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,53 @@
# Reverse String
Reverse a string
For example:
input: "cool"
output: "looc"
Run the tests with:
```bash
bats reverse_string_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats reverse_string_test.sh
```
## Source
Introductory challenge to reverse an input string [https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb](https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,14 @@
#!/usr/bin/env bash
[[ $# != 1 ]] && echo "usage: $0 string" && exit 1
str=$1
len=${#str}
rev=""
for (( i=0; i<len; ++i ))
do
rev="${str:i:1}$rev"
done
echo "$rev"

View File

@@ -0,0 +1,65 @@
# RNA Transcription
Given a DNA strand, return 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`
Run the tests with:
```bash
bats rna_transcription_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats rna_transcription_test.sh
```
## Source
Hyperphysics [http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html](http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,60 @@
#!/usr/bin/env bash
#
# External tools: none.
#
# V1: initial version
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
#(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: rna_transcription.sh [seq1] [...]"
}
declare -A complement=([G]='C'
[C]='G'
[T]='A'
[A]='U')
debug 1 keys/vals=${!complement[@]}/${complement[@]}
# we will accept multiple args (out of topic for exercise), meaning that:
# rna_transcription.sh GCTA
# is equivalent to
# rna_transcription.sh G C T A
# or
# rna_transcription.sh G CTA
dna="${@}"
dna="${dna// /}" # remove spaces
(($# > 0 )) && [[ "$dna" != +([GCTA]) ]] && die "Invalid nucleotide detected."
((ldna=${#dna}))
debug 1 "dna=$dna, length=$ldna"
rna="" # rna sequence
for ((i=0; i<ldna; ++i)); do
seq=${dna:$i:1}
rna+="${complement[$seq]}"
debug 2 "rna=$rna"
done
echo "$rna" # not perfect, empty line if no args.
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 40
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,86 @@
# Scrabble Score
Given a word, compute the scrabble score for that word.
## Letter Values
You'll need these:
```text
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.
Run the tests with:
```bash
bats scrabble_score_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats scrabble_score_test.sh
```
## Source
Inspired by the Extreme Startup game [https://github.com/rchatley/extreme_startup](https://github.com/rchatley/extreme_startup)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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,56 @@
#!/usr/bin/env bash
#
# V1: initial version
# V2: check for alphabetic chars only
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
#(( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: scrabble_score.sh word"
}
declare -A values=(
[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
)
(($# != 1)) && usage
word="${1^^}" # capitalize
[[ "$word" != +([[:upper:]]) ]] && usage # accept only alpha chars
debug 1 arg="$word"
((score=0))
for (( i=0; i<${#word}; ++i )); do
c="${word:$i:1}"
((score += ${values[$c]}))
done
echo "$score"
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 50
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

View File

@@ -0,0 +1,75 @@
# 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".
```text
1 = wink
10 = double blink
100 = close your eyes
1000 = jump
10000 = Reverse the order of the operations in the secret handshake.
```
Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.
Here's a couple of examples:
Given the input 3, the function would return the array
["wink", "double blink"] because 3 is 11 in binary.
Given the input 19, the function would return the array
["double blink", "wink"] because 19 is 10011 in binary.
Notice that the addition of 16 (10000 in binary)
has caused the array to be reversed.
Run the tests with:
```bash
bats secret_handshake_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats secret_handshake_test.sh
```
## Source
Bert, in Mary Poppins [http://www.imdb.com/title/tt0058331/quotes/qt0437047](http://www.imdb.com/title/tt0058331/quotes/qt0437047)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## 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 @@
#!/usr/bin/env bash
num=$1
strings=(
"wink"
"double blink"
"close your eyes"
"jump"
)
reverse=n
result=()
(( $num & 2#10000 )) && reverse=y
# get matching bits
for (( i=0 ; i<4 ; ++i )); do
(( $num & 1<<$i )) && result+=( "${strings[$i]}" )
done
# output in normal or reverse order
for (( i=0 ; i<${#result[@]} ; ++i)) ; do
[[ $reverse == n ]] && echo -n "$sep${result[i]}" || echo -n "$sep${result[~i]}"
sep=","
done
echo
exit 0

76
bash/sieve/README.md Normal file
View File

@@ -0,0 +1,76 @@
# Sieve
Use 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. It does not use any division or remainder operation.
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. A good first test is to check that you do not use
division or remainder operations (div, /, mod or % depending on the
language).
Run the tests with:
```bash
bats sieve_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats sieve_test.sh
```
## Source
Sieve of Eratosthenes at Wikipedia [http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes](http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

24
bash/sieve/sieve.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
usage() {
echo "Usage: ./seave.sh <number>"
exit 1
}
end=$1
[[ ! "$end" =~ ^[[:digit:]]*$ ]] && usage
declare -a numbers
sep=""
for (( i=2; i<=end; ++i )); do
if [[ ${numbers[$i]} == "" ]]; then
echo -n "$sep$i"
for (( j=i*2; j<=end; j+=i )); do
numbers[$j]=t
done
sep=" "
fi
done
echo
exit 0

43
bash/template.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env bash
#
# External tools: none.
#
# V1: initial version
shopt -s extglob
# set to mask to enable logs. 0: none, 255: all
(( debug=2#00000000 ))
# (( debug=2#00001111 ))
# $1: log level (mask), then strings to display.
debug () {
(( debug & $1 )) && shift && echo Line ${BASH_LINENO[0]}: "${@}" >&2
#local -i i
#if (( debug & $1 )) ; then
# for ((i=1; i<$1; ++i)); do
# echo -n " "
# done
# shift
# echo "${BASH_LINENO[0]}: ${@}" >&2
#fi
}
die () {
echo "${@}" >&2
exit 1
}
usage() {
die "usage: resistor_color_trio.sh color1 [color2 [color3]]"
}
exit 0
# emacs/vim settings.
# Local Variables:
# sh-basic-offset: 4
# indent-tabs-mode: nil
# comment-column: 40
# fill-column: 80
# End:
# vim: set tabstop=4 expandtab:

108
bash/tournament/README.md Normal file
View File

@@ -0,0 +1,108 @@
# Tournament
Tally the results of a small football competition.
Based on an input file containing which team played against which and what the
outcome was, create a file with a table like this:
```text
Team | MP | W | D | L | P
Devastating Donkeys | 3 | 2 | 1 | 0 | 7
Allegoric Alaskans | 3 | 2 | 0 | 1 | 6
Blithering Badgers | 3 | 1 | 0 | 2 | 3
Courageous Californians | 3 | 0 | 1 | 2 | 1
```
What do those abbreviations mean?
- MP: Matches Played
- W: Matches Won
- D: Matches Drawn (Tied)
- L: Matches Lost
- P: Points
A win earns a team 3 points. A draw earns 1. A loss earns 0.
The outcome should be ordered by points, descending. In case of a tie, teams are ordered alphabetically.
###
Input
Your tallying program will receive input that looks like:
```text
Allegoric Alaskans;Blithering Badgers;win
Devastating Donkeys;Courageous Californians;draw
Devastating Donkeys;Allegoric Alaskans;win
Courageous Californians;Blithering Badgers;loss
Blithering Badgers;Devastating Donkeys;loss
Allegoric Alaskans;Courageous Californians;win
```
The result of the match refers to the first team listed. So this line
```text
Allegoric Alaskans;Blithering Badgers;win
```
Means that the Allegoric Alaskans beat the Blithering Badgers.
This line:
```text
Courageous Californians;Blithering Badgers;loss
```
Means that the Blithering Badgers beat the Courageous Californians.
And this line:
```text
Devastating Donkeys;Courageous Californians;draw
```
Means that the Devastating Donkeys and Courageous Californians tied.
Run the tests with:
```bash
bats tournament_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats tournament_test.sh
```
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

132
bash/tournament/tournament.sh Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/env bash
# v1: - initial version
# v2-3: - backport bubble sort (while -> for) & debug system from next exercises
# - always read from stdin
# - some syntax improvement
# v4: - cosmetic/syntax changes
# - change from empty file handling (empty string becomes valid filename)
# v5: - cosmetic changes following "shellcheck" usage.
# v6: - removed debug calls.
# v7-8: - cosmetic changes
die() {
echo "${@}" >&2
exit 1
}
# the results, associative arrays with team name as key. Some tables look
# redundant, but easier to understand.
declare -A mp # matches played
declare -A win # matches won
declare -A draw # matches tied
declare -A loss # matches lost
declare -A points # points
declare -a order # final order.
nteams=0
# create a team entry in arrays if non existent. $1: team
create_team() {
if ! [[ -v "mp[$1]" ]]; then
(( nteams++ ))
(( mp["$1"]=0 ))
(( win["$1"]=0 ))
(( loss["$1"]=0 ))
(( draw["$1"]=0 ))
(( points["$1"]=0 ))
order[$nteams]="$1"
fi
}
# update results for a team: $1, $2: teams, $3: result for $1: win/draw/loss
update_results() {
create_team "$1"
create_team "$2"
((mp["$1"]++))
((mp["$2"]++))
case "$3" in
win)
((win["$1"]++))
((loss["$2"]++))
((points["$1"]+=3))
;;
loss)
((win["$2"]++))
((loss["$1"]++))
((points["$2"]+=3))
;;
draw)
((draw["$1"]++))
((draw["$2"]++))
((points["$1"]++))
((points["$2"]++))
;;
*) # should not happen
die "fatal: invalid result $3, exiting."
esac
}
# inspired from https://stackoverflow.com/questions/7442417/how-to-sort-an-array-in-bash
# (bubble sort)
sort_teams()
{
local max i
for ((max=nteams; max>0; max--)); do
for ((i=1; i<max; ++i )); do
local team1=${order[$i]} team2=${order[$i + 1]} switch=0
if (( ${points["$team1"]} < ${points["$team2"]} )) || \
( (( ${points["$team1"]} == ${points["$team2"]} )) && \
[[ "$team1" > "$team2" ]] ); then
order[$i]="$team2"
order[$i + 1]="$team1"
fi
done
done
}
output() {
printf "%-30s |%3s |%3s |%3s |%3s |%3s\n" "${@:1:6}"
}
output_team() {
output "$1" "${mp[$1]}" "${win[$1]}" "${draw[$1]}" "${loss[$1]}" "${points[$1]}"
}
# output teams, according to "order" table
output_teams() {
local i
# header
output "Team" "MP" "W" "D" "L" "P"
for (( i=1; i<= nteams; ++i )); do
output_team "${order[$i]}"
done
}
load_teams() {
# set separator. Note we ignore escaping ';': a\;a;b;win wont work
local team1 team2 result
local IFS=$';\n'
while read -r team1 team2 result ; do
# should empty result considered as error or ignored? Ignored here.
[[ -z "$team1" || -z "$team2" || -z "$result" ]] && continue
update_results "$team1" "$team2" "$result"
done
}
# we will accept both argument (file name) or stdin input
if (( $# == 0 )); then
load_teams
elif [[ -f "$1" ]]; then
load_teams < "$1"
else
die Invalid "[$1]" file. Exiting.
fi
sort_teams
output_teams
exit 0

72
bash/two-fer/README.md Normal file
View File

@@ -0,0 +1,72 @@
# Two Fer
`Two-fer` or `2-fer` is short for two for one. One for you and one for me.
Given a name, return a string with the message:
```text
One for X, one for me.
```
Where X is the given name.
However, if the name is missing, return the string:
```text
One for you, one for me.
```
Here are some examples:
|Name |String to return
|:-------|:------------------
|Alice |One for Alice, one for me.
|Bob |One for Bob, one for me.
| |One for you, one for me.
|Zaphod |One for Zaphod, one for me.
Run the tests with:
```bash
bats two_fer_test.sh
```
After the first test(s) pass, continue by commenting out or removing the
`[[ $BATS_RUN_SKIPPED == true ]] || skip`
annotations prepending other tests.
To run all tests, including the ones with `skip` annotations, run:
```bash
BATS_RUN_SKIPPED=true bats two_fer_test.sh
```
## Source
[https://github.com/exercism/problem-specifications/issues/757](https://github.com/exercism/problem-specifications/issues/757)
## External utilities
`Bash` is a language to write "scripts" -- programs that can call
external tools, such as
[`sed`](https://www.gnu.org/software/sed/),
[`awk`](https://www.gnu.org/software/gawk/),
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
and even programs written in other programming languages,
like [`Python`](https://www.python.org/).
This track does not restrict the usage of these utilities, and as long
as your solution is portable between systems and does not require
installation of third party applications, feel free to use them to solve
the exercise.
For an extra challenge, if you would like to have a better understanding
of the language, try to re-implement the solution in pure `Bash`,
without using any external tools. Note that there are some types of
problems that bash cannot solve, such as performing floating point
arithmetic and manipulating dates: for those, you must call out to an
external tool.
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others
have completed the exercise.

12
bash/two-fer/two_fer.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
#str=$1
# the next two lines would trim leading & trailing blank chars. I believe the exercise
# should be amended to avoid "One for , one for me."
#str="${str#"${str%%[![:space:]]*}"}" # remove leading blanks
#str="${str%"${str##*[![:space:]]}"}" # remove trailing blanks
#[[ ${#str} = 0 ]] && str="you"
echo "One for ${1:-you}, one for me."

41
c/acronym/GNUmakefile Normal file
View File

@@ -0,0 +1,41 @@
# The original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means :
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
# not practical at all.
# - Also, it does not allow to run all tests without editing the test source
# code.
#
# To use this makefile (GNU make only):
# "make": build with all predefined tests (without editing test source code)
# "make mem": perform memcheck with all tests enabled
# "make unit": build standalone (unit) test
# "make debug": build standalone test with debugging code
#
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
.PHONY: default all mem unit debug std
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL -g
all: clean test
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG -g
debug: clean std
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

46
c/acronym/README.md Normal file
View File

@@ -0,0 +1,46 @@
# Acronym
Convert a phrase to its acronym.
Techies love their TLA (Three Letter Acronyms)!
Help generate some jargon by writing a program that converts a long name
like Portable Network Graphics to its acronym (PNG).
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
Julien Vanier [https://github.com/monkbroc](https://github.com/monkbroc)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

37
c/acronym/makefile Normal file
View File

@@ -0,0 +1,37 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

69
c/acronym/src/acronym.c Normal file
View File

@@ -0,0 +1,69 @@
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include "acronym.h"
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
#endif
#define SKIPWORD(p) { while (*(p) && (isalpha(*(p)) || *p=='\'')) (p)++;}
#define NEXTWORD(p) { while (*(p) && !isalpha(*(p))) (p)++;}
char *abbreviate(const char *phrase)
{
/* Yet another approach (to avoid scanning phrase twice):
* We (re)allocate a ALLOCSIZE buffer when current one is not large
* enough to accept next character + 1 ('\0')
*
* Other solutions would be to scan phrase twice (for example an initial
* strlen() to find out a maximum length), or the (bad idea) using a fixed
* size buffer.
*
* The usual choices.
*/
char *buf=NULL;
int c=0, size=0;
if (!phrase)
return NULL;
while (*phrase) {
NEXTWORD(phrase);
if (*phrase) {
/* buffer too small */
if (c>=size-1) {
size+=ALLOCSIZE;
if (!(buf=realloc(buf, size)))
return NULL;
}
*(buf+c++)=toupper(*phrase++);
SKIPWORD(phrase);
}
}
/* at least one character */
if (c)
*(buf+c)=0;
return buf;
}
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
char *p;
for (; arg<ac; ++arg) {
p=abbreviate(*(av+arg));
printf("acronym(%s)=[%s]\n", *(av+arg), p? p: "NULL");
if (p)
free(p);
}
}
#endif

20
c/acronym/src/acronym.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef ACRONYM_H
#define ACRONYM_H
char *abbreviate(const char *phrase);
#ifdef DEBUG
#define ALLOCSIZE 2
#else
#define ALLOCSIZE 1024
#endif
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

View File

@@ -0,0 +1,21 @@
# the original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means we need to edit 'makefile' for different builds (DEBUG, etc...),
# which is not practical at all.
#
# I hope this will be use-able for next exercises...
#include gmsl
include makefile
manual=-DUNIT_TEST
debug=$(manual) -DDEBUG
.PHONY: manual debug
manual debug: src/*.c src/*.h
$(CC) $($@) src/*.c -o $@.out
#debug: src/*.c src/*.h
# $(CC) $(DEBUG) src/*.c -o $@.out

View File

@@ -0,0 +1,50 @@
# Armstrong Numbers
An [Armstrong number](https://en.wikipedia.org/wiki/Narcissistic_number) is a number that is the sum of its own digits each raised to the power of the number of digits.
For example:
- 9 is an Armstrong number, because `9 = 9^1 = 9`
- 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 1`
- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153`
- 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190`
Write some code to determine whether a number is an Armstrong number.
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
Wikipedia [https://en.wikipedia.org/wiki/Narcissistic_number](https://en.wikipedia.org/wiki/Narcissistic_number)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

View File

@@ -0,0 +1,35 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

View File

@@ -0,0 +1,40 @@
#include <stdio.h>
#include <stdlib.h>
#include "armstrong_numbers.h"
static inline int power(int n, int p) {
int res=n;
/* useless here
* if (p==0)
* return 1;
*/
while (--p)
res*=n;
return res;
}
bool is_armstrong_number(int candidate)
{
int p=1, r=0, tmp=candidate;
while (tmp/=10)
p++;
for (tmp=candidate; tmp; tmp /=10)
r+=power(tmp%10, p);
return r==candidate;
}
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1, n;
for (; arg<ac; ++arg) {
n=atoi(av[arg]);
printf("armstrong(%d)=%d\n", n, is_armstrong_number(n));
}
}
#endif

View File

@@ -0,0 +1,8 @@
#ifndef ARMSTRONG_NUMBERS
#define ARMSTRONG_NUMBERS
#include <stdbool.h>
bool is_armstrong_number(int candidate);
#endif

34
c/darts/GNUmakefile Normal file
View File

@@ -0,0 +1,34 @@
# the original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means we need to edit 'makefile' for different builds (DEBUG, etc...),
# which is not practical at all.
#
# To use this makefile:
# "make": build with all predefined tests
# "make unit": build standalone (unit) test
# "make debug": build standalone test with debugging code
#
# Original 'makefile' targets can be used (make test, etc...)
.PHONY: default all unit debug std
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
debug: clean std
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

55
c/darts/README.md Normal file
View File

@@ -0,0 +1,55 @@
# Darts
Write a function that returns the earned points in a single toss of a Darts game.
[Darts](https://en.wikipedia.org/wiki/Darts) is a game where players
throw darts to a [target](https://en.wikipedia.org/wiki/Darts#/media/File:Darts_in_a_dartboard.jpg).
In our particular instance of the game, the target rewards with 4 different amounts of points, depending on where the dart lands:
* If the dart lands outside the target, player earns no points (0 points).
* If the dart lands in the outer circle of the target, player earns 1 point.
* If the dart lands in the middle circle of the target, player earns 5 points.
* If the dart lands in the inner circle of the target, player earns 10 points.
The outer circle has a radius of 10 units (This is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1. Of course, they are all centered to the same point (That is, the circles are [concentric](http://mathworld.wolfram.com/ConcentricCircles.html)) defined by the coordinates (0, 0).
Write a function that given a point in the target (defined by its `real` cartesian coordinates `x` and `y`), returns the correct amount earned by a dart landing in that point.
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
Inspired by an exercise created by a professor Della Paolera in Argentina
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

37
c/darts/makefile Normal file
View File

@@ -0,0 +1,37 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

49
c/darts/src/darts.c Normal file
View File

@@ -0,0 +1,49 @@
#include "darts.h"
score_t scores[] ={
{ 1.0F, 10 },
{ 25.0F, 5 },
{ 100.0F, 1 },
{ -1.0F, 0 }
};
/* Below function is basically incorrect for general case.
* However, it should mostly work here, as we compare relatively small numbers.
* see below for better alternatives :
* https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
*/
static inline bool float_almost_equal(float x, float y)
{
register float f=x-y;
return f<MIN_FLOAT_EQUAL && f>-MIN_FLOAT_EQUAL? true: false;
}
unsigned score(coordinate_t c)
{
float x=c.x, y=c.y, radius=x*x+y*y;
int i;
for (i=0; scores[i].score; ++i) {
if (float_almost_equal(radius, scores[i].radius) || radius < scores[i].radius)
break;
}
return scores[i].score;
}
#ifdef UNIT_TEST
#include <stdlib.h>
#include <stdio.h>
int main(int ac, char **av)
{
int arg=1;
float x, y;
for (; arg<ac-1; ++arg, ++arg) {
x=atof(av[arg]);
y=atof(av[arg+1]);
printf("equal(%f, %f)=%d\n", x, y, float_almost_equal(x, y));
}
}
#endif

28
c/darts/src/darts.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef DARTS_H
#define DARTS_H
#include <stdbool.h>
#include <float.h>
typedef struct {
float x, y;
} coordinate_t;
typedef struct {
float radius;
int score;
} score_t;
// to allow float comparisons we consider 2 floats are equal if
// their difference is below this value.
// Use: avoid the '<' & '>' which may be wrong.
#define MIN_FLOAT_EQUAL FLT_EPSILON
extern unsigned score(coordinate_t);
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

View File

@@ -0,0 +1,41 @@
# The original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means :
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
# not practical at all.
# - Also, it does not allow to run all tests without editing the test source
# code.
#
# To use this makefile (GNU make only):
# "make": build with all predefined tests (without editing test source code)
# "make mem": perform memcheck with all tests enabled
# "make unit": build standalone (unit) test
# "make debug": build standalone test with debugging code
#
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
.PHONY: default all mem unit debug std
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
debug: clean std
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

View File

@@ -0,0 +1,55 @@
# Difference Of Squares
Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.
The square of the sum of the first ten natural numbers is
(1 + 2 + ... + 10)² = 55² = 3025.
The sum of the squares of the first ten natural numbers is
1² + 2² + ... + 10² = 385.
Hence the difference between the square of the sum of the first
ten natural numbers and the sum of the squares of the first ten
natural numbers is 3025 - 385 = 2640.
You are not expected to discover an efficient solution to this yourself from
first principles; research is allowed, indeed, encouraged. Finding the best
algorithm for the problem is a key skill in software engineering.
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
Problem 6 at Project Euler [http://projecteuler.net/problem=6](http://projecteuler.net/problem=6)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

View File

@@ -0,0 +1,37 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

View File

@@ -0,0 +1,52 @@
#include "difference_of_squares.h"
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
#endif
unsigned int sum_of_squares(unsigned int number)
{
/* the sum of 1st n integers squares is:
* S = 1² + 2² + 3² ..... + (n-1)² + n²
* = [ n * (n+1) * (2n+1) ] / 6
* some visual explanations on:
* http://www.takayaiwamoto.com/Sums_and_Series/sumsqr_1.html
*/
return number * (number+1) * (2*number + 1) / 6;
}
unsigned int square_of_sum(unsigned int number)
{
register int res;
/* The sum of n 1st integers is:
* S = 1 + 2 + 3 ... + (n-1) + n
* = [ n * (n+1) ] / 2
* demonstration is trivial for this one.
*/
res=number * (number+1) / 2;
return res*res;
}
unsigned int difference_of_squares(unsigned int number)
{
return square_of_sum(number) - sum_of_squares(number);
}
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
int i;
for (; arg<ac; ++arg) {
i=atoi(av[arg]);
printf("sumsq(%d)=%d\n", i, sum_of_squares(i));
printf("sqsum(%d)=%d\n", i, square_of_sum(i));
printf("diff(%d)=%d\n", i, difference_of_squares(i));
}
}
#endif

View File

@@ -0,0 +1,16 @@
#ifndef DIFFERENCE_OF_SQUARES_H
#define DIFFERENCE_OF_SQUARES_H
unsigned int sum_of_squares(unsigned int number);
unsigned int square_of_sum(unsigned int number);
unsigned int difference_of_squares(unsigned int number);
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

41
c/grains/GNUmakefile Normal file
View File

@@ -0,0 +1,41 @@
# The original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means :
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
# not practical at all.
# - Also, it does not allow to run all tests without editing the test source
# code.
#
# To use this makefile (GNU make only):
# "make": build with all predefined tests (without editing test source code)
# "make mem": perform memcheck with all tests enabled
# "make unit": build standalone (unit) test
# "make debug": build standalone test with debugging code
#
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
.PHONY: default all mem unit debug std
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
debug: clean std
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

65
c/grains/README.md Normal file
View File

@@ -0,0 +1,65 @@
# Grains
Calculate 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, with the number
of grains doubling on each successive square.
There are 64 squares on a chessboard (where square 1 has one grain, square 2 has two grains, and so on).
Write code that shows:
- how many grains were on a given square, and
- the total number of grains on the chessboard
## 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?
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
JavaRanch Cattle Drive, exercise 6 [http://www.javaranch.com/grains.jsp](http://www.javaranch.com/grains.jsp)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

37
c/grains/makefile Normal file
View File

@@ -0,0 +1,37 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

45
c/grains/src/grains.c Normal file
View File

@@ -0,0 +1,45 @@
#include "grains.h"
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
#endif
uint64_t square(uint8_t index)
{
return index>0 && index <65 ? (uint64_t)1<<(index-1): 0;
}
uint64_t total(void)
{
/* Geometric series sum formula for 64 terms, ratio 2 and first term 1:
* S = 2⁰ + 2¹ + 2² + ... + 2⁶³
* = (1-2⁶⁴) / (1-2)
* = 2⁶⁴ - 1
* = 0 - 1 for uint64_t
* We should write (2<<64)-1, but gcc won't compile, due to:
* -Werror=shift-count-overflow
* Then we could avoid it by using:
* #pragma GCC diagnostic ignored "-Wshift-count-overflow"
* but i think it is out of scope for this exercise (we should also take
* care of other compilers).
*/
return (uint64_t) -1;
}
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
uint64_t i;
for (; arg<ac; ++arg) {
i=atol(av[arg]);
printf("value(%lu)=%lu\n", i, square(i));
}
printf("total()=%lu\n", total());
}
#endif

17
c/grains/src/grains.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef GRAINS_H
#define GRAINS_H
#include <stdint.h>
extern uint64_t square(uint8_t index);
extern uint64_t total(void);
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

41
c/hamming/GNUmakefile Normal file
View File

@@ -0,0 +1,41 @@
# The original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means :
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
# not practical at all.
# - Also, it does not allow to run all tests without editing the test source
# code.
#
# To use this makefile (GNU make only):
# "make": build with all predefined tests (without editing test source code)
# "make mem": perform memcheck with all tests enabled
# "make unit": build standalone (unit) test
# "make debug": build standalone test with debugging code
#
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
.PHONY: default all mem unit debug std
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
debug: clean std
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

62
c/hamming/README.md Normal file
View File

@@ -0,0 +1,62 @@
# Hamming
Calculate the Hamming Distance between two DNA strands.
Your body is made up of cells that contain DNA. Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime!
When cells divide, their DNA replicates too. Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. If we compare two strands of DNA and count the differences between them we can see how many mistakes occurred. This is known as the "Hamming Distance".
We read DNA using the letters C,A,G and T. Two strands might look like this:
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^ ^ ^ ^^
They have 7 differences, and therefore the Hamming Distance is 7.
The Hamming Distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with :)
# Implementation notes
The Hamming distance is only defined for sequences of equal length, so
an attempt to calculate it between sequences of different lengths should
not work. The general handling of this situation (e.g., raising an
exception vs returning a special value) may differ between languages.
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
The Calculating Point Mutations problem at Rosalind [http://rosalind.info/problems/hamm/](http://rosalind.info/problems/hamm/)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

37
c/hamming/makefile Normal file
View File

@@ -0,0 +1,37 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

41
c/hamming/src/hamming.c Normal file
View File

@@ -0,0 +1,41 @@
#include "hamming.h"
/* Note: For explanation on section below, see 'GNUfilename' included in
* link below :
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
#endif
/* test does not include invalid input, but it should, as the subject is
* about DNA sequence, not ASCII chars sequence :-)
* exercism test needs only:
* #define V(p) (*p)
*/
#define V(p) (*(p)=='A' || *(p)=='C' || *(p)=='G' || *(p)=='T')
int compute(const char *lhs, const char *rhs)
{
int res=0;
const char *l=lhs, *r=rhs;
if (!l || !r)
return -1;
for (; V(l) && V(r); ++l, ++r) {
if (*l != *r)
res++;
}
return *r || *l? -1: res;
}
#ifdef UNIT_TEST
int main(int ac, char **av)
{
if (ac==3) {
printf("compute(%s, %s)=%d\n", *(av+1), *(av+2), compute(*(av+1), *(av+2)));
}
}
#endif

15
c/hamming/src/hamming.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef HAMMING_H
#define HAMMING_H
int compute(const char *lhs, const char *rhs);
/* Note: For explanation on section below, see 'GNUfilename' included in
* link below :
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

53
c/hello-world/README.md Normal file
View File

@@ -0,0 +1,53 @@
# Hello World
The classical introductory exercise. Just say "Hello, World!".
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
the traditional first program for beginning programming in a new language
or environment.
The objectives are simple:
- Write a function that returns the string "Hello, World!".
- Run the test suite and make sure that it succeeds.
- Submit your solution and check it at the website.
If everything goes well, you will be ready to fetch your first real exercise.
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

37
c/hello-world/makefile Normal file
View File

@@ -0,0 +1,37 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

View File

@@ -0,0 +1,7 @@
#include <stddef.h>
#include "hello_world.h"
const char *hello(void)
{
return "Hello, World!";
}

View File

@@ -0,0 +1,14 @@
// This is called an include guard, which ensures that the header is only
// included once. You could alternatively use '#pragma once'. See
// https://en.wikipedia.org/wiki/Include_guard.
#ifndef HELLO_WORLD_H
#define HELLO_WORLD_H
// Declare the 'hello()' function, which takes no arguments and returns a
// 'const char *', i.e. a pointer to a character (in this case the first
// character in a string). The function itself is defined in the hello_world.c
// source file. Ths function is called by the test case(s) in the test source
// file test/test_hello_world.c.
const char *hello(void);
#endif

39
c/isogram/GNUmakefile Normal file
View File

@@ -0,0 +1,39 @@
# the original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means we need to edit 'makefile' for different builds (DEBUG, etc...),
# which is not practical at all. Also, it does not allow to run all tests without
# editing the test source code.
#
# To use this makefile (GNU make only):
# "make": build with all predefined tests (without editing test source code)
# "make mem": perform memcheck with all tests enabled
# "make unit": build standalone (unit) test
# "make debug": build standalone test with debugging code
#
# Original 'makefile' targets can be used (make test, etc...)
.PHONY: default all mem unit debug std
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
debug: clean std
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

52
c/isogram/README.md Normal file
View File

@@ -0,0 +1,52 @@
# Isogram
Determine if a word or phrase is an isogram.
An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times.
Examples of isograms:
- lumberjacks
- background
- downstream
- six-year-old
The word *isograms*, however, is not an isogram, because the s repeats.
## Getting Started
Make sure you have read the "Guides" section of the
[C track][c-track] on the Exercism site. 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][3-tdd-rules].
The included makefile can be used to create and run the tests using the `test`
task.
make test
Create just the functions you need 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, move onto the next test.
As you progress through the tests, take the time to refactor your
implementation for readability and expressiveness and then go on to the next
test.
Try to use standard C99 facilities in preference to writing your own
low-level algorithms or facilities by hand.
## Source
Wikipedia [https://en.wikipedia.org/wiki/Isogram](https://en.wikipedia.org/wiki/Isogram)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

37
c/isogram/makefile Normal file
View File

@@ -0,0 +1,37 @@
### If you wish to use extra libraries (math.h for instance),
### add their flags here (-lm in our case) in the "LIBS" variable.
LIBS = -lm
###
CFLAGS = -std=c99
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror
CFLAGS += -Wmissing-declarations
CFLAGS += -DUNITY_SUPPORT_64
ASANFLAGS = -fsanitize=address
ASANFLAGS += -fno-common
ASANFLAGS += -fno-omit-frame-pointer
.PHONY: test
test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
.PHONY: clean
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

34
c/isogram/src/isogram.c Normal file
View File

@@ -0,0 +1,34 @@
#include "isogram.h"
#include <ctype.h>
#define POS(c) (tolower(c)-'a')
/* This does not work outside English world */
bool is_isogram(const char phrase[])
{
//int map['z'-'a'+1]={0};
int map[1000]={0};
const char *p=phrase;
if (!p)
return false;
for (; *p; ++p) {
if (*p==' ' || *p=='-')
continue;
if (!isalpha((unsigned char)*p) || (++map[POS((unsigned char)*p)])>1)
return false;
}
return true;
}
#ifdef UNIT_TEST
#include <stdio.h>
int main(int ac, char **av)
{
int arg=1;
for (; arg<ac; ++arg) {
printf("isogram[%s]=%d\n", av[arg], is_isogram(av[arg]));
}
}
#endif

13
c/isogram/src/isogram.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef ISOGRAM_H
#define ISOGRAM_H
#include <stdbool.h>
bool is_isogram(const char phrase[]);
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More