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

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

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,72 @@
# 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 has a position and a numeric value.
The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single 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 color names as input and output a two digit number, even if the input is more than two colors!
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
From the example above:
brown-green should return 15
brown-green-violet should return 15 too, ignoring the third color.
## 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
Maud de Vries, Erik Schierboom [https://github.com/exercism/problem-specifications/issues/1464](https://github.com/exercism/problem-specifications/issues/1464)
## 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,26 @@
#include "resistor_color_duo.h"
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
#endif
resistor_band_t color_code(resistor_band_t *colors)
{
resistor_band_t c1=*colors, c2=*(colors+1);
return c1>=BLACK && c1<=WHITE && c2>=BLACK && c2<=WHITE? c1*10+c2: ERROR;
}
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
resistor_band_t i[2];
for (; arg<ac-1; ++arg, ++arg) {
*i=atoi(av[arg]);
*(i+1)=atoi(av[arg+1]);
printf("color(%d, %d)=%d\n", i[0], i[1], color_code(i));
}
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RESISTOR_COLOR_DUO_H
#define RESISTOR_COLOR_DUO_H
typedef enum {
BLACK=0,
BROWN,
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
VIOLET,
GREY,
WHITE,
ERROR=-1,
} resistor_band_t;
extern resistor_band_t color_code(resistor_band_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,83 @@
# 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"
## 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
Maud de Vries, Erik Schierboom [https://github.com/exercism/problem-specifications/issues/1549](https://github.com/exercism/problem-specifications/issues/1549)
## 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,62 @@
#include "resistor_color_trio.h"
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
#endif
static const unsigned p10[] = {
1e0, 1e1, 1e2, 1e3, 1e4,
1e5, 1e6, 1e7, 1e8, 1e9,
};
static const unsigned unit[] = {
p10[9], p10[6], p10[3], p10[0]
};
#define S(a) ((int)(sizeof(a)/sizeof(*a)))
#define RB_OK(b) ((b)>=BLACK && (b)<=WHITE)
static resistor_value_t ui2val(unsigned value)
{
resistor_value_t res={0, OHMS};
int i;
for (i=0; i<S(unit); ++i) {
if (!(value%unit[i])) {
res.value=value/unit[i];
res.unit=i;
break;
}
}
return res;
}
resistor_value_t color_code(resistor_band_t *colors)
{
resistor_band_t c1=*colors, c2=*(colors+1), c3=*(colors+2);
resistor_value_t res={RB_ERR, UN_ERR};
if (RB_OK(c1) && RB_OK(c2) && RB_OK(c3))
res=ui2val((c1*10+c2) * p10[c3]);
return res;
}
/* See GNUmakefile below for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
resistor_band_t i[3];
resistor_value_t res;
for (; arg<ac-2; arg+=3) {
*i=atoi(av[arg]);
*(i+1)=atoi(av[arg+1]);
*(i+2)=atoi(av[arg+2]);
res=color_code(i);
printf("color(%d, %d, %d)=%d, %d\n", i[0], i[1], i[2], res.value, res.unit);
}
}
#endif

View File

@@ -0,0 +1,45 @@
#ifndef RESISTOR_COLOR_TRIO_H
#define RESISTOR_COLOR_TRIO_H
typedef enum {
BLACK=0,
BROWN,
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
VIOLET,
GREY,
WHITE,
RB_ERR=-1,
} resistor_band_t;
/* max=white-white-white =99 000 000 000=99 Giga
* warning: overflow before that (untested) !
*/
typedef enum {
GIGAOHMS=0,
MEGAOHMS,
KILOOHMS,
OHMS,
UN_ERR=-1
} unit_t;
typedef struct {
resistor_band_t value;
unit_t unit;
} resistor_value_t;
extern resistor_value_t color_code(resistor_band_t *);
/* 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

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

View File

@@ -0,0 +1,73 @@
# Resistor Color
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 has a position and a numeric value.
The first 2 bands of a resistor have a simple encoding scheme: each color maps to a single number.
In this exercise you are going to create a helpful program so that you don't have to remember the values of the bands.
These 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
The goal of this exercise is to create a way:
- to look up the numerical value associated with a particular color band
- to list the different band colors
Mnemonics map the colors to the numbers, that, when stored as an array, happen to map to their index in the array: Better Be Right Or Your Great Big Values Go Wrong.
More information on the color encoding of resistors can be found in the [Electronic color code Wikipedia article](https://en.wikipedia.org/wiki/Electronic_color_code)
## 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
Maud de Vries, Erik Schierboom [https://github.com/exercism/problem-specifications/issues/1458](https://github.com/exercism/problem-specifications/issues/1458)
## 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

38
c/resistor-color/makefile Normal file
View File

@@ -0,0 +1,38 @@
### 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 toto $(CFLAGS)
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)

View File

@@ -0,0 +1,44 @@
#include "resistor_color.h"
/* V1: initial version
* V2: add error code in enum
*/
static resistor_band_t mapping[]={
BLACK,
BROWN,
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
VIOLET,
GREY,
WHITE,
ERROR
};
resistor_band_t color_code(resistor_band_t color)
{
return color>=BLACK && color<=WHITE? color: ERROR;
}
resistor_band_t *colors()
{
return mapping;
}
#ifdef UNIT_TEST
#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av)
{
int arg=1, n;
for (; arg<ac; ++arg) {
n=atoi(av[arg]);
printf("color(%d)=%d\n", n, color_code(n));
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef RESISTOR_COLOR_H
#define RESISTOR_COLOR_H
typedef enum {
BLACK=0,
BROWN,
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
VIOLET,
GREY,
WHITE,
ERROR=-1,
} resistor_band_t;
extern resistor_band_t color_code(resistor_band_t);
extern resistor_band_t *colors();
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

41
c/square-root/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

49
c/square-root/README.md Normal file
View File

@@ -0,0 +1,49 @@
# Square Root
Given a natural radicand, return its square root.
Check out the Wikipedia pages on [square root](https://en.wikipedia.org/wiki/Square_root) and [methods of computing square roots](https://en.wikipedia.org/wiki/Methods_of_computing_square_roots).
Note that the term "radicand" refers to the number for which the root is to be determined. That is, it is the number under the root symbol.
Recall also that natural numbers are positive real whole numbers (i.e. 1, 2, 3 and up).
When implementing this in a language with a built-in square root function, implement your own function.
## 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
wolf99 [https://github.com/exercism/problem-specifications/pull/1582](https://github.com/exercism/problem-specifications/pull/1582)
## 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/square-root/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,44 @@
#include "square_root.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
/* Newton's method:
* https://en.wikipedia.org/wiki/Newton%27s_method#Square_root
* return the largest integer equal or less than i square root.
*/
unsigned square_root(unsigned i)
{
unsigned sq, sq2;
if (i<=1) /* 0 and 1 */
return i;
sq = i/2; /* we take i/2 as initial seed */
sq2 = ((i/sq) + sq) / 2; /* first iteration */
while (sq2 != sq) {
sq = sq2;
sq2 = ((i/sq) + sq) /2; /* next iteration */
}
return sq;
}
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
unsigned i;
for (; arg<ac; ++arg) {
i=atol(av[arg]);
printf("sqrt(%u)=%u\n", i, square_root(i));
}
}
#endif

View File

@@ -0,0 +1,16 @@
#ifndef SQUARE_ROOT_H
#define SQUARE_ROOT_H
#include <stdint.h>
extern unsigned square_root(unsigned);
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif

51
c/templates/GNUmakefile Normal file
View File

@@ -0,0 +1,51 @@
# 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 debugall": build with all predefined tests and debug 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 debugtest
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
debugall: CFLAGS+=-DDEBUG
debugall: all
debugtest: CFLAGS+=-DDEBUG
debugtest: test
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
debug: clean std
debugtest: CFLAGS+=-DDEBUG
debugtest: test
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

23
c/templates/ex.c Normal file
View File

@@ -0,0 +1,23 @@
/* 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
#ifdef UNIT_TEST
int main(int ac, char **av)
{
int arg=1;
resistor_band_t i[2];
for (; arg<ac-1; ++arg, ++arg) {
*i=atoi(av[arg]);
*(i+1)=atoi(av[arg+1]);
printf("color(%d, %d)=%d\n", i[0], i[1], color_code(i));
}
}
#endif

7
c/templates/ex.h Normal file
View File

@@ -0,0 +1,7 @@
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif

51
c/word-count/GNUmakefile Normal file
View File

@@ -0,0 +1,51 @@
# 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 debugall": build with all predefined tests and debug 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 debugtest
default: all
# default is to build with all predefined tests
BUILD := teststall
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
debugall: CFLAGS+=-DDEBUG
debugall: all
debugtest: CFLAGS+=-DDEBUG
debugtest: test
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unit: CFLAGS+=-DUNIT_TEST
unit: clean std
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
debug: clean std
debugtest: CFLAGS+=-DDEBUG
debugtest: test
std: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o test.out

71
c/word-count/README.md Normal file
View File

@@ -0,0 +1,71 @@
# Word Count
Given a phrase, count the occurrences of each _word_ in that phrase.
For the purposes of this exercise you can expect that a _word_ will always be one of:
1. A _number_ composed of one or more ASCII digits (ie "0" or "1234") OR
2. A _simple word_ composed of one or more ASCII letters (ie "a" or "they") OR
3. A _contraction_ of two _simple words_ joined by a single apostrophe (ie "it's" or "they're")
When counting words you can assume the following rules:
1. The count is _case insensitive_ (ie "You", "you", and "YOU" are 3 uses of the same word)
2. The count is _unordered_; the tests will ignore how words and counts are ordered
3. Other than the apostrophe in a _contraction_ all forms of _punctuation_ are ignored
4. The words can be separated by _any_ form of whitespace (ie "\t", "\n", " ")
For example, for the phrase `"That's the password: 'PASSWORD 123'!", cried the Special Agent.\nSo I fled.` the count would be:
```text
that's: 1
the: 2
password: 2
123: 1
cried: 1
special: 1
agent: 1
so: 1
i: 1
fled: 1
```
- Note that the tests for this exercise expect the output words to be proper C strings. That is, they should be NUL terminated. See https://en.wikipedia.org/wiki/C_string_handling
## 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 a classic toy problem, but we were reminded of it by seeing it in the Go Tour.
## 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/word-count/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)

124
c/word-count/src/hash.c Normal file
View File

@@ -0,0 +1,124 @@
#include <string.h>
#include <malloc.h>
#include "hash.h"
#define HASH_SIZE 50
//static hash_t *hash_table[HASH_SIZE];
static h_entry_t *pool_free, *alloc_entries;
static int n_entries;
void h_init(hash_t *hash)
{
memset(hash->entries, 0, sizeof(h_entry_t)*hash->size);
}
hash_t *h_create(int size)
{
hash_t *hash;
if ( !(hash=calloc(sizeof(hash_t) + size*(sizeof (h_entry_t *)), 1)) )
return NULL;
hash->size=size;
return hash;
}
void h_destroy(hash_t *h)
{
h_entry_t *tmp;
for (int i=0; i<h->size; ++i) {
while (h->entries[i]) {
tmp=h->entries[i]->next;
h_entry_free(h->entries[i]);
h->entries[i]=tmp;
}
}
free(h);
}
/* Daniel J. Bernstein's djb2 hash function */
unsigned long hash_djb2(const unsigned char *str, const int len)
{
unsigned long hash = 5381;
for (int i=0; i<len; ++i)
hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + str[i] */
return hash;
}
void h_entry_free(h_entry_t *e)
{
e->next=pool_free;
pool_free=e;
}
h_entry_t *h_entry_find(hash_t *h, const unsigned char *s, const int l)
{
unsigned long hash=hash_djb2(s, l);
h_entry_t *entry;
int found=0;
# ifdef DEBUG
printf("h_entry_find([%.*s]): hash=%#lx (%lu) - ", l, s, hash, hash%h->size);
# endif
hash%=h->size;
for (entry=h->entries[hash]; entry; entry=entry->next) {
if (l == entry->key_len && !memcmp(entry->data, s, l)) {
found=1;
break;
}
}
# ifdef DEBUG
printf("ret=%p\n", found? (void *)entry: (void *)-1);
# endif
return found? entry: NULL;
}
h_entry_t *h_entry_add(hash_t *h, const unsigned char *s, const int l, int *insert)
{
unsigned long hash;
h_entry_t *entry;
*insert=0;
if (!pool_free) {
register int i=n_entries;
n_entries+=ENTRY_ALLOC_SIZE;
# ifdef DEBUG
printf("get_hash: allocating %d new entries - total entries=%d\n",
ENTRY_ALLOC_SIZE, n_entries);
# endif
alloc_entries=reallocarray(alloc_entries, n_entries, sizeof(h_entry_t));
for (; i<n_entries; ++i) { /* create free entries list */
(alloc_entries+i)->next=pool_free;
pool_free=alloc_entries+i;
}
}
if ((entry=h_entry_find(h, s, l)))
return entry;
*insert=1;
hash=hash_djb2(s, l)%h->size;
/* get a free entry from pool */
entry=pool_free;
pool_free=pool_free->next;
/* set entry in hash */
entry->next=h->entries[hash];
h->entries[hash]=entry;
entry->data=(unsigned char *)s;
entry->key_len=l;
//assert(entry!=freenodes);
# ifdef DEBUG
printf("h_entry_add: %p\n", (void *)entry);
# endif
return entry;
}

52
c/word-count/src/hash.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef _HASH_H
#define _HASH_H
#include <stdbool.h>
typedef struct h_entry {
void *data;
int key_len;
struct h_entry *prev, *next;
} h_entry_t;
typedef struct {
int size;
h_entry_t *entries[];
} hash_t;
/* a few predefined hash sizes */
typedef struct {
int size;
h_entry_t *entries[16];
} hash_16_t;
typedef struct {
int size;
h_entry_t *entries[128];
} hash_128_t;
typedef struct {
int size;
h_entry_t *entries[1024];
} hash_1024_t;
#define ENTRY_ALLOC_SIZE 20
/* hash map functions */
hash_t *h_create(int size);
void h_init(hash_t *);
void h_destroy(hash_t *);
/* static free_nodes */
void set_pool_free_static(h_entry_t *p);
/* hash entries functions */
h_entry_t *h_entry_add(hash_t *, const unsigned char *, const int, int *);
h_entry_t *h_entry_find(hash_t *, const unsigned char *, const int);
void h_entry_free(h_entry_t *);
/* hash function */
unsigned long hash_djb2(const unsigned char *str, const int len);
#endif

View File

@@ -0,0 +1,162 @@
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "word_count.h"
#include "hash.h"
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#if defined UNIT_TEST || defined DEBUG
#include <stdlib.h>
#endif
/* Some cases are not well explained. So I will consider words mixing
* alphabetic characters and digits as invalid, as well as multiple "'"
* inside an alphabetic word:
* The following will return INVALID_WORD:
* P2P
* 0xFF
* A'2
* The following will return 2 numbers/words:
* 1'2
* A''B
*/
/* get next word in string
*/
static word_t next_word(const char **p)
{
word_t res={NULL, 0};
const char *q, *p1=*p;
static char tmp[1024];
int pos=0;
# ifdef DEBUG
printf("next_word(%s)\n", *p);
# endif
for (; *p1 && !isalpha(*p1) && !isdigit(*p1); ++p1)
;
if (*p1) {
q=p1;
/* alphabetic word */
if (isalpha(*p1)) {
for (; *q &&(isalpha(*q) || *q=='\''); q++) {
if (*q=='\'' && *(q-1)=='\'') { /* two consecutive apostrophes */
res.len=INVALID_WORD;
goto end;
}
tmp[pos++]=tolower(*q);
}
if (*(q-1) == '\'')
q--;
else if (isdigit(*q)) { /* digit in word */
res.len=INVALID_WORD;
goto end;
}
} else {
for (; *q &&(isdigit(*q)); q++)
tmp[pos++]=tolower(*q);
if (isalpha(*q)) { /* alphabetic char in number */
res.len=INVALID_WORD;
goto end;
}
}
res.word=tmp;
res.len=q-p1;
*p=q;
}
end:
# ifdef DEBUG
printf("next_word: [%s], %d\n", res.word? res.word: "NULL", res.len);
# endif
return res;
}
static int insert_word(word_count_word_t *words, word_t w, int pos)
{
#ifdef DEBUG
printf("insert words(len=%d word=[%.*s])\n", w.len, w.len, w.word);
#endif
memcpy(words[pos].text, w.word, w.len);
words[pos].text[w.len]=0;
words[pos].count=0;
return 1;
}
int count_words(const char *sentence, word_count_word_t *words)
{
word_t w;
int current=0, new, index;
hash_t *hash;
h_entry_t *e;
# ifdef DEBUG
const char *s=sentence;
# endif
hash=h_create(16);
# ifdef DEBUG
printf("count_words([%s], %p)\n", sentence, (void *)words);
# endif
for (; *sentence;) {
w=next_word(&sentence);
if (!w.word)
break;
if (w.len > MAX_WORD_LENGTH)
return EXCESSIVE_LENGTH_WORD;
if (!(e=h_entry_find(hash, (const unsigned char *)w.word, w.len))) {
if (current==MAX_WORDS)
return EXCESSIVE_NUMBER_OF_WORDS;
insert_word(words, w, current);
e=h_entry_add(hash, (void *)&words[current], w.len, &new);
current++;
}
index=(word_count_word_t *)e->data-&words[0];
words[index].count++;
//sentence=w.word+w.len;
//sentence+=w.len;
# ifdef DEBUG
printf("count_words: index=%d\n", index);
printf("offset=%d\n", (int)(sentence-s));
# endif
}
h_destroy(hash);
return current;
}
#ifdef UNIT_TEST
static word_count_word_t wtable[MAX_WORDS];
static void reset_wtable()
{
memset(wtable, 0, sizeof(wtable));
}
static void print_wtable(int n)
{
for (int i=0; i<n; ++i) {
printf ("%2d: %2d x \"%s\"\n", i, wtable[i].count, wtable[i].text);
//djb2_hash(wtable[i].text));
}
}
int main(int ac, char **av)
{
int arg=1;
int res;
//hash=h_create(16);
for (; arg<ac; ++arg) {
reset_wtable();
res=count_words(av[arg], wtable);
printf ("res=%d\n", res);
print_wtable(res);
}
//printf("h_destroy 1\n");
//h_destroy(hash);
//printf("h_destroy 1\n");
}
#endif

View File

@@ -0,0 +1,41 @@
#ifndef WORD_COUNT_H
#define WORD_COUNT_H
#define MAX_WORDS 20 // at most MAX_WORDS can be found in the test input string
#define MAX_WORD_LENGTH 50 // no individual word can exceed this length
// results structure
typedef struct word_count_word {
char text[MAX_WORD_LENGTH + 1]; // allow for the string to be null-terminated
int count;
} word_count_word_t;
#define EXCESSIVE_LENGTH_WORD -1
#define EXCESSIVE_NUMBER_OF_WORDS -2
#define INVALID_WORD -3
// count_words - routine to classify the unique words and their frequency in a sentence
// inputs:
// sentence = a null-terminated string containing that is analyzed
//
// outputs:
// words = allocated structure to record the words found and their frequency
// uniqueWords - number of words in the words structure
// returns a negative number if an error.
// words will contain the results up to that point.
int count_words(const char *sentence, word_count_word_t * words);
typedef struct {
char *word;
int len;
} word_t;
/* See GNUmakefile in following link for explanation
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
*/
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
#endif
#endif