├── branding
└── logo.png
├── .gitignore
├── README.md
├── src
├── math
│ ├── ceil.d
│ └── math_parser.d
├── sort
│ ├── stalin_sort.d
│ ├── bubble_sort.d
│ ├── insert_sort.d
│ └── selection_sort.d
├── problems
│ ├── codewars
│ │ ├── primes_in_numbers.d
│ │ ├── counting_duplicates.d
│ │ ├── human_readable_duration_format.d
│ │ └── screen_locking_patterns.d
│ └── geekforgeek
│ │ └── majority_element_2.d
├── dynamic_programming
│ └── cut_rod.d
├── compilers
│ └── brainfuck.d
└── data_structures
│ └── binary_heap.d
└── LICENSE
/branding/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dlangalgorithms/Algorithms/HEAD/branding/logo.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.o
3 | *.obj
4 |
5 | # Compiled Dynamic libraries
6 | *.so
7 | *.dylib
8 | *.dll
9 |
10 | # Compiled Static libraries
11 | *.a
12 | *.lib
13 |
14 | # Executables
15 | *.exe
16 |
17 | # DUB
18 | .dub
19 | docs.json
20 | __dummy.html
21 | docs/
22 |
23 | # Code coverage
24 | *.lst
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
Algorithms
5 | All algorithms implemented in D
6 |
7 |
8 | >[!NOTE]
9 | > This repository is designed for beginners who want to get acquainted with the D language, but it can be useful for professionals as well.
10 |
11 | The repository contains a lot of algorithms,
12 | from the simplest to the most complex.
13 |
14 | Here you can find everything from bubble sort
15 | to a compiler for your own language.
16 |
17 | If you want, you can contribute to the project.
18 |
19 | Even if you are new to D, but can write simple algorithms,
20 | you can find an interesting algorithm, implement it and add it here!
--------------------------------------------------------------------------------
/src/math/ceil.d:
--------------------------------------------------------------------------------
1 | import std;
2 |
3 | /**
4 | * Returns the smallest (closest to negative infinity)
5 | *
6 | * @param number the number
7 | * @return the smallest (closest to negative infinity) of given
8 | * {@code number}
9 | */
10 |
11 | double ceil(double number) {
12 | if (number - cast(int) number == 0) {
13 | return number;
14 | } else if (number - cast(int) number > 0) {
15 | return cast(int)(number + 1);
16 | } else {
17 | return cast(int) number;
18 | }
19 | }
20 |
21 | unittest {
22 |
23 | assert(ceil(10.2) == 11);
24 | assert(ceil(9) == 9);
25 | assert(ceil(12.6) == 13);
26 |
27 | }
28 |
29 | /*Program tests are performed above in the unittest block*/
30 | int main(){
31 | return 0;
32 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Dlang Algorithms
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/sort/stalin_sort.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 |
3 | /*
4 | * Stalin Sort is a humorous sorting algorithm that modifies the input array in-place.
5 | * It keeps elements that are in non-decreasing order and removes elements that break this order.
6 | *
7 | * 1) Start with the first element of the array as the base.
8 | * 2) Iterate through the array, keeping only elements that are greater than or equal to the last kept element.
9 | * 3) Shift all valid elements to the left, effectively removing invalid ones.
10 | * 4) Resize the array to include only valid elements.
11 | *
12 | * @param arr the array of integers to be sorted
13 | */
14 | void stalin_sort(ref ulong[] arr) {
15 | if (arr.length == 0) return; // No action for an empty array
16 |
17 | ulong index = 0; // Position to keep the current element
18 |
19 | for (ulong i = 1; i < arr.length; i++) {
20 | if (arr[i] >= arr[index]) {
21 | index++;
22 | arr[index] = arr[i]; // Keep valid element in place
23 | }
24 | }
25 |
26 | arr.length = index + 1; // Truncate the array to contain only valid elements
27 | }
28 |
29 | unittest{
30 | ulong[] data = [64, 34, 25, 12, 22, 11, 90];
31 | stalin_sort(data);
32 | assert(data == [64,90]);
33 | }
34 |
35 | void main() {}
--------------------------------------------------------------------------------
/src/sort/bubble_sort.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 |
3 | /**
4 | * Sorts an array of integers in ascending order using the Bubble Sort algorithm.
5 | *
6 | * This algorithm repeatedly steps through the list, compares adjacent elements,
7 | * and swaps them if they are in the wrong order. The pass through the list is
8 | * repeated until the list is sorted.
9 | *
10 | * @param arr the array of integers to be sorted
11 | */
12 | void bubbleSort(int[] arr) {
13 | // Get the length of the array
14 | ulong n = arr.length;
15 |
16 | // Outer loop for each element in the array, except the last one
17 | for (int i = 0; i < n - 1; i++) {
18 | // Inner loop for comparing adjacent elements
19 | // The last i elements are already sorted, so we reduce the range
20 | for (int j = 0; j < n - 1 - i; j++) {
21 | // If the current element is greater than the next element, swap them
22 | if (arr[j] > arr[j + 1]) {
23 | // Temporary variable to hold the current element during swap
24 | int temp = arr[j];
25 | arr[j] = arr[j + 1]; // Assign next element to current position
26 | arr[j + 1] = temp; // Assign the temporary variable to next position
27 | }
28 | }
29 | }
30 | }
31 |
32 | /*
33 | TESTS
34 | */
35 | unittest{
36 | int[] data = [64, 34, 25, 12, 22, 11, 90];
37 | bubbleSort(data);
38 | assert(data == [11,12,22,25,34,64,90]);
39 | }
40 |
41 |
42 | void main() {}
--------------------------------------------------------------------------------
/src/sort/insert_sort.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 |
3 | /*
4 | * Insertion sort is a simple sorting algorithm that works by iteratively inserting each element of an unsorted list into its correct position in a sorted portion of the list.
5 | * It is like sorting playing cards in your hands. You split the cards into two groups: the sorted cards and the unsorted cards.
6 | * Then, you pick a card from the unsorted group and put it in the right place in the sorted group.
7 | *
8 | * 1) We start with second element of the array as first element in the array is assumed to be sorted.
9 | * 2) Compare second element with the first element and check if the second element is smaller then swap them.
10 | * 3) Move to the third element and compare it with the first two elements and put at its correct position
11 | * 4) Repeat until the entire array is sorted.
12 | *
13 | * @param arr the array of integers to be sorted
14 | */
15 | void insert_sort(ulong[] arr) {
16 | for (int i = 1; i < arr.length; i++) {
17 | ulong key = arr[i];
18 | int j = i - 1;
19 | // Move elements of arr[0..i-1], that are greater than key, to one position ahead of their current position
20 | while (j >= 0 && key < arr[j]) {
21 | arr[j + 1] = arr[j];
22 | j--;
23 | }
24 | arr[j + 1] = key;
25 | }
26 | }
27 |
28 | unittest{
29 | ulong[] data = [64, 34, 25, 12, 22, 11, 90];
30 | insert_sort(data);
31 | assert(data == [11,12,22,25,34,64,90]);
32 | }
33 |
34 | void main() {}
--------------------------------------------------------------------------------
/src/sort/selection_sort.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 |
3 | /*
4 | * Selection Sort is a comparison-based sorting algorithm.
5 | * It sorts an array by repeatedly selecting the smallest (or largest) element from the unsorted portion and swapping it with the first unsorted element.
6 | * This process continues until the entire array is sorted.
7 | *
8 | * 1) First we find the smallest element and swap it with the first element. This way we get the smallest element at its correct position.
9 | * 2) Then we find the smallest among remaining elements (or second smallest) and move it to its correct position by swapping.
10 | * 3) We keep doing this until we get all elements moved to correct position.
11 | *
12 | * @param arr the array of integers to be sorted
13 | */
14 | void selection_sort(ulong[] arr) {
15 | // Get the length of the array
16 | ulong n = arr.length;
17 |
18 | for (ulong i = 0; i < n-1; i++) {
19 | // Assume the current position holds the minimum element
20 | ulong min_index = i;
21 |
22 | // Iterate through the unsorted portion to find the actual minimum
23 | for (ulong j = i + 1; j < n; j++) {
24 | // Update min_idx if a smaller element is found
25 | if (arr[j] < arr[min_index]) min_index = j;
26 | }
27 |
28 | // Move minimum element to its correct position
29 | ulong temp = arr[i];
30 | arr[i] = arr[min_index];
31 | arr[min_index] = temp;
32 | }
33 | }
34 |
35 | unittest{
36 | ulong[] data = [64, 34, 25, 12, 22, 11, 90];
37 | selection_sort(data);
38 | assert(data == [11,12,22,25,34,64,90]);
39 | }
40 |
41 | void main() {}
--------------------------------------------------------------------------------
/src/problems/codewars/primes_in_numbers.d:
--------------------------------------------------------------------------------
1 | import std.format;
2 | import std.math : sqrt;
3 | import std.algorithm : sort;
4 |
5 | /*
6 | * Link: https://www.codewars.com/kata/54d512e62a5e54c96200019e
7 | *
8 | * Primes in numbers
9 | * Difficulty: 5 kyu
10 | *
11 | * Problem:
12 | * Given a positive number n > 1 find the prime factor decomposition of n.
13 | * The result will be a string with the following form: "(p1**n1)(p2**n2)...(pk**nk)"
14 | *
15 | * With the p(i) in increasing order and n(i) empty if n(i) is 1.
16 | *
17 | * Example:
18 | * n = 86240 should return "(2**5)(5)(7**2)(11)"
19 | *
20 | * Tags: Fundamentals, Mathematics
21 | *
22 | */
23 | string primeFactors(long n) {
24 | string result;
25 | int count = 0;
26 |
27 | while (n % 2 == 0) {
28 | n /= 2;
29 | count++;
30 | }
31 |
32 | if (count > 0) result ~= (count == 1) ? "(2)" : format("(2**%d)", count);
33 |
34 | for (int i = 3; i < (sqrt(cast(float)n) + 1); i+=2) {
35 | count = 0;
36 | while (n % i == 0) {
37 | n /= i;
38 | count++;
39 | }
40 | if (count > 0) result ~= (count == 1) ? format("(%d)", i) : format("(%d**%d)", i, count);
41 | }
42 |
43 | if (n > 2) {
44 | result ~= format("(%d)", n);
45 | }
46 |
47 | return result;
48 | }
49 |
50 | unittest {
51 | assert(primeFactors(7775460) == "(2**2)(3**3)(5)(7)(11**2)(17)");
52 | assert(primeFactors(7919) == "(7919)");
53 | assert(primeFactors(17*17*93*677) == "(3)(17**2)(31)(677)");
54 | assert(primeFactors(933555431) == "(7537)(123863)");
55 | }
56 |
57 | void main() {
58 |
59 | }
--------------------------------------------------------------------------------
/src/problems/codewars/counting_duplicates.d:
--------------------------------------------------------------------------------
1 | import std;
2 | import std.uni : toLower;
3 | /*
4 | * Link: https://www.codewars.com/kata/54bf1c2cd5b56cc47f0007a1
5 | *
6 | * Counting Duplicates
7 | * Difficulty: 6 kyu
8 | *
9 | * Problem:
10 | * Count the number of Duplicates
11 | * Write a function that will return the count of distinct case-insensitive alphabetic characters and numeric digits that occur more than once in the input string.
12 | * The input string can be assumed to contain only alphabets (both uppercase and lowercase) and numeric digits.
13 | *
14 | * Examples
15 | * "abcde" -> 0 # no characters repeats more than once
16 | * "aabbcde" -> 2 # 'a' and 'b'
17 | * "aabBcde" -> 2 # 'a' occurs twice and 'b' twice (`b` and `B`)
18 | * "indivisibility" -> 1 # 'i' occurs six times
19 | * "Indivisibilities" -> 2 # 'i' occurs seven times and 's' occurs twice
20 | * "aA11" -> 2 # 'a' and '1'
21 | * "ABBA" -> 2 # 'A' and 'B' each occur twice
22 | *
23 | * Tags: Strings, Fundamentals
24 | *
25 | */
26 |
27 | /*
28 | * Returns amount of duplicated chars in the text.
29 | *
30 | * @param text just text
31 | * @return amount of duplicated chars
32 | * {@code text}
33 | */
34 | uint duplicate_count(string text) {
35 | text = toLower(text);
36 | int[char] map;
37 | int result = 0;
38 |
39 | foreach (c; text) {
40 | if (c !in map) map[c] = 0;
41 | map[c]++;
42 | }
43 |
44 | foreach (key, value; map) {
45 | if (value > 1) result++;
46 | }
47 |
48 | return result;
49 | }
50 |
51 | unittest {
52 | assert(duplicate_count("abcde") == 0);
53 | assert(duplicate_count("aabbcde") == 2);
54 | assert(duplicate_count("aabBcde") == 2);
55 | assert(duplicate_count("indivisibility") == 1);
56 | assert(duplicate_count("Indivisibilities") == 2);
57 | assert(duplicate_count("aA11") == 2);
58 | assert(duplicate_count("ABBA") == 2);
59 | }
60 |
61 | // Program tests are performed above in the unittest block
62 | int main(){
63 | return 0;
64 | }
--------------------------------------------------------------------------------
/src/dynamic_programming/cut_rod.d:
--------------------------------------------------------------------------------
1 | import std;
2 |
3 | /**
4 | * Calculates the maximum profit that can be obtained by cutting a rod
5 | * of length n and selling the pieces based on the given price array.
6 | *
7 | * @param price an array of integers representing the prices for each
8 | * length of the rod (1-indexed, where price[i-1] is the
9 | * price for a rod of length i).
10 | * @param n the total length of the rod.
11 | * @return the maximum profit that can be obtained by cutting the rod.
12 | */
13 | int maxProfitByCuttingRod(int[] price, uint64_t n) {
14 | // Array to store maximum profits for each length of the rod
15 | int[] profit = new int[n + 1];
16 |
17 | // Base case: No profit can be made from a rod of length 0
18 | profit[0] = 0;
19 |
20 | // Iterate over lengths from 1 to n
21 | for (size_t i = 1; i <= n; i++) {
22 | int q = int.min; // Initialize maximum profit for this length
23 |
24 | // Check all possible cuts of the rod
25 | for (size_t j = 1; j <= i; j++) {
26 | // Calculate profit by making a cut at length j
27 | q = max(q, price[j - 1] + profit[i - j]);
28 | }
29 |
30 | // Store the maximum profit for rod length i
31 | profit[i] = q;
32 | }
33 |
34 | // Return the maximum profit for the full length of the rod
35 | return profit[n];
36 | }
37 |
38 | /**
39 | TESTS
40 | */
41 |
42 | unittest {
43 | // Test case to validate the maxProfitByCuttingRod function
44 | const int n1 = 8; // Length of the rod
45 | int[] price1 = [1 , 5, 8, 9, 10, 17 , 17 , 20]; // Prices for each length
46 | const int max_profit1 = maxProfitByCuttingRod(price1, n1); // Calculate max profit
47 | const int expected_max_profit1 = 22; // Expected result
48 | assert(max_profit1 == expected_max_profit1); // Assert that calculated profit matches expected
49 | writeln(max_profit1); // Output result
50 | }
51 |
52 | /**
53 | Program tests are performed above in the unittest block
54 | */
55 | void main() {}
56 |
--------------------------------------------------------------------------------
/src/compilers/brainfuck.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 | import std.file;
3 | import std.string;
4 |
5 | void main(string[] args) {
6 | if (args.length < 2) {
7 | writeln("Usage: ", args[0], " filename");
8 | return;
9 | }
10 |
11 | auto inputFile = args[1];
12 | auto outputFile = inputFile[0 .. inputFile.length - inputFile.lastIndexOf('.')].dup ~ ".txt";
13 |
14 | try {
15 | auto content = readText(inputFile);
16 | auto writer = File(outputFile, "w");
17 |
18 | writer.write("#include \nint main(){unsigned char tape[30000] = { 0 };unsigned char* ptr = tape;\n");
19 |
20 | int i = 0;
21 | while (i < content.length) {
22 | char ch = content[i];
23 | int sameCh = 1;
24 |
25 | while (i + sameCh < content.length && content[i + sameCh] == ch) {
26 | sameCh++;
27 | }
28 |
29 | final switch (ch) {
30 | case '>':
31 | writer.write("ptr+=", sameCh, ";\n");
32 | break;
33 | case '<':
34 | writer.write("ptr-=", sameCh, ";\n");
35 | break;
36 | case '+':
37 | writer.write("*ptr+=", sameCh, ";\n");
38 | break;
39 | case '-':
40 | writer.write("*ptr-=", sameCh, ";\n");
41 | break;
42 | case '.':
43 | writer.write("putchar(*ptr);\n");
44 | break;
45 | case ',':
46 | writer.write("*ptr=getchar();\n");
47 | break;
48 | case '[':
49 | writer.write("while(*ptr){\n");
50 | break;
51 | case ']':
52 | writer.write("}\n");
53 | break;
54 | }
55 |
56 | i += sameCh;
57 | }
58 |
59 | writer.write("}\n");
60 | writer.close();
61 | } catch (Exception e) {
62 | writeln("File not found or an error occurred: ", e.msg);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/problems/geekforgeek/majority_element_2.d:
--------------------------------------------------------------------------------
1 | import std;
2 | import std.algorithm : sort;
3 | /*
4 | * Link: https://www.geeksforgeeks.org/problems/majority-vote/1
5 | *
6 | * Majority Element II
7 | * Difficulty: Medium
8 | *
9 | * Problem:
10 | * You are given an array of integer int[] where each number represents a vote to a candidate.
11 | * Return the candidates that have votes greater than one-third of the total votes, If there's not a majority vote, return an empty array.
12 | *
13 | * Note: The answer should be returned in an increasing format.
14 | *
15 | * Examples:
16 | * ====================================================
17 | * Input: int[] array = [2, 1, 5, 5, 5, 5, 6, 6, 6, 6, 6];
18 | * Output: [5, 6]
19 | * Explanation: 5 and 6 occur more n/3 times.
20 | * ====================================================
21 | *
22 | * ====================================================
23 | * Input: int[] array = [1, 2, 3, 4, 5];
24 | * Output: []
25 | * Explanation: no candidate occur more than n/3 times.
26 | * ====================================================
27 | *
28 | * Constraint:
29 | * 1 <= arr.size() <= 10^6
30 | * -10^9 <= arr[i] <= 10^9
31 | *
32 | */
33 |
34 | /*
35 | * Returns an array of major numbers where each number represents a candidate whos amount of votes greater than one-third of the total votes.
36 | *
37 | * @param array array of votes
38 | * @return an array of major numbers
39 | * {@code array}
40 | */
41 | int[] find_majority(int[] array) {
42 | int[int] counter = new int[int];
43 |
44 | foreach(int num; array) {
45 | if (num in counter) {
46 | counter[num]++;
47 | } else {
48 | counter[num] = 1;
49 | }
50 | }
51 |
52 | int[] result = [];
53 | foreach(key, value; counter) {
54 | if (value > array.length / 3) result ~= key;
55 | }
56 |
57 | sort(result); // The answer should be returned in an increasing format.
58 | return result;
59 | }
60 |
61 | unittest {
62 | assert(find_majority([2, 1, 5, 5, 5, 5, 6, 6, 6, 6, 6]) == [5, 6]);
63 | assert(find_majority([1, 2, 3, 4, 5]) == []);
64 | assert(find_majority([1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 6, 6, 6, 7, 8]) == [2]);
65 | assert(find_majority([1]) == [1]);
66 | assert(find_majority([1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]) == []);
67 | }
68 |
69 | // Program tests are performed above in the unittest block
70 | int main(){
71 | return 0;
72 | }
--------------------------------------------------------------------------------
/src/problems/codewars/human_readable_duration_format.d:
--------------------------------------------------------------------------------
1 | import std;
2 | import std.conv;
3 |
4 | /*
5 | * Link: https://www.codewars.com/kata/52742f58faf5485cae000b9a
6 | *
7 | * Human readable duration format
8 | * Difficulty: 4 kyu
9 | *
10 | * Problem:
11 | * Your task in order to complete this Kata is to write a function which formats a duration, given as a number of seconds, in a human-friendly way.
12 | *
13 | * The function must accept a non-negative integer. If it is zero, it just returns `"now"`.
14 | * Otherwise, the duration is expressed as a combination of `years`, `days`, `hours`, `minutes` and `seconds`.
15 | *
16 | * It is much easier to understand with an example:
17 | *
18 | * For seconds = 62, your function should return
19 | * "1 minute and 2 seconds"
20 | * For seconds = 3662, your function should return
21 | * "1 hour, 1 minute and 2 seconds"
22 | *
23 | * For the purpose of this Kata, a year is 365 days and a day is 24 hours.
24 | *
25 | * Note that spaces are important.
26 | *
27 | * Detailed rules
28 | *
29 | * The resulting expression is made of components like `4 seconds`, `1 year`, etc.
30 | * In general, a positive integer and one of the valid units of time, separated by a space.
31 | * The unit of time is used in plural if the integer is greater than 1.
32 | *
33 | * The components are separated by a comma and a space (`", "`).
34 | * Except the last component, which is separated by `" and "`, just like it would be written in English.
35 | *
36 | * A more significant units of time will occur before than a least significant one.
37 | * Therefore, `1 second and 1 year` is not correct, but `1 year and 1 second` is.
38 | *
39 | * Different components have different unit of times.
40 | * So there is not repeated units like in `5 seconds and 1 second`.
41 | *
42 | * A component will not appear at all if its value happens to be zero.
43 | * Hence, `1 minute and 0 seconds` is not valid, but it should be just `1 minute`.
44 | *
45 | * A unit of time must be used "as much as possible".
46 | * It means that the function should not return `61 seconds`, but `1 minute and 1 second` instead.
47 | * Formally, the duration specified by of a component must not be greater than any valid more significant unit of time.
48 | *
49 | * Tags: Strings, Date Time, Algorithms
50 | *
51 | */
52 |
53 | enum TimeUnit {
54 | Years,
55 | Days,
56 | Hours,
57 | Minutes,
58 | Seconds
59 | }
60 |
61 | struct Time {
62 | TimeUnit unit;
63 | uint amount;
64 |
65 | /*
66 | * Converts struct for example to "3 seconds"
67 | */
68 | string toString() const {
69 | return amount.to!string ~ ' ' ~ getUnitName(this);
70 | }
71 | }
72 |
73 | /*
74 | * Gives name of unit in plural or singular form depend
75 | */
76 | string getUnitName(Time unit) {
77 | switch (unit.unit) {
78 | case TimeUnit.Years:
79 | return (unit.amount > 1) ? "years" : "year";
80 | case TimeUnit.Days:
81 | return (unit.amount > 1) ? "days" : "day";
82 | case TimeUnit.Hours:
83 | return (unit.amount > 1) ? "hours" : "hour";
84 | case TimeUnit.Minutes:
85 | return (unit.amount > 1) ? "minutes" : "minute";
86 | case TimeUnit.Seconds:
87 | return (unit.amount > 1) ? "seconds" : "second";
88 | default:
89 | return "Why do you read this? :^)";
90 | }
91 | }
92 |
93 | /*
94 | * Converts seconds to list of units
95 | */
96 | Time[] calculate(uint seconds) {
97 | Time[] time = [];
98 |
99 | uint a = seconds / (365*24*60*60);
100 | if (a != 0) {
101 | time ~= Time(TimeUnit.Years, a);
102 | seconds %= 365*24*60*60;
103 | }
104 | a = seconds / (24*60*60);
105 | if (a != 0) {
106 | time ~= Time(TimeUnit.Days, a);
107 | seconds %= 24*60*60;
108 | }
109 | a = seconds / (60*60);
110 | if (a != 0) {
111 | time ~= Time(TimeUnit.Hours, a);
112 | seconds %= 60*60;
113 | }
114 | a = seconds / 60;
115 | if (a != 0) {
116 | time ~= Time(TimeUnit.Minutes, a);
117 | seconds %= 60;
118 | }
119 | if (seconds != 0) {
120 | time ~= Time(TimeUnit.Seconds, seconds);
121 | }
122 | return time;
123 |
124 | }
125 |
126 | string formatDuration(uint seconds) {
127 | if (seconds == 0) return "now";
128 |
129 | Time[] time = calculate(seconds);
130 |
131 | if (time.length == 1) {
132 | return time[0].to!string;
133 | }
134 |
135 | string result;
136 | for (int i = 0; i < time.length; i++) {
137 | result ~= time[i].to!string;
138 | if (i == time.length - 1) break;
139 | if (i == time.length - 2) result ~= " and ";
140 | else result ~= ", ";
141 | }
142 | return result;
143 | }
144 |
145 | unittest {
146 | assert(formatDuration(0) == "now");
147 | assert(formatDuration(1) == "1 second");
148 | assert(formatDuration(62) == "1 minute and 2 seconds");
149 | assert(formatDuration(120) == "2 minutes");
150 | assert(formatDuration(3600) == "1 hour");
151 | assert(formatDuration(3662) == "1 hour, 1 minute and 2 seconds");
152 | }
153 |
154 | void main() {}
--------------------------------------------------------------------------------
/src/data_structures/binary_heap.d:
--------------------------------------------------------------------------------
1 | import std.stdio;
2 | import std.algorithm : swap;
3 |
4 | /**
5 | * Implementation of a Min Heap (Minimum Priority Queue) data structure.
6 | * A Min Heap is a complete binary tree where the value of each node is
7 | * less than or equal to the values of its children.
8 | */
9 | class MinHeap {
10 | private int[] harr; // Array to store heap elements
11 | private int capacity; // Maximum capacity of the heap
12 | private int heap_size; // Current number of elements in the heap
13 |
14 | /**
15 | * Constructs a new MinHeap with the specified capacity.
16 | *
17 | * @param cap the maximum number of elements the heap can hold
18 | */
19 | this(int cap) {
20 | heap_size = 0;
21 | capacity = cap;
22 | harr = new int[cap];
23 | }
24 |
25 | /**
26 | * Recursively heapifies a subtree rooted at index i to maintain the min-heap property.
27 | *
28 | * @param i the index of the root node of the subtree to heapify
29 | */
30 | void minHeapify(int i) {
31 | int l = left(i); // Index of left child
32 | int r = right(i); // Index of right child
33 | int smallest = i; // Assume current node is the smallest
34 |
35 | // Compare with left child
36 | if (l < heap_size && harr[l] < harr[i])
37 | smallest = l;
38 | // Compare with right child
39 | if (r < heap_size && harr[r] < harr[smallest])
40 | smallest = r;
41 | // If smallest is not the current node, swap and continue heapifying
42 | if (smallest != i) {
43 | swap(harr[i], harr[smallest]);
44 | minHeapify(smallest);
45 | }
46 | }
47 |
48 | /**
49 | * Returns the index of the parent node for a given index.
50 | *
51 | * @param i the index of the child node
52 | * @return the index of the parent node
53 | */
54 | int parent(int i) { return (i - 1) / 2; }
55 |
56 | /**
57 | * Returns the index of the left child for a given index.
58 | *
59 | * @param i the index of the parent node
60 | * @return the index of the left child node
61 | */
62 | int left(int i) { return (2 * i + 1); }
63 |
64 | /**
65 | * Returns the index of the right child for a given index.
66 | *
67 | * @param i the index of the parent node
68 | * @return the index of the right child node
69 | */
70 | int right(int i) { return (2 * i + 2); }
71 |
72 | /**
73 | * Removes and returns the minimum element (root) from the heap.
74 | * Maintains the heap property after removal.
75 | *
76 | * @return the minimum element in the heap, or int.max if heap is empty
77 | */
78 | int extractMin() {
79 | if (heap_size <= 0)
80 | return int.max;
81 | if (heap_size == 1) {
82 | heap_size--;
83 | return harr[0];
84 | }
85 |
86 | int root = harr[0]; // Store the root value
87 | harr[0] = harr[heap_size - 1]; // Move last element to root
88 | heap_size--;
89 | minHeapify(0); // Heapify from the root
90 |
91 | return root;
92 | }
93 |
94 | /**
95 | * Decreases the value of a key at the specified index to a new value.
96 | * Adjusts the heap to maintain the min-heap property.
97 | *
98 | * @param i the index of the key to decrease
99 | * @param new_val the new value for the key (must be smaller than current value)
100 | */
101 | void decreaseKey(int i, int new_val) {
102 | harr[i] = new_val;
103 | // Bubble up the decreased key to maintain heap property
104 | while (i != 0 && harr[parent(i)] > harr[i]) {
105 | swap(harr[i], harr[parent(i)]);
106 | i = parent(i);
107 | }
108 | }
109 |
110 | /**
111 | * Returns the minimum element from the heap without removing it.
112 | *
113 | * @return the minimum element in the heap (root element)
114 | */
115 | int getMin() { return harr[0]; }
116 |
117 | /**
118 | * Deletes a key at the specified index from the heap.
119 | *
120 | * @param i the index of the key to delete
121 | */
122 | void deleteKey(int i) {
123 | decreaseKey(i, int.min); // Decrease key to minimum value
124 | extractMin(); // Extract the now-minimum key
125 | }
126 |
127 | /**
128 | * Inserts a new key into the heap.
129 | * Maintains the heap property after insertion.
130 | *
131 | * @param k the key value to insert
132 | */
133 | void insertKey(int k) {
134 | if (heap_size == capacity) {
135 | writeln("\nOverflow: Could not insertKey");
136 | return;
137 | }
138 |
139 | heap_size++;
140 | int i = heap_size - 1;
141 | harr[i] = k;
142 |
143 | // Bubble up the new key to maintain heap property
144 | while (i != 0 && harr[parent(i)] > harr[i]) {
145 | swap(harr[i], harr[parent(i)]);
146 | i = parent(i);
147 | }
148 | }
149 | }
150 |
151 | /**
152 | TESTS
153 | */
154 | unittest {
155 | // Test basic insertion and extraction in order
156 | auto h = new MinHeap(11);
157 | h.insertKey(3);
158 | h.insertKey(2);
159 | h.insertKey(1);
160 | assert(h.extractMin() == 1);
161 | assert(h.extractMin() == 2);
162 | assert(h.extractMin() == 3);
163 | assert(h.extractMin() == int.max); // Test empty heap extraction
164 |
165 | }
166 |
167 | /**
168 | * Program tests are performed above in the unittest block.
169 | * The main function is empty as tests are run automatically.
170 | */
171 | void main() {}
172 |
--------------------------------------------------------------------------------
/src/math/math_parser.d:
--------------------------------------------------------------------------------
1 | import std;
2 |
3 | /**
4 | * The Parser class is responsible for parsing and evaluating mathematical expressions.
5 | */
6 | class Parser {
7 | private string input; // The input string containing the expression to parse.
8 | private int pos; // The current position in the input string.
9 |
10 | /**
11 | * Constructs a Parser with the given input string.
12 | *
13 | * @param input The string representation of the mathematical expression.
14 | */
15 | this(string input) {
16 | this.input = input;
17 | this.pos = 0; // Initialize position to the start of the input.
18 | }
19 |
20 | /**
21 | * Peeks at the next character in the input without consuming it.
22 | *
23 | * @return The next character or '0' if the end of the input is reached.
24 | */
25 | private char peek() {
26 | if (pos < input.length) {
27 | return input[pos]; // Return the current character at position pos.
28 | }
29 | return '0'; // Return '0' if we are at the end of the input.
30 | }
31 |
32 | /**
33 | * Consumes and returns the next character in the input.
34 | *
35 | * @return The next character or '0' if the end of the input is reached.
36 | */
37 | private char next() {
38 | if (pos < input.length) {
39 | return input[pos++]; // Return the current character and increment position.
40 | }
41 | return '0'; // Return '0' if we are at the end of the input.
42 | }
43 |
44 | /**
45 | * Skips whitespace characters in the input.
46 | */
47 | private void skipWhitespace() {
48 | // Continue skipping while there are characters left and they are whitespace.
49 | while (pos < input.length && (peek == ' ' || peek == 't')) {
50 | next(); // Consume whitespace characters.
51 | }
52 | }
53 |
54 | /**
55 | * Parses an expression, which may consist of terms combined by '+' or '-'.
56 | *
57 | * @return The result of evaluating the expression as a double.
58 | */
59 | double parseExpr() {
60 | double result = parseTerm(); // Start with the first term.
61 | while (true) {
62 | skipWhitespace(); // Skip any whitespace before the operator.
63 | char op = peek(); // Peek at the next character (operator).
64 | if (op == '+' || op == '-') { // Check for addition or subtraction.
65 | next(); // Consume the operator.
66 | double rhs = parseTerm(); // Parse the right-hand side term.
67 | if (op == '+') {
68 | result += rhs; // Add to result if operator is '+'.
69 | } else {
70 | result -= rhs; // Subtract from result if operator is '-'.
71 | }
72 | } else {
73 | break; // Exit loop if no more '+' or '-' operators are found.
74 | }
75 | }
76 | return result; // Return the final evaluated result.
77 | }
78 |
79 | /**
80 | * Parses a term, which may consist of factors combined by '*' or '/'.
81 | *
82 | * @return The result of evaluating the term as a double.
83 | */
84 | double parseTerm() {
85 | double result = parseFactor(); // Start with the first factor.
86 | while (true) {
87 | skipWhitespace(); // Skip any whitespace before the operator.
88 | char op = peek(); // Peek at the next character (operator).
89 | if (op == '*' || op == '/') { // Check for multiplication or division.
90 | next(); // Consume the operator.
91 | double rhs = parseFactor(); // Parse the right-hand side factor.
92 | if (op == '*') {
93 | result *= rhs; // Multiply result if operator is '*'.
94 | } else {
95 | result /= rhs; // Divide result if operator is '/'.
96 | }
97 | } else {
98 | break; // Exit loop if no more '*' or '/' operators are found.
99 | }
100 | }
101 | return result; // Return the final evaluated term result.
102 | }
103 |
104 | /**
105 | * Parses a factor, which may be a number or a nested expression in parentheses.
106 | *
107 | * @return The result of evaluating the factor as a double.
108 | */
109 | double parseFactor() {
110 | skipWhitespace(); // Skip any whitespace before processing factor.
111 | if (peek() == '(') { // Check for opening parenthesis indicating a nested expression.
112 | next(); // Consume the '(' character.
113 | double result = parseExpr(); // Parse the nested expression.
114 | next(); // Consume the closing ')' character.
115 | return result; // Return the evaluated result of the nested expression.
116 | } else {
117 | return parseNumber(); // Otherwise, parse a number directly.
118 | }
119 | }
120 |
121 | /**
122 | * Parses a number from the input string.
123 | *
124 | * @return The parsed number as a double.
125 | */
126 | double parseNumber() {
127 | skipWhitespace(); // Skip any whitespace before processing number.
128 | size_t start = pos; // Mark the start position of the number.
129 | while (pos < input.length && (isDigit(peek()) || peek == '.')) {
130 | next(); // Consume digits or decimal point to form a number.
131 | }
132 | return to!double(input[start..pos]); // Convert and return the substring as a double.
133 | }
134 | }
135 |
136 | /* TESTS */
137 | double testExpr(string expr){
138 | Parser parser = new Parser(expr);
139 | return parser.parseExpr();
140 | }
141 |
142 | unittest{
143 |
144 | assert(testExpr("2+4") == 6);
145 | assert(testExpr("3 + (67 - 17)") == 53);
146 | assert(testExpr("2 * 3 * 4 + (2 * 4)") == 32);
147 | }
148 |
149 | /*Program tests are performed above in the unittest block*/
150 | int main() {
151 | return 0;
152 | }
153 |
--------------------------------------------------------------------------------
/src/problems/codewars/screen_locking_patterns.d:
--------------------------------------------------------------------------------
1 | import std;
2 | import std.algorithm : filter, map;
3 | import std.array : array;
4 | import std.conv : to;
5 |
6 | /*
7 | * Link: https://www.codewars.com/kata/585894545a8a07255e0002f1
8 | *
9 | * Screen Locking Patterns
10 | * Difficulty: 3 kyu
11 | *
12 | * Problem:
13 | *
14 | * You might already be familiar with many smartphones that allow you to use a geometric pattern as a security measure.
15 | * To unlock the device, you need to connect a sequence of dots/points in a grid by swiping your finger without lifting it as you trace the pattern through the screen.
16 | *
17 | * The image below has an example pattern of 7 dots/points: (A -> B -> I -> E -> D -> G -> C).
18 | *
19 | * IMAGE (https://i.imgur.com/zmPNYdv.png)
20 | *
21 | * For this kata, your job is to implement a function that returns the number of possible patterns starting from a given first point, that have a given length.
22 | *
23 | * More specifically, for a function `count_patterns_from(first_point, length)`, the parameter `first_point` is a single-character string corresponding to the point in the grid (e.g.: `'A'`) where your patterns start, and the parameter `length` is an integer indicating the number of points (length) every pattern must have.
24 | *
25 | * For example, `countPatternsFrom("C", 2)`, should return the number of patterns starting from `'C'` that have `2` two points.
26 | * The return value in this case would be `5`, because there are 5 possible patterns:
27 | *
28 | * (C -> B), (C -> D), (C -> E), (C -> F) and (C -> H).
29 | *
30 | * Bear in mind that this kata requires returning the number of patterns, not the patterns themselves, so you only need to count them.
31 | * Also, the name of the function might be different depending on the programming language used, but the idea remains the same.
32 | *
33 | * Rules
34 | * 1) In a pattern, the dots/points cannot be repeated: they can only be used once, at most.
35 | * 2) In a pattern, any two subsequent dots/points can only be connected with direct straight lines in either of these ways:
36 | * 3) Horizontally: like (A -> B) in the example pattern image.
37 | * 4) Vertically: like (D -> G) in the example pattern image.
38 | * 5) Diagonally: like (I -> E), as well as (B -> I), in the example pattern image.
39 | * 6) Passing over a point between them that has already been 'used': like (G -> C) passing over E, in the example pattern image.
40 | * This is the trickiest rule.
41 | * Normally, you wouldn't be able to connect G to C, because E is between them, however when E has already been used as part the pattern you are tracing, you can connect G to C passing over E, because E is ignored, as it was already used once.
42 | *
43 | * The sample tests have some examples of the number of combinations for some cases to help you check your code.
44 | *
45 | * Fun fact:
46 | *
47 | * In case you're wondering out of curiosity, for the Android lock screen, the valid patterns must have between 4 and 9 dots/points.
48 | * There are 389112 possible valid patterns in total; that is, patterns with a length between 4 and 9 dots/points.
49 | *
50 | * Tags: Mathematics, Combinatorics, Geometry, Algorithms, Graph Theory
51 | *
52 | */
53 |
54 | char[] get_next_possible_dots(char dot, char[] used) {
55 | char[] possible;
56 | switch (dot) {
57 | case 'A':
58 | possible = ['B', 'D', 'E', 'F', 'H'];
59 | break;
60 | case 'B':
61 | possible = ['A', 'C', 'D', 'E', 'F', 'G', 'I'];
62 | break;
63 | case 'C':
64 | possible = ['B', 'D', 'E', 'F', 'H'];
65 | break;
66 | case 'D':
67 | possible = ['A', 'B', 'C', 'E', 'G', 'H', 'I'];
68 | break;
69 | case 'E':
70 | possible = ['A', 'B', 'C', 'D', 'F', 'G', 'H', 'I'];
71 | break;
72 | case 'F':
73 | possible = ['A', 'B', 'C', 'E', 'G', 'H', 'I'];
74 | break;
75 | case 'G':
76 | possible = ['B', 'D', 'E', 'F', 'H'];
77 | break;
78 | case 'H':
79 | possible = ['A', 'C', 'D', 'E', 'F', 'G', 'I'];
80 | break;
81 | case 'I':
82 | possible = ['B', 'D', 'E', 'F', 'H'];
83 | break;
84 | default: return [];
85 | }
86 |
87 | switch (dot) {
88 | case 'A':
89 | if (used.canFind('B')) possible ~= 'C';
90 | if (used.canFind('D')) possible ~= 'G';
91 | if (used.canFind('E')) possible ~= 'I';
92 | break;
93 | case 'C':
94 | if (used.canFind('B')) possible ~= 'A';
95 | if (used.canFind('E')) possible ~= 'G';
96 | if (used.canFind('F')) possible ~= 'I';
97 | break;
98 | case 'G':
99 | if (used.canFind('D')) possible ~= 'A';
100 | if (used.canFind('E')) possible ~= 'C';
101 | if (used.canFind('H')) possible ~= 'I';
102 | break;
103 | case 'I':
104 | if (used.canFind('E')) possible ~= 'A';
105 | if (used.canFind('F')) possible ~= 'C';
106 | if (used.canFind('H')) possible ~= 'G';
107 | break;
108 | case 'B':
109 | if (used.canFind('E')) possible ~= 'H';
110 | break;
111 | case 'D':
112 | if (used.canFind('E')) possible ~= 'F';
113 | break;
114 | case 'F':
115 | if (used.canFind('E')) possible ~= 'D';
116 | break;
117 | case 'H':
118 | if (used.canFind('E')) possible ~= 'B';
119 | break;
120 | default: break;
121 | }
122 | return possible.filter!(x => !used.canFind(x)).map!(c => to!char(c)).array;
123 | }
124 |
125 | uint count_patterns(char current, uint remaining_length, char[] used) {
126 | if (remaining_length == 1) return 1;
127 |
128 | uint count = 0;
129 |
130 | char[] next_dots = get_next_possible_dots(current, used);
131 |
132 | foreach (next_dot; next_dots) {
133 | count += count_patterns(next_dot, remaining_length - 1, used ~ next_dot);
134 | }
135 |
136 | return count;
137 | }
138 |
139 | uint count_patterns_from(char first_point, uint length) {
140 | if (length > 9 || length == 0) return 0;
141 | if (length == 1) return 1;
142 |
143 | return count_patterns(first_point, length, [first_point]);
144 | }
145 |
146 | unittest {
147 | assert(count_patterns_from('A', 0) == 0);
148 | assert(count_patterns_from('A', 10) == 0);
149 | assert(count_patterns_from('B', 1) == 1);
150 | assert(count_patterns_from('C', 2) == 5);
151 | assert(count_patterns_from('D', 3) == 37);
152 | assert(count_patterns_from('E', 4) == 256);
153 | assert(count_patterns_from('E', 8) == 23280);
154 | }
155 |
156 | void main() {}
--------------------------------------------------------------------------------