From b3b4b52882d669d0eca926590292327173f56ff3 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Wed, 18 Dec 2019 10:37:59 +0100 Subject: [PATCH] 2019-12-18 in class --- checker/checker.cc | 37 +++++++ chess_paths/chess_paths.c | 2 +- roadmap/Makefile | 142 ++++++++++++++++++++++++ roadmap/roadmap.cpp | 44 ++++++++ roadmap/roadmap.h | 59 ++++++++++ roadmap/tests/basic_testing.h | 112 +++++++++++++++++++ roadmap/tests/test0.cpp | 18 ++++ roadmap/tests/test1.cpp | 40 +++++++ roadmap/tests/test2.cpp | 197 ++++++++++++++++++++++++++++++++++ 9 files changed, 650 insertions(+), 1 deletion(-) create mode 100644 checker/checker.cc create mode 100644 roadmap/Makefile create mode 100644 roadmap/roadmap.cpp create mode 100644 roadmap/roadmap.h create mode 100644 roadmap/tests/basic_testing.h create mode 100644 roadmap/tests/test0.cpp create mode 100644 roadmap/tests/test1.cpp create mode 100644 roadmap/tests/test2.cpp diff --git a/checker/checker.cc b/checker/checker.cc new file mode 100644 index 0000000..64948dd --- /dev/null +++ b/checker/checker.cc @@ -0,0 +1,37 @@ +// vim: set ts=2 sw=2 et tw=80: + +#include +#include + +class checker { + struct pos { + unsigned x; + unsigned y; + pos(unsigned x, unsigned y) : x(x), y(y) {}; + }; + + unsigned c; + unsigned r; + std::map map; + + public: + checker(unsigned c, unsigned r) : c(c), r(r), map() {} + + void visit(unsigned int x, unsigned int y); + bool visited(unsigned x, unsigned y); +}; + +void checker::visit(unsigned x, unsigned y) { + this->map[pos(] = true; +} + +bool checker::visited(unsigned x, unsigned y) { + return this->map[x * this->c + y]; +} + +int main() { + checker a(10, 10); + a.visit(1, 1); + assert(a.visited(1,1)); + assert(!a.visited(1,0)); +} diff --git a/chess_paths/chess_paths.c b/chess_paths/chess_paths.c index 31957e3..c5ff568 100644 --- a/chess_paths/chess_paths.c +++ b/chess_paths/chess_paths.c @@ -56,7 +56,7 @@ unsigned long table_total_size(const struct chessboard*); unsigned long table_hash(const struct chessboard*, unsigned, unsigned); inline unsigned long table_total_size(const struct chessboard* c) { - return 100; + return 1000; } inline unsigned long table_hash(const struct chessboard* c, unsigned col, diff --git a/roadmap/Makefile b/roadmap/Makefile new file mode 100644 index 0000000..75d359f --- /dev/null +++ b/roadmap/Makefile @@ -0,0 +1,142 @@ +OBJECTS = roadmap.o +CFLAGS=-Wall -g +CXXFLAGS=-Wall -g +SHELL=/bin/bash + +TIMEOUT=8 + +TESTS_DIR=tests + +TESTS_SH:=$(wildcard $(TESTS_DIR)/*.sh) +TESTS_SH_NAMES:=$(patsubst $(TESTS_DIR)/%.sh, %, $(TESTS_SH)) + +TESTS_IO:=$(wildcard $(TESTS_DIR)/*.in) +TESTS_IO_NAMES:=$(patsubst $(TESTS_DIR)/%.in, %, $(TESTS_IO)) + +TESTS_C:=$(wildcard $(TESTS_DIR)/*.c) +TESTS_CXX:=$(wildcard $(TESTS_DIR)/*.cpp) +TESTS_BIN:=$(patsubst $(TESTS_DIR)/%.c, $(TESTS_DIR)/%, $(TESTS_C)) \ + $(patsubst $(TESTS_DIR)/%.cpp, $(TESTS_DIR)/%, $(TESTS_CXX)) +TESTS_BIN_NAMES:=$(patsubst $(TESTS_DIR)/%.c, %, $(TESTS_C)) $(patsubst $(TESTS_DIR)/%.cpp, %, $(TESTS_CXX)) + +.PHONY: all +all: compile check + +.PHONY: compile-program + +compile: $(PROGRAMS) $(OBJECTS) + +.PHONY: check +check: check-bin check-io-sh + +.PHONY: check-io-sh +check-io-sh: compile $(TESTS_IO) $(TESTS_SH) + @exec 2> /dev/null; \ + for p in $(foreach prog,$(PROGRAMS),$(dir $(prog))$(prog)); do \ + echo "Testing $${p}:" ; \ + for t in $(TESTS_IO_NAMES); do \ + echo -n "Running test $$t..." ; \ + "$$p" < "$(TESTS_DIR)/$$t.in" > "$$t.out" 2>&1 & \ + prog_pid=$$!; \ + ( sleep $(TIMEOUT); kill $$prog_pid > /dev/null 2>&1 ) & \ + killer_pid=$$!; \ + wait $$prog_pid; \ + res=$$?; \ + if test $$res -gt 128; \ + then \ + case `kill -l $$(($$res - 128))` in \ + ABRT ) echo "FAIL"; ;; \ + TERM ) echo "TIME OUT"; ;; \ + * ) echo "UNKNOWN ERROR"; ;; \ + esac ; \ + echo "see $(TESTS_DIR)/$$t.in" ;\ + echo "you may run $$p < $(TESTS_DIR)/$$t.in" ;\ + echo "to see what went wrong";\ + rm -f "$$t.out" ;\ + else \ + kill $$killer_pid > /dev/null 2>&1 ;\ + wait $$killer_pid; \ + if cmp -s "$$t.out" "$(TESTS_DIR)/$$t.expected"; \ + then \ + echo "PASS" ;\ + rm -f "$$t.out" ;\ + else \ + echo "FAIL" ;\ + echo "see $(TESTS_DIR)/$$t.sh" ;\ + echo "run diff $$t.out $(TESTS_DIR)/$$t.expected";\ + echo "to see the difference between the actual and expected output";\ + fi; \ + fi; \ + done; \ + for t in $(TESTS_SH_NAMES); do \ + echo -n "Running test $$t..." ; \ + $(SHELL) "$(TESTS_DIR)/$$t.sh" "$$p" > "$$t.out" 2>&1 & \ + prog_pid=$$!; \ + ( sleep $(TIMEOUT); kill $$prog_pid > /dev/null 2>&1 ) & \ + killer_pid=$$!; \ + wait $$prog_pid; \ + res=$$?; \ + if test $$res -gt 128; \ + then \ + case `kill -l $$(($$res - 128))` in \ + ABRT ) echo "FAIL"; ;; \ + TERM ) echo "TIME OUT"; ;; \ + * ) echo "UNKNOWN ERROR"; ;; \ + esac ; \ + echo "see $(TESTS_DIR)/$$t.sh" ;\ + echo "you may run $(TESTS_DIR)/$$t.sh $$p" ;\ + echo "to see what went wrong";\ + rm -f "$$t.out" ;\ + else \ + kill $$killer_pid > /dev/null 2>&1 ;\ + wait $$killer_pid; \ + if cmp -s "$$t.out" "$(TESTS_DIR)/$$t.expected"; \ + then \ + echo "PASS" ;\ + rm -f "$$t.out" ;\ + else \ + echo "FAIL" ;\ + echo "see $(TESTS_DIR)/$$t.sh" ;\ + echo "run diff $$t.out $(TESTS_DIR)/$$t.expected";\ + echo "to see the difference between the actual and expected output";\ + fi; \ + fi; \ + done; \ + done + +$(TESTS_DIR)/%: $(TESTS_DIR)/%.c $(OBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) $(TESTS_DIR)/$*.c $(OBJECTS) -o $@ + +$(TESTS_DIR)/%: $(TESTS_DIR)/%.cpp $(OBJECTS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(TESTS_DIR)/$*.cpp $(OBJECTS) -o $@ + +.PHONY: check-bin +check-bin: $(TESTS_BIN) + @exec 2> /dev/null; \ + for t in $(TESTS_BIN_NAMES); do \ + echo -n "Running test $$t..." ; \ + "$(TESTS_DIR)/$$t" &\ + prog_pid=$$!; \ + ( sleep $(TIMEOUT); kill $$prog_pid > /dev/null 2>&1 ) & \ + killer_pid=$$!; \ + wait $$prog_pid; \ + res=$$?; \ + if test $$res -gt 128; \ + then \ + case `kill -l $$(($$res - 128))` in \ + ABRT ) echo "FAIL"; ;; \ + TERM ) echo "TIME OUT"; ;; \ + * ) echo "UNKNOWN ERROR"; ;; \ + esac ; \ + echo "you may run $(TESTS_DIR)/$$t to see what went wrong" ;\ + else \ + kill $$killer_pid > /dev/null 2>&1 ;\ + wait $$killer_pid; \ + echo "PASS" ;\ + fi; \ + done + + +.PHONY: clean +clean: + rm -f $(PROGRAMS) $(OBJECTS) tests/*.o $(TESTS_BIN) diff --git a/roadmap/roadmap.cpp b/roadmap/roadmap.cpp new file mode 100644 index 0000000..3996e8d --- /dev/null +++ b/roadmap/roadmap.cpp @@ -0,0 +1,44 @@ +#include "roadmap.h" +#include +#include + +using std::map; +using std::set; + +class ConcreteRoadMap : public AbstractRoadMap { +private: + int cities; + + map< string, set > adj; + + /* + * Adds in the map for key city1 a new set with city2 inside if there is no + * prior set, otherwise it appends city2 into the existing set + */ + void addPair(const string& city1, const string& city2) { + this->adj[city1].insert(city2); + } + +public: + ConcreteRoadMap() : adj(), cities(0) {}; + + void addRoad(const string& city1, const string& city2) override { + addPair(city1, city2); + addPair(city2, city1); + } + + void addRoad(const vector& cities) override { + for (size_t i = 0; i < cities.size() - 1; i++) { + addRoad(cities[i], cities[i + 1]); + } + } + + void clear() override { + this->adj.clear(); + } + + int neighborCountForCity(const string& city) const override { + auto i = this->adj.find(city); + return i->second.size(); + } +}; diff --git a/roadmap/roadmap.h b/roadmap/roadmap.h new file mode 100644 index 0000000..619c0cf --- /dev/null +++ b/roadmap/roadmap.h @@ -0,0 +1,59 @@ +#ifndef __ROADMAP_H__ +#define __ROADMAP_H__ + +#include +#include + +using std::vector; +using std::string; + +class AbstractRoadMap { + public: + /* Add a road that connects city1 with city2. All roads are bidirectional. + */ + virtual void addRoad(const string & city1, const string & city2) = 0; + + /* Add a road that goes through all the cities in the cities + * vector. In other words, add a road between each pair of + * adjacent cities in the vector. + */ + virtual void addRoad(const vector & cities) = 0; + + /* Clear the road map completely. + */ + virtual void clear() = 0; + + /* Return the number of neighboring cities for the given city, or + * -1 if the given city is not in the map. + */ + virtual int neighborCountForCity(const string & city) const = 0; + + /* Return true if and only if there is a path that starts from a + * city X and then leads back to X by taking each no more than + * once. + */ + virtual bool hasLoop() const = 0; + + /* Return true if there is a path from city1 to city2. + */ + virtual bool reachable(const string & city1, const string & city2) const = 0; + + /* Return the number of "islands" in the map. An island is a + * maximal group of cities that are reachable from each other. + * All cities in an island are reachable from each other, but they + * are not reachable from any another city from another island. + */ + virtual int countIslands() const = 0; + + /* Destructor + */ + virtual ~AbstractRoadMap() {}; +}; + +/* Return a new road map object that implements AbstractRoadMap. The + * new road map must be empty, meaning that it does not contain any + * road or city. +*/ +extern AbstractRoadMap * createRoadMap(); + +#endif // __ROADMAP_H__ diff --git a/roadmap/tests/basic_testing.h b/roadmap/tests/basic_testing.h new file mode 100644 index 0000000..223ff77 --- /dev/null +++ b/roadmap/tests/basic_testing.h @@ -0,0 +1,112 @@ +#ifndef BASIC_TESTING_H_INCLUDED +#define BASIC_TESTING_H_INCLUDED + +#include +#include +#include + +#define ck_assert_msg(expr, ...) \ + if (!(expr)) { \ + fprintf(stderr, "%s:%d: Assertion '"#expr"' failed\n" , __FILE__, __LINE__); \ + fprintf(stderr, ## __VA_ARGS__, NULL); \ + return 0; \ + } + +#define ck_assert_int(X, OP, Y) do { \ + intmax_t _ck_x = (X); \ + intmax_t _ck_y = (Y); \ + if (!(_ck_x OP _ck_y)) { \ + fprintf(stderr, "%s:%d: Assertion '%s' failed: %s == %jd, %s == %jd\n", \ + __FILE__, __LINE__, #X" "#OP" "#Y, #X, _ck_x, #Y, _ck_y); \ + return 0; \ + } \ +} while (0) + +#define ck_assert_uint(X, OP, Y) do { \ + uintmax_t _ck_x = (X); \ + uintmax_t _ck_y = (Y); \ + if (!(_ck_x OP _ck_y)) { \ + fprintf(stderr, "%s:%d: Assertion '%s' failed: %s == %ju, %s == %ju\n", \ + __FILE__, __LINE__, #X" "#OP" "#Y, #X, _ck_x, #Y, _ck_y); \ + return 0; \ + } \ +} while (0) + +#define assert_int_eq(X, Y) ck_assert_int(X,==,Y) +#define assert_uint_eq(X, Y) ck_assert_uint(X,==,Y) + +#define assert_true(X) do { \ + if (!(X)) { \ + fprintf(stderr, "%s:%d: Assertion failed: '"#X"' is false (should be true)\n", __FILE__, __LINE__); \ + return 0; \ + } \ +} while (0) + +#define assert_false(X) do { \ + if (X) { \ + fprintf(stderr, "%s:%d: Assertion failed: '"#X"' is true (should be false)\n", __FILE__, __LINE__); \ + return 0; \ + } \ +} while (0) + +typedef struct { + const char * name; + int (*test_function)(); + const char * file; + int line; +} test_descriptor; + +#define TEST(_Name) \ +static int _Name ## _fn (); \ +static const test_descriptor _Name ## _descr = { # _Name, _Name ## _fn, __FILE__, __LINE__}; \ +static const test_descriptor * _Name = & _Name ## _descr; \ +static int _Name ## _fn () + +#define TEST_PASSED do { return (1); } while(0) + +#define TEST_SUITE(_Name) \ +unsigned int _Name ## _failed; \ +unsigned int _Name ## _passed; \ +const test_descriptor * _Name ## _suite [] + +#define RUN_SUITE(_Name) \ + do { \ + _Name ## _failed = 0; \ + _Name ## _passed = 0; \ + for (int _i = 0; _i < sizeof( _Name ## _suite )/sizeof(test_descriptor *); ++_i) { \ + if (!(_Name ## _suite [_i]->test_function())) { \ + _Name ## _failed += 1; \ + fprintf(stderr, "Test suite "#_Name": test %s failed\n", _Name ## _suite [_i]->name); \ + } else { \ + _Name ## _passed += 1; \ + } \ + } \ +} while (0) + +#define TEST_SUITE_PASS(_Name) (_Name ## _failed == 0) + +#define PRINT_SUITE_RESULTS(_Name) \ + do { \ + printf("Test suite "#_Name": pass %u/%u ", _Name ## _passed, _Name ## _passed + _Name ## _failed); \ + } while(0) + +static unsigned int tests_run_fail = 0; +static unsigned int tests_run_pass = 0; + +#define RUN_TEST(_Name) \ + do { \ + if (!(_Name ->test_function())) { \ + tests_run_fail += 1; \ + fprintf(stderr, "Test %s failed\n", _Name ->name); \ + } else { \ + tests_run_pass += 1; \ + } \ + } while (0) + +#define PRINT_TEST_RESULTS do { \ + printf(" %u/%u ", tests_run_pass, tests_run_pass + tests_run_fail); \ + } while (0); + +#define ALL_TESTS_PASSED (tests_run_fail == 0) + +#endif /* BASIC_TESTING_H_INCLUDED */ diff --git a/roadmap/tests/test0.cpp b/roadmap/tests/test0.cpp new file mode 100644 index 0000000..762a67a --- /dev/null +++ b/roadmap/tests/test0.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +#include "basic_testing.h" + +#include "../roadmap.h" + +TEST(empty) { + std::unique_ptr m(createRoadMap()); + TEST_PASSED; +} + +int main() { + RUN_TEST(empty); + PRINT_TEST_RESULTS; + assert(ALL_TESTS_PASSED); +} diff --git a/roadmap/tests/test1.cpp b/roadmap/tests/test1.cpp new file mode 100644 index 0000000..55d2c09 --- /dev/null +++ b/roadmap/tests/test1.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "basic_testing.h" + +#include "../roadmap.h" + +TEST(example) { + std::unique_ptr m(createRoadMap()); + + // Add roads on one island: + m->addRoad("Sengkol", "Sakra"); + m->addRoad({"Mataram", "Mangsit", "Pamenang"}); + m->addRoad({"Mataram", "Sengkol", "Koeta"}); + + assert_int_eq(m->countIslands(), 1); + assert_true(m->reachable("Sengkol", "Mataram")); + assert_int_eq(m->neighborCountForCity("Mataram"), 2); + assert_int_eq(m->neighborCountForCity("Pamenang"), 1); + assert_false(m->hasLoop()); + + // Create a loop: + m->addRoad("Sakra", "Mataram"); + assert_true(m->hasLoop()); + + // Add roads on another island: + m->addRoad({"Denpasar", "Sukawati", "Ubud"}); + assert_int_eq(m->countIslands(), 2); + + // Cities on different islands are not reachable: + assert_false(m->reachable("Sengkol", "Sukawati")); + TEST_PASSED; +} + +int main() { + RUN_TEST(example); + PRINT_TEST_RESULTS; + assert(ALL_TESTS_PASSED); +} diff --git a/roadmap/tests/test2.cpp b/roadmap/tests/test2.cpp new file mode 100644 index 0000000..74199e6 --- /dev/null +++ b/roadmap/tests/test2.cpp @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +#include "basic_testing.h" + +#include "../roadmap.h" + +using std::string; + +TEST(basic_reachability) { + std::unique_ptr m(createRoadMap()); + + assert_false(m->reachable("Sengkol", "Sakra")); + assert_false(m->reachable("Sakra", "Sengkol")); + + m->addRoad("Sengkol", "Sakra"); + + assert_true(m->reachable("Sengkol", "Sakra")); + assert_true(m->reachable("Sakra", "Sengkol")); + + m->addRoad({"Mataram", "Mangsit", "Pamenang"}); + + assert_true(m->reachable("Mataram", "Pamenang")); + assert_true(m->reachable("Pamenang", "Mataram")); + + assert_false(m->reachable("Sakra", "Pamenang")); + assert_false(m->reachable("Sengkol", "Mataram")); + + m->addRoad({"Mataram", "Sengkol", "Koeta"}); + + assert_true(m->reachable("Sakra", "Pamenang")); + assert_true(m->reachable("Sengkol", "Mataram")); + + TEST_PASSED; +} + +TEST(clear) { + std::unique_ptr m(createRoadMap()); + + assert_false(m->reachable("Sengkol", "Sakra")); + assert_false(m->reachable("Sakra", "Sengkol")); + + m->addRoad("Sengkol", "Sakra"); + + assert_true(m->reachable("Sengkol", "Sakra")); + assert_true(m->reachable("Sakra", "Sengkol")); + + m->clear(); + + assert_false(m->reachable("Sengkol", "Sakra")); + assert_false(m->reachable("Sakra", "Sengkol")); + + m->addRoad("Sengkol", "Sakra"); + assert_true(m->reachable("Sengkol", "Sakra")); + assert_true(m->reachable("Sakra", "Sengkol")); + + m->addRoad({"Mataram", "Mangsit", "Pamenang"}); + + assert_true(m->reachable("Mataram", "Pamenang")); + assert_true(m->reachable("Pamenang", "Mataram")); + + assert_false(m->reachable("Sakra", "Pamenang")); + assert_false(m->reachable("Sengkol", "Mataram")); + + m->addRoad({"Mataram", "Sengkol", "Koeta"}); + + assert_true(m->reachable("Sakra", "Pamenang")); + assert_true(m->reachable("Sengkol", "Mataram")); + + m->clear(); + + assert_false(m->reachable("Sakra", "Pamenang")); + assert_false(m->reachable("Sengkol", "Mataram")); + assert_false(m->reachable("Mataram", "Pamenang")); + assert_false(m->reachable("Pamenang", "Mataram")); + + TEST_PASSED; +} + +TEST(tree) { + std::unique_ptr m(createRoadMap()); + + std::deque Q; + Q.push_back("0"); + while (!Q.empty()) { + string s = Q.back(); + Q.pop_back(); + if (s.length() >= 8) + continue; + string s0 = s + "0"; + string s1 = s + "1"; + m->addRoad(s, s0); + m->addRoad(s, s1); + Q.push_back(s0); + Q.push_back(s1); + } + + assert_int_eq(m->countIslands(), 1); + assert_false(m->hasLoop()); + TEST_PASSED; +} + +TEST(islands) { + std::unique_ptr m(createRoadMap()); + + std::deque Q; + Q.push_back("0"); + while (!Q.empty()) { + string s = Q.back(); + Q.pop_back(); + if (s.length() >= 8) + continue; + string s0 = s + "0"; + string s1 = s + "1"; + m->addRoad(s1, s0); + Q.push_back(s0); + Q.push_back(s1); + } + + assert_int_eq(m->countIslands(), 127); + assert_false(m->hasLoop()); + TEST_PASSED; +} + +TEST(big_loop) { + std::unique_ptr m(createRoadMap()); + + std::deque Q; + Q.push_back("0"); + while (!Q.empty()) { + string s = Q.back(); + Q.pop_back(); + if (s.length() >= 8) { + m->addRoad(s, "0"); + } else { + string s0 = s + "0"; + string s1 = s + "1"; + m->addRoad(s, s0); + m->addRoad(s, s1); + Q.push_back(s0); + Q.push_back(s1); + } + } + assert_int_eq(m->countIslands(), 1); + assert_true(m->hasLoop()); + TEST_PASSED; +} + +TEST(big_island) { + std::unique_ptr m(createRoadMap()); + + std::vector cities = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" }; + + for (unsigned int i = 0; i < cities.size(); ++i) + for (unsigned int j = i + 1; j < cities.size(); ++j) + m->addRoad(cities[i], cities[j]); + + assert_int_eq(m->countIslands(), 1); + assert_true(m->hasLoop()); + for (unsigned int i = 0; i < cities.size(); ++i) + assert_int_eq(m->neighborCountForCity(cities[i]), cities.size()-1); + TEST_PASSED; +} + +TEST(unknown_city) { + std::unique_ptr m(createRoadMap()); + + std::vector cities = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" }; + + for (unsigned int i = 0; i < cities.size(); ++i) + assert_int_eq(m->neighborCountForCity(cities[i]), -1); + + for (unsigned int i = 0; i < cities.size(); ++i) + for (unsigned int j = i + 1; j < cities.size(); ++j) + m->addRoad(cities[i], cities[j]); + + for (unsigned int i = 0; i < cities.size(); ++i) { + string s = cities[i] + "X"; + assert_int_eq(m->neighborCountForCity(s), -1); + } + TEST_PASSED; +} + +int main() { + RUN_TEST(basic_reachability); + RUN_TEST(clear); + RUN_TEST(tree); + RUN_TEST(islands); + RUN_TEST(big_loop); + RUN_TEST(big_island); + RUN_TEST(unknown_city); + PRINT_TEST_RESULTS; + assert(ALL_TESTS_PASSED); +}