meetup (C)
This commit is contained in:
51
c/meetup/GNUmakefile
Normal file
51
c/meetup/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
|
65
c/meetup/README.md
Normal file
65
c/meetup/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Meetup
|
||||
|
||||
Calculate the date of meetups.
|
||||
|
||||
Typically meetups happen on the same day of the week. In this exercise, you
|
||||
will take a description of a meetup date, and return the actual meetup date.
|
||||
|
||||
Examples of general descriptions are:
|
||||
|
||||
- The first Monday of January 2017
|
||||
- The third Tuesday of January 2017
|
||||
- The wednesteenth of January 2017
|
||||
- The last Thursday of January 2017
|
||||
|
||||
The descriptors you are expected to parse are:
|
||||
first, second, third, fourth, fifth, last, monteenth, tuesteenth, wednesteenth,
|
||||
thursteenth, friteenth, saturteenth, sunteenth
|
||||
|
||||
Note that "monteenth", "tuesteenth", etc are all made up words. There was a
|
||||
meetup whose members realized that there are exactly 7 numbered days in a month
|
||||
that end in '-teenth'. Therefore, one is guaranteed that each day of the week
|
||||
(Monday, Tuesday, ...) will have exactly one date that is named with '-teenth'
|
||||
in every month.
|
||||
|
||||
Given examples of a meetup dates, each containing a month, day, year, and
|
||||
descriptor calculate the date of the actual meetup. For example, if given
|
||||
"The first Monday of January 2017", the correct meetup date is 2017/1/2.
|
||||
|
||||
## 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
|
||||
|
||||
Jeremy Hinegardner mentioned a Boulder meetup that happens on the Wednesteenth of every month [https://twitter.com/copiousfreetime](https://twitter.com/copiousfreetime)
|
||||
|
||||
## 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/meetup/makefile
Normal file
37
c/meetup/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)
|
106
c/meetup/src/meetup.c
Normal file
106
c/meetup/src/meetup.c
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "meetup.h"
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* The explanation tells about 'fifth', not included in tests.
|
||||
* I will manage this, returning "-1" if it does not exist.
|
||||
*/
|
||||
|
||||
/* convert the 2/3 first chars of string to big endian integer */
|
||||
#define S2BE(a, b) ((a<<8)+b)
|
||||
#define S3BE(a, b, c) ((a<<16)+(b<<8)+c)
|
||||
|
||||
#define TEENTH 42
|
||||
#define LAST 21
|
||||
|
||||
static int str2day(const char *d)
|
||||
{
|
||||
switch (S2BE(*d, *(d+1))) {
|
||||
case S2BE('M', 'o'): return 1;
|
||||
case S2BE('T', 'u'): return 2;
|
||||
case S2BE('W', 'e'): return 3;
|
||||
case S2BE('T', 'h'): return 4;
|
||||
case S2BE('F', 'r'): return 5;
|
||||
case S2BE('S', 'a'): return 6;
|
||||
case S2BE('S', 'u'): return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int str2nth(const char *d)
|
||||
{
|
||||
switch (S3BE(*d, *(d+1), *(d+2))) {
|
||||
case S3BE('f', 'i', 'r'): return 0;
|
||||
case S3BE('s', 'e', 'c'): return 1;
|
||||
case S3BE('t', 'h', 'i'): return 2;
|
||||
case S3BE('f', 'o', 'u'): return 3;
|
||||
case S3BE('f', 'i', 'f'): return 4;
|
||||
case S3BE('l', 'a', 's'): return LAST;
|
||||
case S3BE('t', 'e', 'e'): return TEENTH;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int m_1st(unsigned y, unsigned m)
|
||||
{
|
||||
struct tm time = {
|
||||
.tm_year=y-1900,
|
||||
.tm_mon=m-1,
|
||||
.tm_mday=1
|
||||
};
|
||||
mktime (&time);
|
||||
return time.tm_wday;
|
||||
}
|
||||
|
||||
static int m_ndays(unsigned y, unsigned m)
|
||||
{
|
||||
static int days[]={31, 42, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
return m!=2 ? days[m-1]:
|
||||
(!(y % 4) && (y % 100 || !(y % 400)))? 29: 28;
|
||||
|
||||
}
|
||||
|
||||
int meetup_day_of_month(unsigned int yy, unsigned int mm, const char *sweek,
|
||||
const char *sday)
|
||||
{
|
||||
|
||||
int nth, ndays, wanted, res=-1;
|
||||
|
||||
ndays=m_ndays(yy, mm);
|
||||
if ((nth=str2nth(sweek))<0 || (wanted=str2day(sday))<0)
|
||||
return -1;
|
||||
if ((res=wanted-m_1st(yy, mm)+1) <= 0)
|
||||
res+=7;
|
||||
|
||||
if (nth<5) {
|
||||
if ((res+=7*nth)>ndays)
|
||||
res=-1;
|
||||
} else if (nth==TEENTH) {
|
||||
if ((res+=7)<13)
|
||||
res+=7;
|
||||
} else { /* last */
|
||||
if ((res+=7*4)>ndays)
|
||||
res-=7;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
unsigned y, m;
|
||||
|
||||
for (; arg<ac-3; arg+=4) {
|
||||
y=atoi(av[arg]);
|
||||
m=atoi(av[arg+1]);
|
||||
printf("meetup(%d, %d, %s, %s)=%d\n",
|
||||
y, m, av[arg+2], av[arg+3],
|
||||
meetup_day_of_month(y, m, av[arg+2], av[arg+3]));
|
||||
}
|
||||
}
|
||||
#endif
|
19
c/meetup/src/meetup.h
Normal file
19
c/meetup/src/meetup.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef MEETUP_H
|
||||
#define MEETUP_H
|
||||
|
||||
int meetup_day_of_month(unsigned int year, unsigned int month, const char *week,
|
||||
const char *day_of_week);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user