diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..deff9bb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +charset = utf-8 + +[*.{c,h,cpp,hpp}] +indent_size = 2 +indent_style = tab \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7b50090..f9e8677 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/.idea/ -/cmake-build-debug/ +.vscode/ +build/ *.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index ac7a61e..d1d98d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,10 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.26) project(c2023_challenge) set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 23) add_subdirectory(level1) + +add_subdirectory(level2/PI) +add_subdirectory(level2/SkipList) \ No newline at end of file diff --git "a/C\350\257\255\350\250\200\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/C\350\257\255\350\250\200\345\255\246\344\271\240\347\254\224\350\256\260.md" old mode 100755 new mode 100644 diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/level0/README.md b/level0/README.md old mode 100755 new mode 100644 diff --git a/level0/bubbleSort/README.md b/level0/bubbleSort/README.md old mode 100755 new mode 100644 diff --git a/level1/CMakeLists.txt b/level1/CMakeLists.txt index 7c004e8..5795c2d 100644 --- a/level1/CMakeLists.txt +++ b/level1/CMakeLists.txt @@ -1,21 +1,29 @@ project(level1) -add_executable(p01_running_letter p01_running_letter/main.c) +find_package(Curses REQUIRED) -add_executable(p02_is_prime p02_is_prime/main.c) +add_executable(p01_running_letter p01_running_letter/main.cpp) +target_include_directories(p01_running_letter PRIVATE ${CURSES_INCLUDE_DIR}) +target_link_libraries(p01_running_letter PRIVATE ${CURSES_LIBRARIES}) -add_executable(p03_all_primes p03_all_primes/main.c) +add_executable(p02_is_prime p02_is_prime/main.cpp) -add_executable(p04_goldbach p04_goldbach/main.c) +add_executable(p03_all_primes p03_all_primes/main.cpp) -add_executable(p05_encrypt_decrypt p05_encrypt_decrypt/main.c) +add_executable(p04_goldbach p04_goldbach/main.cpp) -add_executable(p06_hanoi p06_hanoi/main.c) +add_executable(p05_encrypt_decrypt p05_encrypt_decrypt/main.cpp) -add_executable(p07_maze p07_maze/main.c) +add_executable(p06_hanoi p06_hanoi/main.cpp) -add_executable(p08_push_boxes p08_push_boxes/main.c) +add_executable(p07_maze p07_maze/main.cpp) +target_include_directories(p07_maze PRIVATE ${CURSES_INCLUDE_DIR}) +target_link_libraries(p07_maze PRIVATE ${CURSES_LIBRARIES}) -add_executable(p09_linked_list p09_linked_list/main.c) +add_executable(p08_push_boxes p08_push_boxes/main.cpp) +target_include_directories(p08_push_boxes PRIVATE ${CURSES_INCLUDE_DIR}) +target_link_libraries(p08_push_boxes PRIVATE ${CURSES_LIBRARIES}) -add_executable(p10_warehouse p10_warehouse/main.c) \ No newline at end of file +add_executable(p09_linked_list p09_linked_list/main.cpp) + +add_executable(p10_warehouse p10_warehouse/main.cpp) \ No newline at end of file diff --git a/level1/p01_running_letter/README.md b/level1/p01_running_letter/README.md old mode 100755 new mode 100644 diff --git a/level1/p01_running_letter/main.c b/level1/p01_running_letter/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p01_running_letter/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p01_running_letter/main.cpp b/level1/p01_running_letter/main.cpp new file mode 100644 index 0000000..a224810 --- /dev/null +++ b/level1/p01_running_letter/main.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +int main() { + using namespace ::std; + using namespace ::std::chrono_literals; + + initscr(); + cbreak(); + noecho(); + + auto f = [](int i) { + mvaddch(0, i, '*'); + refresh(); + this_thread::sleep_for(50ms); + clear(); + }; + while (true) { + for (int i = 0; i < COLS; ++i) f(i); + for (int i = COLS; i-- > 0; ) f(i); + } + + return 0; +} \ No newline at end of file diff --git a/level1/p02_is_prime/README.md b/level1/p02_is_prime/README.md old mode 100755 new mode 100644 diff --git a/level1/p02_is_prime/main.c b/level1/p02_is_prime/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p02_is_prime/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p02_is_prime/main.cpp b/level1/p02_is_prime/main.cpp new file mode 100644 index 0000000..e60ba4e --- /dev/null +++ b/level1/p02_is_prime/main.cpp @@ -0,0 +1,18 @@ +#include + +bool is_prime(unsigned n) { + if (n == 0 || n == 1) return false; + for (unsigned i = 2; i * i <= n; ++i) + if (n % i == 0) return false; + return true; +} + +int main() { + using namespace std; + + unsigned n; + cin >> n; + cout << n << ' ' << (is_prime(n) ? "is" : "is not") << ' ' << "prime." << endl; + + return 0; +} \ No newline at end of file diff --git a/level1/p03_all_primes/README.md b/level1/p03_all_primes/README.md old mode 100755 new mode 100644 diff --git a/level1/p03_all_primes/main.c b/level1/p03_all_primes/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p03_all_primes/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p03_all_primes/main.cpp b/level1/p03_all_primes/main.cpp new file mode 100644 index 0000000..d982011 --- /dev/null +++ b/level1/p03_all_primes/main.cpp @@ -0,0 +1,35 @@ +#include +#include +#include + +// O(n) +std::vector sieve(unsigned n) { + std::vector v(n + 1); + std::vector ps; + + for (unsigned i = 2; i <= n; ++i) { + if (!v[i]) ps.push_back(i); + for (unsigned p : ps) { + if (i * p > n) break; + v[i * p] = true; + if (i % p == 0) break; + } + } + + return ps; +} + +int main() { + using namespace std; + using namespace chrono; + + auto start = chrono::steady_clock::now(); + auto primes = sieve(1000); + auto end = chrono::steady_clock::now(); + + for (unsigned p : primes) cout << p << ' '; + cout << endl; + cout << "Time cost for the calculation: " << (end - start) << endl; + + return 0; +} \ No newline at end of file diff --git a/level1/p04_goldbach/README.md b/level1/p04_goldbach/README.md old mode 100755 new mode 100644 diff --git a/level1/p04_goldbach/main.c b/level1/p04_goldbach/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p04_goldbach/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p04_goldbach/main.cpp b/level1/p04_goldbach/main.cpp new file mode 100644 index 0000000..aabac5a --- /dev/null +++ b/level1/p04_goldbach/main.cpp @@ -0,0 +1,28 @@ +#include +#include + +int main() { + using namespace std; + + constexpr int n = 100; + vector v(n + 1); + vector ps; + for (int i = 2; i <= n; ++i) { + if (!v[i]) ps.push_back(i); + for (int p : ps) { + if (i * p > n) break; + v[i * p] = true; + if (i % p == 0) break; + } + } + for (int i = 4; i <= n; i += 2) { + for (int p : ps) { + if (!v[i - p]) { + printf("%d = %d + %d\n", i, p, i - p); + break; + } + } + } + + return 0; +} \ No newline at end of file diff --git a/level1/p05_encrypt_decrypt/README.md b/level1/p05_encrypt_decrypt/README.md old mode 100755 new mode 100644 diff --git a/level1/p05_encrypt_decrypt/main.c b/level1/p05_encrypt_decrypt/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p05_encrypt_decrypt/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p05_encrypt_decrypt/main.cpp b/level1/p05_encrypt_decrypt/main.cpp new file mode 100644 index 0000000..db53071 --- /dev/null +++ b/level1/p05_encrypt_decrypt/main.cpp @@ -0,0 +1,116 @@ +#include + +namespace tkz::b64 { + +using byte = unsigned char; + +// clang-format off +inline constexpr ::std::array to = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P','Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; +// clang-format on + +inline constexpr ::std::array from = [] { + ::std::array from; + ::std::ranges::fill(from, 255); + for (byte i = 0; i < 64; ++i) { + from[to[i]] = i; + } + return from; +}(); + +inline constexpr struct encode_fn { + template <::std::input_iterator I, ::std::sentinel_for S, ::std::output_iterator O> + requires ::std::convertible_to<::std::iter_value_t, byte> + static constexpr void operator()(I b, S e, O o) { + byte s[3]; + ::std::size_t i = 0; + while (b != e) { + s[i++] = static_cast(*b++); + if (i == 3) { + *o++ = to[(s[0] & byte(0b11111100)) >> 2]; + *o++ = to[((s[0] & byte(0b00000011)) << 4) | ((s[1] & byte(0b11110000)) >> 4)]; + *o++ = to[((s[1] & byte(0b00001111)) << 2) | ((s[2] & byte(0b11000000)) >> 6)]; + *o++ = to[s[2] & byte(0b00111111)]; + i = 0; + } + } + switch (i) { + case 0: + break; + case 1: + *o++ = to[(s[0] & byte(0b11111100)) >> 2]; + *o++ = to[(s[0] & byte(0b00000011)) << 4]; + *o++ = '='; + *o++ = '='; + break; + case 2: + *o++ = to[(s[0] & byte(0b11111100)) >> 2]; + *o++ = to[((s[0] & byte(0b00000011)) << 4) | ((s[1] & byte(0b11110000)) >> 4)]; + *o++ = to[(s[1] & byte(0b00001111)) << 2]; + *o++ = '='; + break; + } + } + + template <::std::ranges::range R, ::std::output_iterator O> static constexpr void operator()(R &&r, O o) { + return operator()(::std::ranges::begin(r), ::std::ranges::end(r), ::std::move(o)); + } +} encode{}; + +inline constexpr struct decode_fn { + template <::std::input_iterator I, ::std::sentinel_for S, ::std::output_iterator O> + requires ::std::convertible_to<::std::iter_value_t, char> + static constexpr void operator()(I b, S e, O o) { + char c[4]; + ::std::size_t i = 0; + while (b != e) { + if ((c[i++] = static_cast(*b++)) == '=') { + --i; + break; + } + if (i == 4) { + *o++ = from[c[0]] << 2 | from[c[1]] >> 4; + *o++ = from[c[1]] << 4 | from[c[2]] >> 2; + *o++ = from[c[2]] << 6 | from[c[3]]; + i = 0; + } + } + switch (i) { + case 0: + break; + case 1: + break; + case 2: + *o++ = from[c[0]] << 2 | from[c[1]] >> 4; + break; + case 3: + *o++ = from[c[0]] << 2 | from[c[1]] >> 4; + *o++ = from[c[1]] << 4 | from[c[2]] >> 2; + break; + } + } + + template <::std::ranges::range R, ::std::output_iterator O> static constexpr void operator()(R &&r, O o) { + return operator()(::std::ranges::begin(r), ::std::ranges::end(r), ::std::move(o)); + } +} decode{}; + +} // namespace tkz::b64 + +int main() { + using namespace std; + string r = "hello world!"; + cout << r << endl; + string e; + ::tkz::b64::encode(r, back_inserter(e)); + cout << e << endl; + string d; + ::tkz::b64::decode(e, back_inserter(d)); + cout << d << endl; + return 0; +} \ No newline at end of file diff --git a/level1/p06_hanoi/README.md b/level1/p06_hanoi/README.md old mode 100755 new mode 100644 diff --git a/level1/p06_hanoi/main.c b/level1/p06_hanoi/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p06_hanoi/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p06_hanoi/main.cpp b/level1/p06_hanoi/main.cpp new file mode 100644 index 0000000..ee77273 --- /dev/null +++ b/level1/p06_hanoi/main.cpp @@ -0,0 +1,20 @@ +#include + +using namespace std; + +void hanoi(int n, char a, char b, char c) { + if (n == 1) { + printf("%c -> %c\n", a, c); + return; + } + hanoi(n - 1, a, c, b); + printf("%c -> %c\n", a, c); + hanoi(n - 1, b, a, c); +} + +int main() { + int n; + scanf("%d", &n); + hanoi(n, 'A', 'B', 'C'); + return 0; +} \ No newline at end of file diff --git a/level1/p07_maze/README.md b/level1/p07_maze/README.md old mode 100755 new mode 100644 diff --git a/level1/p07_maze/main.c b/level1/p07_maze/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p07_maze/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p07_maze/main.cpp b/level1/p07_maze/main.cpp new file mode 100644 index 0000000..967c251 --- /dev/null +++ b/level1/p07_maze/main.cpp @@ -0,0 +1,61 @@ +#include +#include + +int main() { + using namespace ::std; + + static constexpr int X = 11, Y = 11; + static constexpr char map[X * Y] = { + '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', + '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'O', '#', + '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', + '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', + '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', + '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', + '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', + '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', + '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', + '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', + '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', + }; + static constexpr auto getm = [](int x, int y) -> char { + return map[y * X + x]; + }; + + initscr(); + cbreak(); + noecho(); + curs_set(0); + + for (int y = 0; y < Y; ++y) + for (int x = 0; x < X; ++x) + mvaddch(y, x, getm(x, y)); + int px = 1, py = 9; + mvaddch(py, px, '*'); + refresh(); + + while (true) { + if (getm(px, py) == 'O') { + clear(); + mvaddstr(0, 0, "You win!\n"); + refresh(); + return 0; + } + int c = getch(); + int npx = px, npy = py; + switch (c) { + case 'w': --npy; break; + case 'a': --npx; break; + case 's': ++npy; break; + case 'd': ++npx; break; + default: break; + } + if (getm(npx, npy) != '#') { + mvaddch(py, px, getm(px, py)); + mvaddch(npy, npx, '*'); + px = npx; + py = npy; + refresh(); + } + } +} \ No newline at end of file diff --git a/level1/p08_push_boxes/README.md b/level1/p08_push_boxes/README.md old mode 100755 new mode 100644 diff --git a/level1/p08_push_boxes/main.c b/level1/p08_push_boxes/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p08_push_boxes/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p08_push_boxes/main.cpp b/level1/p08_push_boxes/main.cpp new file mode 100644 index 0000000..adfce53 --- /dev/null +++ b/level1/p08_push_boxes/main.cpp @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct File { + struct Deleter { + static void operator()(FILE* f) { + ::std::fclose(f); + } + }; + + ::std::unique_ptr f; + + File(::std::filesystem::path path, const char* modes): + f(::std::fopen(path.c_str(), modes)) + { } + + FILE* get() const { return this->f.get(); } +}; + +struct Position { int y, x; }; + +enum Direction { + UP = 'w', + LEFT = 'a', + DOWN = 's', + RIGHT = 'd' +}; + +Position advance(Position p, Direction d) { + switch (d) { + case UP: --p.y; break; + case DOWN: ++p.y; break; + case LEFT: --p.x; break; + case RIGHT: ++p.x; break; + } + return p; +} + +enum Mask : unsigned char { + EMPTY = 0, + WALL = 1 << 0, + PLAYER = 1 << 1, + BOX = 1 << 2, + DEST = 1 << 3, +}; +using Cell = ::std::underlying_type_t; + +bool contains(Cell c, Mask m) { return c & m; } +void set(Cell& c, Mask m) { c |= m; } +void remove(Cell& c, Mask m) { c &= ~m; } + +char toChar(Cell c) { + switch (c) { + case EMPTY: return '.'; + case WALL: return '#'; + case PLAYER: return 'P'; + case PLAYER | DEST: return 'P'; + case BOX: return 'B'; + case DEST: return 'O'; + case BOX | DEST: return 'V'; + default: assert(false); // invalid state + } +} + +Cell fromChar(char c) { + switch (c) { + case '.': return EMPTY; + case '#': return WALL; + case 'P': return PLAYER; + case 'B': return BOX; + case 'O': return DEST; + default: assert(false); // invalid map + } +} + +struct Map { + int rows, cols; + ::std::vector cells; + ::std::vector dests; + Position player; + + int indexOf(Position p) const { return p.y * cols + p.x; } + Cell& get(Position p) { return cells[indexOf(p)]; } + Cell get(Position p) const { return cells[indexOf(p)]; } + + explicit Map(File&& f) { + ::std::fscanf(f.get(), "%dx%d", &rows, &cols); + cells.resize(rows * cols); + for (int y = 0; y < rows; ++y) { + assert(::std::fgetc(f.get()) == '\n'); + for (int x = 0; x < cols; ++x) { + Position p{y, x}; + switch (get(p) = fromChar(::std::fgetc(f.get()))) { + case PLAYER: player = p; break; + case DEST: dests.push_back(p); break; + default: break; + } + } + } + } + + bool step(Direction d, ::std::invocable auto&& f) { + Position p1 = advance(player, d); + if (contains(get(p1), WALL)) return false; + if (contains(get(p1), BOX)) { + Position p2 = advance(p1, d); + if (contains(get(p2), WALL)) return false; + if (contains(get(p2), BOX)) return false; + remove(get(p1), BOX); + set(get(p2), BOX); + ::std::invoke(f, p2, get(p2)); + } + remove(get(player), PLAYER); + set(get(p1), PLAYER); + ::std::invoke(f, p1, get(p1)); + ::std::invoke(f, player, get(player)); + player = p1; + return true; + } + + bool win() const { + for (auto&& p : dests) { + if (!contains(get(p), BOX)) { + return false; + } + } + return true; + } +}; + +int main() { + using namespace std; + namespace fs = std::filesystem; + + initscr(); + cbreak(); + + clear(); + mvprintw(0, 0, "Enter the level name: "); + refresh(); + string level; + level.resize_and_overwrite(80, [](char* buf, int size) { + getnstr(buf, size); + return strlen(buf); + }); + + noecho(); + curs_set(0); + + fs::path mapPath = fs::current_path() / "map" / (level + ".txt"); + fs::path scorePath = fs::current_path() / "score" / (level + ".txt"); + + Map map(File(mapPath, "r")); + auto print = [](Map const& map) { + clear(); + for (int y = 0; y < map.rows; ++y) { + for (int x = 0; x < map.cols; ++x) { + mvaddch(y, x, toChar(map.get({y, x}))); + } + } + refresh(); + }; + int steps = 0; + while (!map.win()) { + print(map); + auto c = getch(); + switch (c) { + case UP: case DOWN: case LEFT: case RIGHT: { + bool succeed = map.step(Direction(c), [](Position p, Cell c) { + mvaddch(p.y, p.x, toChar(c)); + }); + if (succeed) ++steps; + break; + } + default: break; + } + } + print(map); + mvprintw(map.rows + 1, 0, "You win! Steps: %d\n", steps); + refresh(); + File scoreFile(scorePath, "a"); + fprintf(scoreFile.get(), "%d\n", steps); + + return 0; +} diff --git a/level1/p09_linked_list/README.md b/level1/p09_linked_list/README.md old mode 100755 new mode 100644 diff --git a/level1/p09_linked_list/main.c b/level1/p09_linked_list/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p09_linked_list/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p09_linked_list/main.cpp b/level1/p09_linked_list/main.cpp new file mode 100644 index 0000000..411101e --- /dev/null +++ b/level1/p09_linked_list/main.cpp @@ -0,0 +1,64 @@ +#include + +struct node { + node* next; + int value; +}; + +int main() { + using namespace ::std; + + node* head = + new node { + .next = new node { + .next = new node { + .next = new node { + .next = nullptr, + .value = 3, + }, + .value = 5 + }, + .value = 2, + }, + .value = 1, + }; + + // display + for (auto curr = head; curr; curr = curr->next) { + cout << curr << ": " << curr->value << '\n'; + } + + // reverse + { + auto p = head; + auto q = p->next; + p->next = nullptr; + while (q) { + auto r = q->next; + q->next = p; + p = q; + q = r; + } + head = p; + } + + // display again + for (auto curr = head; curr; curr = curr->next) { + cout << curr << ": " << curr->value << '\n'; + } + + auto find = [](node* p, int value) -> node* { + for (; p; p = p->next) { + if (p->value == value) { + return p; + } + } + return nullptr; + }; + auto f1 = find(head, 5); + cout << f1 << ": " << (f1 ? f1->value : -1) << '\n'; + auto f2 = find(f1 ? f1->next : nullptr, 5); + cout << f2 << ": " << (f2 ? f2->value : -1) << '\n'; + + return 0; +} \ No newline at end of file diff --git a/level1/p10_warehouse/README.md b/level1/p10_warehouse/README.md old mode 100755 new mode 100644 diff --git a/level1/p10_warehouse/main.c b/level1/p10_warehouse/main.c deleted file mode 100644 index f84d224..0000000 --- a/level1/p10_warehouse/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("hello world!\n"); - return 0; -} \ No newline at end of file diff --git a/level1/p10_warehouse/main.cpp b/level1/p10_warehouse/main.cpp new file mode 100644 index 0000000..0b17850 --- /dev/null +++ b/level1/p10_warehouse/main.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include + +struct Database { + ::std::filesystem::path file; + ::std::map<::std::string, int> items; + + Database(::std::filesystem::path file): + file{::std::move(file)}, + items{} + { + ::std::ifstream in(this->file); + ::std::string name; + int count; + while (in >> name >> count) { + this->items[name] = count; + } + } + + ~Database() { + ::std::ofstream out(this->file); + for (auto&& [name, count] : this->items) { + out << name << ' ' << count << '\n'; + } + } +}; + +int main() { + using namespace ::std; + namespace fs = ::std::filesystem; + + string name; + cout << "Enter database file name: "; + cin >> name; + Database db(fs::current_path() / "db" / (name + ".txt")); + + while (true) { + cout << "Type \"display\" to display all items\n"; + cout << "Type \"add\" to add an item\n"; + cout << "Type \"remove\" to remove an item\n"; + cout << "Type \"exit\" to exit\n"; + + string command; + cout << "Enter command: "; + cin >> command; + + if (command == "display") { + if (db.items.empty()) { + cout << "No items\n"; + } + else { + for (auto&& [name, count] : db.items) { + cout << name << ' ' << count << '\n'; + } + } + } + else if (command == "add") [&]{ + cout << "Enter the name of the item: "; + string name; + cin >> name; + cout << "Enter the number to add: "; + int count; + cin >> count; + if (count <= 0) { + cout << "Invalid number\n"; + return; + } + db.items[name] += count; + }(); + else if (command == "remove") [&]{ + cout << "Enter the name of the item: "; + string name; + cin >> name; + auto it = db.items.find(name); + if (it == db.items.end()) { + cout << "Item not found\n"; + return; + } + cout << "The number of item is " << it->second << '\n'; + cout << "Enter the number to remove: "; + int count; + cin >> count; + if (count <= 0 || count > it->second) { + cout << "Invalid number\n"; + return; + } + it->second -= count; + if (it->second == 0) { + db.items.erase(it); + } + }(); + else if (command == "exit") { + break; + } + else { + cout << "Unknown command: " << command << '\n'; + } + + cout << endl; + } + + return 0; +} diff --git a/level2/GA/README.md b/level2/GA/README.md old mode 100755 new mode 100644 diff --git a/level2/NeuralNetworks/README.md b/level2/NeuralNetworks/README.md old mode 100755 new mode 100644 diff --git a/level2/PI/CMakeLists.txt b/level2/PI/CMakeLists.txt new file mode 100644 index 0000000..ef9e682 --- /dev/null +++ b/level2/PI/CMakeLists.txt @@ -0,0 +1,4 @@ +find_package(Boost REQUIRED) + +add_executable(pi main.cpp) +target_link_libraries(pi PRIVATE Boost::boost) \ No newline at end of file diff --git a/level2/PI/README.md b/level2/PI/README.md old mode 100755 new mode 100644 diff --git a/level2/PI/main.cpp b/level2/PI/main.cpp new file mode 100644 index 0000000..325f03a --- /dev/null +++ b/level2/PI/main.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +constexpr int DIGITS = 100000; +constexpr int ITERATION = 20; + +inline constexpr auto sqr(auto&& x) { return x * x; } + +// https://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_algorithm +template +auto Gauss_Legendre() { + using namespace ::boost::multiprecision; + using F = number>; + F a = 1, + b = 1 / sqrt(F(2)), + t = 0.25, + p = 1; + for (int i = 1; i <= ITERATION; ++i) { + F a_ = (a + b) / 2, + b_ = sqrt(a * b), + t_ = t - p * sqr(a - a_), + p_ = 2 * p; + a = a_; b = b_; t = t_; p = p_; + } + return sqr(a + b) / (4 * t); +} + +int main() { + using namespace ::std; + cout << setprecision(DIGITS) << Gauss_Legendre() << '\n'; + return 0; +} \ No newline at end of file diff --git a/level2/SkipList/CMakeLists.txt b/level2/SkipList/CMakeLists.txt new file mode 100644 index 0000000..055435a --- /dev/null +++ b/level2/SkipList/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(skip_list main.cpp) \ No newline at end of file diff --git a/level2/SkipList/README.md b/level2/SkipList/README.md old mode 100755 new mode 100644 diff --git a/level2/SkipList/main.cpp b/level2/SkipList/main.cpp new file mode 100644 index 0000000..9bed4cd --- /dev/null +++ b/level2/SkipList/main.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include + +template < + ::std::totally_ordered K, + typename M, + double P = 0.5 +> + requires (0.0 < P && P < 1.0) +struct skip_list { + using key_type = K; + using mapped_type = M; + using value_type = ::std::pair; + static inline auto dist = ::std::bernoulli_distribution(P); + + struct node { + value_type value; + ::std::vector<::std::shared_ptr> next; + + node(value_type value, ::std::size_t level): + value(::std::move(value)), next(level) { } + + key_type const& key() const { return value.first; } + mapped_type& mapped() { return value.second; } + mapped_type const& mapped() const { return value.second; } + }; + + ::std::default_random_engine eng; + ::std::vector<::std::shared_ptr> head; + + skip_list(::std::size_t max_level): + head(max_level) {} + + ::std::size_t random_level() { + ::std::size_t level = 1; + while (level < head.size() && dist(eng)) + ++level; + return level; + } + + ::std::shared_ptr find_node(key_type const& key) { + ::std::size_t level = head.size(); + ::std::shared_ptr p; + while (level-- > 0) { + if (auto q = head[level]; q && q->key() < key) { + p = q; + break; + } + } + if (!p) return nullptr; + while (level-- > 0) { + auto q = p->next[level]; + while (q && q->key() < key) { + p = q; + q = q->next[level]; + } + } + auto q = p->next[0]; + if (q->key() == key) return q; + else return nullptr; + } + + void insert(value_type v) { + auto x = ::std::make_shared(::std::move(v), random_level()); + ::std::size_t level = x->next.size(); + ::std::shared_ptr p; + while (level-- > 0) { + if (!p) { + if (!head[level]) { + head[level] = x; + continue; + } + auto q = head[level]; + if (!(q->key() < x->key())) { + head[level] = x; + x->next[level] = q; + continue; + } + p = q; + } + auto q = p->next[level]; + while (q && q->key() < x->key()) { + p = q; + q = q->next[level]; + } + p->next[level] = x; + x->next[level] = q; + } + } + + void remove(key_type const& key) { + ::std::size_t level = head.size(); + ::std::shared_ptr p; + while (level-- > 0) { + if (!p) { + auto q = head[level]; + if (!q || q->key() > key) { + continue; + } + else if (q->key() == key) { + head[level] = q->next[level]; + continue; + } + else { + p = q; + } + } + auto q = p->next[level]; + while (q && q->key() < key) { + p = q; + q = q->next[level]; + } + if (q && q->key() == key) { + p->next[level] = q->next[level]; + } + } + } +}; + +int main() { + using namespace std; + skip_list l(5); + l.insert({1, 2}); + l.insert({3, 5}); + l.insert({2, 3}); + cout << l.find_node(2) << '\n'; + l.remove(2); + cout << l.find_node(2) << '\n'; + l.insert({2, 4}); + cout << l.find_node(2) << '\n'; + return 0; +} \ No newline at end of file