initial commit
This commit is contained in:
41
c/acronym/GNUmakefile
Normal file
41
c/acronym/GNUmakefile
Normal 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
46
c/acronym/README.md
Normal 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
37
c/acronym/makefile
Normal 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
69
c/acronym/src/acronym.c
Normal 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
20
c/acronym/src/acronym.h
Normal 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
|
21
c/armstrong-numbers/GNUmakefile
Normal file
21
c/armstrong-numbers/GNUmakefile
Normal 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
|
50
c/armstrong-numbers/README.md
Normal file
50
c/armstrong-numbers/README.md
Normal 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
|
35
c/armstrong-numbers/makefile
Normal file
35
c/armstrong-numbers/makefile
Normal 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)
|
40
c/armstrong-numbers/src/armstrong_numbers.c
Normal file
40
c/armstrong-numbers/src/armstrong_numbers.c
Normal 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
|
8
c/armstrong-numbers/src/armstrong_numbers.h
Normal file
8
c/armstrong-numbers/src/armstrong_numbers.h
Normal 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
34
c/darts/GNUmakefile
Normal 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
55
c/darts/README.md
Normal 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
37
c/darts/makefile
Normal 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
49
c/darts/src/darts.c
Normal 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
28
c/darts/src/darts.h
Normal 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
|
41
c/difference-of-squares/GNUmakefile
Normal file
41
c/difference-of-squares/GNUmakefile
Normal 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
|
55
c/difference-of-squares/README.md
Normal file
55
c/difference-of-squares/README.md
Normal 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
|
37
c/difference-of-squares/makefile
Normal file
37
c/difference-of-squares/makefile
Normal 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)
|
52
c/difference-of-squares/src/difference_of_squares.c
Normal file
52
c/difference-of-squares/src/difference_of_squares.c
Normal 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
|
16
c/difference-of-squares/src/difference_of_squares.h
Normal file
16
c/difference-of-squares/src/difference_of_squares.h
Normal 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
41
c/grains/GNUmakefile
Normal 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
65
c/grains/README.md
Normal 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
37
c/grains/makefile
Normal 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
45
c/grains/src/grains.c
Normal 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
17
c/grains/src/grains.h
Normal 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
41
c/hamming/GNUmakefile
Normal 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
62
c/hamming/README.md
Normal 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
37
c/hamming/makefile
Normal 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
41
c/hamming/src/hamming.c
Normal 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
15
c/hamming/src/hamming.h
Normal 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
53
c/hello-world/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Hello World
|
||||
|
||||
The classical introductory exercise. Just say "Hello, World!".
|
||||
|
||||
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
|
||||
the traditional first program for beginning programming in a new language
|
||||
or environment.
|
||||
|
||||
The objectives are simple:
|
||||
|
||||
- Write a function that returns the string "Hello, World!".
|
||||
- Run the test suite and make sure that it succeeds.
|
||||
- Submit your solution and check it at the website.
|
||||
|
||||
If everything goes well, you will be ready to fetch your first real exercise.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "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
37
c/hello-world/makefile
Normal 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)
|
7
c/hello-world/src/hello_world.c
Normal file
7
c/hello-world/src/hello_world.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stddef.h>
|
||||
#include "hello_world.h"
|
||||
|
||||
const char *hello(void)
|
||||
{
|
||||
return "Hello, World!";
|
||||
}
|
14
c/hello-world/src/hello_world.h
Normal file
14
c/hello-world/src/hello_world.h
Normal 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
39
c/isogram/GNUmakefile
Normal 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
52
c/isogram/README.md
Normal 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
37
c/isogram/makefile
Normal 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
34
c/isogram/src/isogram.c
Normal 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
13
c/isogram/src/isogram.h
Normal 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
|
41
c/resistor-color-duo/GNUmakefile
Normal file
41
c/resistor-color-duo/GNUmakefile
Normal 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
|
72
c/resistor-color-duo/README.md
Normal file
72
c/resistor-color-duo/README.md
Normal 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
|
37
c/resistor-color-duo/makefile
Normal file
37
c/resistor-color-duo/makefile
Normal 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)
|
26
c/resistor-color-duo/src/resistor_color_duo.c
Normal file
26
c/resistor-color-duo/src/resistor_color_duo.c
Normal 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
|
25
c/resistor-color-duo/src/resistor_color_duo.h
Normal file
25
c/resistor-color-duo/src/resistor_color_duo.h
Normal 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
|
41
c/resistor-color-trio/GNUmakefile
Normal file
41
c/resistor-color-trio/GNUmakefile
Normal 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
|
83
c/resistor-color-trio/README.md
Normal file
83
c/resistor-color-trio/README.md
Normal 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
|
37
c/resistor-color-trio/makefile
Normal file
37
c/resistor-color-trio/makefile
Normal 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)
|
62
c/resistor-color-trio/src/resistor_color_trio.c
Normal file
62
c/resistor-color-trio/src/resistor_color_trio.c
Normal 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
|
45
c/resistor-color-trio/src/resistor_color_trio.h
Normal file
45
c/resistor-color-trio/src/resistor_color_trio.h
Normal 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
|
34
c/resistor-color/GNUmakefile
Normal file
34
c/resistor-color/GNUmakefile
Normal 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
|
73
c/resistor-color/README.md
Normal file
73
c/resistor-color/README.md
Normal 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
38
c/resistor-color/makefile
Normal 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)
|
44
c/resistor-color/src/resistor_color.c
Normal file
44
c/resistor-color/src/resistor_color.c
Normal 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
|
26
c/resistor-color/src/resistor_color.h
Normal file
26
c/resistor-color/src/resistor_color.h
Normal 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
41
c/square-root/GNUmakefile
Normal 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
49
c/square-root/README.md
Normal 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
37
c/square-root/makefile
Normal 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)
|
44
c/square-root/src/square_root.c
Normal file
44
c/square-root/src/square_root.c
Normal 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
|
16
c/square-root/src/square_root.h
Normal file
16
c/square-root/src/square_root.h
Normal 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
51
c/templates/GNUmakefile
Normal 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
23
c/templates/ex.c
Normal 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
7
c/templates/ex.h
Normal 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
51
c/word-count/GNUmakefile
Normal 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
71
c/word-count/README.md
Normal 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
37
c/word-count/makefile
Normal 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
124
c/word-count/src/hash.c
Normal 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
52
c/word-count/src/hash.h
Normal 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
|
162
c/word-count/src/word_count.c
Normal file
162
c/word-count/src/word_count.c
Normal 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
|
41
c/word-count/src/word_count.h
Normal file
41
c/word-count/src/word_count.h
Normal 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
|
Reference in New Issue
Block a user